simplify MemReadEngine a bit

simplify MemReadEngine a bit

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

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

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

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

module mkMemReadEngine(MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(busWidth, 8), 8, busWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(busWidth, 0, userWidth)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(d__, TLog#(numServers), 6)
	    );
   let rv <- mkMemReadEngineBuff(valueOf(cmdQDepth) * valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemReadEngineBuff#(Integer bufferSizeBytes) (MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos (Div#(busWidth,8,busWidthBytes),
	     Mul#(busWidthBytes,8,busWidth),
	     Log#(busWidthBytes,beatShift),
	     Log#(cmdQDepth,logCmdQDepth),
	     Mul#(cmdQDepth,numServers,cmdBuffSz),
	     Log#(cmdBuffSz, cmdBuffAddrSz),
	     Log#(numServers, serverIdxSz),
	     Add#(busWidth, 0, userWidth),
	     Add#(1,logCmdQDepth, outCntSz),
	     Add#(1, c__, numServers),
	     Add#(b__, TLog#(numServers), cmdBuffAddrSz),
	     Add#(e__, TLog#(numServers), TAdd#(1, cmdBuffAddrSz)),
	     Add#(a__, serverIdxSz, cmdBuffAddrSz),
	     Min#(2,TLog#(numServers),bpc),
	     Add#(d__, TLog#(numServers), TAdd#(1, serverIdxSz)),
	     Add#(f__, serverIdxSz, 6));

   let verbose = False;

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Vector#(numServers, Reg#(Bool))          clientInFlight <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))  clientAvail <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))  clientCommand <- replicateM(mkReg(unpack(0)));
   Vector#(numServers, FIFOF#(MemDataF#(userWidth))) clientDataFifo <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   Vector#(numServers, FIFO#(MemengineCmd)) clientRequest <- replicateM(mkFIFO());

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple4#(MemengineCmd,Bool,Bool,Bit#(BurstLenSize)))              serverCheckAvail <- mkSizedFIFO(1);
   FIFO#(Tuple4#(Bit#(serverIdxSz),MemengineCmd,Bool,Bit#(BurstLenSize))) serverRequest <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(serverIdxSz),Bool)) serverProcessing <- mkSizedFIFO(valueOf(cmdQDepth));

   FIFOF#(MemData#(busWidth))                       serverDataFifo <- mkFIFOF;

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   Reg#(Bit#(TAdd#(1,serverIdxSz))) loadIdx <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   let cmd_q_depth = fromInteger(valueOf(cmdQDepth));
   Reg#(Bit#(32)) counter <- mkReg(0);

   rule incCounter;
      counter <= counter + 1;
   endrule

   function Action incr_loadIdx =
      (action
       if(loadIdx+1 >= fromInteger(valueOf(numServers)))
	  loadIdx <= 0;
       else
	  loadIdx <= loadIdx+1;
       endaction);

   for (Integer idx = 0; idx < valueOf(numServers); idx = idx + 1)
      rule store_cmd if (!clientInFlight[idx]);
	 let cmd <- toGet(clientRequest[idx]).get();
	 clientInFlight[idx] <= True;
	 clientCommand[idx] <= cmd;
	 if (verbose) $display("mkMemReadEngineBuff::%d store_cmd %d %d", counter, idx, clientAvail[idx].read);
      endrule

   rule load_ctxt_a (!load_in_progress);
      if (clientInFlight[loadIdx]) begin
	 load_in_progress <= True;
	 let cmd = clientCommand[loadIdx];
         let last_burst = cmd.len <= extend(cmd.burstLen);
         Bit#(BurstLenSize) cmd_len = cmd.burstLen;
	 if (last_burst)
             cmd_len = truncate(cmd.len);
	 let cond0 <- clientAvail[loadIdx].maybeDecrement(unpack(extend(cmd_len>>beat_shift)));
	 serverCheckAvail.enq(tuple4(cmd,cond0,last_burst,cmd_len));
	 if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b clientAvail[%d] %d burstLen %d cond0 %d last_burst %d", counter, loadIdx, clientAvail[loadIdx].read(), cmd_len>>beat_shift, cond0, last_burst);
      end
      else begin
	 incr_loadIdx;
      end
   endrule

   // should use an EHR for clientInFlight to avoid the need for this pragma
   (* descending_urgency = "load_ctxt_c, store_cmd" *)
   rule load_ctxt_c if (load_in_progress);
      load_in_progress <= False;
      incr_loadIdx;
      match {.cmd,.cond0,.last_burst,.cmd_len} <- toGet(serverCheckAvail).get;
      if  (cond0) begin
	 if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_c cmd.len %d idx %d cond0 %d last_burst %d", counter, cmd.len, loadIdx, cond0, last_burst);
	 serverRequest.enq(tuple4(truncate(loadIdx),cmd,last_burst,cmd_len));
	 if (last_burst) begin
	    if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b last_burst %d", counter, last_burst);
	    clientInFlight[loadIdx] <= False;
	 end
	 else begin
	    clientCommand[loadIdx] <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
	       burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule read_data_rule;
      let d <- toGet(serverDataFifo).get();
      match {.rc, .idx, .last_burst} = serverProcessing.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("mkMemReadEngineBuff::%d data %h new_respCnt %d rc %d last_burst %d idx %d clientInFlight %d eob %d", counter, d.data, new_respCnt, rc, last_burst, idx, clientInFlight[idx], d.last);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 serverProcessing.deq;
	 //$display("eob %d", idx);
	 l = last_burst;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      clientDataFifo[idx].enq(MemDataF { data: d.data, tag: d.tag, first: (respCnt == 0), last: l});
   endrule

   Vector#(numServers, MemReadEngineServer#(userWidth)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface MemReadEngineServer#(userWidth);
		  interface Put request;
		     method Action put(MemengineCmd cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef SIMULATION
			Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
			let mdw = ((cmd.len)/dw)*dw != cmd.len;
			let bbl = extend(cmd.burstLen) > bsb;
			if(bbl || mdw) begin
			   if (bbl)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
			   if (mdw)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported len %d", cmd.len);
			end
			else
`endif
                           begin
			   clientRequest[i].enq(cmd);
			   end
 		     endmethod
		  endinterface
                  interface data = interface PipeOut;
	             method MemDataF#(userWidth) first;
	                return clientDataFifo[i].first;
	             endmethod
	             method Action deq;
	                if (verbose) $display("mkMemReadEngineBuff::check_out: idx %d data %h clientAvail %d eob %d", i, clientDataFifo[i].first.data, clientAvail[i].read(), clientDataFifo[i].first.last);
	                clientDataFifo[i].deq;
	                clientAvail[i].increment(1);
	             endmethod
	             method Bool notEmpty = clientDataFifo[i].notEmpty;
                  endinterface;
               endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd, .last_burst, .bl} <- toGet(serverRequest).get;
	    serverProcessing.enq(tuple3(truncate(bl>>beat_shift), idx, last_burst));
	    if (verbose) $display("MemReadEngine::%d readReq idx %d offset %h burstLenBytes %h last_burst %d", counter, idx, cmd.base, bl, last_burst);
	    return MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: (cmd.tag << valueOf(serverIdxSz)) | extend(idx)
`ifdef BYTE_ENABLES
			       , firstbe: maxBound, lastbe: maxBound
`endif
};
	 endmethod
      endinterface
      interface Put readData = toPut(serverDataFifo);
   endinterface
endmodule

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

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

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

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

module mkMemReadEngine(MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(busWidth, 8), 8, busWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(busWidth, 0, userWidth)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(d__, TLog#(numServers), 6)
	    );
   let rv <- mkMemReadEngineBuff(valueOf(cmdQDepth) * valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemReadEngineBuff#(Integer bufferSizeBytes) (MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos (Div#(busWidth,8,busWidthBytes),
	     Mul#(busWidthBytes,8,busWidth),
	     Log#(busWidthBytes,beatShift),
	     Log#(cmdQDepth,logCmdQDepth),
	     Mul#(cmdQDepth,numServers,cmdBuffSz),
	     Log#(cmdBuffSz, cmdBuffAddrSz),
	     Log#(numServers, serverIdxSz),
	     Add#(busWidth, 0, userWidth),
	     Add#(1,logCmdQDepth, outCntSz),
	     Add#(1, c__, numServers),
	     Add#(b__, TLog#(numServers), cmdBuffAddrSz),
	     Add#(e__, TLog#(numServers), TAdd#(1, cmdBuffAddrSz)),
	     Add#(a__, serverIdxSz, cmdBuffAddrSz),
	     Min#(2,TLog#(numServers),bpc),
	     Add#(d__, TLog#(numServers), TAdd#(1, serverIdxSz)),
	     Add#(f__, serverIdxSz, 6));

   let verbose = False;

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Vector#(numServers, Reg#(Bool))          clientInFlight <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))  clientAvail <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))  clientCommand <- replicateM(mkReg(unpack(0)));
   Vector#(numServers, Reg#(Bool))          clientFirstBurst <- replicateM(mkReg(False));

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple5#(MemengineCmd,Bool,Bool,Bool,Bit#(BurstLenSize)))              serverCheckAvail <- mkSizedFIFO(1);
   FIFO#(Tuple5#(Bit#(serverIdxSz),MemengineCmd,Bool,Bool,Bit#(BurstLenSize))) serverRequest <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple4#(Bit#(8),Bit#(serverIdxSz),Bool,Bool)) serverProcessing <- mkSizedFIFO(valueOf(cmdQDepth));

   Vector#(numServers, FIFO#(MemengineCmd)) clientRequest <- replicateM(mkFIFO());

   FIFOF#(MemData#(busWidth))                       serverDataFifo <- mkFIFOF;
   Vector#(numServers, FIFOF#(MemDataF#(userWidth))) clientDataFifo <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   function PipeOut#(MemDataF#(userWidth)) mem_data_out(PipeOut#(MemDataF#(userWidth)) inpipe, Integer i) =
      (interface PipeOut;
	  method MemDataF#(userWidth) first;
	     return inpipe.first;
	  endmethod
	  method Action deq;
	     if (verbose) $display("mkMemReadEngineBuff::check_out: idx %d data %h clientAvail %d eob %d", i, inpipe.first.data, clientAvail[i].read(), inpipe.first.last);
	     inpipe.deq;
	     clientAvail[i].increment(1);
	  endmethod
	  method Bool notEmpty = inpipe.notEmpty;
       endinterface);
   Vector#(numServers, PipeOut#(MemDataF#(userWidth))) memDataPipes = zipWith(mem_data_out, map(toPipeOut,clientDataFifo), genVector);

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   Reg#(Bit#(TAdd#(1,serverIdxSz))) loadIdx <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   let cmd_q_depth = fromInteger(valueOf(cmdQDepth));
   Reg#(Bit#(32)) counter <- mkReg(0);

   rule incCounter;
      counter <= counter + 1;
   endrule

   function Action incr_loadIdx =
      (action
       if(loadIdx+1 >= fromInteger(valueOf(numServers)))
	  loadIdx <= 0;
       else
	  loadIdx <= loadIdx+1;
       endaction);

   for (Integer idx = 0; idx < valueOf(numServers); idx = idx + 1)
      rule store_cmd if (!clientInFlight[idx]);
	 let cmd <- toGet(clientRequest[idx]).get();
	 clientInFlight[idx] <= True;
	 clientCommand[idx] <= cmd;
	 clientFirstBurst[idx] <= True;
	 if (verbose) $display("mkMemReadEngineBuff::%d store_cmd %d %d", counter, idx, clientAvail[idx].read);
      endrule

   rule load_ctxt_a (!load_in_progress);
      if (clientInFlight[loadIdx]) begin
	 load_in_progress <= True;
	 let cmd = clientCommand[loadIdx];
	 let first_burst = clientFirstBurst[loadIdx];
         let last_burst = cmd.len <= extend(cmd.burstLen);
         Bit#(BurstLenSize) cmd_len = cmd.burstLen;
	 if (last_burst)
             cmd_len = truncate(cmd.len);
	 let cond0 <- clientAvail[loadIdx].maybeDecrement(unpack(extend(cmd_len>>beat_shift)));
	 serverCheckAvail.enq(tuple5(cmd,cond0,first_burst,last_burst,cmd_len));
	 if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b clientAvail[%d] %d burstLen %d cond0 %d last_burst %d", counter, loadIdx, clientAvail[loadIdx].read(), cmd_len>>beat_shift, cond0, last_burst);
      end
      else begin
	 incr_loadIdx;
      end
   endrule

   // should use an EHR for clientInFlight to avoid the need for this pragma
   (* descending_urgency = "load_ctxt_c, store_cmd" *)
   rule load_ctxt_c if (load_in_progress);
      load_in_progress <= False;
      incr_loadIdx;
      match {.cmd,.cond0,.first_burst,.last_burst,.cmd_len} <- toGet(serverCheckAvail).get;
      if  (cond0) begin
	 if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_c cmd.len %d idx %d cond0 %d last_burst %d", counter, cmd.len, loadIdx, cond0, last_burst);
	 serverRequest.enq(tuple5(truncate(loadIdx),cmd,first_burst,last_burst,cmd_len));
	 clientFirstBurst[loadIdx] <= False;
	 if (last_burst) begin
	    if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b last_burst %d", counter, last_burst);
	    clientInFlight[loadIdx] <= False;
	 end
	 else begin
	    clientCommand[loadIdx] <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
	       burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule read_data_rule;
      let d <- toGet(serverDataFifo).get();
      match {.rc, .idx, .first_burst, .last_burst} = serverProcessing.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("mkMemReadEngineBuff::%d data %h new_respCnt %d rc %d last_burst %d idx %d clientInFlight %d eob %d", counter, d.data, new_respCnt, rc, last_burst, idx, clientInFlight[idx], d.last);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 serverProcessing.deq;
	 //$display("eob %d", idx);
	 l = last_burst;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      clientDataFifo[idx].enq(MemDataF { data: d.data, tag: d.tag,
         first: //first_burst &&
(respCnt == 0), last: l});
   endrule

   Vector#(numServers, MemReadEngineServer#(userWidth)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface MemReadEngineServer#(userWidth);
		  interface Put request;
		     method Action put(MemengineCmd cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef SIMULATION
			Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
			let mdw = ((cmd.len)/dw)*dw != cmd.len;
			let bbl = extend(cmd.burstLen) > bsb;
			if(bbl || mdw) begin
			   if (bbl)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
			   if (mdw)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported len %d", cmd.len);
			end
			else
`endif
                           begin
			   clientRequest[i].enq(cmd);
			   end
 		     endmethod
		  endinterface
                  interface data = memDataPipes[i];
               endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd, .first_burst, .last_burst, .bl} <- toGet(serverRequest).get;
	    serverProcessing.enq(tuple4(truncate(bl>>beat_shift), idx, first_burst, last_burst));
	    if (verbose) $display("MemReadEngine::%d readReq idx %d offset %h burstLenBytes %h last_burst %d", counter, idx, cmd.base, bl, last_burst);
	    return MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: (cmd.tag << valueOf(serverIdxSz)) | extend(idx)
`ifdef BYTE_ENABLES
			       , firstbe: maxBound, lastbe: maxBound
`endif
};
	 endmethod
      endinterface
      interface Put readData = toPut(serverDataFifo);
   endinterface
endmodule


14 bit

14 bit

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

module mkHirschA#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL)(MCSAlgorithm)
      provisos(Add#(0, 14, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(14)) aStartReg <- mkReg(0);
   Reg#(Bit#(14)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) aLenReg <- mkReg(0);
   Reg#(Bit#(14)) bLenReg <- mkReg(0);
   Reg#(Bit#(14)) rLenReg <- 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#(16)) lim1jm1 <- mkReg(0);
   Reg#(Bit#(16)) lim1j <- mkReg(0);
   Reg#(Bit#(16)) lijm1 <- mkReg(0);

   Stmt hirschA =
   seq
//      $display("hirschA running alen %d blen %d", aLenReg, bLenReg);
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii[6:0],0}, datain: 0});
	    endseq
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {0,ii[6:0]}, datain: 0});
	 endseq
      for (ii<= 1; ii <= aLenReg; ii <= ii + 1)
	 for (jj<= 1; jj <= bLenReg; jj <= jj + 1)
	    seq
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: aStartReg + ii-1, datain: 0});
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: bStartReg + jj-1, datain: 0});
	       action
		  let ta <- strA.response.get();
		  let tb <- strB.response.get();
		  aData <= ta;
		  bData <= tb;
	       endaction
	       if (aData == bData)
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii[6:0]-1,jj[6:0]-1}, datain: 0});
		     action
			let temp <- matL.response.get();
			lim1jm1 <= temp;
		     endaction
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii[6:0],jj[6:0]}, datain: lim1jm1+1});

		  endseq
	       else
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii[6:0],jj[6:0]-1}, datain: 0});
		     action
			let tlijm1 <- matL.response.get();
			lijm1 <= tlijm1;
		     endaction
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii[6:0]-1,jj[6:0]}, datain: 0});
		     action
			let tlim1j <- matL.response.get();
			lim1j <= tlim1j;
		     endaction
			matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii[6:0],jj[6:0]}, datain: max(lijm1,lim1j)});
		  endseq
	    endseq
   endseq;

   FSM hA <- mkFSM(hirschA);

   method Action setupA(Bit#(14) start, Bit#(14) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(14) start, Bit#(14) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
   endmethod

   method Bit#(14) result();
      return(zeroExtend(aLenReg) * zeroExtend(bLenReg));
   endmethod

   interface FSM fsm = hA;

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 MCSAlgorithm::*;

module mkHirschA#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL)(MCSAlgorithm)
      provisos(Add#(0, 7, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(7)) aStartReg <- mkReg(0);
   Reg#(Bit#(7)) bStartReg <- mkReg(0);
   Reg#(Bit#(7)) aLenReg <- mkReg(0);
   Reg#(Bit#(7)) bLenReg <- mkReg(0);
   Reg#(Bit#(14)) rLenReg <- mkReg(0);
   Reg#(Bit#(7)) ii <- mkReg(0);
   Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) lim1jm1 <- mkReg(0);
   Reg#(Bit#(16)) lim1j <- mkReg(0);
   Reg#(Bit#(16)) lijm1 <- mkReg(0);

   Stmt hirschA =
   seq
//      $display("hirschA running alen %d blen %d", aLenReg, bLenReg);
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,0}, datain: 0});
	    endseq
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {0,ii}, datain: 0});
	 endseq
      for (ii<= 1; ii <= aLenReg; ii <= ii + 1)
	 for (jj<= 1; jj <= bLenReg; jj <= jj + 1)
	    seq
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: aStartReg + ii-1, datain: 0});
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: bStartReg + jj-1, datain: 0});
	       action
		  let ta <- strA.response.get();
		  let tb <- strB.response.get();
		  aData <= ta;
		  bData <= tb;
	       endaction
	       if (aData == bData)
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii-1,jj-1}, datain: 0});
		     action
			let temp <- matL.response.get();
			lim1jm1 <= temp;
		     endaction
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,jj}, datain: lim1jm1+1});

		  endseq
	       else
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii,jj-1}, datain: 0});
		     action
			let tlijm1 <- matL.response.get();
			lijm1 <= tlijm1;
		     endaction
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii-1,jj}, datain: 0});
		     action
			let tlim1j <- matL.response.get();
			lim1j <= tlim1j;
		     endaction
			matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,jj}, datain: max(lijm1,lim1j)});
		  endseq
	    endseq
   endseq;

   FSM hA <- mkFSM(hirschA);

   method Action setupA(Bit#(7) start, Bit#(7) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(7) start, Bit#(7) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
   endmethod

   method Bit#(14) result();
      return(zeroExtend(aLenReg) * zeroExtend(bLenReg));
   endmethod

   interface FSM fsm = hA;

endmodule


export DataBusWidth and NumberOfMasters

export DataBusWidth and NumberOfMasters

Change-Id: Ia6a0d6296ac8c108eaf1e40f271ba0720017bf80

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

////////////////////////////// common /////////////////////////////////

`ifndef DataBusWidth
`define DataBusWidth 64
`endif

typedef `DataBusWidth DataBusWidth;
typedef `NumberOfMasters NumberOfMasters;

////////////////////////////// Bsim /////////////////////////////////
`ifdef BsimHostTypeIF

import Vector            :: *;
import AxiMasterSlave    :: *;
import MemTypes          :: *;

// this interface should allow for different master and slave bus paraters;
interface BsimHost#(numeric type clientAddrWidth, numeric type clientBusWidth, numeric type clientIdWidth,
		    numeric type serverAddrWidth, numeric type serverBusWidth, numeric type serverIdWidth,
		    numeric type nSlaves);
   interface MemMaster#(clientAddrWidth, clientBusWidth)  mem_client;
   interface Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))  axi_servers;
   interface Clock doubleClock;
   interface Reset doubleReset;
