missed method decls in Ingress interface

// Copyright (c) 2016 Cornell University.

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

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

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

import AcceptorTable::*;
import BuildVector::*;
import ClientServer::*;
import Connectable::*;
import ConnectalTypes::*;
import DbgTypes::*;
import DbgDefs::*;
import DstMacTable::*;
import DropTable::*;
import Ethernet::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;
import MemTypes::*;
import PaxosTypes::*;
import Pipe::*;
import RegFile::*;
import Register::*;
import RoleTable::*;
import RoundTable::*;
import SequenceTable::*;
import Vector::*;

interface Ingress;
   interface MemWriteClient#(`DataBusWidth) writeClient;
   interface PipeOut#(MetadataRequest) eventPktSend;
   interface Get#(Role) role_reg_read_resp;
   method Action datapath_id_reg_write(Bit#(DatapathSize) datapath);
   method Action instance_reg_write(Bit#(InstanceSize) instance_);
   method Action role_reg_write(Role r);
   method Action role_reg_read();
   method Action vround_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) vround);
   method Action round_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) round);
   method Action value_reg_write(Bit#(TLog#(InstanceCount)) inst, Vector#(8, Bit#(32)) value);
   method Action sequenceTable_add_entry(Bit#(16) msgtype, SequenceTblActionT action_);
   method Action acceptorTable_add_entry(Bit#(16) msgtype, AcceptorTblActionT action_);
   method Action dmacTable_add_entry(Bit#(48) mac, Bit#(9) port);
   // Debug
   method IngressDbgRec read_debug_info;
   method PerfDbgRec read_perf_info;
endinterface

module mkIngress#(Vector#(numClients, MetadataClient) mdc)(Ingress);
   let verbose = True;
   Reg#(LUInt) fwdCount <- mkReg(0);
   FIFOF#(MetadataRequest) currPacketFifo <- mkFIFOF;
   FIFO#(MetadataRequest) inReqFifo <- mkFIFO;
   FIFO#(MetadataResponse) outRespFifo <- mkFIFO;

   Vector#(numClients, MetadataServer) metadataServers = newVector;
   for (Integer i=0; i<valueOf(numClients); i=i+1) begin
      metadataServers[i] = (interface MetadataServer;
         interface Put request = toPut(inReqFifo);
         interface Get response = toGet(outRespFifo);
      endinterface);
   end
   mkConnection(mdc, metadataServers);

   // Request/Response Fifos
   FIFO#(MetadataRequest) dmacReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) roleReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) roundReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) sequenceReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) acceptorReqFifo <- mkFIFO;
   // FIFO#(MetadataRequest) dropRequestFifo <- mkFIFO;
   FIFO#(MetadataResponse) dmacRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) roleRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) roundRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) sequenceRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) acceptorRespFifo <- mkFIFO;
   // FIFO#(MetadataResponse) dropResponseFifo <- mkFIFO;

   Reg#(Bit#(32)) clk_cnt <- mkReg(0);
   Reg#(Bit#(32)) ingress_start_time <- mkReg(0);
   Reg#(Bit#(32)) ingress_end_time <- mkReg(0);
   Reg#(Bit#(32)) acceptor_start_time <- mkReg(0);
   Reg#(Bit#(32)) acceptor_end_time <- mkReg(0);
   Reg#(Bit#(32)) sequence_start_time <- mkReg(0);
   Reg#(Bit#(32)) sequence_end_time <- mkReg(0);
   rule clockrule;
      clk_cnt <= clk_cnt + 1;
   endrule

   // Tables
   DstMacTable dstMacTable <- mkDstMacTable(toGPClient(dmacReqFifo, dmacRespFifo));
   RoleTable roleTable <- mkRoleTable(toGPClient(roleReqFifo, roleRespFifo));
   RoundTable roundTable <- mkRoundTable(toGPClient(roundReqFifo, roundRespFifo));
   SequenceTable sequenceTable <- mkSequenceTable(toGPClient(sequenceReqFifo, sequenceRespFifo));
   AcceptorTable acceptorTable <- mkAcceptorTable(toGPClient(acceptorReqFifo, acceptorRespFifo));
   //DropTable dropTable <- mkDropTable();//roundTable.next1);

   // BasicBlocks
   BasicBlockForward bb_fwd <- mkBasicBlockForward();
   BasicBlockIncreaseInstance bb_increase_instance <- mkBasicBlockIncreaseInstance();
   BasicBlockHandle1A bb_handle_1a <- mkBasicBlockHandle1A();
   BasicBlockHandle2A bb_handle_2a <- mkBasicBlockHandle2A();
   BasicBlockDrop bb_handle_drop <- mkBasicBlockDrop();
   BasicBlockRound bb_read_round <- mkBasicBlockRound();
   BasicBlockRole bb_read_role <- mkBasicBlockRole();

   // Registers
   FIFO#(RoundRegRequest) roundRegReqFifo <- mkFIFO;
   FIFO#(RoleRegRequest) roleRegReqFifo <- mkFIFO;
   FIFO#(DatapathIdRegRequest) datapathIdRegReqFifo <- mkFIFO;
   FIFO#(InstanceRegRequest) instanceRegReqFifo <- mkFIFO;
   FIFO#(VRoundRegRequest) vroundRegReqFifo <- mkFIFO;
   FIFO#(ValueRegRequest) valueRegReqFifo <- mkFIFO;

   FIFO#(RoundRegResponse) roundRegRespFifo <- mkFIFO;
   FIFO#(RoleRegResponse) roleRegRespFifo <- mkFIFO;
   FIFO#(DatapathIdRegResponse) datapathIdRegRespFifo <- mkFIFO;
   FIFO#(InstanceRegResponse) instanceRegRespFifo <- mkFIFO;
   FIFO#(VRoundRegResponse) vroundRegRespFifo <- mkFIFO;
   FIFO#(ValueRegResponse) valueRegRespFifo <- mkFIFO;

   FIFO#(Role) roleRegReadFifo <- mkFIFO;
   rule readRole;
      let v <- toGet(roleRegRespFifo).get;
      roleRegReadFifo.enq(unpack(v.data));
   endrule

   RegisterIfc#(1, SizeOf#(Role)) roleReg <- mkP4Register(vec(bb_read_role.regClient, toGPClient(roleRegReqFifo, roleRegRespFifo)));
   RegisterIfc#(1, DatapathSize) datapathIdReg <- mkP4Register(vec(bb_handle_2a.regClient_datapath_id, bb_handle_1a.regClient_datapath_id, toGPClient(datapathIdRegReqFifo, datapathIdRegRespFifo)));
   RegisterIfc#(1, InstanceSize) instanceReg <- mkP4Register(vec(bb_increase_instance.regClient, toGPClient(instanceRegReqFifo, instanceRegRespFifo)));
   RegisterIfc#(TLog#(InstanceCount), RoundSize) roundReg <- mkP4Register(vec(bb_read_round.regClient, bb_handle_2a.regClient_round, bb_handle_1a.regClient_round, toGPClient(roundRegReqFifo, roundRegRespFifo)));
   RegisterIfc#(TLog#(InstanceCount), RoundSize) vroundReg <- mkP4Register(vec(bb_handle_1a.regClient_vround, bb_handle_2a.regClient_vround, toGPClient(vroundRegReqFifo, vroundRegRespFifo)));
   RegisterIfc#(TLog#(InstanceCount), ValueSize) valueReg <- mkP4Register(vec(bb_handle_1a.regClient_value, bb_handle_2a.regClient_value, toGPClient(valueRegReqFifo, valueRegRespFifo)));

   // Connect Table with BasicBlock
   mkConnection(dstMacTable.next_control_state_0, bb_fwd.prev_control_state);
   mkConnection(sequenceTable.next_control_state_0, bb_increase_instance.prev_control_state);
   mkConnection(acceptorTable.next_control_state_0, bb_handle_1a.prev_control_state);
   mkConnection(acceptorTable.next_control_state_1, bb_handle_2a.prev_control_state);
   mkConnection(acceptorTable.next_control_state_2, bb_handle_drop.prev_control_state);
   mkConnection(roundTable.next_control_state_0, bb_read_round.prev_control_state);
   mkConnection(roleTable.next_control_state_0, bb_read_role.prev_control_state);

   // Resolve rule conflicts
   (* descending_urgency ="sequence_tbl_next_control_state, acceptor_tbl_next_control_state" *)

   // Control Flow
   rule start_control_state if (inReqFifo.first matches tagged DefaultRequest {pkt: .pkt, meta: .meta});
      inReqFifo.deq;
      ingress_start_time <= clk_cnt;
   //   if (isValid(meta.valid_ipv4)) begin
   //      MetadataRequest req = tagged DstMacLookupRequest {pkt: pkt, meta: meta};
   //      dmacReqFifo.enq(req);
   //   end
   //endrule

   //rule dmac_tbl_next_control_state if (dmacRespFifo.first matches tagged DstMacResponse {pkt: .pkt, meta: .meta});
   //   dmacRespFifo.deq;
      if (isValid(meta.valid_paxos)) begin
         MetadataRequest req = tagged RoleLookupRequest {pkt: pkt, meta: meta};
         roleReqFifo.enq(req);
      end
      $display("(%0d) Ingress: dmac_tbl next control state", $time);
   endrule

   rule role_tbl_next_control_state if (roleRespFifo.first matches tagged RoleResponse {pkt: .pkt, meta: .meta});
      roleRespFifo.deq;
      if (meta.switch_metadata$role matches tagged Valid .role) begin
         case (role) matches
            ACCEPTOR: begin
               $display("(%0d) Role: Acceptor %h", $time, pkt.id);
               MetadataRequest req = tagged RoundTblRequest {pkt: pkt, meta: meta};
               roundReqFifo.enq(req);
               acceptor_start_time <= clk_cnt;
            end
            COORDINATOR: begin
               $display("(%0d) Role: Coordinator %h", $time, pkt.id);
               MetadataRequest req = tagged SequenceTblRequest {pkt: pkt, meta: meta};
               sequenceReqFifo.enq(req);
               sequence_start_time <= clk_cnt;
            end
         endcase
      end
   endrule

   rule sequence_tbl_next_control_state if (sequenceRespFifo.first matches tagged SequenceTblResponse {pkt: .pkt, meta: .meta});
      sequenceRespFifo.deq;
      sequence_end_time <= clk_cnt;
      $display("(%0d) Sequence: fwd %h", $time, pkt.id);
      //FIXME: check action
      MetadataRequest req = tagged ForwardQueueRequest {pkt: pkt, meta: meta};
      currPacketFifo.enq(req);
   endrule

   rule round_tbl_next_control_state if (roundRespFifo.first matches tagged RoundTblResponse {pkt: .pkt, meta: .meta});
      roundRespFifo.deq;
      $display("(%0d) round table response", $time);
      if (meta.paxos_packet_meta$round matches tagged Valid .round) begin
         if (round <= fromMaybe(?, meta.paxos$rnd)) begin
            $display("(%0d) Round: Acceptor %h, round=%h, rnd=%h", $time, pkt.id, round, fromMaybe(?, meta.paxos$rnd));
            MetadataRequest req = tagged AcceptorTblRequest {pkt: pkt, meta: meta};
            acceptorReqFifo.enq(req);
         end
      end
   endrule

   rule acceptor_tbl_next_control_state if (acceptorRespFifo.first matches tagged AcceptorTblResponse {pkt: .pkt, meta: .meta});
      acceptorRespFifo.deq;
      acceptor_end_time <= clk_cnt;
      $display("(%0d) Acceptor: fwd ", $time, fshow(meta));
      MetadataRequest req = tagged ForwardQueueRequest {pkt: pkt, meta: meta};
      currPacketFifo.enq(req);
   endrule

   interface writeClient = dstMacTable.writeClient;
   interface eventPktSend = toPipeOut(currPacketFifo);
   method IngressDbgRec read_debug_info();
      return IngressDbgRec {
         fwdCount: fwdCount,
         accTbl: acceptorTable.read_debug_info,
         seqTbl: sequenceTable.read_debug_info,
         dmacTbl: dstMacTable.read_debug_info
      };
   endmethod
   method PerfDbgRec read_perf_info();
      return PerfDbgRec {
         ingress_start_time: ingress_start_time,
         ingress_end_time: ingress_end_time,
         acceptor_start_time: acceptor_start_time,
         acceptor_end_time: acceptor_end_time,
         sequence_start_time: sequence_start_time,
         sequence_end_time: sequence_end_time
      };
   endmethod
   method Action round_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) round);
      RoundRegRequest req = RoundRegRequest {addr: inst, data: round, write: True};
      roundRegReqFifo.enq(req);
   endmethod
   method Action vround_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) round);
      VRoundRegRequest req = VRoundRegRequest {addr: inst, data: round, write: True};
      vroundRegReqFifo.enq(req);
   endmethod
   method Action role_reg_write(Role role);
      RoleRegRequest req = RoleRegRequest {addr: 0, data: pack(role), write: True};
      roleRegReqFifo.enq(req);
   endmethod
   method Action datapath_id_reg_write(Bit#(DatapathSize) datapath);
      DatapathIdRegRequest req = DatapathIdRegRequest {addr: 0, data: datapath, write: True};
      datapathIdRegReqFifo.enq(req);
   endmethod
   method Action instance_reg_write(Bit#(InstanceSize) instance_);
      InstanceRegRequest req = InstanceRegRequest {addr: 0, data: instance_, write: True};
      instanceRegReqFifo.enq(req);
   endmethod
   method Action value_reg_write(Bit#(TLog#(InstanceCount)) inst, Vector#(8, Bit#(32)) value);
      ValueRegRequest req = ValueRegRequest {addr: inst, data: pack(value), write: True};
      valueRegReqFifo.enq(req);
   endmethod
   method Action role_reg_read();
      RoleRegRequest req = RoleRegRequest {addr: 0, data: ?, write: False};
      roleRegReqFifo.enq(req);
   endmethod
   interface role_reg_read_resp = toGet(roleRegReadFifo);
   method sequenceTable_add_entry = sequenceTable.add_entry;
   method acceptorTable_add_entry = acceptorTable.add_entry;
   method dmacTable_add_entry = dstMacTable.add_entry;
endmodule

// Copyright (c) 2016 Cornell University.

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

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

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

import AcceptorTable::*;
import BuildVector::*;
import ClientServer::*;
import Connectable::*;
import ConnectalTypes::*;
import DbgTypes::*;
import DbgDefs::*;
import DstMacTable::*;
import DropTable::*;
import Ethernet::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;
import MemTypes::*;
import PaxosTypes::*;
import Pipe::*;
import RegFile::*;
import Register::*;
import RoleTable::*;
import RoundTable::*;
import SequenceTable::*;
import Vector::*;

interface Ingress;
   interface MemWriteClient#(`DataBusWidth) writeClient;
   interface PipeOut#(MetadataRequest) eventPktSend;
   interface Get#(Role) role_reg_read_resp;
   method Action datapath_id_reg_write(Bit#(DatapathSize) datapath);
   method Action instance_reg_write(Bit#(InstanceSize) instance_);
   method Action role_reg_write(Role r);
   method Action role_reg_read();
   method Action vround_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) vround);
   method Action round_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) round);
   method Action value_reg_write(Bit#(TLog#(InstanceCount)) inst, Vector#(8, Bit#(32)) value);
   method Action sequenceTable_add_entry(Bit#(16) msgtype, SequenceTblActionT action_);
   method Action acceptorTable_add_entry(Bit#(16) msgtype, AcceptorTblActionT action_);
   method Action dmacTable_add_entry(Bit#(48) mac, Bit#(9) port);
   // Debug
   method IngressDbgRec read_debug_info;
endinterface

module mkIngress#(Vector#(numClients, MetadataClient) mdc)(Ingress);
   let verbose = True;
   Reg#(LUInt) fwdCount <- mkReg(0);
   FIFOF#(MetadataRequest) currPacketFifo <- mkFIFOF;
   FIFO#(MetadataRequest) inReqFifo <- mkFIFO;
   FIFO#(MetadataResponse) outRespFifo <- mkFIFO;

   Vector#(numClients, MetadataServer) metadataServers = newVector;
   for (Integer i=0; i<valueOf(numClients); i=i+1) begin
      metadataServers[i] = (interface MetadataServer;
         interface Put request = toPut(inReqFifo);
         interface Get response = toGet(outRespFifo);
      endinterface);
   end
   mkConnection(mdc, metadataServers);

   // Request/Response Fifos
   FIFO#(MetadataRequest) dmacReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) roleReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) roundReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) sequenceReqFifo <- mkFIFO;
   FIFO#(MetadataRequest) acceptorReqFifo <- mkFIFO;
   // FIFO#(MetadataRequest) dropRequestFifo <- mkFIFO;
   FIFO#(MetadataResponse) dmacRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) roleRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) roundRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) sequenceRespFifo <- mkFIFO;
   FIFO#(MetadataResponse) acceptorRespFifo <- mkFIFO;
   // FIFO#(MetadataResponse) dropResponseFifo <- mkFIFO;

   Reg#(Bit#(32)) clk_cnt <- mkReg(0);
   Reg#(Bit#(32)) ingress_start_time <- mkReg(0);
   Reg#(Bit#(32)) ingress_end_time <- mkReg(0);
   Reg#(Bit#(32)) acceptor_start_time <- mkReg(0);
   Reg#(Bit#(32)) acceptor_end_time <- mkReg(0);
   Reg#(Bit#(32)) sequence_start_time <- mkReg(0);
   Reg#(Bit#(32)) sequence_end_time <- mkReg(0);
   rule clockrule;
      clk_cnt <= clk_cnt + 1;
   endrule

   // Tables
   DstMacTable dstMacTable <- mkDstMacTable(toGPClient(dmacReqFifo, dmacRespFifo));
   RoleTable roleTable <- mkRoleTable(toGPClient(roleReqFifo, roleRespFifo));
   RoundTable roundTable <- mkRoundTable(toGPClient(roundReqFifo, roundRespFifo));
   SequenceTable sequenceTable <- mkSequenceTable(toGPClient(sequenceReqFifo, sequenceRespFifo));
   AcceptorTable acceptorTable <- mkAcceptorTable(toGPClient(acceptorReqFifo, acceptorRespFifo));
   //DropTable dropTable <- mkDropTable();//roundTable.next1);

   // BasicBlocks
   BasicBlockForward bb_fwd <- mkBasicBlockForward();
   BasicBlockIncreaseInstance bb_increase_instance <- mkBasicBlockIncreaseInstance();
   BasicBlockHandle1A bb_handle_1a <- mkBasicBlockHandle1A();
   BasicBlockHandle2A bb_handle_2a <- mkBasicBlockHandle2A();
   BasicBlockDrop bb_handle_drop <- mkBasicBlockDrop();
   BasicBlockRound bb_read_round <- mkBasicBlockRound();
   BasicBlockRole bb_read_role <- mkBasicBlockRole();

   // Registers
   FIFO#(RoundRegRequest) roundRegReqFifo <- mkFIFO;
   FIFO#(RoleRegRequest) roleRegReqFifo <- mkFIFO;
   FIFO#(DatapathIdRegRequest) datapathIdRegReqFifo <- mkFIFO;
   FIFO#(InstanceRegRequest) instanceRegReqFifo <- mkFIFO;
   FIFO#(VRoundRegRequest) vroundRegReqFifo <- mkFIFO;
   FIFO#(ValueRegRequest) valueRegReqFifo <- mkFIFO;

   FIFO#(RoundRegResponse) roundRegRespFifo <- mkFIFO;
   FIFO#(RoleRegResponse) roleRegRespFifo <- mkFIFO;
   FIFO#(DatapathIdRegResponse) datapathIdRegRespFifo <- mkFIFO;
   FIFO#(InstanceRegResponse) instanceRegRespFifo <- mkFIFO;
   FIFO#(VRoundRegResponse) vroundRegRespFifo <- mkFIFO;
   FIFO#(ValueRegResponse) valueRegRespFifo <- mkFIFO;

   FIFO#(Role) roleRegReadFifo <- mkFIFO;
   rule readRole;
      let v <- toGet(roleRegRespFifo).get;
      roleRegReadFifo.enq(unpack(v.data));
   endrule

   RegisterIfc#(1, SizeOf#(Role)) roleReg <- mkP4Register(vec(bb_read_role.regClient, toGPClient(roleRegReqFifo, roleRegRespFifo)));
   RegisterIfc#(1, DatapathSize) datapathIdReg <- mkP4Register(vec(bb_handle_2a.regClient_datapath_id, bb_handle_1a.regClient_datapath_id, toGPClient(datapathIdRegReqFifo, datapathIdRegRespFifo)));
   RegisterIfc#(1, InstanceSize) instanceReg <- mkP4Register(vec(bb_increase_instance.regClient, toGPClient(instanceRegReqFifo, instanceRegRespFifo)));
   RegisterIfc#(TLog#(InstanceCount), RoundSize) roundReg <- mkP4Register(vec(bb_read_round.regClient, bb_handle_2a.regClient_round, bb_handle_1a.regClient_round, toGPClient(roundRegReqFifo, roundRegRespFifo)));
   RegisterIfc#(TLog#(InstanceCount), RoundSize) vroundReg <- mkP4Register(vec(bb_handle_1a.regClient_vround, bb_handle_2a.regClient_vround, toGPClient(vroundRegReqFifo, vroundRegRespFifo)));
   RegisterIfc#(TLog#(InstanceCount), ValueSize) valueReg <- mkP4Register(vec(bb_handle_1a.regClient_value, bb_handle_2a.regClient_value, toGPClient(valueRegReqFifo, valueRegRespFifo)));

   // Connect Table with BasicBlock
   mkConnection(dstMacTable.next_control_state_0, bb_fwd.prev_control_state);
   mkConnection(sequenceTable.next_control_state_0, bb_increase_instance.prev_control_state);
   mkConnection(acceptorTable.next_control_state_0, bb_handle_1a.prev_control_state);
   mkConnection(acceptorTable.next_control_state_1, bb_handle_2a.prev_control_state);
   mkConnection(acceptorTable.next_control_state_2, bb_handle_drop.prev_control_state);
   mkConnection(roundTable.next_control_state_0, bb_read_round.prev_control_state);
   mkConnection(roleTable.next_control_state_0, bb_read_role.prev_control_state);

   // Resolve rule conflicts
   (* descending_urgency ="sequence_tbl_next_control_state, acceptor_tbl_next_control_state" *)

   // Control Flow
   rule start_control_state if (inReqFifo.first matches tagged DefaultRequest {pkt: .pkt, meta: .meta});
      inReqFifo.deq;
      ingress_start_time <= clk_cnt;
   //   if (isValid(meta.valid_ipv4)) begin
   //      MetadataRequest req = tagged DstMacLookupRequest {pkt: pkt, meta: meta};
   //      dmacReqFifo.enq(req);
   //   end
   //endrule

   //rule dmac_tbl_next_control_state if (dmacRespFifo.first matches tagged DstMacResponse {pkt: .pkt, meta: .meta});
   //   dmacRespFifo.deq;
      if (isValid(meta.valid_paxos)) begin
         MetadataRequest req = tagged RoleLookupRequest {pkt: pkt, meta: meta};
         roleReqFifo.enq(req);
      end
      $display("(%0d) Ingress: dmac_tbl next control state", $time);
   endrule

   rule role_tbl_next_control_state if (roleRespFifo.first matches tagged RoleResponse {pkt: .pkt, meta: .meta});
      roleRespFifo.deq;
      if (meta.switch_metadata$role matches tagged Valid .role) begin
         case (role) matches
            ACCEPTOR: begin
               $display("(%0d) Role: Acceptor %h", $time, pkt.id);
               MetadataRequest req = tagged RoundTblRequest {pkt: pkt, meta: meta};
               roundReqFifo.enq(req);
               acceptor_start_time <= clk_cnt;
            end
            COORDINATOR: begin
               $display("(%0d) Role: Coordinator %h", $time, pkt.id);
               MetadataRequest req = tagged SequenceTblRequest {pkt: pkt, meta: meta};
               sequenceReqFifo.enq(req);
               sequence_start_time <= clk_cnt;
            end
         endcase
      end
   endrule

   rule sequence_tbl_next_control_state if (sequenceRespFifo.first matches tagged SequenceTblResponse {pkt: .pkt, meta: .meta});
      sequenceRespFifo.deq;
      sequence_end_time <= clk_cnt;
      $display("(%0d) Sequence: fwd %h", $time, pkt.id);
      //FIXME: check action
      MetadataRequest req = tagged ForwardQueueRequest {pkt: pkt, meta: meta};
      currPacketFifo.enq(req);
   endrule

   rule round_tbl_next_control_state if (roundRespFifo.first matches tagged RoundTblResponse {pkt: .pkt, meta: .meta});
      roundRespFifo.deq;
      $display("(%0d) round table response", $time);
      if (meta.paxos_packet_meta$round matches tagged Valid .round) begin
         if (round <= fromMaybe(?, meta.paxos$rnd)) begin
            $display("(%0d) Round: Acceptor %h, round=%h, rnd=%h", $time, pkt.id, round, fromMaybe(?, meta.paxos$rnd));
            MetadataRequest req = tagged AcceptorTblRequest {pkt: pkt, meta: meta};
            acceptorReqFifo.enq(req);
         end
      end
   endrule

   rule acceptor_tbl_next_control_state if (acceptorRespFifo.first matches tagged AcceptorTblResponse {pkt: .pkt, meta: .meta});
      acceptorRespFifo.deq;
      acceptor_end_time <= clk_cnt;
      $display("(%0d) Acceptor: fwd ", $time, fshow(meta));
      MetadataRequest req = tagged ForwardQueueRequest {pkt: pkt, meta: meta};
      currPacketFifo.enq(req);
   endrule

   interface writeClient = dstMacTable.writeClient;
   interface eventPktSend = toPipeOut(currPacketFifo);
   method IngressDbgRec read_debug_info();
      return IngressDbgRec {
         fwdCount: fwdCount,
         accTbl: acceptorTable.read_debug_info,
         seqTbl: sequenceTable.read_debug_info,
         dmacTbl: dstMacTable.read_debug_info
      };
   endmethod
   method PerfDbgRec read_perf_info();
      return PerfDbgRec {
         ingress_start_time: ingress_start_time,
         ingress_end_time: ingress_end_time,
         acceptor_start_time: acceptor_start_time,
         acceptor_end_time: acceptor_end_time,
         sequence_start_time: sequence_start_time,
         sequence_end_time: sequence_end_time
      };
   endmethod
   method Action round_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) round);
      RoundRegRequest req = RoundRegRequest {addr: inst, data: round, write: True};
      roundRegReqFifo.enq(req);
   endmethod
   method Action vround_reg_write(Bit#(TLog#(InstanceCount)) inst, Bit#(RoundSize) round);
      VRoundRegRequest req = VRoundRegRequest {addr: inst, data: round, write: True};
      vroundRegReqFifo.enq(req);
   endmethod
   method Action role_reg_write(Role role);
      RoleRegRequest req = RoleRegRequest {addr: 0, data: pack(role), write: True};
      roleRegReqFifo.enq(req);
   endmethod
   method Action datapath_id_reg_write(Bit#(DatapathSize) datapath);
      DatapathIdRegRequest req = DatapathIdRegRequest {addr: 0, data: datapath, write: True};
      datapathIdRegReqFifo.enq(req);
   endmethod
   method Action instance_reg_write(Bit#(InstanceSize) instance_);
      InstanceRegRequest req = InstanceRegRequest {addr: 0, data: instance_, write: True};
      instanceRegReqFifo.enq(req);
   endmethod
   method Action value_reg_write(Bit#(TLog#(InstanceCount)) inst, Vector#(8, Bit#(32)) value);
      ValueRegRequest req = ValueRegRequest {addr: inst, data: pack(value), write: True};
      valueRegReqFifo.enq(req);
   endmethod
   method Action role_reg_read();
      RoleRegRequest req = RoleRegRequest {addr: 0, data: ?, write: False};
      roleRegReqFifo.enq(req);
   endmethod
   interface role_reg_read_resp = toGet(roleRegReadFifo);
   method sequenceTable_add_entry = sequenceTable.add_entry;
   method acceptorTable_add_entry = acceptorTable.add_entry;
   method dmacTable_add_entry = dstMacTable.add_entry;
endmodule


Fixed admission-control problem I introduced into mkDmaReadBuffer

Change-Id: Id8161868097e975d26211fe49d2c1d8556405c56

// 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 BRAM::*;
import FIFO::*;
import Vector::*;
import Gearbox::*;
import FIFOF::*;
import SpecialFIFOs::*;

import BRAMFIFOFLevel::*;
import GetPut::*;
import Dma::*;

function ObjectReadClient#(dataWidth) orc(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaClient;
function ObjectWriteClient#(dataWidth) owc(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaClient;
function ObjectReadServer#(dataWidth) ors(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaServer;
function ObjectWriteServer#(dataWidth) ows(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaServer;

//
// @brief A buffer for reading from a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaReadBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectReadServer #(dataWidth) dmaServer;
   interface ObjectReadClient#(dataWidth) dmaClient;
endinterface

//
// @brief A buffer for writing to a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaWriteBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectWriteServer#(dataWidth) dmaServer;
   interface ObjectWriteClient#(dataWidth) dmaClient;
endinterface

//
// @brief Makes a Dma buffer for reading wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaReadBuffer(DmaReadBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1,TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth))  readBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(ObjectRequest)        reqReady       <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableBuffers <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      Bool ready = (unpack(requested) <= availableBuffers.read());
      if (ready) begin
	 let req <- toGet(reqOutstanding).get();
	 reqReady.enq(req);
	 availableBuffers.decrement(unpack(requested));
      end
   endrule

   // only issue the readRequest when sufficient buffering is available.  This includes the buffering we have already committed.
   interface ObjectReadServer dmaServer;
      interface Put readReq = toPut(reqOutstanding);
      interface Get readData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    availableBuffers.increment(1);
	    let resp <- toGet(readBuffer).get();
	    return resp;
	 endmethod
      endinterface
   endinterface
   interface ObjectReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(ObjectRequest) get;
	    let req <- toGet(reqReady).get();
	    return req;
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(ObjectData#(dataWidth) x);
	    readBuffer.enq(x);
	 endmethod
      endinterface
   endinterface
endmodule

//
// @brief Makes a Dma channel for writing wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaWriteBuffer(DmaWriteBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1, TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth)) writeBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(Bit#(ObjectTagSize))  doneTags <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableWords <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   FIFOF#(Bool) hasEnoughCapacity <- mkFIFOF();
   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      if (unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)) <= availableWords.read())
	 hasEnoughCapacity.enq(True);
   endrule

   // only issue the writeRequest when sufficient data is available.  This includes the data we have already committed.
   interface ObjectWriteServer dmaServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData;
	 method Action put(ObjectData#(dataWidth) d);
	    writeBuffer.enq(d);
	    availableWords.increment(1);
	 endmethod
      endinterface
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	 method ActionValue#(ObjectRequest) get if (hasEnoughCapacity.notEmpty());
	    hasEnoughCapacity.deq();
	    reqOutstanding.deq;
	    availableWords.decrement(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    writeBuffer.deq;
	    return writeBuffer.first;
	 endmethod
      endinterface
      interface Put writeDone = toPut(doneTags);
   endinterface
endmodule

module mkDmaReadMux#(Vector#(numClients,ObjectReadClient#(dataWidth)) readClients)(ObjectReadClient#(dataWidth))
   provisos(Log#(numClients,tagsz),
	    Add#(tagsz,a__,ObjectTagSize));

   FIFO#(ObjectRequest)          readReqFifo  <- mkFIFO();
   FIFO#(ObjectData#(dataWidth)) readRespFifo <- mkFIFO();

   for (Integer i = 0; i < valueOf(numClients); i = i + 1) begin
      // assume fixed tag per client
      Reg#(Bit#(ObjectTagSize)) tagReg <- mkReg(0);
      rule getreq;
	 let req <- readClients[i].readReq.get();
	 tagReg <= req.tag;
	 req.tag = fromInteger(i);
	 readReqFifo.enq(req);
      endrule
      rule sendresp if (readRespFifo.first.tag == fromInteger(i));
	 let resp <- toGet(readRespFifo).get();
	 resp.tag = tagReg;
	 readClients[i].readData.put(resp);
      endrule
   end

   interface Get readReq = toGet(readReqFifo);
   interface Put readData = toPut(readRespFifo);
endmodule

module mkDmaWriteMux#(Vector#(numClients,ObjectWriteClient#(dataWidth)) writeClients)(ObjectWriteClient#(dataWidth))
   provisos(Log#(numClients,tagsz),
	    Add#(tagsz,a__,ObjectTagSize));

   FIFO#(ObjectRequest)          writeReqFifo  <- mkFIFO();
   FIFO#(ObjectData#(dataWidth)) writeDataFifo <- mkFIFO();
   FIFO#(Bit#(ObjectTagSize))    writeDoneFifo <- mkFIFO();
   FIFO#(Bit#(ObjectTagSize))    arbFifo       <- mkFIFO();

   for (Integer i = 0; i < valueOf(numClients); i = i + 1) begin
      // assume fixed tag per client
      Reg#(Bit#(ObjectTagSize)) tagReg <- mkReg(0);
      rule getreq;
	 let req <- writeClients[i].writeReq.get();
	 tagReg <= req.tag;
	 req.tag = fromInteger(i);
	 writeReqFifo.enq(req);
	 arbFifo.enq(req.tag);
      endrule
      rule senddata if (fromInteger(i) == arbFifo.first);
	 let data <- writeClients[i].writeData.get();
	 data.tag = tagReg;
	 writeDataFifo.enq(data);
      endrule
      rule senddone if (writeDoneFifo.first == fromInteger(i));
	 arbFifo.deq();
	 let done <- toGet(writeDoneFifo).get();
	 writeClients[i].writeDone.put(tagReg);
      endrule
   end

   interface Get writeReq = toGet(writeReqFifo);
   interface Get writeData = toGet(writeDataFifo);
   interface Put writeDone = toPut(writeDoneFifo);
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 BRAM::*;
import FIFO::*;
import Vector::*;
import Gearbox::*;
import FIFOF::*;
import SpecialFIFOs::*;

import BRAMFIFOFLevel::*;
import GetPut::*;
import Dma::*;

function ObjectReadClient#(dataWidth) orc(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaClient;
function ObjectWriteClient#(dataWidth) owc(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaClient;
function ObjectReadServer#(dataWidth) ors(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaServer;
function ObjectWriteServer#(dataWidth) ows(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaServer;

//
// @brief A buffer for reading from a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaReadBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectReadServer #(dataWidth) dmaServer;
   interface ObjectReadClient#(dataWidth) dmaClient;
endinterface

//
// @brief A buffer for writing to a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaWriteBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectWriteServer#(dataWidth) dmaServer;
   interface ObjectWriteClient#(dataWidth) dmaClient;
endinterface

//
// @brief Makes a Dma buffer for reading wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaReadBuffer(DmaReadBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1,TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth))  readBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableBuffers <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   FIFOF#(Bool) hasEnoughCapacity <- mkFIFOF();
   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      Bool ready = (unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)) <= availableBuffers.read());
      if (ready) begin
	 hasEnoughCapacity.enq(True);
      end
   endrule

   // only issue the readRequest when sufficient buffering is available.  This includes the buffering we have already committed.
   interface ObjectReadServer dmaServer;
      interface Put readReq = toPut(reqOutstanding);
      interface Get readData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    availableBuffers.increment(1);
	    let resp <- toGet(readBuffer).get();
	    return resp;
	 endmethod
      endinterface
   endinterface
   interface ObjectReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(ObjectRequest) get if (hasEnoughCapacity.notEmpty);
	    hasEnoughCapacity.deq();
	    reqOutstanding.deq;
	    availableBuffers.decrement(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(ObjectData#(dataWidth) x);
	    readBuffer.enq(x);
	 endmethod
      endinterface
   endinterface
endmodule

//
// @brief Makes a Dma channel for writing wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaWriteBuffer(DmaWriteBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1, TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth)) writeBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(Bit#(ObjectTagSize))  doneTags <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableWords <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   FIFOF#(Bool) hasEnoughCapacity <- mkFIFOF();
   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      if (unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)) <= availableWords.read())
	 hasEnoughCapacity.enq(True);
   endrule

   // only issue the writeRequest when sufficient data is available.  This includes the data we have already committed.
   interface ObjectWriteServer dmaServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData;
	 method Action put(ObjectData#(dataWidth) d);
	    writeBuffer.enq(d);
	    availableWords.increment(1);
	 endmethod
      endinterface
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	 method ActionValue#(ObjectRequest) get if (hasEnoughCapacity.notEmpty());
	    hasEnoughCapacity.deq();
	    reqOutstanding.deq;
	    availableWords.decrement(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    writeBuffer.deq;
	    return writeBuffer.first;
	 endmethod
      endinterface
      interface Put writeDone = toPut(doneTags);
   endinterface
endmodule

module mkDmaReadMux#(Vector#(numClients,ObjectReadClient#(dataWidth)) readClients)(ObjectReadClient#(dataWidth))
   provisos(Log#(numClients,tagsz),
	    Add#(tagsz,a__,ObjectTagSize));

   FIFO#(ObjectRequest)          readReqFifo  <- mkFIFO();
   FIFO#(ObjectData#(dataWidth)) readRespFifo <- mkFIFO();

   for (Integer i = 0; i < valueOf(numClients); i = i + 1) begin
      // assume fixed tag per client
      Reg#(Bit#(ObjectTagSize)) tagReg <- mkReg(0);
      rule getreq;
	 let req <- readClients[i].readReq.get();
	 tagReg <= req.tag;
	 req.tag = fromInteger(i);
	 readReqFifo.enq(req);
      endrule
      rule sendresp if (readRespFifo.first.tag == fromInteger(i));
	 let resp <- toGet(readRespFifo).get();
	 resp.tag = tagReg;
	 readClients[i].readData.put(resp);
      endrule
   end

   interface Get readReq = toGet(readReqFifo);
   interface Put readData = toPut(readRespFifo);
endmodule

module mkDmaWriteMux#(Vector#(numClients,ObjectWriteClient#(dataWidth)) writeClients)(ObjectWriteClient#(dataWidth))
   provisos(Log#(numClients,tagsz),
	    Add#(tagsz,a__,ObjectTagSize));

   FIFO#(ObjectRequest)          writeReqFifo  <- mkFIFO();
   FIFO#(ObjectData#(dataWidth)) writeDataFifo <- mkFIFO();
   FIFO#(Bit#(ObjectTagSize))    writeDoneFifo <- mkFIFO();
   FIFO#(Bit#(ObjectTagSize))    arbFifo       <- mkFIFO();

   for (Integer i = 0; i < valueOf(numClients); i = i + 1) begin
      // assume fixed tag per client
      Reg#(Bit#(ObjectTagSize)) tagReg <- mkReg(0);
      rule getreq;
	 let req <- writeClients[i].writeReq.get();
	 tagReg <= req.tag;
	 req.tag = fromInteger(i);
	 writeReqFifo.enq(req);
	 arbFifo.enq(req.tag);
      endrule
      rule senddata if (fromInteger(i) == arbFifo.first);
	 let data <- writeClients[i].writeData.get();
	 data.tag = tagReg;
	 writeDataFifo.enq(data);
      endrule
      rule senddone if (writeDoneFifo.first == fromInteger(i));
	 arbFifo.deq();
	 let done <- toGet(writeDoneFifo).get();
	 writeClients[i].writeDone.put(tagReg);
      endrule
   end

   interface Get writeReq = toGet(writeReqFifo);
   interface Get writeData = toGet(writeDataFifo);
   interface Put writeDone = toPut(writeDoneFifo);
endmodule


added function memDataData

added function memDataData

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

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

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

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

import ConnectalConfig::*;
import Pipe::*;
import ConnectalMemory::*;
import DefaultValue::*;

`include "ConnectalProjectConfig.bsv"

typedef Bit#(32) SGLId;
`ifndef ZYNQ
typedef 40 MemOffsetSize; // must be at least as large as PhysAddrSize
`else
typedef 32 MemOffsetSize;
`endif
`ifdef MemTagSize
typedef `MemTagSize MemTagSize;
`else
typedef 6 MemTagSize;
`endif
typedef `BurstLenSize BurstLenSize;

`ifndef USE_ACP
`ifdef PCIE3
// as configured, the Xilinx gen3 PCIe core supports 5 bit tags, and
// we need to use unique tags for all transactions in flight. Since
// MemServer uses the same tag numbers for reads and writes, we use
// tag[4] to distinguish the two, leaving 4 bits for unique tags.
// TODO: There is an option for longer tags in the gen3 core.
typedef 16 MemServerTags;
`else
typedef 32 MemServerTags;
`endif
`else
typedef 8 MemServerTags;
`endif
`ifdef DataBusWidth
typedef TDiv#(`DataBusWidth,8) ByteEnableSize;
`else
typedef TDiv#(64,8) ByteEnableSize;
`endif

// memory request with physical addresses.
// these can be transmitted directly to the bus master
typedef struct {
   Bit#(addrWidth) addr;
   Bit#(BurstLenSize) burstLen;
   Bit#(MemTagSize) tag;
`ifdef BYTE_ENABLES
   Bit#(TDiv#(dataBusWidth,8)) firstbe; // maybe we only need lastbe
   Bit#(TDiv#(dataBusWidth,8)) lastbe;
`endif
   } PhysMemRequest#(numeric type addrWidth, numeric type dataBusWidth) deriving (Bits, FShow);

instance DefaultValue#(PhysMemRequest#(addrWidth,dataBusWidth));
   defaultValue = PhysMemRequest { addr: 0, burstLen: 0, tag: 0
`ifdef BYTE_ENABLES
				  , firstbe: maxBound, lastbe: maxBound
`endif
      };
endinstance

// memory request with "virtual" addresses.
// these need to be translated before they can be send to the bus
typedef struct {
   SGLId sglId;
   Bit#(MemOffsetSize) offset;
   Bit#(BurstLenSize) burstLen;
   Bit#(MemTagSize)  tag;
`ifdef BYTE_ENABLES
   Bit#(ByteEnableSize) firstbe; // maybe we only need lastbe
   Bit#(ByteEnableSize) lastbe;
`endif
   } MemRequest deriving (Bits, FShow);

instance DefaultValue#(MemRequest);
   defaultValue = MemRequest {
      sglId: 0, offset: 0, burstLen: 0, tag: 0
`ifdef BYTE_ENABLES
      , firstbe: maxBound, lastbe: maxBound
`endif
      };
endinstance

// memory payload
typedef struct {
   Bit#(dsz) data;
   Bit#(MemTagSize) tag;
   Bool last;
   } MemData#(numeric type dsz) deriving (Bits, FShow);

function Bit#(dsz) memDataData(MemData#(dsz) md); return md.data; endfunction

typeclass ReqByteEnables#(type t, numeric type besz);
   function Bit#(besz) reqFirstByteEnable(t req);
   function Bit#(besz) reqLastByteEnable(t req);
endtypeclass
instance ReqByteEnables#(PhysMemRequest#(addrWidth,dataBusWidth),TDiv#(dataBusWidth,8));
`ifdef BYTE_ENABLES
   function Bit#(TDiv#(dataBusWidth,8)) reqFirstByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return req.firstbe; endfunction
   function Bit#(TDiv#(dataBusWidth,8)) reqLastByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return req.lastbe; endfunction
`else
   function Bit#(TDiv#(dataBusWidth,8)) reqFirstByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return maxBound; endfunction
   function Bit#(TDiv#(dataBusWidth,8)) reqLastByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return maxBound; endfunction
`endif
endinstance
instance ReqByteEnables#(MemRequest,ByteEnableSize);
`ifdef BYTE_ENABLES
   function Bit#(ByteEnableSize) reqFirstByteEnable(MemRequest req); return req.firstbe; endfunction
   function Bit#(ByteEnableSize) reqLastByteEnable(MemRequest req); return req.lastbe; endfunction
`else
   function Bit#(ByteEnableSize) reqFirstByteEnable(MemRequest req); return maxBound; endfunction
   function Bit#(ByteEnableSize) reqLastByteEnable(MemRequest req); return maxBound; endfunction
`endif
endinstance

///////////////////////////////////////////////////////////////////////////////////
//

typedef struct {SGLId sglId;
		Bit#(32) base;
		Bit#(BurstLenSize) burstLen;
		Bit#(32) len;
		Bit#(MemTagSize) tag;
		} MemengineCmd deriving (Eq,Bits);

interface MemWriteEngineServer#(numeric type userWidth);
   interface Put#(MemengineCmd)       request;
   interface Get#(Bool)               done;
   interface PipeIn#(Bit#(userWidth)) data;
   interface PipeOut#(MemRequestCycles)     requestCycles;
endinterface

interface MemWriteEngine#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth, numeric type numServers);
   interface MemWriteClient#(busWidth) dmaClient;
   interface Vector#(numServers, MemWriteEngineServer#(userWidth)) writeServers;
endinterface

typedef struct {
   Bit#(dsz) data;
   Bit#(MemTagSize) tag;
   Bool first;
   Bool last;
   } MemDataF#(numeric type dsz) deriving (Bits);

typedef struct {
   Bit#(MemTagSize) tag;
   Bit#(32)         cycles;
   } MemRequestCycles deriving (Bits);

interface MemReadEngineServer#(numeric type userWidth);
   interface Put#(MemengineCmd)             request;
   interface PipeOut#(MemDataF#(userWidth)) data;
   interface PipeOut#(MemRequestCycles)     requestCycles;
endinterface

interface MemReadEngine#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth, numeric type numServers);
   interface MemReadClient#(busWidth) dmaClient;
   interface Vector#(numServers, MemReadEngineServer#(userWidth)) readServers;
endinterface

//
///////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////
//

interface MemReadClient#(numeric type dsz);
   interface Get#(MemRequest)    readReq;
   interface Put#(MemData#(dsz)) readData;
endinterface

interface MemWriteClient#(numeric type dsz);
   interface Get#(MemRequest)    writeReq;
   interface Get#(MemData#(dsz)) writeData;
   interface Put#(Bit#(MemTagSize))       writeDone;
endinterface

interface MemClient#(numeric type dsz);
   interface MemReadClient#(dsz) readClient;
   interface MemWriteClient#(dsz) writeClient;
endinterface

interface MemReadServer#(numeric type dsz);
   interface Put#(MemRequest) readReq;
   interface Get#(MemData#(dsz))     readData;
endinterface

interface MemWriteServer#(numeric type dsz);
   interface Put#(MemRequest) writeReq;
   interface Put#(MemData#(dsz))     writeData;
   interface Get#(Bit#(MemTagSize))           writeDone;
endinterface

interface MemServer#(numeric type dataWidth);
   interface MemReadServer#(dataWidth) readServer;
   interface MemWriteServer#(dataWidth) writeServer;
endinterface

//
///////////////////////////////////////////////////////////////////////////////////
//

interface PhysMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemReadServer#(addrWidth, dataWidth) read_server;
   interface PhysMemWriteServer#(addrWidth, dataWidth) write_server;
endinterface

interface PhysMemMaster#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemReadClient#(addrWidth, dataWidth) read_client;
   interface PhysMemWriteClient#(addrWidth, dataWidth) write_client;
endinterface

interface PhysMemReadClient#(numeric type asz, numeric type dsz);
   interface Get#(PhysMemRequest#(asz,dsz))    readReq;
   interface Put#(MemData#(dsz)) readData;
endinterface

interface PhysMemWriteClient#(numeric type asz, numeric type dsz);
   interface Get#(PhysMemRequest#(asz,dsz))    writeReq;
   interface Get#(MemData#(dsz)) writeData;
   interface Put#(Bit#(MemTagSize))       writeDone;
endinterface

interface PhysMemReadServer#(numeric type asz, numeric type dsz);
   interface Put#(PhysMemRequest#(asz,dsz)) readReq;
   interface Get#(MemData#(dsz))     readData;
endinterface

interface PhysMemWriteServer#(numeric type asz, numeric type dsz);
   interface Put#(PhysMemRequest#(asz,dsz)) writeReq;
   interface Put#(MemData#(dsz))     writeData;
   interface Get#(Bit#(MemTagSize))           writeDone;
endinterface

//
///////////////////////////////////////////////////////////////////////////////////

instance Connectable#(MemReadClient#(dsz), MemReadServer#(dsz));
   module mkConnection#(MemReadClient#(dsz) source, MemReadServer#(dsz) sink)(Empty);
      rule mr_request;
	 let req <- source.readReq.get();
	 sink.readReq.put(req);
      endrule
      rule mr_response;
	 let resp <- sink.readData.get();
	 source.readData.put(resp);
      endrule
   endmodule
endinstance

instance Connectable#(MemWriteClient#(dsz), MemWriteServer#(dsz));
   module mkConnection#(MemWriteClient#(dsz) source, MemWriteServer#(dsz) sink)(Empty);
      rule mw_request;
	 let req <- source.writeReq.get();
	 sink.writeReq.put(req);
      endrule
      rule mw_response;
	 let resp <- source.writeData.get();
	 sink.writeData.put(resp);
      endrule
      rule mw_done;
	 let resp <- sink.writeDone.get();
	 source.writeDone.put(resp);
      endrule
   endmodule
endinstance

instance Connectable#(MemClient#(dsz), MemServer#(dsz));
   module mkConnection#(MemClient#(dsz) source, MemServer#(dsz) sink)(Empty);
      mkConnection(source.readClient, sink.readServer);
      mkConnection(source.writeClient, sink.writeServer);
   endmodule
endinstance

instance Connectable#(PhysMemMaster#(addrWidth, busWidth), PhysMemSlave#(addrWidth, busWidth));
   module mkConnection#(PhysMemMaster#(addrWidth, busWidth) m, PhysMemSlave#(addrWidth, busWidth) s)(Empty);
      mkConnection(m.read_client.readReq, s.read_server.readReq);
      mkConnection(s.read_server.readData, m.read_client.readData);
      mkConnection(m.write_client.writeReq, s.write_server.writeReq);
      mkConnection(m.write_client.writeData, s.write_server.writeData);
      mkConnection(s.write_server.writeDone, m.write_client.writeDone);
   endmodule
endinstance

// this is used for debugging MemToPcie/PcieToMem in BsimTop.bsv
instance Connectable#(PhysMemMaster#(32, busWidth), PhysMemSlave#(40, busWidth));
   module mkConnection#(PhysMemMaster#(32, busWidth) m, PhysMemSlave#(40, busWidth) s)(Empty);
      //mkConnection(m.read_client.readReq, s.read_server.readReq);
      rule readreq;
	 let req <- m.read_client.readReq.get();
	 s.read_server.readReq.put(PhysMemRequest { addr: extend(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						   , firstbe: req.firstbe, lastbe: req.lastbe
`endif
	    });
      endrule

      mkConnection(s.read_server.readData, m.read_client.readData);
      //mkConnection(m.write_client.writeReq, s.write_server.writeReq);
      rule writereq;
	 let req <- m.write_client.writeReq.get();
	 s.write_server.writeReq.put(PhysMemRequest { addr: extend(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						     , firstbe: req.firstbe, lastbe: req.lastbe
`endif
 });
      endrule
      mkConnection(m.write_client.writeData, s.write_server.writeData);
      mkConnection(s.write_server.writeDone, m.write_client.writeDone);
   endmodule
endinstance

function Bool isQuadWordAligned(Bit#(7) lower_addr);
   return (lower_addr[2:0]==3'b0);
endfunction

function Put#(t) null_put();
   return (interface Put;
              method Action put(t x) if (False);
                 noAction;
              endmethod
           endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
              method ActionValue#(t) get() if (False);
                 return ?;
              endmethod
           endinterface);
endfunction

function  PhysMemWriteClient#(addrWidth, busWidth) null_phys_mem_write_client();
   return (interface PhysMemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  PhysMemReadClient#(addrWidth, busWidth) null_phys_mem_read_client();
   return (interface PhysMemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

function  MemWriteClient#(busWidth) null_mem_write_client();
   return (interface MemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  MemReadClient#(busWidth) null_mem_read_client();
   return (interface MemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

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

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

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

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

import ConnectalConfig::*;
import Pipe::*;
import ConnectalMemory::*;
import DefaultValue::*;

`include "ConnectalProjectConfig.bsv"

typedef Bit#(32) SGLId;
`ifndef ZYNQ
typedef 40 MemOffsetSize; // must be at least as large as PhysAddrSize
`else
typedef 32 MemOffsetSize;
`endif
`ifdef MemTagSize
typedef `MemTagSize MemTagSize;
`else
typedef 6 MemTagSize;
`endif
typedef `BurstLenSize BurstLenSize;

`ifndef USE_ACP
`ifdef PCIE3
// as configured, the Xilinx gen3 PCIe core supports 5 bit tags, and
// we need to use unique tags for all transactions in flight. Since
// MemServer uses the same tag numbers for reads and writes, we use
// tag[4] to distinguish the two, leaving 4 bits for unique tags.
// TODO: There is an option for longer tags in the gen3 core.
typedef 16 MemServerTags;
`else
typedef 32 MemServerTags;
`endif
`else
typedef 8 MemServerTags;
`endif
`ifdef DataBusWidth
typedef TDiv#(`DataBusWidth,8) ByteEnableSize;
`else
typedef TDiv#(64,8) ByteEnableSize;
`endif

// memory request with physical addresses.
// these can be transmitted directly to the bus master
typedef struct {
   Bit#(addrWidth) addr;
   Bit#(BurstLenSize) burstLen;
   Bit#(MemTagSize) tag;
`ifdef BYTE_ENABLES
   Bit#(TDiv#(dataBusWidth,8)) firstbe; // maybe we only need lastbe
   Bit#(TDiv#(dataBusWidth,8)) lastbe;
`endif
   } PhysMemRequest#(numeric type addrWidth, numeric type dataBusWidth) deriving (Bits, FShow);

instance DefaultValue#(PhysMemRequest#(addrWidth,dataBusWidth));
   defaultValue = PhysMemRequest { addr: 0, burstLen: 0, tag: 0
`ifdef BYTE_ENABLES
				  , firstbe: maxBound, lastbe: maxBound
`endif
      };
endinstance

// memory request with "virtual" addresses.
// these need to be translated before they can be send to the bus
typedef struct {
   SGLId sglId;
   Bit#(MemOffsetSize) offset;
   Bit#(BurstLenSize) burstLen;
   Bit#(MemTagSize)  tag;
`ifdef BYTE_ENABLES
   Bit#(ByteEnableSize) firstbe; // maybe we only need lastbe
   Bit#(ByteEnableSize) lastbe;
`endif
   } MemRequest deriving (Bits, FShow);

instance DefaultValue#(MemRequest);
   defaultValue = MemRequest {
      sglId: 0, offset: 0, burstLen: 0, tag: 0
`ifdef BYTE_ENABLES
      , firstbe: maxBound, lastbe: maxBound
`endif
      };
endinstance

// memory payload
typedef struct {
   Bit#(dsz) data;
   Bit#(MemTagSize) tag;
   Bool last;
   } MemData#(numeric type dsz) deriving (Bits, FShow);

typeclass ReqByteEnables#(type t, numeric type besz);
   function Bit#(besz) reqFirstByteEnable(t req);
   function Bit#(besz) reqLastByteEnable(t req);
endtypeclass
instance ReqByteEnables#(PhysMemRequest#(addrWidth,dataBusWidth),TDiv#(dataBusWidth,8));
`ifdef BYTE_ENABLES
   function Bit#(TDiv#(dataBusWidth,8)) reqFirstByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return req.firstbe; endfunction
   function Bit#(TDiv#(dataBusWidth,8)) reqLastByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return req.lastbe; endfunction
`else
   function Bit#(TDiv#(dataBusWidth,8)) reqFirstByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return maxBound; endfunction
   function Bit#(TDiv#(dataBusWidth,8)) reqLastByteEnable(PhysMemRequest#(addrWidth,dataBusWidth) req); return maxBound; endfunction
`endif
endinstance
instance ReqByteEnables#(MemRequest,ByteEnableSize);
`ifdef BYTE_ENABLES
   function Bit#(ByteEnableSize) reqFirstByteEnable(MemRequest req); return req.firstbe; endfunction
   function Bit#(ByteEnableSize) reqLastByteEnable(MemRequest req); return req.lastbe; endfunction
`else
   function Bit#(ByteEnableSize) reqFirstByteEnable(MemRequest req); return maxBound; endfunction
   function Bit#(ByteEnableSize) reqLastByteEnable(MemRequest req); return maxBound; endfunction
`endif
endinstance

///////////////////////////////////////////////////////////////////////////////////
//

typedef struct {SGLId sglId;
		Bit#(32) base;
		Bit#(BurstLenSize) burstLen;
		Bit#(32) len;
		Bit#(MemTagSize) tag;
		} MemengineCmd deriving (Eq,Bits);

interface MemWriteEngineServer#(numeric type userWidth);
   interface Put#(MemengineCmd)       request;
   interface Get#(Bool)               done;
   interface PipeIn#(Bit#(userWidth)) data;
   interface PipeOut#(MemRequestCycles)     requestCycles;
endinterface

interface MemWriteEngine#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth, numeric type numServers);
   interface MemWriteClient#(busWidth) dmaClient;
   interface Vector#(numServers, MemWriteEngineServer#(userWidth)) writeServers;
endinterface

typedef struct {
   Bit#(dsz) data;
   Bit#(MemTagSize) tag;
   Bool first;
   Bool last;
   } MemDataF#(numeric type dsz) deriving (Bits);

typedef struct {
   Bit#(MemTagSize) tag;
   Bit#(32)         cycles;
   } MemRequestCycles deriving (Bits);

interface MemReadEngineServer#(numeric type userWidth);
   interface Put#(MemengineCmd)             request;
   interface PipeOut#(MemDataF#(userWidth)) data;
   interface PipeOut#(MemRequestCycles)     requestCycles;
endinterface

interface MemReadEngine#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth, numeric type numServers);
   interface MemReadClient#(busWidth) dmaClient;
   interface Vector#(numServers, MemReadEngineServer#(userWidth)) readServers;
endinterface

//
///////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////
//

interface MemReadClient#(numeric type dsz);
   interface Get#(MemRequest)    readReq;
   interface Put#(MemData#(dsz)) readData;
endinterface

interface MemWriteClient#(numeric type dsz);
   interface Get#(MemRequest)    writeReq;
   interface Get#(MemData#(dsz)) writeData;
   interface Put#(Bit#(MemTagSize))       writeDone;
endinterface

interface MemClient#(numeric type dsz);
   interface MemReadClient#(dsz) readClient;
   interface MemWriteClient#(dsz) writeClient;
endinterface

interface MemReadServer#(numeric type dsz);
   interface Put#(MemRequest) readReq;
   interface Get#(MemData#(dsz))     readData;
endinterface

interface MemWriteServer#(numeric type dsz);
   interface Put#(MemRequest) writeReq;
   interface Put#(MemData#(dsz))     writeData;
   interface Get#(Bit#(MemTagSize))           writeDone;
endinterface

interface MemServer#(numeric type dataWidth);
   interface MemReadServer#(dataWidth) readServer;
   interface MemWriteServer#(dataWidth) writeServer;
endinterface

//
///////////////////////////////////////////////////////////////////////////////////
//

interface PhysMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemReadServer#(addrWidth, dataWidth) read_server;
   interface PhysMemWriteServer#(addrWidth, dataWidth) write_server;
endinterface

interface PhysMemMaster#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemReadClient#(addrWidth, dataWidth) read_client;
   interface PhysMemWriteClient#(addrWidth, dataWidth) write_client;
endinterface

interface PhysMemReadClient#(numeric type asz, numeric type dsz);
   interface Get#(PhysMemRequest#(asz,dsz))    readReq;
   interface Put#(MemData#(dsz)) readData;
endinterface

interface PhysMemWriteClient#(numeric type asz, numeric type dsz);
   interface Get#(PhysMemRequest#(asz,dsz))    writeReq;
   interface Get#(MemData#(dsz)) writeData;
   interface Put#(Bit#(MemTagSize))       writeDone;
endinterface

interface PhysMemReadServer#(numeric type asz, numeric type dsz);
   interface Put#(PhysMemRequest#(asz,dsz)) readReq;
   interface Get#(MemData#(dsz))     readData;
endinterface

interface PhysMemWriteServer#(numeric type asz, numeric type dsz);
   interface Put#(PhysMemRequest#(asz,dsz)) writeReq;
   interface Put#(MemData#(dsz))     writeData;
   interface Get#(Bit#(MemTagSize))           writeDone;
endinterface

//
///////////////////////////////////////////////////////////////////////////////////

instance Connectable#(MemReadClient#(dsz), MemReadServer#(dsz));
   module mkConnection#(MemReadClient#(dsz) source, MemReadServer#(dsz) sink)(Empty);
      rule mr_request;
	 let req <- source.readReq.get();
	 sink.readReq.put(req);
      endrule
      rule mr_response;
	 let resp <- sink.readData.get();
	 source.readData.put(resp);
      endrule
   endmodule
endinstance

instance Connectable#(MemWriteClient#(dsz), MemWriteServer#(dsz));
   module mkConnection#(MemWriteClient#(dsz) source, MemWriteServer#(dsz) sink)(Empty);
      rule mw_request;
	 let req <- source.writeReq.get();
	 sink.writeReq.put(req);
      endrule
      rule mw_response;
	 let resp <- source.writeData.get();
	 sink.writeData.put(resp);
      endrule
      rule mw_done;
	 let resp <- sink.writeDone.get();
	 source.writeDone.put(resp);
      endrule
   endmodule
endinstance

instance Connectable#(MemClient#(dsz), MemServer#(dsz));
   module mkConnection#(MemClient#(dsz) source, MemServer#(dsz) sink)(Empty);
      mkConnection(source.readClient, sink.readServer);
      mkConnection(source.writeClient, sink.writeServer);
   endmodule
endinstance

instance Connectable#(PhysMemMaster#(addrWidth, busWidth), PhysMemSlave#(addrWidth, busWidth));
   module mkConnection#(PhysMemMaster#(addrWidth, busWidth) m, PhysMemSlave#(addrWidth, busWidth) s)(Empty);
      mkConnection(m.read_client.readReq, s.read_server.readReq);
      mkConnection(s.read_server.readData, m.read_client.readData);
      mkConnection(m.write_client.writeReq, s.write_server.writeReq);
      mkConnection(m.write_client.writeData, s.write_server.writeData);
      mkConnection(s.write_server.writeDone, m.write_client.writeDone);
   endmodule
endinstance

// this is used for debugging MemToPcie/PcieToMem in BsimTop.bsv
instance Connectable#(PhysMemMaster#(32, busWidth), PhysMemSlave#(40, busWidth));
   module mkConnection#(PhysMemMaster#(32, busWidth) m, PhysMemSlave#(40, busWidth) s)(Empty);
      //mkConnection(m.read_client.readReq, s.read_server.readReq);
      rule readreq;
	 let req <- m.read_client.readReq.get();
	 s.read_server.readReq.put(PhysMemRequest { addr: extend(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						   , firstbe: req.firstbe, lastbe: req.lastbe
`endif
	    });
      endrule

      mkConnection(s.read_server.readData, m.read_client.readData);
      //mkConnection(m.write_client.writeReq, s.write_server.writeReq);
      rule writereq;
	 let req <- m.write_client.writeReq.get();
	 s.write_server.writeReq.put(PhysMemRequest { addr: extend(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						     , firstbe: req.firstbe, lastbe: req.lastbe
`endif
 });
      endrule
      mkConnection(m.write_client.writeData, s.write_server.writeData);
      mkConnection(s.write_server.writeDone, m.write_client.writeDone);
   endmodule
endinstance

function Bool isQuadWordAligned(Bit#(7) lower_addr);
   return (lower_addr[2:0]==3'b0);
endfunction

function Put#(t) null_put();
   return (interface Put;
              method Action put(t x) if (False);
                 noAction;
              endmethod
           endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
              method ActionValue#(t) get() if (False);
                 return ?;
              endmethod
           endinterface);
endfunction

function  PhysMemWriteClient#(addrWidth, busWidth) null_phys_mem_write_client();
   return (interface PhysMemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  PhysMemReadClient#(addrWidth, busWidth) null_phys_mem_read_client();
   return (interface PhysMemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

function  MemWriteClient#(busWidth) null_mem_write_client();
   return (interface MemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  MemReadClient#(busWidth) null_mem_read_client();
   return (interface MemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction


Added addrWidth and idWidth to FrameBufferBram

// Copyright (c) 2013 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 NrccSyncBRAM::*;
import BRAMFIFO::*;
import GetPut::*;
import FIFOF::*;
import Vector::*;
import SpecialFIFOs::*;
import AxiMasterSlave::*;
import AxiClientServer::*;

typedef struct {
    Bit#(32) base;
    Bit#(11) lines;
    Bit#(12) pixels;
    Bit#(14) stridebytes;
} FrameBufferConfig deriving (Bits);

Integer bytesperpixel = 4;

interface FrameBufferBram;
    method Bool running();
    method Bit#(32) base();
    method Action configure(FrameBufferConfig fbc);
    method Action startFrame();
    method Action startLine();
    method Action setSgEntry(Bit#(8) index, Bit#(24) startingOffset, Bit#(20) address, Bit#(20) length);
    interface Axi3Client#(32,32,4,6) axi;
    interface BRAM#(Bit#(12), Bit#(32)) buffer;
endinterface

typedef struct {
    Bit#(24) startingOffset;
    Bit#(24) limitOffset;
    Bit#(20) address; // these are page aligned, so 12 bits of zeros
    Bit#(20) length;
}  ScatterGather deriving (Bits);

module mkFrameBufferBram#(Clock displayClk, Reset displayRst)(FrameBufferBram);
    Reg#(FrameBufferConfig) nextFbc <- mkReg(FrameBufferConfig {base: 0, lines: 0, pixels: 0, stridebytes: 0});
    Reg#(FrameBufferConfig) fbc <- mkReg(FrameBufferConfig {base: 0, lines: 0, pixels: 0, stridebytes: 0});
    Reg#(Bool) runningReg <- mkReg(False);

    //let burstCount = 16;
    let burstCount = 4;
    let bytesPerWord = 4;
    let busWidth = bytesPerWord * 8;
    let bytesPerPixel = 4;
    let pixelsPerWord = bytesPerWord / bytesPerPixel;

    Reg#(Bit#(8))  sglistIndexReg <- mkReg(0); // which segment we're reading from
    Reg#(Bit#(24)) lineAddrReg <- mkReg(0); // address of start of line
    Reg#(Bit#(24)) readAddrReg <- mkReg(0); // next address to read
    Reg#(Bit#(24)) readLimitReg <- mkReg(0); // address of end of line

    Reg#(Bit#(24)) segmentLimitReg <- mkReg(0);
    Reg#(Bit#(32)) segmentOffsetReg <- mkReg(0);

    Reg#(Bit#(12)) pixelCountReg <- mkReg(0);
    Reg#(Bit#(11)) lineCountReg <- mkReg(0);

    Clock clk <- exposeCurrentClock ;
    Reset rst <- exposeCurrentReset ;

    //Vector#(16, Reg#(ScatterGather)) sglist <- replicateM(mkReg(unpack(0)));
    SyncBRAM#(Bit#(8), ScatterGather) sglist <- mkSyncBRAM( 256, clk, rst, clk, rst);

    //Axi3Master#(32,4,6) nullAxiMaster <- mkNullAxi3Master();

    SyncBRAM#(Bit#(12), Bit#(32)) syncBRAM <- mkSyncBRAM( 4096, displayClk, displayRst, clk, rst );
    //SyncBRAM#(Bit#(12), Bit#(32)) syncBRAM <- mkSimSyncBRAM( 4096, displayClk, displayRst, clk, rst );
    Reg#(Bit#(12)) pixelCountReg2 <- mkReg(0);

    Reg#(Bool) nextent2Enabled <- mkReg(False);
    Reg#(Bool) startFrameEnabled <- mkReg(False);

    rule nextent if (readAddrReg != 24'hFFFFFF
    && readAddrReg > segmentLimitReg
                     && !nextent2Enabled);
        $display("nextent readAddrReg %h segmentLimitReg %h", readAddrReg, segmentLimitReg);
        let index = sglistIndexReg+1;
        nextent2Enabled <= True;
        sglist.portA.readAddr(index);
    endrule

    rule nextent2 if (nextent2Enabled);
        nextent2Enabled <= False;
        let index = sglistIndexReg+1;
        let sgent <- sglist.portA.readData();
        sglistIndexReg <= index;
        let segmentOffset = {sgent.address,12'd0} - extend(sgent.startingOffset);
        let segmentLimit = sgent.limitOffset;
        segmentOffsetReg <= segmentOffset;
        segmentLimitReg <= segmentLimit;
    endrule

    rule startFrameRule if (startFrameEnabled);
        startFrameEnabled <= False;
        fbc <= nextFbc;
        Bit#(8) segmentIndex = truncate(nextFbc.base);
        ScatterGather sgent <- sglist.portB.readData();
        sglistIndexReg <= segmentIndex;
        let segmentOffset = {sgent.address,12'd0} - extend(sgent.startingOffset);
        let segmentLimit = sgent.limitOffset;
        segmentOffsetReg <= segmentOffset;
        segmentLimitReg <= segmentLimit;
        $display("startFrame address %h startingOffset %h segmentOffset %h readLimit %h",
                 {sgent.address,12'd0}, sgent.startingOffset,
                 segmentOffset,
                 sgent.startingOffset + extend(nextFbc.stridebytes));

        lineAddrReg <= sgent.startingOffset;
        readAddrReg <= 24'hFFFFFF; // indicates have not received first hsync pulse
        readLimitReg <= sgent.startingOffset + extend(nextFbc.stridebytes);
        lineCountReg <= nextFbc.lines;
        pixelCountReg <= nextFbc.pixels;

        runningReg <= True;
    endrule

    method Bool running();
        return runningReg;
    endmethod

    method Bit#(32) base();
        return fbc.base;
    endmethod

    method Action configure(FrameBufferConfig newConfig);
        nextFbc <= newConfig;
    endmethod

    method Action setSgEntry(Bit#(8) index, Bit#(24) startingOffset, Bit#(20) address, Bit#(20) length);
        ScatterGather newEnt = ScatterGather {
            startingOffset: startingOffset,
            address:  address,
            length:  length,
            limitOffset: startingOffset + truncate({length,12'd0})
        };
        $display("setSgEntry startingOffset %d address %d length %h limitOffset %h",
                 startingOffset, address, length, startingOffset + {length,4'd0});
        sglist.portA.write(index, newEnt);
    endmethod

    method Action startFrame() if (!startFrameEnabled);
        startFrameEnabled <= True;
        Bit#(8) segmentIndex = truncate(nextFbc.base);
        sglist.portB.readAddr(segmentIndex);
    endmethod

    method Action startLine();
        if (runningReg)
        begin
            let lineAddr = lineAddrReg;
            let readLimit = readLimitReg;
            let lineCount = lineCountReg;
            if (readAddrReg != 24'hFFFFFF) // if not the first line
            begin
                lineAddr = lineAddr + extend(fbc.stridebytes);
                readLimit = readLimit + extend(fbc.stridebytes);
                lineCount = lineCount - 1;
            end
            $display("startLine readAddr %h readLimit %h stridebytes %h", lineAddr, readLimit, fbc.stridebytes);

            lineAddrReg <= lineAddr;
            readAddrReg <= lineAddr;
            readLimitReg <= readLimit;
            lineCountReg <= lineCount;

            pixelCountReg2 <= 0;

            if (lineCount == 0)
            begin
                runningReg <= False;
            end
        end
    endmethod

   interface Axi3Client axi;
       interface Axi3ReadClient read;
           method ActionValue#(Axi3ReadRequest#(32,6)) address() if (runningReg
								  && readAddrReg != 24'hFFFFFF
								  && readAddrReg < readLimitReg
								  && readAddrReg <= segmentLimitReg
								  );
               Bit#(32) addr = extend(readAddrReg) + segmentOffsetReg;
	       Bit#(5) burstLen = burstCount-1;
               readAddrReg <= readAddrReg + burstCount*bytesPerWord;
               return Axi3ReadRequest { address: addr, burstLen: truncate(burstLen), id: 0} ;
           endmethod
           method Action data(Axi3ReadResponse#(32,6) response);
               pixelCountReg2 <= pixelCountReg2 + pixelsPerWord;
               syncBRAM.portB.write(pixelCountReg2 / pixelsPerWord, response.data);
           endmethod
       endinterface

       //interface Axi3WriteClient write = nullAxiClient.write;
   endinterface
   interface NrccBRAM buffer = syncBRAM.portA;
endmodule

// Copyright (c) 2013 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 NrccSyncBRAM::*;
import BRAMFIFO::*;
import GetPut::*;
import FIFOF::*;
import Vector::*;
import SpecialFIFOs::*;
import AxiMasterSlave::*;
import AxiClientServer::*;

typedef struct {
    Bit#(32) base;
    Bit#(11) lines;
    Bit#(12) pixels;
    Bit#(14) stridebytes;
} FrameBufferConfig deriving (Bits);

Integer bytesperpixel = 4;

interface FrameBufferBram;
    method Bool running();
    method Bit#(32) base();
    method Action configure(FrameBufferConfig fbc);
    method Action startFrame();
    method Action startLine();
    method Action setSgEntry(Bit#(8) index, Bit#(24) startingOffset, Bit#(20) address, Bit#(20) length);
    interface Axi3Client#(32,4,6) axi;
    interface BRAM#(Bit#(12), Bit#(32)) buffer;
endinterface

typedef struct {
    Bit#(24) startingOffset;
    Bit#(24) limitOffset;
    Bit#(20) address; // these are page aligned, so 12 bits of zeros
    Bit#(20) length;
}  ScatterGather deriving (Bits);

module mkFrameBufferBram#(Clock displayClk, Reset displayRst)(FrameBufferBram);
    Reg#(FrameBufferConfig) nextFbc <- mkReg(FrameBufferConfig {base: 0, lines: 0, pixels: 0, stridebytes: 0});
    Reg#(FrameBufferConfig) fbc <- mkReg(FrameBufferConfig {base: 0, lines: 0, pixels: 0, stridebytes: 0});
    Reg#(Bool) runningReg <- mkReg(False);

    //let burstCount = 16;
    let burstCount = 4;
    let bytesPerWord = 4;
    let busWidth = bytesPerWord * 8;
    let bytesPerPixel = 4;
    let pixelsPerWord = bytesPerWord / bytesPerPixel;

    Reg#(Bit#(8))  sglistIndexReg <- mkReg(0); // which segment we're reading from
    Reg#(Bit#(24)) lineAddrReg <- mkReg(0); // address of start of line
    Reg#(Bit#(24)) readAddrReg <- mkReg(0); // next address to read
    Reg#(Bit#(24)) readLimitReg <- mkReg(0); // address of end of line

    Reg#(Bit#(24)) segmentLimitReg <- mkReg(0);
    Reg#(Bit#(32)) segmentOffsetReg <- mkReg(0);

    Reg#(Bit#(12)) pixelCountReg <- mkReg(0);
    Reg#(Bit#(11)) lineCountReg <- mkReg(0);

    Clock clk <- exposeCurrentClock ;
    Reset rst <- exposeCurrentReset ;

    //Vector#(16, Reg#(ScatterGather)) sglist <- replicateM(mkReg(unpack(0)));
    SyncBRAM#(Bit#(8), ScatterGather) sglist <- mkSyncBRAM( 256, clk, rst, clk, rst);

    //Axi3Master#(32,4,6) nullAxiMaster <- mkNullAxi3Master();

    SyncBRAM#(Bit#(12), Bit#(32)) syncBRAM <- mkSyncBRAM( 4096, displayClk, displayRst, clk, rst );
    //SyncBRAM#(Bit#(12), Bit#(32)) syncBRAM <- mkSimSyncBRAM( 4096, displayClk, displayRst, clk, rst );
    Reg#(Bit#(12)) pixelCountReg2 <- mkReg(0);

    Reg#(Bool) nextent2Enabled <- mkReg(False);
    Reg#(Bool) startFrameEnabled <- mkReg(False);

    rule nextent if (readAddrReg != 24'hFFFFFF
    && readAddrReg > segmentLimitReg
                     && !nextent2Enabled);
        $display("nextent readAddrReg %h segmentLimitReg %h", readAddrReg, segmentLimitReg);
        let index = sglistIndexReg+1;
        nextent2Enabled <= True;
        sglist.portA.readAddr(index);
    endrule

    rule nextent2 if (nextent2Enabled);
        nextent2Enabled <= False;
        let index = sglistIndexReg+1;
        let sgent <- sglist.portA.readData();
        sglistIndexReg <= index;
        let segmentOffset = {sgent.address,12'd0} - extend(sgent.startingOffset);
        let segmentLimit = sgent.limitOffset;
        segmentOffsetReg <= segmentOffset;
        segmentLimitReg <= segmentLimit;
    endrule

    rule startFrameRule if (startFrameEnabled);
        startFrameEnabled <= False;
        fbc <= nextFbc;
        Bit#(8) segmentIndex = truncate(nextFbc.base);
        ScatterGather sgent <- sglist.portB.readData();
        sglistIndexReg <= segmentIndex;
        let segmentOffset = {sgent.address,12'd0} - extend(sgent.startingOffset);
        let segmentLimit = sgent.limitOffset;
        segmentOffsetReg <= segmentOffset;
        segmentLimitReg <= segmentLimit;
        $display("startFrame address %h startingOffset %h segmentOffset %h readLimit %h",
                 {sgent.address,12'd0}, sgent.startingOffset,
                 segmentOffset,
                 sgent.startingOffset + extend(nextFbc.stridebytes));

        lineAddrReg <= sgent.startingOffset;
        readAddrReg <= 24'hFFFFFF; // indicates have not received first hsync pulse
        readLimitReg <= sgent.startingOffset + extend(nextFbc.stridebytes);
        lineCountReg <= nextFbc.lines;
        pixelCountReg <= nextFbc.pixels;

        runningReg <= True;
    endrule

    method Bool running();
        return runningReg;
    endmethod

    method Bit#(32) base();
        return fbc.base;
    endmethod

    method Action configure(FrameBufferConfig newConfig);
        nextFbc <= newConfig;
    endmethod

    method Action setSgEntry(Bit#(8) index, Bit#(24) startingOffset, Bit#(20) address, Bit#(20) length);
        ScatterGather newEnt = ScatterGather {
            startingOffset: startingOffset,
            address:  address,
            length:  length,
            limitOffset: startingOffset + truncate({length,12'd0})
        };
        $display("setSgEntry startingOffset %d address %d length %h limitOffset %h",
                 startingOffset, address, length, startingOffset + {length,4'd0});
        sglist.portA.write(index, newEnt);
    endmethod

    method Action startFrame() if (!startFrameEnabled);
        startFrameEnabled <= True;
        Bit#(8) segmentIndex = truncate(nextFbc.base);
        sglist.portB.readAddr(segmentIndex);
    endmethod

    method Action startLine();
        if (runningReg)
        begin
            let lineAddr = lineAddrReg;
            let readLimit = readLimitReg;
            let lineCount = lineCountReg;
            if (readAddrReg != 24'hFFFFFF) // if not the first line
            begin
                lineAddr = lineAddr + extend(fbc.stridebytes);
                readLimit = readLimit + extend(fbc.stridebytes);
                lineCount = lineCount - 1;
            end
            $display("startLine readAddr %h readLimit %h stridebytes %h", lineAddr, readLimit, fbc.stridebytes);

            lineAddrReg <= lineAddr;
            readAddrReg <= lineAddr;
            readLimitReg <= readLimit;
            lineCountReg <= lineCount;

            pixelCountReg2 <= 0;

            if (lineCount == 0)
            begin
                runningReg <= False;
            end
        end
    endmethod

   interface Axi3Client axi;
       interface Axi3ReadClient read;
           method ActionValue#(Axi3ReadRequest#(6)) address() if (runningReg
								  && readAddrReg != 24'hFFFFFF
								  && readAddrReg < readLimitReg
								  && readAddrReg <= segmentLimitReg
								  );
               Bit#(32) addr = extend(readAddrReg) + segmentOffsetReg;
	       Bit#(5) burstLen = burstCount-1;
               readAddrReg <= readAddrReg + burstCount*bytesPerWord;
               return Axi3ReadRequest { address: addr, burstLen: truncate(burstLen), id: 0} ;
           endmethod
           method Action data(Axi3ReadResponse#(32,6) response);
               pixelCountReg2 <= pixelCountReg2 + pixelsPerWord;
               syncBRAM.portB.write(pixelCountReg2 / pixelsPerWord, response.data);
           endmethod
       endinterface

       //interface Axi3WriteClient write = nullAxiClient.write;
   endinterface
   interface NrccBRAM buffer = syncBRAM.portA;
endmodule