endinterface

typedef BsimHost#(32,32,12,40,DataBusWidth,6,NumberOfMasters) HostType;
`endif

////////////////////////////// PciE /////////////////////////////////
`ifdef PcieHostTypeIF

import Vector            :: *;
import GetPut            :: *;
import ClientServer      :: *;
import PCIE               :: *;
import PCIEWRAPPER       :: *;
import PcieCsr           :: *;
import MemTypes          :: *;
import Bscan             :: *;
`ifndef BSIM
import PcieEndpointX7    :: *;
`endif

interface PcieHost#(numeric type dsz, numeric type nSlaves);
   interface Vector#(16,ReadOnly_MSIX_Entry)     msixEntry;
   interface MemMaster#(32,32)                   master;
   interface Vector#(nSlaves,MemSlave#(40,dsz))  slave;
   interface Put#(Tuple2#(Bit#(64),Bit#(32)))    interruptRequest;
   interface Client#(TLPData#(16), TLPData#(16)) pci;
   interface BscanTop bscanif;
endinterface

interface PcieHostTop;
   interface Clock tepClock125;
   interface Reset tepReset125;
   interface PcieHost#(DataBusWidth, NumberOfMasters) tpciehost;
`ifndef BSIM
   interface Clock tsys_clk_200mhz;
   interface Clock tsys_clk_200mhz_buf;
   interface Clock tpci_clk_100mhz_buf;
   interface PcieEndpointX7#(PcieLanes) tep7;
`endif
   interface Clock portalClock;
   interface Reset portalReset;
   interface Clock doubleClock;
   interface Reset doubleReset;
endinterface

typedef PcieHostTop HostType;
`endif

////////////////////////////// Zynq /////////////////////////////////
`ifdef ZynqHostTypeIF
import PS7LIB::*;

typedef PS7 HostType;

export PS7LIB::*;
export HostType;
export DataBusWidth;
export NumberOfMasters;
`endif

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

////////////////////////////// common /////////////////////////////////

`ifndef DataBusWidth
`define DataBusWidth 64
`endif

typedef `DataBusWidth DataBusWidth;
typedef `NumberOfMasters NumberOfMasters;

////////////////////////////// Bsim /////////////////////////////////
`ifdef BsimHostTypeIF

import Vector            :: *;
import AxiMasterSlave    :: *;
import MemTypes          :: *;

// this interface should allow for different master and slave bus paraters;
interface BsimHost#(numeric type clientAddrWidth, numeric type clientBusWidth, numeric type clientIdWidth,
		    numeric type serverAddrWidth, numeric type serverBusWidth, numeric type serverIdWidth,
		    numeric type nSlaves);
   interface MemMaster#(clientAddrWidth, clientBusWidth)  mem_client;
   interface Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))  axi_servers;
   interface Clock doubleClock;
   interface Reset doubleReset;
endinterface

typedef BsimHost#(32,32,12,40,DataBusWidth,6,NumberOfMasters) HostType;
`endif

////////////////////////////// PciE /////////////////////////////////
`ifdef PcieHostTypeIF

import Vector            :: *;
import GetPut            :: *;
import ClientServer      :: *;
import PCIE               :: *;
import PCIEWRAPPER       :: *;
import PcieCsr           :: *;
import MemTypes          :: *;
import Bscan             :: *;
`ifndef BSIM
import PcieEndpointX7    :: *;
`endif

interface PcieHost#(numeric type dsz, numeric type nSlaves);
   interface Vector#(16,ReadOnly_MSIX_Entry)     msixEntry;
   interface MemMaster#(32,32)                   master;
   interface Vector#(nSlaves,MemSlave#(40,dsz))  slave;
   interface Put#(Tuple2#(Bit#(64),Bit#(32)))    interruptRequest;
   interface Client#(TLPData#(16), TLPData#(16)) pci;
   interface BscanTop bscanif;
endinterface

interface PcieHostTop;
   interface Clock tepClock125;
   interface Reset tepReset125;
   interface PcieHost#(DataBusWidth, NumberOfMasters) tpciehost;
`ifndef BSIM
   interface Clock tsys_clk_200mhz;
   interface Clock tsys_clk_200mhz_buf;
   interface Clock tpci_clk_100mhz_buf;
   interface PcieEndpointX7#(PcieLanes) tep7;
`endif
   interface Clock portalClock;
   interface Reset portalReset;
   interface Clock doubleClock;
   interface Reset doubleReset;
endinterface

typedef PcieHostTop HostType;
`endif

////////////////////////////// Zynq /////////////////////////////////
`ifdef ZynqHostTypeIF
import PS7LIB::*;

typedef PS7 HostType;

export PS7LIB::*;
export HostType;
`endif


update Platform.bsv to use upper two bits of tag wrt MemTagSize to indicate tile number

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import ConnectalConfig::*;
import Vector::*;
import Portal::*;
import HostInterface::*;
import MMU::*;
import MemServer::*;
import MemTypes::*;
import CtrlMux::*;
import FIFO::*;
import GetPut::*;
import SpecialFIFOs::*;
import Pipe::*;
import ConnectalMemory::*;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import IfcNames::*;
`include "ConnectalProjectConfig.bsv"
import `PinTypeInclude::*;

interface Platform;
   interface PhysMemSlave#(32,32) slave;
   interface Vector#(NumberOfMasters,PhysMemMaster#(PhysAddrWidth, DataBusWidth)) masters;
   interface Vector#(MaxNumberOfPortals,ReadOnly#(Bool)) interrupt;
   interface `PinType pins;
endinterface

function Bit#(TSub#(MemTagSize,2)) tagLsb(Bit#(MemTagSize) tag); return truncate(tag); endfunction
function Bit#(2) tagMsb(Bit#(MemTagSize) tag); return truncate(tag >> valueOf(TSub#(MemTagSize,2))); endfunction

module renameReads#(Integer tile, MemReadClient#(DataBusWidth) reader, MemServerIndication err)(MemReadClient#(DataBusWidth));
   interface Get readReq;
      method ActionValue#(MemRequest) get;
	 let req <- reader.readReq.get;
	 Bit#(TSub#(MemTagSize,2)) lsb = tagLsb(req.tag);
	 Bit#(2) msb = tagMsb(req.tag);
	 if(req.tag != extend(lsb)) begin
	    $display("renameReads tile tag out of range: 'h%h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Put readData;
      method Action put(MemData#(DataBusWidth) v);
	 reader.readData.put(MemData{data:v.data, tag:{0,tagLsb(v.tag)}, last:v.last});
      endmethod
   endinterface
endmodule

module renameWrites#(Integer tile, MemWriteClient#(DataBusWidth) writer, MemServerIndication err)(MemWriteClient#(DataBusWidth));
   interface Get writeReq;
      method ActionValue#(MemRequest) get;
	 let req <- writer.writeReq.get;
	 Bit#(TSub#(MemTagSize,2)) lsb = tagLsb(req.tag);
	 Bit#(2) msb = tagMsb(req.tag);
	 if(req.tag != extend(lsb)) begin
	    $display("renameWrites tile tag out of range: 'h%h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Get writeData;
      method ActionValue#(MemData#(DataBusWidth)) get;
	 let rv <- writer.writeData.get;
   	 return MemData{data:rv.data, tag:{0,tagLsb(rv.tag)}, last:rv.last};
      endmethod
   endinterface
   interface Put writeDone;
      method Action put(Bit#(MemTagSize) v);
	 writer.writeDone.put({0,tagLsb(v)});
      endmethod
   endinterface
endmodule

module mkPlatform#(Vector#(NumberOfUserTiles, ConnectalTop) tiles)(Platform);
   /////////////////////////////////////////////////////////////
   // connecting up the tiles

   Vector#(NumberOfUserTiles, PhysMemSlave#(18,32)) tile_slaves;
   Vector#(NumberOfUserTiles, ReadOnly#(Bool)) tile_interrupts;
   Vector#(NumberOfUserTiles, Vector#(NumReadClients, MemReadClient#(DataBusWidth))) tile_read_clients;
   Vector#(NumberOfUserTiles, Vector#(NumWriteClients, MemWriteClient#(DataBusWidth))) tile_write_clients;
   for(Integer i = 0; i < valueOf(NumberOfUserTiles); i=i+1) begin
      tile_slaves[i] = tiles[i].slave;
      let imux <- mkInterruptMux(tiles[i].interrupt);
      //ReadOnly#(Bool) imux = tiles[i].interrupt;
      tile_interrupts[i] = imux;
      tile_read_clients[i] = tiles[i].readers;
      tile_write_clients[i] = tiles[i].writers;
   end

   /////////////////////////////////////////////////////////////
   // framework internal portals

   MMUIndicationProxy lMMUIndicationProxy <- mkMMUIndicationProxy(IfcNames_MMUIndicationH2S);
   MemServerIndicationProxy lMemServerIndicationProxy <- mkMemServerIndicationProxy(IfcNames_MemServerIndicationH2S);

   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationProxy.ifc);
   Vector#(TMul#(NumberOfUserTiles,NumReadClients), MemReadClient#(DataBusWidth)) tile_read_clients_renamed <- zipWith3M(renameReads, genVector, concat(tile_read_clients), replicate(lMemServerIndicationProxy.ifc));
   Vector#(TMul#(NumberOfUserTiles,NumWriteClients), MemWriteClient#(DataBusWidth)) tile_write_clients_renamed <- zipWith3M(renameWrites, genVector, concat(tile_write_clients), replicate(lMemServerIndicationProxy.ifc));
   MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(tile_read_clients_renamed, tile_write_clients_renamed, cons(lMMU,nil), lMemServerIndicationProxy.ifc);

   MMURequestWrapper lMMURequestWrapper <- mkMMURequestWrapper(IfcNames_MMURequestS2H, lMMU.request);
   MemServerRequestWrapper lMemServerRequestWrapper <- mkMemServerRequestWrapper(IfcNames_MemServerRequestS2H, lMemServer.request);

   Vector#(4,StdPortal) framework_portals;
   framework_portals[0] = lMMUIndicationProxy.portalIfc;
   framework_portals[1] = lMemServerIndicationProxy.portalIfc;
   framework_portals[2] = lMMURequestWrapper.portalIfc;
   framework_portals[3] = lMemServerRequestWrapper.portalIfc;
   PhysMemSlave#(18,32) framework_ctrl_mux <- mkSlaveMux(framework_portals);
   let framework_intr <- mkInterruptMux(getInterruptVector(framework_portals));

   /////////////////////////////////////////////////////////////
   // expose interface to top

   PhysMemSlave#(32,32) ctrl_mux <- mkMemPortalMux(cons(framework_ctrl_mux,tile_slaves));
   Vector#(MaxNumberOfPortals, ReadOnly#(Bool)) interrupts = replicate(interface ReadOnly; method Bool _read(); return False; endmethod endinterface);
   interrupts[0] = framework_intr;
   for (Integer i = 1; i < valueOf(NumberOfTiles); i = i + 1)
      interrupts[i] = tile_interrupts[i-1];
   interface interrupt = interrupts;
   interface slave = ctrl_mux;
   interface masters = lMemServer.masters;
   interface pins = tiles[0].pins;
endmodule

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import ConnectalConfig::*;
import Vector::*;
import Portal::*;
import HostInterface::*;
import MMU::*;
import MemServer::*;
import MemTypes::*;
import CtrlMux::*;
import FIFO::*;
import GetPut::*;
import SpecialFIFOs::*;
import Pipe::*;
import ConnectalMemory::*;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import IfcNames::*;
`include "ConnectalProjectConfig.bsv"
import `PinTypeInclude::*;

interface Platform;
   interface PhysMemSlave#(32,32) slave;
   interface Vector#(NumberOfMasters,PhysMemMaster#(PhysAddrWidth, DataBusWidth)) masters;
   interface Vector#(MaxNumberOfPortals,ReadOnly#(Bool)) interrupt;
   interface `PinType pins;
endinterface

module renameReads#(Integer tile, MemReadClient#(DataBusWidth) reader, MemServerIndication err)(MemReadClient#(DataBusWidth));
   interface Get readReq;
      method ActionValue#(MemRequest) get;
	 let req <- reader.readReq.get;
	 Bit#(4) lsb = req.tag[3:0];
	 Bit#(2) msb = req.tag[5:4];
	 if(msb != 0) begin
	    $display("renameReads tile tag out of range: %h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Put readData;
      method Action put(MemData#(DataBusWidth) v);
	 reader.readData.put(MemData{data:v.data, tag:{0,v.tag[3:0]}, last:v.last});
      endmethod
   endinterface
endmodule

module renameWrites#(Integer tile, MemWriteClient#(DataBusWidth) writer, MemServerIndication err)(MemWriteClient#(DataBusWidth));
   interface Get writeReq;
      method ActionValue#(MemRequest) get;
	 let req <- writer.writeReq.get;
	 Bit#(4) lsb = req.tag[3:0];
	 Bit#(2) msb = req.tag[5:4];
	 if(msb != 0) begin
	    $display("renameWrites tile tag out of range: %h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Get writeData;
      method ActionValue#(MemData#(DataBusWidth)) get;
	 let rv <- writer.writeData.get;
   	 return MemData{data:rv.data, tag:{0,rv.tag[3:0]}, last:rv.last};
      endmethod
   endinterface
   interface Put writeDone;
      method Action put(Bit#(MemTagSize) v);
	 writer.writeDone.put({0,v[3:0]});
      endmethod
   endinterface
endmodule

module mkPlatform#(Vector#(NumberOfUserTiles, ConnectalTop) tiles)(Platform);
   /////////////////////////////////////////////////////////////
   // connecting up the tiles

   Vector#(NumberOfUserTiles, PhysMemSlave#(18,32)) tile_slaves;
   Vector#(NumberOfUserTiles, ReadOnly#(Bool)) tile_interrupts;
   Vector#(NumberOfUserTiles, Vector#(NumReadClients, MemReadClient#(DataBusWidth))) tile_read_clients;
   Vector#(NumberOfUserTiles, Vector#(NumWriteClients, MemWriteClient#(DataBusWidth))) tile_write_clients;
   for(Integer i = 0; i < valueOf(NumberOfUserTiles); i=i+1) begin
      tile_slaves[i] = tiles[i].slave;
      let imux <- mkInterruptMux(tiles[i].interrupt);
      //ReadOnly#(Bool) imux = tiles[i].interrupt;
      tile_interrupts[i] = imux;
      tile_read_clients[i] = tiles[i].readers;
      tile_write_clients[i] = tiles[i].writers;
   end

   /////////////////////////////////////////////////////////////
   // framework internal portals

   MMUIndicationProxy lMMUIndicationProxy <- mkMMUIndicationProxy(IfcNames_MMUIndicationH2S);
   MemServerIndicationProxy lMemServerIndicationProxy <- mkMemServerIndicationProxy(IfcNames_MemServerIndicationH2S);

   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationProxy.ifc);
   Vector#(TMul#(NumberOfUserTiles,NumReadClients), MemReadClient#(DataBusWidth)) tile_read_clients_renamed <- zipWith3M(renameReads, genVector, concat(tile_read_clients), replicate(lMemServerIndicationProxy.ifc));
   Vector#(TMul#(NumberOfUserTiles,NumWriteClients), MemWriteClient#(DataBusWidth)) tile_write_clients_renamed <- zipWith3M(renameWrites, genVector, concat(tile_write_clients), replicate(lMemServerIndicationProxy.ifc));
   MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(tile_read_clients_renamed, tile_write_clients_renamed, cons(lMMU,nil), lMemServerIndicationProxy.ifc);

   MMURequestWrapper lMMURequestWrapper <- mkMMURequestWrapper(IfcNames_MMURequestS2H, lMMU.request);
   MemServerRequestWrapper lMemServerRequestWrapper <- mkMemServerRequestWrapper(IfcNames_MemServerRequestS2H, lMemServer.request);

   Vector#(4,StdPortal) framework_portals;
   framework_portals[0] = lMMUIndicationProxy.portalIfc;
   framework_portals[1] = lMemServerIndicationProxy.portalIfc;
   framework_portals[2] = lMMURequestWrapper.portalIfc;
   framework_portals[3] = lMemServerRequestWrapper.portalIfc;
   PhysMemSlave#(18,32) framework_ctrl_mux <- mkSlaveMux(framework_portals);
   let framework_intr <- mkInterruptMux(getInterruptVector(framework_portals));

   /////////////////////////////////////////////////////////////
   // expose interface to top

   PhysMemSlave#(32,32) ctrl_mux <- mkMemPortalMux(cons(framework_ctrl_mux,tile_slaves));
   Vector#(MaxNumberOfPortals, ReadOnly#(Bool)) interrupts = replicate(interface ReadOnly; method Bool _read(); return False; endmethod endinterface);
   interrupts[0] = framework_intr;
   for (Integer i = 1; i < valueOf(NumberOfTiles); i = i + 1)
      interrupts[i] = tile_interrupts[i-1];
   interface interrupt = interrupts;
   interface slave = ctrl_mux;
   interface masters = lMemServer.masters;
   interface pins = tiles[0].pins;
endmodule


include portal number in serial portal header

// 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 BuildVector::*;
import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import FIFOF::*;
import Gearbox::*;
import GetPut::*;
import MIMO::*;
import Probe::*;
import Vector::*;

import Pipe::*;
import Portal::*;
import MemTypes::*;
import ConnectalMemory::*;
import SharedMemoryFifo::*;

module mkSharedMemoryRequestPortal#(PipePortal#(numRequests, numIndications, 32) portal,
   function Bit#(16) messageSize(Bit#(16) methodNumber),
   Vector#(2, MemReadEngineServer#(64)) readEngine, Vector#(2, MemWriteEngineServer#(64)) writeEngine)(SharedMemoryPortal#(64));
   SharedMemoryPipeOut#(64,numRequests) pipeOut <- mkSharedMemoryPipeOut(readEngine, writeEngine);
   mapM_(uncurry(mkConnection), zip(pipeOut.data, portal.requests));

   interface SharedMemoryPortalConfig cfg = pipeOut.cfg;
endmodule

// adds a header word to each message out of an indication pipe
module mkFramedMessagePipe#(Integer portalNumber,
			    PipePortal#(numRequests,numIndications,32) pipePortal,
			    function Bit#(16) messageSize(Bit#(16) methodNumber),
			    Integer i)(PipeOut#(Bit#(32)));

   let pipeOut = pipePortal.indications[i];
   Bit#(16) messageBits = messageSize(fromInteger(i));
   Bit#(16) roundup = messageBits[4:0] == 0 ? 0 : 1;
   Bit#(16) numWords = (messageBits >> 5) + roundup;
   Bit#(16) totalWords = numWords + 1;
   Bit#(32) hdr = (fromInteger(portalNumber) << 24) | (fromInteger(i) << 16) | extend(numWords + 1);
   let sendHeader <- mkReg(True);
   Reg#(Bit#(16)) burstLenReg <- mkReg(0);
   return (interface PipeOut;
	      method Bit#(32) first() if (pipeOut.notEmpty());
	         if (sendHeader)
		    return hdr;
		 else
		    return pipeOut.first();
	      endmethod
	      method Action deq() if (pipeOut.notEmpty());
	         if (sendHeader) begin
		    sendHeader <= False;
		    burstLenReg <= numWords;
		 end
		 else begin
		    pipeOut.deq();
		    burstLenReg <= burstLenReg - 1;
		    if (burstLenReg == 1)
		       sendHeader <= True;
		 end
	      endmethod
	      method Bool notEmpty(); return pipeOut.notEmpty(); endmethod
	   endinterface);
endmodule

module mkSharedMemoryIndicationPortal#(PipePortal#(numRequests,numIndications,32) pipePortal,
				       function Bit#(16) messageSize(Bit#(16) methodNumber),
				       Vector#(2, MemReadEngineServer#(64)) readEngines, Vector#(2, MemWriteEngineServer#(64)) writeEngines)
   (SharedMemoryPortal#(64));

   Vector#(numIndications, PipeOut#(Bit#(32))) indicationPipes <- genWithM(mkFramedMessagePipe(0,pipePortal,messageSize));

   SharedMemoryPipeIn#(64) pipeIn <- mkSharedMemoryPipeIn(indicationPipes, readEngines, writeEngines);
   interface SharedMemoryPortalConfig cfg = pipeIn.cfg;
endmodule

interface SerialPortalDemux#(numeric type pipeCount);
   interface Vector#(pipeCount, PipeOut#(Bit#(32))) data;
   interface PipeIn#(Bit#(32))                      inputPipe;
endinterface

typedef enum {
   Idle,
   MessageHeader,
   MessageBody,
   Stop
   } SerialPortalState deriving (Bits,Eq);

typedef enum {
   Portal,
   Method
   } SerialPortalDemuxLevel deriving (Bits,Eq);

module mkSerialPortalDemux#(SerialPortalDemuxLevel portalDemux)(SerialPortalDemux#(pipeCount));
   let clock <- exposeCurrentClock();
   let reset <- exposeCurrentReset();
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(8))  selectorReg <- mkReg(0);
   Reg#(SerialPortalState) state <- mkReg(Idle);
   FIFOF#(Bit#(32)) inputFifo <- mkFIFOF();
   Vector#(pipeCount, FIFOF#(Bit#(32))) dataFifo <- replicateM(mkFIFOF);

   let verbose = False;

   rule idle if (state == Idle);
      state <= MessageHeader;
   endrule

   rule receiveMessageHeader if (state == MessageHeader);
      let hdr <- toGet(inputFifo).get();
      let selector = (portalDemux == Portal) ? hdr[31:24] : hdr[23:16];
      let messageWords = hdr[15:0];
      selectorReg <= selector;
      if (verbose)
         $display("receiveMessageHeader hdr=%x selector=%x messageWords=%d", hdr, selector, messageWords);
      if (portalDemux == Portal) // methodDemux need the header
         dataFifo[selector].enq(hdr);
      messageWordsReg <= messageWords - 1;
      if (messageWords == 1)
         state <= MessageHeader;
      else
         state <= MessageBody;
   endrule

   rule receiveMessage if (state == MessageBody);
      let data <- toGet(inputFifo).get();
      if (verbose)
         $display("receiveMessage data=%x messageWords=%d", data, messageWordsReg);
      if (selectorReg != 8'hFF)
         dataFifo[selectorReg].enq(data);
      messageWordsReg <= messageWordsReg - 1;
      if (messageWordsReg == 1)
         state <= MessageHeader;
   endrule

   interface data      = map(toPipeOut, dataFifo);
   interface inputPipe = toPipeIn(inputFifo);
endmodule

module mkSerialPortalMux#(Vector#(numIndications, PipeOut#(Bit#(32))) pipes)(PipeOut#(Bit#(32)));
   let clock <- exposeCurrentClock;
   let reset <- exposeCurrentReset;
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(Bool) paddingReg <- mkReg(False);
   Reg#(SerialPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, pipes);
   Bool      interruptStatus = False;
   Bit#(16)  readyChannel = -1;
   FIFOF#(Bit#(32)) outputFifo <- mkFIFOF();

   let verbose = True;
   let stateProbe <- mkProbe();
   let messageWordsProbe <- mkProbe();
   let messageDataProbe <- mkProbe();

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

   rule idle if (state == Idle);
      state <= MessageHeader;
      stateProbe <= MessageHeader;
   endrule

   rule sendHeader if (state == MessageHeader && interruptStatus);
      Bit#(32) hdr <- toGet(pipes[readyChannel]).get();
      Bit#(16) totalWords = hdr[15:0];
      let messageWords = totalWords-1;
      messageWordsProbe <= messageWords;

      messageWordsReg <= messageWords;
      methodIdReg <= readyChannel;
      outputFifo.enq(hdr);
      state <= MessageBody;
      stateProbe <= MessageBody;
      messageDataProbe <= hdr;
   endrule

   rule sendMessage if (state == MessageBody);
      messageWordsReg <= messageWordsReg - 1;
      let v <- toGet(pipes[methodIdReg]).get();
      outputFifo.enq(v);
      $display("sendMessage v=%h messageWords=%d paddingReg=%d", v, messageWordsReg, paddingReg);
      if (messageWordsReg == 1) begin
         state <= MessageHeader;
	 stateProbe <= MessageHeader;
      end
      messageDataProbe <= v;
   endrule

   return toPipeOut(outputFifo);
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 BuildVector::*;
import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import FIFOF::*;
import Gearbox::*;
import GetPut::*;
import MIMO::*;
import Probe::*;
import Vector::*;

import Pipe::*;
import Portal::*;
import MemTypes::*;
import ConnectalMemory::*;
import SharedMemoryFifo::*;

module mkSharedMemoryRequestPortal#(PipePortal#(numRequests, numIndications, 32) portal,
   function Bit#(16) messageSize(Bit#(16) methodNumber),
   Vector#(2, MemReadEngineServer#(64)) readEngine, Vector#(2, MemWriteEngineServer#(64)) writeEngine)(SharedMemoryPortal#(64));
   SharedMemoryPipeOut#(64,numRequests) pipeOut <- mkSharedMemoryPipeOut(readEngine, writeEngine);
   mapM_(uncurry(mkConnection), zip(pipeOut.data, portal.requests));

   interface SharedMemoryPortalConfig cfg = pipeOut.cfg;
endmodule

// adds a header word to each message out of an indication pipe
module mkFramedMessagePipe#(PipePortal#(numRequests,numIndications,32) pipePortal,
			       function Bit#(16) messageSize(Bit#(16) methodNumber),
			       Integer i)(PipeOut#(Bit#(32)));

   let pipeOut = pipePortal.indications[i];
   Bit#(16) messageBits = messageSize(fromInteger(i));
   Bit#(16) roundup = messageBits[4:0] == 0 ? 0 : 1;
   Bit#(16) numWords = (messageBits >> 5) + roundup;
   Bit#(16) totalWords = numWords + 1;
   Bit#(32) hdr = fromInteger(i) << 16 | extend(numWords + 1);
   let sendHeader <- mkReg(True);
   Reg#(Bit#(16)) burstLenReg <- mkReg(0);
   return (interface PipeOut;
	      method Bit#(32) first() if (pipeOut.notEmpty());
	         if (sendHeader)
		    return hdr;
		 else
		    return pipeOut.first();
	      endmethod
	      method Action deq() if (pipeOut.notEmpty());
	         if (sendHeader) begin
		    sendHeader <= False;
		    burstLenReg <= numWords;
		 end
		 else begin
		    pipeOut.deq();
		    burstLenReg <= burstLenReg - 1;
		    if (burstLenReg == 1)
		       sendHeader <= True;
		 end
	      endmethod
	      method Bool notEmpty(); return pipeOut.notEmpty(); endmethod
	   endinterface);
endmodule

module mkSharedMemoryIndicationPortal#(PipePortal#(numRequests,numIndications,32) pipePortal,
				       function Bit#(16) messageSize(Bit#(16) methodNumber),
				       Vector#(2, MemReadEngineServer#(64)) readEngines, Vector#(2, MemWriteEngineServer#(64)) writeEngines)
   (SharedMemoryPortal#(64));

   Vector#(numIndications, PipeOut#(Bit#(32))) indicationPipes <- genWithM(mkFramedMessagePipe(pipePortal,messageSize));

   SharedMemoryPipeIn#(64) pipeIn <- mkSharedMemoryPipeIn(indicationPipes, readEngines, writeEngines);
   interface SharedMemoryPortalConfig cfg = pipeIn.cfg;
endmodule

interface SerialPortalDemux#(numeric type pipeCount);
   interface Vector#(pipeCount, PipeOut#(Bit#(32))) data;
   interface PipeIn#(Bit#(32))                      inputPipe;
endinterface

typedef enum {
   Idle,
   MessageHeader,
   MessageBody,
   Stop
   } SerialPortalState deriving (Bits,Eq);

typedef enum {
   Portal,
   Method
   } SerialPortalDemuxLevel deriving (Bits,Eq);

module mkSerialPortalDemux#(SerialPortalDemuxLevel portalDemux)(SerialPortalDemux#(pipeCount));
   let clock <- exposeCurrentClock();
   let reset <- exposeCurrentReset();
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(8))  selectorReg <- mkReg(0);
   Reg#(SerialPortalState) state <- mkReg(Idle);
   FIFOF#(Bit#(32)) inputFifo <- mkFIFOF();
   Vector#(pipeCount, FIFOF#(Bit#(32))) dataFifo <- replicateM(mkFIFOF);

   let verbose = False;

   rule idle if (state == Idle);
      state <= MessageHeader;
   endrule

   rule receiveMessageHeader if (state == MessageHeader);
      let hdr <- toGet(inputFifo).get();
      let selector = (portalDemux == Portal) ? hdr[31:24] : hdr[23:16];
      let messageWords = hdr[15:0];
      selectorReg <= selector;
      if (verbose)
         $display("receiveMessageHeader hdr=%x selector=%x messageWords=%d", hdr, selector, messageWords);
      if (portalDemux == Portal) // methodDemux need the header
         dataFifo[selector].enq(hdr);
      messageWordsReg <= messageWords - 1;
      if (messageWords == 1)
         state <= MessageHeader;
      else
         state <= MessageBody;
   endrule

   rule receiveMessage if (state == MessageBody);
      let data <- toGet(inputFifo).get();
      if (verbose)
         $display("receiveMessage data=%x messageWords=%d", data, messageWordsReg);
      if (selectorReg != 8'hFF)
         dataFifo[selectorReg].enq(data);
      messageWordsReg <= messageWordsReg - 1;
      if (messageWordsReg == 1)
         state <= MessageHeader;
   endrule

   interface data      = map(toPipeOut, dataFifo);
   interface inputPipe = toPipeIn(inputFifo);
endmodule

module mkSerialPortalMux#(Vector#(numIndications, PipeOut#(Bit#(32))) pipes)(PipeOut#(Bit#(32)));
   let clock <- exposeCurrentClock;
   let reset <- exposeCurrentReset;
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(Bool) paddingReg <- mkReg(False);
   Reg#(SerialPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, pipes);
   Bool      interruptStatus = False;
   Bit#(16)  readyChannel = -1;
   FIFOF#(Bit#(32)) outputFifo <- mkFIFOF();

   let verbose = True;
   let stateProbe <- mkProbe();
   let messageWordsProbe <- mkProbe();
   let messageDataProbe <- mkProbe();

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

   rule idle if (state == Idle);
      state <= MessageHeader;
      stateProbe <= MessageHeader;
   endrule

   rule sendHeader if (state == MessageHeader && interruptStatus);
      Bit#(32) hdr <- toGet(pipes[readyChannel]).get();
      Bit#(16) totalWords = hdr[15:0];
      let messageWords = totalWords-1;
      messageWordsProbe <= messageWords;

      messageWordsReg <= messageWords;
      methodIdReg <= readyChannel;
      outputFifo.enq(hdr);
      state <= MessageBody;
      stateProbe <= MessageBody;
      messageDataProbe <= hdr;
   endrule

   rule sendMessage if (state == MessageBody);
      messageWordsReg <= messageWordsReg - 1;
      let v <- toGet(pipes[methodIdReg]).get();
      outputFifo.enq(v);
      $display("sendMessage v=%h messageWords=%d paddingReg=%d", v, messageWordsReg, paddingReg);
      if (messageWordsReg == 1) begin
         state <= MessageHeader;
	 stateProbe <= MessageHeader;
      end
      messageDataProbe <= v;
   endrule

   return toPipeOut(outputFifo);
endmodule


remove possibly unneeded dreg from the read only register. This makes sense if it is only used for the IDCODE reg in the tap. It doesn't export the reg interface, just sets it to ?

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

// The Jtag state machine is copied from the Bluespec Small Examples Tap.bsv

interface JtagReg#(type a);
   method Action update();
   method Action capture();
   method Action shift(bit d);
   interface Reg#(a) r;
   interface ReadOnly#(bit) tdo;
endinterface

// can I pass in an initial value for the register?

module mkJtagReg(JtagReg#(a))
   provisos(Bits#(a,asize), Add#(1,__a,asize));

   Reg#(a) dreg <- mkReg(?);
   Reg#(a) sreg <- mkReg(?);
   Reg#(bit) oreg <- mkReg(?);

   method Action update ();
      dreg <= sreg;
   endmethod

   method Action capture ();
      sreg <= dreg;
   endmethod

   method Action shift (bit d);
      Bit#(asize) svalue = pack(sreg);
      svalue = {d, svalue[(valueof(asize)-1):1]};
      sreg <= unpack(svalue);
      oreg <= svalue[0];
   endmethod

   interface r = dreg;
   interface tdo = regToReadOnly(oreg);

endmodule

module mkReadOnlyJtagReg#(a v)(JtagReg#(a))
   provisos(Bits#(a,asize), Add#(1,__a,asize));

   Reg#(a) sreg <- mkReg(?);
   Reg#(bit) oreg <- mkReg(?);

   method Action update ();

   endmethod

   method Action capture ();
      sreg <= v;
   endmethod

   method Action shift (bit d);
      Bit#(asize) svalue = pack(sreg);
      svalue = {d, svalue[(valueof(asize)-1):1]};
      sreg <= unpack(svalue);
      oreg <= svalue[0];
   endmethod

   interface r = ?;
   interface tdo = regToReadOnly(oreg);

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.

// The Jtag state machine is copied from the Bluespec Small Examples Tap.bsv

interface JtagReg#(type a);
   method Action update();
   method Action capture();
   method Action shift(bit d);
   interface Reg#(a) r;
   interface ReadOnly#(bit) tdo;
endinterface

// can I pass in an initial value for the register?

module mkJtagReg(JtagReg#(a))
   provisos(Bits#(a,asize), Add#(1,__a,asize));

   Reg#(a) dreg <- mkReg(?);
   Reg#(a) sreg <- mkReg(?);
   Reg#(bit) oreg <- mkReg(?);

   method Action update ();
      dreg <= sreg;
   endmethod

   method Action capture ();
      sreg <= dreg;
   endmethod

   method Action shift (bit d);
      Bit#(asize) svalue = pack(sreg);
      svalue = {d, svalue[(valueof(asize)-1):1]};
      sreg <= unpack(svalue);
      oreg <= svalue[0];
   endmethod

   interface r = dreg;
   interface tdo = regToReadOnly(oreg);

endmodule

module mkReadOnlyJtagReg#(a v)(JtagReg#(a))
   provisos(Bits#(a,asize), Add#(1,__a,asize));

   Reg#(a) dreg <- mkReg(v);
   Reg#(a) sreg <- mkReg(?);
   Reg#(bit) oreg <- mkReg(?);

   method Action update ();

   endmethod

   method Action capture ();
      sreg <= dreg;
   endmethod

   method Action shift (bit d);
      Bit#(asize) svalue = pack(sreg);
      svalue = {d, svalue[(valueof(asize)-1):1]};
      sreg <= unpack(svalue);
      oreg <= svalue[0];
   endmethod

   interface r = dreg;
   interface tdo = regToReadOnly(oreg);

endmodule


add medium size

add medium size

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

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

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

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

//`define PERF_COUNT // defined in makefile

`define REUSE_FMA // use FMA for add and mul

`define LOG_BOOT_ROM_BYTES 12 // 4KB boot rom

// tournament predictor, other options are: BHT, TOUR, GSELECT, GSHARE. NOTE
// that the predictors are of different size.
`define DIR_PRED_TOUR

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

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

`define TLB_SIZE 32 // L1 TLB size

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

// non-blocking DTLB
`define DTLB_REQ_NUM 4
// non-blocking L2 TLB
`define L2TLB_REQ_NUM 2

`define DRAM_MAX_READS TExp#(`LOG_LLC_WAYS) // max reads in DRAM, match LLC ways
`define DRAM_MAX_WRITES 16 // write buffer size in AWS DRAM controller
`define DRAM_MAX_REQS 24
`define DRAM_LATENCY 120 // model a constant dram latency

//
// ==== CACHE SIZE ====
//

`ifdef CACHE_SMALL

    // L1
    `define LOG_L1_LINES 8 // 16KB
    `define LOG_L1_WAYS 3 // 8 ways

    // LLC
    `define LOG_LLC_LINES 12 // 256KB
    `define LOG_LLC_WAYS 4 // 16 ways

`endif

`ifdef CACHE_LARGE

    // L1
    `define LOG_L1_LINES 9 // 32KB
    `define LOG_L1_WAYS 3 // 8 ways

    // LLC
    `define LOG_LLC_LINES 14 // 1MB
    `define LOG_LLC_WAYS 4 // 16 ways

`endif

`ifdef CACHE_MC

    // L1
    `define LOG_L1_LINES 9 // 32KB
    `define LOG_L1_WAYS 2 // 4 ways

    // LLC
    `define LOG_LLC_LINES 14 // 1MB
    `define LOG_LLC_WAYS 4 // 16 ways

`endif

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

`ifdef CORE_TINY

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 48

    // speculation
    `define NUM_EPOCHS 8
    `define NUM_SPEC_TAGS 8

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

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

`endif

`ifdef CORE_SMALL

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 64

    // speculation
    `define NUM_EPOCHS 8
    `define NUM_SPEC_TAGS 8

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

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

`endif

`ifdef CORE_MEDIUM

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 80

    // speculation
    `define NUM_EPOCHS 12
    `define NUM_SPEC_TAGS 12

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

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

`endif

`ifdef CORE_SMALL_WIDE

    // superscalar
    `define sizeSup 4

    // ROB
    `define ROB_SIZE 64

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 16

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

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

`endif

`ifdef CORE_BOOM
    // we extend SMALL to match BOOM's ROB and memory latency, we also increase
    // spec tags because of increased ROB size

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 80

    // speculation
    `define NUM_EPOCHS 12
    `define NUM_SPEC_TAGS 12

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

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

    // change memory latency to 80
    `undef DRAM_LATENCY
    `define DRAM_LATENCY 80

`endif

`ifdef CORE_LARGE

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 128

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 32

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

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

`endif

`ifdef CORE_LARGE_WIDE

    // superscalar
    `define sizeSup 4

    // ROB
    `define ROB_SIZE 128

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 32

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

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

`endif

//`ifdef CORE_MEDIUM
//
//    // ROB
//    `define ROB_SIZE 96
//
//    // speculation
//    `define NUM_EPOCHS 32
//    `define NUM_SPEC_TAGS 32
//
//    // LSQ
//    `define LDQ_SIZE 36
//    `define STQ_SIZE 21
//    `define SB_SIZE 4
//
//    // reservation station sizes
//    `define RS_ALU_SIZE 24
//    `define RS_MEM_SIZE 24
//    `define RS_FPUMULDIV_SIZE 24
//
//`endif

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

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

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

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

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

//`define PERF_COUNT // defined in makefile

`define REUSE_FMA // use FMA for add and mul

`define LOG_BOOT_ROM_BYTES 12 // 4KB boot rom

// tournament predictor, other options are: BHT, TOUR, GSELECT, GSHARE. NOTE
// that the predictors are of different size.
`define DIR_PRED_TOUR

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

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

`define TLB_SIZE 32 // L1 TLB size

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

// non-blocking DTLB
`define DTLB_REQ_NUM 4
// non-blocking L2 TLB
`define L2TLB_REQ_NUM 2

`define DRAM_MAX_READS TExp#(`LOG_LLC_WAYS) // max reads in DRAM, match LLC ways
`define DRAM_MAX_WRITES 16 // write buffer size in AWS DRAM controller
`define DRAM_MAX_REQS 24
`define DRAM_LATENCY 120 // model a constant dram latency

//
// ==== CACHE SIZE ====
//

`ifdef CACHE_SMALL

    // L1
    `define LOG_L1_LINES 8 // 16KB
    `define LOG_L1_WAYS 3 // 8 ways

    // LLC
    `define LOG_LLC_LINES 12 // 256KB
    `define LOG_LLC_WAYS 4 // 16 ways

`endif

`ifdef CACHE_LARGE

    // L1
    `define LOG_L1_LINES 9 // 32KB
    `define LOG_L1_WAYS 3 // 8 ways

    // LLC
    `define LOG_LLC_LINES 14 // 1MB
    `define LOG_LLC_WAYS 4 // 16 ways

`endif

`ifdef CACHE_MC

    // L1
    `define LOG_L1_LINES 9 // 32KB
    `define LOG_L1_WAYS 2 // 4 ways

    // LLC
    `define LOG_LLC_LINES 14 // 1MB
    `define LOG_LLC_WAYS 4 // 16 ways

`endif

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

`ifdef CORE_TINY

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 48

    // speculation
    `define NUM_EPOCHS 8
    `define NUM_SPEC_TAGS 8

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

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

`endif

`ifdef CORE_SMALL

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 64

    // speculation
    `define NUM_EPOCHS 8
    `define NUM_SPEC_TAGS 8

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

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

`endif

`ifdef CORE_SMALL_WIDE

    // superscalar
    `define sizeSup 4

    // ROB
    `define ROB_SIZE 64

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 16

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

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

`endif

`ifdef CORE_BOOM
    // we extend SMALL to match BOOM's ROB and memory latency, we also increase
    // spec tags because of increased ROB size

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 80

    // speculation
    `define NUM_EPOCHS 12
    `define NUM_SPEC_TAGS 12

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

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

    // change memory latency to 80
    `undef DRAM_LATENCY
    `define DRAM_LATENCY 80

`endif

`ifdef CORE_LARGE

    // superscalar
    `define sizeSup 2

    // ROB
    `define ROB_SIZE 128

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 32

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

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

`endif

`ifdef CORE_LARGE_WIDE

    // superscalar
    `define sizeSup 4

    // ROB
    `define ROB_SIZE 128

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 32

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

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

`endif

//`ifdef CORE_MEDIUM
//
//    // ROB
//    `define ROB_SIZE 96
//
//    // speculation
//    `define NUM_EPOCHS 32
//    `define NUM_SPEC_TAGS 32
//
//    // LSQ
//    `define LDQ_SIZE 36
//    `define STQ_SIZE 21
//    `define SB_SIZE 4
//
//    // reservation station sizes
//    `define RS_ALU_SIZE 24
//    `define RS_MEM_SIZE 24
//    `define RS_FPUMULDIV_SIZE 24
//
//`endif

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


fix connections

fix connections

// 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 SerialFIFO::*;
import NocNode::*;
import Connectable::*;
import StmtFSM::*;
import Vector::*;
import FIFOF::*;
import Pipe::*;

interface NocIndication;
   method Action ack(Bit#(8) recvnode, Bit#(8) to, Bit#(32) message);
endinterface

interface NocRequest;
   method Action send(Bit#(8) sendnode, Bit#(8) to, Bit#(32) message);
endinterface

module mkPipeOutDiscard#(PipeOut#(Bit#(1)) x)(Empty);
   rule toss;
      x.deq();
   endrule
endmodule

module mkNocRequest#(NocIndication indication)(NocRequest);

   Vector#(4, Vector#(4, NocNode#(2))) node = replicate(newVector);

   for (Bit#(4) x = 0; x < 4; x = x + 1)
      for (Bit#(4) y = 0; y < 4; y = y + 1)
	 begin
	    Vector#(2, Bit#(4)) id = newVector;
	    id[0] = x;
	    id[1] = y;
	    node[x][y] <- mkNocNode(id);
	 end

   // wire up the links in the x direction
   Vector#(3, Integer) indexes3 = genVector();
   Vector#(4, Integer) indexes4 = genVector();
   module mkXLinks#(Integer x)(Empty);
      module mkXLink#(Integer x, Integer y)(Empty);
	 mkConnection(node[x][y].linkupout[0], node[x+1][y].linkdownin[0]);
	 mkConnection(node[x+1][y].linkdownout[0], node[x][y].linkupin[0]);
      endmodule
      mapM_(mkXLink(x), indexes4);
   endmodule

   mapM_(mkXLinks, indexes3);

   // wire up the links in the y direction

   module mkYLinks#(Integer y)(Empty);
   module mkYLink#(Integer y, Integer x)(Empty);
      mkConnection(node[x][y].linkupout[1], node[x][y+1].linkdownin[1]);
      mkConnection(node[x][y+1].linkdownout[1], node[x][y].linkupin[1]);
   endmodule
      mapM_(mkYLink(y), indexes4);
   endmodule
   mapM_(mkYLinks, indexes3);

   // discard traffic from loose ends in x direction
   for (Bit#(4) x = 0; x < 4; x = x + 1)
      begin
	 mkPipeOutDiscard(node[x][0].linkdownout[1]);
	 mkPipeOutDiscard(node[x][3].linkupout[1]);
      end
   // discard traffic from loose ends in y direction
   for (Bit#(4) y = 0; y < 4; y = y + 1)
      begin
	 mkPipeOutDiscard(node[0][y].linkdownout[0]);
	 mkPipeOutDiscard(node[3][y].linkupout[0]);
      end

  // fsm to read from host ports and generate indications

  Reg#(Bit#(4)) idx <- mkReg(0);
  Reg#(Bit#(4)) idy <- mkReg(0);

  Stmt readindications =
    seq
    while(True) seq
      for(idx <= 0; idx < 4; idx <= idy + 1)
	 for(idy <= 0; idy < 4; idy <= idy + 1)
            if (node[idx][idy].nodetohost.notEmpty())
	      seq
		 $display("recv at [%d,%d] to [%d,%d] m %x",
		    idx,idy,
		    node[idx][idy].nodetohost.first.address[0],
		    node[idx][idy].nodetohost.first.address[1],
	            node[idx][idy].nodetohost.first.payload);
		 indication.ack((idx<<4) +idy,
		    (node[idx][idy].nodetohost.first.address[0]<<4)+
		    node[idx][idy].nodetohost.first.address[1],
	            node[idx][idy].nodetohost.first.payload);
		 node[idx][idy].nodetohost.deq();
              endseq
      endseq
    endseq;

    mkAutoFSM(readindications);

   method Action send(Bit#(8) sendnode, Bit#(8) to, Bit#(32) message);
      Vector#(2,Bit#(4)) id = newVector;
      Vector#(2,Bit#(4)) dest = newVector;
      id[0] = sendnode[7:4];
      id[1] = sendnode[3:0];
      dest[0] = to[7:4];
      dest[1] = to[3:0];
      $display("send f %x t %x m %x", sendnode, to, message);
      node[id[0]][id[1]].hosttonode.enq(DataMessage{address: dest, payload: message});
   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 SerialFIFO::*;
import NocNode::*;
import Connectable::*;
import StmtFSM::*;
import Vector::*;
import FIFOF::*;
import Pipe::*;

interface NocIndication;
   method Action ack(Bit#(8) recvnode, Bit#(8) to, Bit#(32) message);
endinterface

interface NocRequest;
   method Action send(Bit#(8) sendnode, Bit#(8) to, Bit#(32) message);
endinterface

module mkPipeOutDiscard#(PipeOut#(Bit#(1)) x)(Empty);
   rule toss;
      x.deq();
   endrule
endmodule

module mkNocRequest#(NocIndication indication)(NocRequest);

   Vector#(4, Vector#(4, NocNode#(2))) node = replicate(newVector);

   for (Bit#(4) x = 0; x < 4; x = x + 1)
      for (Bit#(4) y = 0; y < 4; y = y + 1)
	 begin
	    Vector#(2, Bit#(4)) id = newVector;
	    id[0] = x;
	    id[1] = y;
	    node[x][y] <- mkNocNode(id);
	 end

   // wire up the links in the x direction
   Vector#(3, Integer) indexes3 = genVector();
   Vector#(4, Integer) indexes4 = genVector();
   module mkXLinks#(Integer x)(Empty);
      module mkXLink#(Integer x, Integer y)(Empty);
	 mkConnection(node[x][y].linkupout[0], node[x+1][y].linkupin[0]);
	 mkConnection(node[x+1][y].linkdownout[0], node[x][y].linkupin[0]);
      endmodule
      mapM_(mkXLink(x), indexes4);
   endmodule

   mapM_(mkXLinks, indexes3);
   /*
   for (Bit#(4) x = 0; x < 3; x = x + 1)
      for (Bit#(4) y = 0; y < 4; y = y + 1)
	 begin
	    mkConnection(node[x][y].linkupout[0], node[x+1][y].linkupin[0]);
	    mkConnection(node[x+1][y].linkdownout[0], node[x][y].linkupin[0]);
	 end
*/
   // wire up the links in the y direction

   module mkYLinks#(Integer y)(Empty);
   module mkYLink#(Integer y, Integer x)(Empty);
      mkConnection(node[x][y].linkupout[1], node[x][y+1].linkupin[1]);
      mkConnection(node[x][y+1].linkdownout[1], node[x][y].linkupin[1]);
   endmodule
      mapM_(mkYLink(y), indexes4);
   endmodule
   mapM_(mkYLinks, indexes3);

   /*
   for (Bit#(4) x = 0; x < 4; x = x + 1)
      for (Bit#(4) y = 0; y < 3; y = y + 1)
	 begin
	    mkConnection(node[x][y].linkupout[1], node[x][y+1].linkupin[1]);
	    mkConnection(node[x][y+1].linkdownout[1], node[x][y].linkupin[1]);
	 end
*/
   // discard traffic from loose ends in x direction
   for (Bit#(4) x = 0; x < 4; x = x + 1)
      begin
	 mkPipeOutDiscard(node[x][0].linkdownout[1]);
	 mkPipeOutDiscard(node[x][3].linkupout[1]);
      end
   // discard traffic from loose ends in y direction
   for (Bit#(4) y = 0; y < 4; y = y + 1)
      begin
	 mkPipeOutDiscard(node[0][y].linkdownout[0]);
	 mkPipeOutDiscard(node[3][y].linkupout[0]);
      end

  // fsm to read from host ports and generate indications

  Reg#(Bit#(4)) idx <- mkReg(0);
  Reg#(Bit#(4)) idy <- mkReg(0);

  Stmt readindications =
    seq
    while(True) seq
      for(idx <= 0; idx < 4; idx <= idy + 1)
	 for(idy <= 0; idy < 4; idy <= idy + 1)
            if (node[idx][idy].nodetohost.notEmpty())
	      seq
		 $display("recv at [%d,%d] to [%d,%d] m %x",
		    idx,idy,
		    node[idx][idy].nodetohost.first.address[0],
		    node[idx][idy].nodetohost.first.address[1],
	            node[idx][idy].nodetohost.first.payload);
		 indication.ack({idx,idy},
		    unpack(pack(node[idx][idy].nodetohost.first.address)),
	            node[idx][idy].nodetohost.first.payload);
		 node[idx][idy].nodetohost.deq();
              endseq
      endseq
    endseq;

    mkAutoFSM(readindications);

   method Action send(Bit#(8) sendnode, Bit#(8) to, Bit#(32) message);
      Vector#(2,Bit#(4)) id = newVector;
      Vector#(2,Bit#(4)) dest = newVector;
      id[0] = sendnode[7:4];
      id[1] = sendnode[3:0];
      dest[0] = to[7:4];
      dest[1] = to[3:0];
      $display("send f %x t %x m %x", sendnode, to, message);
      node[id[0]][id[1]].hosttonode.enq(DataMessage{address: dest, payload: message});
   endmethod

endmodule