comment out multiple vlan related code

comment out multiple vlan related code

// Copyright (c) 2015 Cornell University.

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

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

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

/* DO NOT MODIFY, AUTO GENERATED BY P4 COMPILER */

import BuildVector::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import Pipe::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;

import Ethernet::*;
import P4Types::*;

interface Parser;
   // derive parseReset from start of packet
   method Action parserReset();
   interface PipeIn#(EtherData) frameIn;
   interface PipeOut#(void) parseDone;
   interface PipeOut#(MatchKey_port_mapping) match_key_port_mapping;
   interface PipeOut#(MatchKey_bd) match_key_bd;
   interface PipeOut#(MatchKey_ipv4_fib) match_key_ipv4_fib;
   interface PipeOut#(MatchKey_ipv4_fib_lpm) match_key_ipv4_fib_lpm;
   interface PipeOut#(MatchKey_nexthop) match_key_nexthop;
   interface PipeOut#(MatchKey_rewrite_mac) match_rewrite_mac;
   interface PipeOut#(Bit#(128)) payloadOut;
endinterface

interface ParseEthernet;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeOut#(Ethernet_t) parsedOut;
   interface PipeOut#(Bit#(16)) unparsedOutIpv4; // number is parse state id
   interface PipeOut#(Bit#(16)) unparsedOutVlan; // number is parse state id
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseVlan;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Vlan_tag_t) parsedOut;
   interface PipeOut#(Bit#(112)) unparsedOutVlan0;
   //interface PipeOut#(Bit#(80)) unparsedOutVlan1;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseIpv4;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Ipv4_t) parsedOut;
   interface PipeIn#(Bit#(112)) unparsedInVlan0;
   //interface PipeIn#(Bit#(80)) unparsedInVlan1;
   interface PipeOut#(Bit#(112)) unparsedOut;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

typedef enum {S0, S1, S2, S3, S4} ParserState deriving (Bits, Eq);
instance FShow#(ParserState);
   function Fmt fshow (ParserState state);
      return $format(" State %x", state);
   endfunction
endinstance

module mkParseEthernet(ParseEthernet);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Ethernet_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_ipv4_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_vlan_fifo <- mkSizedFIFOF(1);
   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule cycleRule if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
   endrule

   Stmt parse_ethernet =
   seq
   action // parse_ethernet
      let data = packet_in_wire;
      Vector#(128, Bit#(1)) dataVec = unpack(data);
      let ethernet = extrace_ethernet(pack(takeAt(0, dataVec)));
      Vector#(16, Bit#(1)) unparsed = takeAt(112, dataVec);
      if (verbose) $display(fshow(cycle)
                            +fshow(" ether.dstAddr=")+fshow(ethernet.dstAddr)
                            +fshow(" ether.srcAddr=")+fshow(ethernet.srcAddr)
                            +fshow(" ether.etherType=")+fshow(ethernet.etherType));

      ParserState nextState = S0;
      case (byteSwap2B(ethernet.etherType)) matches
         'h_8100: begin
            unparsed_out_parse_vlan_fifo.enq(pack(unparsed));
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            unparsed_out_parse_ipv4_fifo.enq(pack(unparsed));
            nextState = S3;
         end
         default: begin
            $display("null");
         end
      endcase
      next_state_fifo.enq(nextState);
   endaction
   endseq;

   FSM fsm_parse_ethernet <- mkFSM(parse_ethernet);

   method Action start();
      fsm_parse_ethernet.start;
   endmethod
   method Action clear();
      fsm_parse_ethernet.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedOutIpv4 = toPipeOut(unparsed_out_parse_ipv4_fifo);
   interface unparsedOutVlan = toPipeOut(unparsed_out_parse_vlan_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseVlanArbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(2, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseVlanArbiter(ParseVlanArbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(2, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<2; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

// Parse second VLAN
module mkParseVlan(ParseVlan);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan0 <- mkBypassFIFOF;
//   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan1 <- mkBypassFIFOF;
   FIFOF#(Vlan_tag_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(112)) unparsed_out_parse_vlan0_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(80)) unparsed_out_parse_vlan1_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseVlanArbiter nextStateArbiter <- mkParseVlanArbiter();

   function ParserState compute_next_state(Bit#(16) etherType);
      ParserState nextState = S0;
      case (byteSwap2B(etherType)) matches
         'h_8100: begin
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            nextState = S3;
         end
      endcase
      return nextState;
   endfunction

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      if (verbose) $display(fshow(cycle) + fshow("load packet in"));
   endrule

   rule load_unparsed_in;
      let data_delayed <- toGet(unparsed_in_fifo).get;
      unparsed_in_fifo_vlan0.enq(data_delayed);
//      unparsed_in_fifo_vlan1.enq(data_delayed);
      if (verbose) $display(fshow(cycle) + fshow("load unparsed in"));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_vlan_0 =
   // VLAN
   seq
   action
      let data_delayed <- toGet(unparsed_in_fifo_vlan0).get;
      let data_current = packet_in_wire;
      $display("VLAN %x", data_current);
      Bit#(144) data = {data_current, data_delayed};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
      let nextState0 = compute_next_state(vlan0.etherType);
      let residue0 = takeAt(32, dataVec);
      if (nextState0 == S3) begin
         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
         unparsed_out_parse_vlan0_fifo.enq(pack(residue0));
         nextStateArbiter.in[0].enq(nextState0);
      end
   endaction
   endseq;

//   Stmt parse_vlan_1 =
//   // VLAN|VLAN
//   seq
//   action
//      let data_delayed <- toGet(unparsed_in_fifo_vlan1).get;
//      let data_current = packet_in_wire;
//      $display("VLAN|VLAN %x", data_current);
//      Bit#(144) data = {data_current, data_delayed};
//      Vector#(144, Bit#(1)) dataVec = unpack(data);
//      let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
//      let nextState0 = compute_next_state(vlan0.etherType);
//      let residue0 = takeAt(32, dataVec);
//      let vlan1 = extract_vlan(pack(takeAt(32, dataVec)));
//      let nextState1 = compute_next_state(vlan1.etherType);
//      let residue1 = takeAt(64, dataVec);
//      if (nextState0 == S2 && nextState1 == S3) begin
//         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
//         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan1.etherType));
//         unparsed_out_parse_vlan1_fifo.enq(pack(residue1));
//         nextStateArbiter.in[1].enq(nextState1);
//      end
//   endaction
//   endseq;

   FSM fsm_parse_vlan_0 <- mkFSM(parse_vlan_0);
//   FSM fsm_parse_vlan_1 <- mkFSM(parse_vlan_0);

   method Action start;
      fsm_parse_vlan_0.start;
//      fsm_parse_vlan_1.start;
   endmethod
   method Action clear;
      fsm_parse_vlan_0.abort;
//      fsm_parse_vlan_1.abort;
   endmethod

   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedOutVlan0 = toPipeOut(unparsed_out_parse_vlan0_fifo);
//   interface unparsedOutVlan1 = toPipeOut(unparsed_out_parse_vlan1_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseIpv4Arbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(3, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseIpv4Arbiter(ParseIpv4Arbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(3, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<3; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

module mkParseIpv4(ParseIpv4);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;

   FIFOF#(Ipv4_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_in_vlan0_fifo <- mkBypassFIFOF;
//   FIFOF#(Bit#(80)) unparsed_in_vlan1_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(144)) internal_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseIpv4Arbiter nextStateArbiter <- mkParseIpv4Arbiter();

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      $display(fshow("loading packet") + fshow(data_current));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_ipv4_0 =
   // IP
   seq
   action // parse_ipv4
      let residue_last <- toGet(unparsed_in_fifo).get; // 16-bit
      let data_current = packet_in_wire;
      Bit#(144) data = {data_current, residue_last};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      internal_fifo.enq(data);
      if (verbose) $display(fshow(cycle) + fshow("wait one cycle!"));
   endaction
   action // parse_ipv4 0
      let data_delayed <- toGet(internal_fifo).get;
      let data_current = packet_in_wire;
      Bit#(272) data = {data_current, data_delayed};
      Vector#(272, Bit#(1)) dataVec = unpack(data);
      Vector#(112, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[0].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_1 =
   // VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan0_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(240) data = {data_current, residue_last};
      Vector#(240, Bit#(1)) dataVec = unpack(data);
      Vector#(80, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[1].enq(S4);
   endaction
   endseq;

//   Stmt parse_ipv4_2 =
//   // VLAN|VLAN|IP
//   seq
//   action
//      let residue_last <- toGet(unparsed_in_vlan1_fifo).get; // 112-bit;
//      let data_current = packet_in_wire;
//      Bit#(208) data = {data_current, residue_last};
//      Vector#(208, Bit#(1)) dataVec = unpack(data);
//      Vector#(48, Bit#(1)) residue = takeAt(160, dataVec);
//      let ipv4 = extract_ipv4(data[159:0]);
//      if (verbose) $display(fshow(cycle)+
//                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
//                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
//      nextStateArbiter.in[2].enq(S4);
//   endaction
//   endseq;

   FSM fsm_parse_ipv4_0 <- mkFSM(parse_ipv4_0);
   FSM fsm_parse_ipv4_1 <- mkFSM(parse_ipv4_1);
//   FSM fsm_parse_ipv4_2 <- mkFSM(parse_ipv4_2);

   method Action start();
      fsm_parse_ipv4_0.start;
      fsm_parse_ipv4_1.start;
//      fsm_parse_ipv4_2.start;
   endmethod
   method Action clear();
      fsm_parse_ipv4_0.abort;
      fsm_parse_ipv4_1.abort;
//      fsm_parse_ipv4_2.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedInVlan0 = toPipeIn(unparsed_in_vlan0_fifo);
//   interface unparsedInVlan1 = toPipeIn(unparsed_in_vlan1_fifo);
   interface unparsedOut = toPipeOut(unparsed_out_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

(* synthesize *)
module mkParser(Parser);
   FIFOF#(EtherData) data_in_fifo <- mkSizedFIFOF(4);
   FIFOF#(void) parse_done_fifo <- mkSizedFIFOF(1);

   ParseEthernet parse_ethernet <- mkParseEthernet();
   ParseVlan parse_vlan <- mkParseVlan();
   ParseIpv4 parse_ipv4 <- mkParseIpv4();

   List#(Reg#(Vlan_tag_t)) vlan_tag_stack <- List::replicateM(2, mkReg(defaultValue));

   mkConnection(parse_ethernet.unparsedOutIpv4, parse_ipv4.unparsedIn);
   mkConnection(parse_ethernet.unparsedOutVlan, parse_vlan.unparsedIn);
   mkConnection(parse_vlan.unparsedOutVlan0, parse_ipv4.unparsedInVlan0);
   //mkConnection(parse_vlan.unparsedOutVlan1, parse_ipv4.unparsedInVlan1);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   Reg#(ParserState) curr_state <- mkReg(S0);
   Reg#(Bool) started <- mkReg(False);

   rule start_fsm (curr_state == S0 && data_in_fifo.notEmpty);
      if (!started) begin
         parse_ethernet.start;
         parse_vlan.start;
         parse_ipv4.start;
         started <= True;
      end
   endrule

   rule stop_fsm (curr_state == S4);
      if (started) begin
         parse_ethernet.clear;
         parse_ipv4.clear;
         parse_vlan.clear;
         started <= False;
      end
   endrule

   // Parsing Graph
   (* fire_when_enabled *)
   rule state_S0 (curr_state == S0 && data_in_fifo.notEmpty);
      let v = data_in_fifo.first;
      if (v.sop) begin
         curr_state <= S1;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
      else begin
         data_in_fifo.deq;
      end
   endrule
   (* fire_when_enabled *)
   rule state_S1 (curr_state == S1);
      let v <- toGet(parse_ethernet.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S2 (curr_state == S2);
      let v <- toGet(parse_vlan.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S3 (curr_state == S3);
      let v <- toGet(parse_ipv4.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S4 (curr_state == S4);
      let v <- toGet(data_in_fifo).get;
      if (v.eop) begin
         curr_state <= S0;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
   endrule

   // Data dispatcher.
   rule state_S1_input (curr_state == S1);
      let v <- toGet(data_in_fifo).get;
      parse_ethernet.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ethernet enqueue ")+ fshow(v));
   endrule
   rule state_S2_input (curr_state == S2);
      let v <- toGet(data_in_fifo).get;
      parse_vlan.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_vlan enqueue ")+ fshow(v));
   endrule
   rule state_S3_input (curr_state == S3);
      let v <- toGet(data_in_fifo).get;
      parse_ipv4.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ipv4 enqueue ") + fshow(v));
   endrule

   // derive parse done from state machine
   interface frameIn = toPipeIn(data_in_fifo);
   interface parseDone = toPipeOut(parse_done_fifo);
endmodule

// Copyright (c) 2015 Cornell University.

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

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

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

/* DO NOT MODIFY, AUTO GENERATED BY P4 COMPILER */

import BuildVector::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import Pipe::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;

import Ethernet::*;
import P4Types::*;

interface Parser;
   // derive parseReset from start of packet
   method Action parserReset();
   interface PipeIn#(EtherData) frameIn;
   interface PipeOut#(void) parseDone;
   interface PipeOut#(MatchKey_port_mapping) match_key_port_mapping;
   interface PipeOut#(MatchKey_bd) match_key_bd;
   interface PipeOut#(MatchKey_ipv4_fib) match_key_ipv4_fib;
   interface PipeOut#(MatchKey_ipv4_fib_lpm) match_key_ipv4_fib_lpm;
   interface PipeOut#(MatchKey_nexthop) match_key_nexthop;
   interface PipeOut#(MatchKey_rewrite_mac) match_rewrite_mac;
   interface PipeOut#(Bit#(128)) payloadOut;
endinterface

interface ParseEthernet;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeOut#(Ethernet_t) parsedOut;
   interface PipeOut#(Bit#(16)) unparsedOutIpv4; // number is parse state id
   interface PipeOut#(Bit#(16)) unparsedOutVlan; // number is parse state id
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseVlan;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Vlan_tag_t) parsedOut;
   interface PipeOut#(Bit#(112)) unparsedOutVlan0;
   interface PipeOut#(Bit#(80)) unparsedOutVlan1;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseIpv4;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Ipv4_t) parsedOut;
   interface PipeIn#(Bit#(112)) unparsedInVlan0;
   interface PipeIn#(Bit#(80)) unparsedInVlan1;
   interface PipeOut#(Bit#(112)) unparsedOut;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

typedef enum {S0, S1, S2, S3, S4} ParserState deriving (Bits, Eq);
instance FShow#(ParserState);
   function Fmt fshow (ParserState state);
      return $format(" State %x", state);
   endfunction
endinstance

module mkParseEthernet(ParseEthernet);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Ethernet_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_ipv4_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_vlan_fifo <- mkSizedFIFOF(1);
   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule cycleRule if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
   endrule

   Stmt parse_ethernet =
   seq
   action // parse_ethernet
      let data = packet_in_wire;
      Vector#(128, Bit#(1)) dataVec = unpack(data);
      let ethernet = extrace_ethernet(pack(takeAt(0, dataVec)));
      Vector#(16, Bit#(1)) unparsed = takeAt(112, dataVec);
      if (verbose) $display(fshow(cycle)
                            +fshow(" ether.dstAddr=")+fshow(ethernet.dstAddr)
                            +fshow(" ether.srcAddr=")+fshow(ethernet.srcAddr)
                            +fshow(" ether.etherType=")+fshow(ethernet.etherType));

      ParserState nextState = S0;
      case (byteSwap2B(ethernet.etherType)) matches
         'h_8100: begin
            unparsed_out_parse_vlan_fifo.enq(pack(unparsed));
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            unparsed_out_parse_ipv4_fifo.enq(pack(unparsed));
            nextState = S3;
         end
         default: begin
            $display("null");
         end
      endcase
      next_state_fifo.enq(nextState);
   endaction
   endseq;

   FSM fsm_parse_ethernet <- mkFSM(parse_ethernet);

   method Action start();
      fsm_parse_ethernet.start;
   endmethod
   method Action clear();
      fsm_parse_ethernet.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedOutIpv4 = toPipeOut(unparsed_out_parse_ipv4_fifo);
   interface unparsedOutVlan = toPipeOut(unparsed_out_parse_vlan_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseVlanArbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(2, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseVlanArbiter(ParseVlanArbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(2, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<2; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

// Parse second VLAN
module mkParseVlan(ParseVlan);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan0 <- mkBypassFIFOF;
//   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan1 <- mkBypassFIFOF;
   FIFOF#(Vlan_tag_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(112)) unparsed_out_parse_vlan0_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(80)) unparsed_out_parse_vlan1_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseVlanArbiter nextStateArbiter <- mkParseVlanArbiter();

   function ParserState compute_next_state(Bit#(16) etherType);
      ParserState nextState = S0;
      case (byteSwap2B(etherType)) matches
         'h_8100: begin
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            nextState = S3;
         end
      endcase
      return nextState;
   endfunction

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      if (verbose) $display(fshow(cycle) + fshow("load packet in"));
   endrule

   rule load_unparsed_in;
      let data_delayed <- toGet(unparsed_in_fifo).get;
      unparsed_in_fifo_vlan0.enq(data_delayed);
//      unparsed_in_fifo_vlan1.enq(data_delayed);
      if (verbose) $display(fshow(cycle) + fshow("load unparsed in"));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_vlan_0 =
   // VLAN
   seq
   action
      let data_delayed <- toGet(unparsed_in_fifo_vlan0).get;
      let data_current = packet_in_wire;
      $display("VLAN %x", data_current);
      Bit#(144) data = {data_current, data_delayed};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
      let nextState0 = compute_next_state(vlan0.etherType);
      let residue0 = takeAt(32, dataVec);
      if (nextState0 == S3) begin
         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
         unparsed_out_parse_vlan0_fifo.enq(pack(residue0));
         nextStateArbiter.in[0].enq(nextState0);
      end
   endaction
   endseq;

//   Stmt parse_vlan_1 =
//   // VLAN|VLAN
//   seq
//   action
//      let data_delayed <- toGet(unparsed_in_fifo_vlan1).get;
//      let data_current = packet_in_wire;
//      $display("VLAN|VLAN %x", data_current);
//      Bit#(144) data = {data_current, data_delayed};
//      Vector#(144, Bit#(1)) dataVec = unpack(data);
//      let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
//      let nextState0 = compute_next_state(vlan0.etherType);
//      let residue0 = takeAt(32, dataVec);
//      let vlan1 = extract_vlan(pack(takeAt(32, dataVec)));
//      let nextState1 = compute_next_state(vlan1.etherType);
//      let residue1 = takeAt(64, dataVec);
//      if (nextState0 == S2 && nextState1 == S3) begin
//         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
//         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan1.etherType));
//         unparsed_out_parse_vlan1_fifo.enq(pack(residue1));
//         nextStateArbiter.in[1].enq(nextState1);
//      end
//   endaction
//   endseq;

   FSM fsm_parse_vlan_0 <- mkFSM(parse_vlan_0);
//   FSM fsm_parse_vlan_1 <- mkFSM(parse_vlan_0);

   method Action start;
      fsm_parse_vlan_0.start;
//      fsm_parse_vlan_1.start;
   endmethod
   method Action clear;
      fsm_parse_vlan_0.abort;
//      fsm_parse_vlan_1.abort;
   endmethod

   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedOutVlan0 = toPipeOut(unparsed_out_parse_vlan0_fifo);
//   interface unparsedOutVlan1 = toPipeOut(unparsed_out_parse_vlan1_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseIpv4Arbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(3, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseIpv4Arbiter(ParseIpv4Arbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(3, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<3; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

module mkParseIpv4(ParseIpv4);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;

   FIFOF#(Ipv4_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_in_vlan0_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(80)) unparsed_in_vlan1_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(144)) internal_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseIpv4Arbiter nextStateArbiter <- mkParseIpv4Arbiter();

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      $display(fshow("loading packet") + fshow(data_current));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_ipv4_0 =
   // IP
   seq
   action // parse_ipv4
      let residue_last <- toGet(unparsed_in_fifo).get; // 16-bit
      let data_current = packet_in_wire;
      Bit#(144) data = {data_current, residue_last};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      internal_fifo.enq(data);
      if (verbose) $display(fshow(cycle) + fshow("wait one cycle!"));
   endaction
   action // parse_ipv4 0
      let data_delayed <- toGet(internal_fifo).get;
      let data_current = packet_in_wire;
      Bit#(272) data = {data_current, data_delayed};
      Vector#(272, Bit#(1)) dataVec = unpack(data);
      Vector#(112, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[0].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_1 =
   // VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan0_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(240) data = {data_current, residue_last};
      Vector#(240, Bit#(1)) dataVec = unpack(data);
      Vector#(80, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[1].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_2 =
   // VLAN|VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan1_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(208) data = {data_current, residue_last};
      Vector#(208, Bit#(1)) dataVec = unpack(data);
      Vector#(48, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[2].enq(S4);
   endaction
   endseq;

   FSM fsm_parse_ipv4_0 <- mkFSM(parse_ipv4_0);
   FSM fsm_parse_ipv4_1 <- mkFSM(parse_ipv4_1);
   FSM fsm_parse_ipv4_2 <- mkFSM(parse_ipv4_2);

   method Action start();
      fsm_parse_ipv4_0.start;
      fsm_parse_ipv4_1.start;
      fsm_parse_ipv4_2.start;
   endmethod
   method Action clear();
      fsm_parse_ipv4_0.abort;
      fsm_parse_ipv4_1.abort;
      fsm_parse_ipv4_2.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedInVlan0 = toPipeIn(unparsed_in_vlan0_fifo);
   interface unparsedInVlan1 = toPipeIn(unparsed_in_vlan1_fifo);
   interface unparsedOut = toPipeOut(unparsed_out_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

(* synthesize *)
module mkParser(Parser);
   FIFOF#(EtherData) data_in_fifo <- mkSizedFIFOF(4);
   FIFOF#(void) parse_done_fifo <- mkSizedFIFOF(1);

   ParseEthernet parse_ethernet <- mkParseEthernet();
   ParseVlan parse_vlan <- mkParseVlan();
   ParseIpv4 parse_ipv4 <- mkParseIpv4();

   List#(Reg#(Vlan_tag_t)) vlan_tag_stack <- List::replicateM(2, mkReg(defaultValue));

   mkConnection(parse_ethernet.unparsedOutIpv4, parse_ipv4.unparsedIn);
   mkConnection(parse_ethernet.unparsedOutVlan, parse_vlan.unparsedIn);
   mkConnection(parse_vlan.unparsedOutVlan0, parse_ipv4.unparsedInVlan0);
   mkConnection(parse_vlan.unparsedOutVlan1, parse_ipv4.unparsedInVlan1);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   Reg#(ParserState) curr_state <- mkReg(S0);
   Reg#(Bool) started <- mkReg(False);

   rule start_fsm (curr_state == S0 && data_in_fifo.notEmpty);
      if (!started) begin
         parse_ethernet.start;
         parse_vlan.start;
         parse_ipv4.start;
         started <= True;
      end
   endrule

   rule stop_fsm (curr_state == S4);
      if (started) begin
         parse_ethernet.clear;
         parse_ipv4.clear;
         parse_vlan.clear;
         started <= False;
      end
   endrule

   // Parsing Graph
   (* fire_when_enabled *)
   rule state_S0 (curr_state == S0 && data_in_fifo.notEmpty);
      let v = data_in_fifo.first;
      if (v.sop) begin
         curr_state <= S1;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
      else begin
         data_in_fifo.deq;
      end
   endrule
   (* fire_when_enabled *)
   rule state_S1 (curr_state == S1);
      let v <- toGet(parse_ethernet.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S2 (curr_state == S2);
      let v <- toGet(parse_vlan.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S3 (curr_state == S3);
      let v <- toGet(parse_ipv4.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S4 (curr_state == S4);
      let v <- toGet(data_in_fifo).get;
      if (v.eop) begin
         curr_state <= S0;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
   endrule

   // Data dispatcher.
   rule state_S1_input (curr_state == S1);
      let v <- toGet(data_in_fifo).get;
      parse_ethernet.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ethernet enqueue ")+ fshow(v));
   endrule
   rule state_S2_input (curr_state == S2);
      let v <- toGet(data_in_fifo).get;
      parse_vlan.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_vlan enqueue ")+ fshow(v));
   endrule
   rule state_S3_input (curr_state == S3);
      let v <- toGet(data_in_fifo).get;
      parse_ipv4.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ipv4 enqueue ") + fshow(v));
   endrule

   // derive parse done from state machine
   interface frameIn = toPipeIn(data_in_fifo);
   interface parseDone = toPipeOut(parse_done_fifo);
endmodule


debugging Gtxe2Common

debugging Gtxe2Common

Change-Id: I7789d354a189a7199d5948eff4f7f9e47722d70c

// 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 FIFO::*;
import Vector::*;
import XbsvXilinxCells::*;
import XilinxCells::*;
import BviAurora::*;
import Clocks::*;
import FrequencyCounter::*;

(* always_enabled, always_ready *)
interface AuroraPins;
   method Action userClk(Bit#(1) p, Bit#(1) n);
   method Action mgtRefClk(Bit#(1) p, Bit#(1) n);
   method Action mgtRx(Bit#(1) p, Bit#(1) n);
   method Bit#(1) mgtTx_p();
   method Bit#(1) mgtTx_n();
   interface DiffPair smaUserClk;
endinterface

interface AuroraIndication;
    method Action received(Bit#(64) v);
    method Action debug(Bit#(1) channelUp, Bit#(1) laneUp, Bit#(1) hard_err, Bit#(1) soft_err, Bit#(1) qpllLock, Bit#(1) qpllRefClkLost);
    method Action userClkElapsedCycles(Bit#(32) cycles);
endinterface

interface AuroraRequest;
    method Action send(Bit#(64) v);
    method Action debug();
    method Action pma_init(Bit#(1) v);
    method Action userClkElapsedCycles(Bit#(32) period);
endinterface

interface Aurora;
   interface AuroraRequest request;
   interface AuroraPins pins;
endinterface

module mkAuroraRequest#(AuroraIndication indication)(Aurora);
   let defaultClock <- exposeCurrentClock;
   let defaultReset <- exposeCurrentReset;

   Wire#(Bit#(1)) userClkWireP <- mkDWire(0);
   Wire#(Bit#(1)) userClkWireN <- mkDWire(0);
   ReadOnly#(Bit#(1)) userClk <- mkIBUFDS(userClkWireP, userClkWireN);

   DiffPair smaUserClockDS <- mkOBUFDS(userClk);

   let userClkFreqCounter <- mkFrequencyCounter(defaultClock, defaultReset);

   Wire#(Bit#(1)) mgtRefClkWireP <- mkDWire(0);
   Wire#(Bit#(1)) mgtRefClkWireN <- mkDWire(0);
   Clock mgtRefClk <- mkClockIBUFDS_GTE2(True, mgtRefClkWireP, mgtRefClkWireN);

   let b2c <- mkB2C();
   Clock txClock <- mkClockBUFG(clocked_by b2c.c);

   Clock syncClock = txClock; // should be doubled

   let gtxe2Common <- mkGtxe2Common(defaultClock, mgtRefClk);

   let aur <- mkBviAurora64(/* init_clk */ defaultClock,
			    mgtRefClk,
			    /* sync_clk */ syncClock,
			    /* user_clk */ txClock,
			    /* init_clk_reset */ defaultReset,
			    /* refclk1_in_reset */ defaultReset,
			    /* reset */ defaultReset,
			    /* sync_clk_reset */ defaultReset,
			    /* user_clk_reset */ defaultReset);

   Reg#(Bit#(1)) pmaInitVal <- mkReg(0);
   Reg#(Bit#(15)) ccCounter <- mkReg(0);

   rule tx_out_clk_rule;
      b2c.inputclock(aur.tx.out_clk());
   endrule
   // gt_pll_lock

   rule settings;
      aur.loopback(1);
      aur.power.down(0);
      aur.pma.init(pmaInitVal);
   endrule
   rule qpll;
      aur.gt_qpllclk_quad2_in(gtxe2Common.qpllOutClk());
      aur.gt_qpllrefclk_quad2_in(gtxe2Common.qpllOutRefClk());
   endrule

   rule receive if (unpack(aur.m_axi_rx.tvalid()));
      let v = 0;
      indication.received(aur.m_axi_rx.tdata());
   endrule

   // The CC block code should be sent atleast once for every 5000 clock cycles.
   rule doCC;
      let counter = ccCounter + 1;
      let doCC = 0;
      if (aur.channel.up() == 0)
	 counter = 0;
      if (counter > 4992)
	 doCC = 1;
      aur.do_.cc(doCC);
      if (counter > 5000)
	 counter = 0;
      ccCounter <= counter;
   endrule
   rule userclkfreqcounter_rule;
      let ec <- userClkFreqCounter.elapsedCycles();
      indication.userClkElapsedCycles(ec);
   endrule

   interface AuroraRequest request;
       method Action send(Bit#(64) v) if (unpack(aur.s_axi_tx.tready()));
	  aur.s_axi_tx.tdata(v);
	  aur.s_axi_tx.tkeep(-1);
	  aur.s_axi_tx.tlast(1);
	  aur.s_axi_tx.tvalid(1);
       endmethod
      method Action debug();
	 indication.debug(aur.channel.up(), aur.lane.up(), aur.hard.err(), aur.soft.err(), gtxe2Common.qpllLock(), gtxe2Common.qpllRefClkLost());
      endmethod
      method Action pma_init(Bit#(1) v);
	 pmaInitVal <= v;
      endmethod
      method Action userClkElapsedCycles(Bit#(32) period);
	 userClkFreqCounter.start(period);
      endmethod
   endinterface
   interface AuroraPins pins;
       method Action userClk(Bit#(1) p, Bit#(1) n);
	  userClkWireP <= p;
	  userClkWireN <= n;
       endmethod
       method Action mgtRefClk(Bit#(1) p, Bit#(1) n);
	  mgtRefClkWireP <= p;
	  mgtRefClkWireN <= n;
       endmethod
       method Action mgtRx(Bit#(1) p, Bit#(1) n);
	  aur.rxp(p);
	  aur.rxn(n);
       endmethod
       method mgtTx_p = aur.txp;
       method mgtTx_n = aur.txn;

       interface DiffClock smaUserClk = smaUserClockDS;
   endinterface

endmodule

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

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

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

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

import FIFO::*;
import Vector::*;
import XbsvXilinxCells::*;
import XilinxCells::*;
import BviAurora::*;
import Clocks::*;

(* always_enabled, always_ready *)
interface AuroraPins;
   method Action userClk(Bit#(1) p, Bit#(1) n);
   method Action mgtRefClk(Bit#(1) p, Bit#(1) n);
   method Action mgtRx(Bit#(1) p, Bit#(1) n);
   method Bit#(1) mgtTx_p();
   method Bit#(1) mgtTx_n();
   interface DiffPair smaUserClk;
endinterface

interface AuroraIndication;
    method Action received(Bit#(64) v);
    method Action debug(Bit#(1) channelUp, Bit#(1) laneUp, Bit#(1) hard_err, Bit#(1) soft_err);
endinterface

interface AuroraRequest;
    method Action send(Bit#(64) v);
    method Action debug();
      method Action pma_init(Bit#(1) v);
endinterface

interface Aurora;
   interface AuroraRequest request;
   interface AuroraPins pins;
endinterface

module mkAuroraRequest#(AuroraIndication indication)(Aurora);
   let defaultClock <- exposeCurrentClock;
   let defaultReset <- exposeCurrentReset;

   Wire#(Bit#(1)) userClkWireP <- mkDWire(0);
   Wire#(Bit#(1)) userClkWireN <- mkDWire(0);
   ReadOnly#(Bit#(1)) userClk <- mkIBUFDS(userClkWireP, userClkWireN);

   DiffPair smaUserClockDS <- mkOBUFDS(userClk);

   Wire#(Bit#(1)) mgtRefClkWireP <- mkDWire(0);
   Wire#(Bit#(1)) mgtRefClkWireN <- mkDWire(0);
   Clock mgtRefClk <- mkClockIBUFDS_GTE2(True, mgtRefClkWireP, mgtRefClkWireN);

   let b2c <- mkB2C();
   Clock txClock <- mkClockBUFG(clocked_by b2c.c);

   Clock syncClock = txClock; // should be doubled

   let aur <- mkBviAurora64(/* init_clk */ defaultClock,
			    mgtRefClk,
			    /* sync_clk */ syncClock,
			    /* user_clk */ txClock,
			    /* init_clk_reset */ defaultReset,
			    /* refclk1_in_reset */ defaultReset,
			    /* reset */ defaultReset,
			    /* sync_clk_reset */ defaultReset,
			    /* user_clk_reset */ defaultReset);

   Reg#(Bit#(1)) pmaInitVal <- mkReg(0);
   Reg#(Bit#(15)) ccCounter <- mkReg(0);

   rule tx_out_clk_rule;
      b2c.inputclock(aur.tx.out_clk());
   endrule
   // gt_pll_lock

   rule settings;
      aur.loopback(1);
      aur.power.down(0);
      aur.pma.init(pmaInitVal);
   endrule

   rule receive if (unpack(aur.m_axi_rx.tvalid()));
      let v = 0;
      indication.received(aur.m_axi_rx.tdata());
   endrule

   // The CC block code should be sent atleast once for every 5000 clock cycles.
   rule doCC;
      let counter = ccCounter + 1;
      let doCC = 0;
      if (aur.channel.up() == 0)
	 counter = 0;
      if (counter > 4992)
	 doCC = 1;
      aur.do_.cc(doCC);
      if (counter > 5000)
	 counter = 0;
      ccCounter <= counter;
   endrule

   interface AuroraRequest request;
       method Action send(Bit#(64) v) if (unpack(aur.s_axi_tx.tready()));
	  aur.s_axi_tx.tdata(v);
	  aur.s_axi_tx.tkeep(-1);
	  aur.s_axi_tx.tlast(1);
	  aur.s_axi_tx.tvalid(1);
       endmethod
      method Action debug();
	 indication.debug(aur.channel.up(), aur.lane.up(), aur.hard.err(), aur.soft.err());
      endmethod
      method Action pma_init(Bit#(1) v);
	 pmaInitVal <= v;
      endmethod
   endinterface
   interface AuroraPins pins;
       method Action userClk(Bit#(1) p, Bit#(1) n);
	  userClkWireP <= p;
	  userClkWireN <= n;
       endmethod
       method Action mgtRefClk(Bit#(1) p, Bit#(1) n);
	  mgtRefClkWireP <= p;
	  mgtRefClkWireN <= n;
       endmethod
       method Action mgtRx(Bit#(1) p, Bit#(1) n);
	  aur.rxp(p);
	  aur.rxn(n);
       endmethod
       method mgtTx_p = aur.txp;
       method mgtTx_n = aur.txn;

       interface DiffClock smaUserClk = smaUserClockDS;
   endinterface

endmodule


pipelined BramMux

pipelined BramMux

Change-Id: I71afe0c20b3261f52516e9088cfe448c6bf98140

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

interface BramServerMux#(numeric type aszn, type dtype);
   interface BRAMServer#(Bit#(aszn), dtype) bramServer;
endinterface

module mkBramServerMux#(Vector#(numServers, BRAMServer#(Bit#(asz),dtype)) bramServers)(BramServerMux#(aszn,dtype))
   provisos (Add#(1,a__,numServers),
	     Log#(numServers,csz),
	     Add#(asz,csz,aszn),
	     Bits#(dtype,dsz),
	     Bits#(Tuple2#(Bit#(csz), BRAM::BRAMRequest#(Bit#(asz), dtype)), c__)
	     );
   FIFO#(Bit#(csz)) clientNumberFifo <- mkPipelineFIFO();
   FIFO#(Tuple2#(Bit#(csz),BRAMRequest#(Bit#(asz), dtype))) reqFifo <- mkPipelineFIFO();
   FIFO#(dtype) responseFifo <- mkPipelineFIFO();
   rule request;
      let clientreq = reqFifo.first();
      reqFifo.deq();
      let clientNumber = tpl_1(clientreq);
      let req          = tpl_2(clientreq);
      bramServers[clientNumber].request.put(req);
   endrule
   rule respond;
      let clientNumber = clientNumberFifo.first();
      clientNumberFifo.deq();
      let response <- bramServers[clientNumber].response.get();
      responseFifo.enq(response);
   endrule
   interface BRAMServer bramServer;
      interface Put request;
	 method Action put(BRAMRequest#(Bit#(aszn), dtype) request);
	    Bit#(csz) clientNumber = request.address[valueOf(aszn)-1:valueOf(asz)];
	    clientNumberFifo.enq(clientNumber);
	    reqFifo.enq(tuple2(clientNumber,
			       BRAMRequest {
					    write: request.write,
					    responseOnWrite: request.responseOnWrite,
					    address: truncate(request.address),
					    datain: request.datain
					    }));
	 endmethod
      endinterface
      interface Get response;
	 method ActionValue#(dtype) get();
	    responseFifo.deq();
	    return responseFifo.first();
	 endmethod
      endinterface
   endinterface
endmodule

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

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

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

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

import ClientServer ::*;
import BRAM         ::*;
import Vector       ::*;
import FIFO         ::*;
import SpecialFIFOs :: *;

interface BramServerMux#(numeric type aszn, type dtype);
   interface BRAMServer#(Bit#(aszn), dtype) bramServer;
endinterface

module mkBramServerMux#(Vector#(numServers, BRAMServer#(Bit#(asz),dtype)) bramServers)(BramServerMux#(aszn,dtype))
   provisos (Add#(1,a__,numServers),
	     Log#(numServers,csz),
	     Add#(asz,csz,aszn)
	     );
   FIFO#(Bit#(csz)) clientNumberFifo <- mkPipelineFIFO();
   interface BRAMServer bramServer;
      interface Put request;
	 method Action put(BRAMRequest#(Bit#(aszn), dtype) request);
	    Bit#(csz) clientNumber = request.address[valueOf(aszn)-1:valueOf(asz)];
	    clientNumberFifo.enq(clientNumber);
	    bramServers[clientNumber].request.put(BRAMRequest {
							       write: request.write,
							       responseOnWrite: request.responseOnWrite,
							       address: truncate(request.address),
							       datain: request.datain
							       });
	 endmethod
      endinterface
      interface Get response;
	 method ActionValue#(dtype) get();
	    let clientNumber = clientNumberFifo.first();
	    clientNumberFifo.deq();
	    let response <- bramServers[clientNumber].response.get();
	    return response;
	 endmethod
      endinterface
   endinterface
endmodule


added writedonerule

added writedonerule

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

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

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

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

import Clocks            :: *;
import Vector            :: *;
import FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import MemTypes          :: *;
import HostInterface     :: *;
import CtrlMux           :: *;
import ClientServer      :: *;
import PCIE              :: *;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimTop;
   method ActionValue#(Bit#(4)) interrupt();
   method ActionValue#(Bit#(32)) directoryEntry();
   method Action read(Bit#(32) addr);
   method ActionValue#(Bit#(32)) readData();
   method Action write(Bit#(32) addr, Bit#(32) data);

   interface Clock singleClock;
   interface Reset singleReset;
endinterface

module  mkXsimTop(XsimTop);
   //let divider <- mkClockDivider(2);
   Clock derivedClock <- exposeCurrentClock; //= divider.fastClock;
   Clock single_clock = derivedClock; //divider.slowClock;
   Reset derivedReset <- exposeCurrentReset;
   //let sr <- mkReset(2, True, single_clock);
   Reset single_reset = derivedReset; //sr.new_rst;

   XsimHost host <- mkXsimHost(clocked_by single_clock, reset_by single_reset, derivedClock, derivedReset);
   ConnectalTop#(PhysAddrWidth,DataBusWidth,PinType,NumberOfMasters) top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`endif
       clocked_by single_clock, reset_by single_reset);
   //mapM(uncurry(mkConnection),zip(top.masters, host.mem_servers), clocked_by single_clock, reset_by single_reset);

   Vector#(16,Reg#(Bool)) interruptSent <- replicateM(mkReg(False));
   FIFO#(Bit#(4)) interruptFifo <- mkFIFO();
   rule int_rule;
      Bool found = False;
      Bit#(4) intrNum = 0;
      for (Integer i = 0; i < 16; i = i + 1) begin
	 if (top.interrupt[i] && !interruptSent[i] && !found) begin
	    found = True;
	    intrNum = fromInteger(i);
	 end
	 if (!top.interrupt[i])
	    interruptSent[i] <= False;
      end
      if (found) begin
	 interruptSent[intrNum] <= True;
	 interruptFifo.enq(intrNum);
      end
   endrule

   Reg#(Bool) readingDirectory <- mkReg(True);
   Reg#(Bool) token <- mkReg(True);
   Reg#(Bit#(8)) portalNumber <- mkReg(0);
   Reg#(Bit#(8)) offset <- mkReg(8'h10);
   Reg#(Bit#(32)) idReg <- mkReg(0);
   FIFO#(Bit#(32)) directoryFifo <- mkFIFO();
   rule readDirectory if (readingDirectory && portalNumber < 16 && token);
      let o = offset;
      let pn = portalNumber;
      top.slave.read_server.readReq.put(PhysMemRequest { addr: (extend(portalNumber) << 16) | extend(offset), burstLen: 4, tag: (o == 8'h10) ? 7 : 9});
      if (offset == 8'h14) begin
	 o = 8'h10;
	 pn = pn + 1;
      end
      else begin
	 o = o + 4;
      end
      offset <= o;
      portalNumber <= pn;
      token <= False;
   endrule
   rule directoryValue if (readingDirectory && !token);
      let memData <- top.slave.read_server.readData.get();

      let t = token;
      if (memData.tag == 7) begin
	 idReg <= memData.data;
	 t = True;
      end
      else begin
	 directoryFifo.enq((extend(memData.data[0]) << 31) | idReg);
	 // if this is not the last one, then read the next portal
	 t = (memData.data[0] == 0);
      end
      token <= t;
   endrule

   FIFO#(Bit#(32)) writeDataFifo <- mkFIFO();
   rule writedatarule;
      let data <- toGet(writeDataFifo).get();
      top.slave.write_server.writeData.put(MemData { data: data, tag: 0, last: True });
   endrule
   rule writedonerule;
      let done <- top.slave.write_server.writeDone.get();
   endrule

   method ActionValue#(Bit#(4)) interrupt();
      let i <- toGet(interruptFifo).get();
      return i;
   endmethod
   method ActionValue#(Bit#(32)) directoryEntry() if (readingDirectory);
      let v <- toGet(directoryFifo).get();
      if (v[31] == 1)
	 readingDirectory <= False;
      return v;
   endmethod

   method Action read(Bit#(32) addr) if (!readingDirectory);
      $display("read addr=%h", addr);
      top.slave.read_server.readReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
   endmethod

   method ActionValue#(Bit#(32)) readData() if (!readingDirectory);
      let memData <- top.slave.read_server.readData.get();
      $display("read data=%h", memData.data);
      return memData.data;
   endmethod

   method Action write(Bit#(32) addr, Bit#(32) data);
      top.slave.write_server.writeReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0});
      writeDataFifo.enq(data);
   endmethod

`ifdef BSIMRESPONDER
   `BSIMRESPONDER (top.pins);
`endif
   interface Clock singleClock = single_clock;
   interface Reset singleReset = single_reset;
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 Clocks            :: *;
import Vector            :: *;
import FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import MemTypes          :: *;
import HostInterface     :: *;
import CtrlMux           :: *;
import ClientServer      :: *;
import PCIE              :: *;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimTop;
   method ActionValue#(Bit#(4)) interrupt();
   method ActionValue#(Bit#(32)) directoryEntry();
   method Action read(Bit#(32) addr);
   method ActionValue#(Bit#(32)) readData();
   method Action write(Bit#(32) addr, Bit#(32) data);

   interface Clock singleClock;
   interface Reset singleReset;
endinterface

module  mkXsimTop(XsimTop);
   //let divider <- mkClockDivider(2);
   Clock derivedClock <- exposeCurrentClock; //= divider.fastClock;
   Clock single_clock = derivedClock; //divider.slowClock;
   Reset derivedReset <- exposeCurrentReset;
   //let sr <- mkReset(2, True, single_clock);
   Reset single_reset = derivedReset; //sr.new_rst;

   XsimHost host <- mkXsimHost(clocked_by single_clock, reset_by single_reset, derivedClock, derivedReset);
   ConnectalTop#(PhysAddrWidth,DataBusWidth,PinType,NumberOfMasters) top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`endif
       clocked_by single_clock, reset_by single_reset);
   //mapM(uncurry(mkConnection),zip(top.masters, host.mem_servers), clocked_by single_clock, reset_by single_reset);

   Vector#(16,Reg#(Bool)) interruptSent <- replicateM(mkReg(False));
   FIFO#(Bit#(4)) interruptFifo <- mkFIFO();
   rule int_rule;
      Bool found = False;
      Bit#(4) intrNum = 0;
      for (Integer i = 0; i < 16; i = i + 1) begin
	 if (top.interrupt[i] && !interruptSent[i] && !found) begin
	    found = True;
	    intrNum = fromInteger(i);
	 end
	 if (!top.interrupt[i])
	    interruptSent[i] <= False;
      end
      if (found) begin
	 interruptSent[intrNum] <= True;
	 interruptFifo.enq(intrNum);
      end
   endrule

   Reg#(Bool) readingDirectory <- mkReg(True);
   Reg#(Bool) token <- mkReg(True);
   Reg#(Bit#(8)) portalNumber <- mkReg(0);
   Reg#(Bit#(8)) offset <- mkReg(8'h10);
   Reg#(Bit#(32)) idReg <- mkReg(0);
   FIFO#(Bit#(32)) directoryFifo <- mkFIFO();
   rule readDirectory if (readingDirectory && portalNumber < 16 && token);
      let o = offset;
      let pn = portalNumber;
      top.slave.read_server.readReq.put(PhysMemRequest { addr: (extend(portalNumber) << 16) | extend(offset), burstLen: 4, tag: (o == 8'h10) ? 7 : 9});
      if (offset == 8'h14) begin
	 o = 8'h10;
	 pn = pn + 1;
      end
      else begin
	 o = o + 4;
      end
      offset <= o;
      portalNumber <= pn;
      token <= False;
   endrule
   rule directoryValue if (readingDirectory && !token);
      let memData <- top.slave.read_server.readData.get();

      let t = token;
      if (memData.tag == 7) begin
	 idReg <= memData.data;
	 t = True;
      end
      else begin
	 directoryFifo.enq((extend(memData.data[0]) << 31) | idReg);
	 // if this is not the last one, then read the next portal
	 t = (memData.data[0] == 0);
      end
      token <= t;
   endrule

   FIFO#(Bit#(32)) writeDataFifo <- mkFIFO();
   rule writedatarule;
      let data <- toGet(writeDataFifo).get();
      top.slave.write_server.writeData.put(MemData { data: data, tag: 0, last: True });
   endrule

   method ActionValue#(Bit#(4)) interrupt();
      let i <- toGet(interruptFifo).get();
      return i;
   endmethod
   method ActionValue#(Bit#(32)) directoryEntry() if (readingDirectory);
      let v <- toGet(directoryFifo).get();
      if (v[31] == 1)
	 readingDirectory <= False;
      return v;
   endmethod

   method Action read(Bit#(32) addr) if (!readingDirectory);
      $display("read addr=%h", addr);
      top.slave.read_server.readReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
   endmethod

   method ActionValue#(Bit#(32)) readData() if (!readingDirectory);
      let memData <- top.slave.read_server.readData.get();
      $display("read data=%h", memData.data);
      return memData.data;
   endmethod

   method Action write(Bit#(32) addr, Bit#(32) data);
      top.slave.write_server.writeReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0});
      writeDataFifo.enq(data);
   endmethod

`ifdef BSIMRESPONDER
   `BSIMRESPONDER (top.pins);
`endif
   interface Clock singleClock = single_clock;
   interface Reset singleReset = single_reset;
endmodule


Improved MBOX critical path with dedicated output register

Earlier, was re-using an input register for the result, but adds a (wide) mux on the input, and complicates the input-enable logic.

// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved

package RISCV_MBox;

// ================================================================
// This package executes the 'M' extension instructions (MUL/DIV/REM)

// ================================================================
// Exports

export
RISCV_MBox_IFC (..),
mkRISCV_MBox;

// ================================================================
// BSV Library imports

import Assert    :: *;
import ConfigReg :: *;

// ----------------
// BSV additional libs

import Cur_Cycle  :: *;
import GetPut_Aux :: *;

// ================================================================
// Project imports

import ISA_Decls :: *;
import IntMulDiv :: *;

// ================================================================
// MBox interface

interface RISCV_MBox_IFC;
   method Action set_verbosity (Bit #(4) verbosity);

   method Action                   req_reset;
   method ActionValue #(Bit #(0))  rsp_reset;

   // MBox interface: request
   (* always_ready *)
   method Action  req (Bool is_OP_not_OP_32, Bit #(3) f3, WordXL v1, WordXL v2);

   // MBox interface: response
   (* always_ready *)   method Bool    valid;
   (* always_ready *)   method WordXL  word;
endinterface

// ================================================================

typedef enum { STATE_MUL1, STATE_MUL2, STATE_DIV_REM } State
deriving (Bits, Eq, FShow);

(* synthesize *)
module mkRISCV_MBox (RISCV_MBox_IFC);

   Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);

   Reg #(State)     rg_state <- mkRegU;

   Reg #(Bool)      rg_is_OP_not_OP_32 <- mkRegU;
   Reg #(Bit #(3))  rg_f3              <- mkRegU;
   Reg #(WordXL)    rg_v1              <- mkRegU;
   Reg #(WordXL)    rg_v2              <- mkRegU;
   Reg #(WordXL)    rg_result          <- mkRegU;

   IntDiv_IFC #(XLEN) intDiv <- mkIntDiv (rg_v1, rg_v2);

`ifdef MULT_SERIAL
`ifdef RV64
   IntMul_IFC#(64) intMul <- mkIntMul_64;
`else
   IntMul_IFC#(32) intMul <- mkIntMul_32;
`endif
`endif

   Reg #(Bool)    dw_valid  <- mkDWire (False);
   Reg #(WordXL)  dw_result <- mkDWire (?);

   // ----------------------------------------------------------------
   // MUL family: SYNTH implementation
   // Relies on the fav_MUL/MULH/MULHU/MULHSU/MULW functions later in
   // this package which do multiplication directly with Verilog's '*'
   // and rely on Verilog synthesis to implement the multiplier.
   // (DSPs on FPGAa).

`ifdef MULT_SYNTH

   rule rl_mul (rg_state == STATE_MUL1);
      if (cfg_verbosity > 1)
	 $display ("    RISCV_MBox.rl_mul");

      WordXL result = '1;

      if      (rg_is_OP_not_OP_32     && (rg_f3 == f3_MUL))     result <- fav_MUL (rg_v1, rg_v2);
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULH))    result <- fav_MULH (rg_v1, rg_v2);
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHU))   result <- fav_MULHU (rg_v1, rg_v2);
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHSU))  result <- fav_MULHSU (rg_v1, rg_v2);
`ifdef RV64
      else if ((! rg_is_OP_not_OP_32) && (rg_f3 == f3_MUL))     result <- fav_MULW (rg_v1, rg_v2);
`endif
      else begin
	 // This should be Impossible
	 $display ("%0d: ERROR: RISCV_MBox.rl_mul: illegal f3.", cur_cycle);
	 $display ("    f3 0x%0h  v1 0x%0h  v2 0x%0h", rg_f3, rg_v1, rg_v2);
	 $finish (1);    // TODO: illegal instruction; should trap
      end

      rg_result <= result;
      rg_state  <= STATE_MUL2;
   endrule

   rule rl_mul2 (rg_state == STATE_MUL2);
      let result = rg_result;
      dw_valid  <= True;
      dw_result <= result;
   endrule

`endif

   // ----------------------------------------------------------------
   // MUL family: SERIAL implementation
   // Uses the iterative multiplier in the 'IntMulDiv' package.

`ifdef MULT_SERIAL
   rule rl_mul (rg_state == STATE_MUL1 && intMul.result_valid);
      WordXL result;
      if      (rg_is_OP_not_OP_32     && (rg_f3 == f3_MUL))     begin
	 result = (intMul.result_value)[xlen-1:0];
      end
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULH))    begin
	 result = (intMul.result_value)[2 * xlen - 1 : xlen];
      end
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHU))   begin
	 result = (intMul.result_value)[2 * xlen - 1 : xlen];
      end
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHSU))  begin
	 result = (intMul.result_value)[2 * xlen - 1 : xlen];
      end
`ifdef RV64
      else if ((! rg_is_OP_not_OP_32) && (rg_f3 == f3_MUL))     begin
	 result = signExtend((intMul.result_value)[31:0]);
      end
`endif
      else begin
	 // This should be Impossible
	 $display ("%0d: ERROR: RISCV_MBox.rl_mul: illegal f3. again", cur_cycle);
	 result = 0; // to keep bsc happy
      end

      dw_valid  <= True;
      dw_result <= result;
   endrule
`endif

   // ----------------------------------------------------------------
   // DIV family and REM family
   // Uses the iterative divider provided in the imported 'IntMulDiv' package.

   rule rg_div_rem ((rg_state == STATE_DIV_REM) && intDiv.result_valid);
      match { .q, .r } = intDiv.result_value;
      WordXL result = ((rg_f3 [1] == 1'b0) ? q : r );

`ifdef RV64
      if (! rg_is_OP_not_OP_32)
	 result = signExtend (result [31:0]);
`endif

      dw_valid  <= True;
      dw_result <= result;
   endrule

   // ================================================================
   // INTERFACE

   method Action set_verbosity (Bit #(4) verbosity);
      cfg_verbosity <= verbosity;
   endmethod

   method Action req_reset;
      noAction;
   endmethod

   method ActionValue #(Bit #(0))  rsp_reset;
      return (?);
   endmethod

   // MBox interface: request
   method Action  req (Bool is_OP_not_OP_32, Bit #(3) f3, WordXL v1, WordXL v2);

      Bool is_signed = (f3 [0] == 1'b0);

`ifdef RV64
      if (! is_OP_not_OP_32) begin
	 // RV64 ops MULW/DIVW/DIVUW/REMW/REMUW)
	 if (is_signed) begin
	    v1 = signExtend (v1 [31:0]);
	    v2 = signExtend (v2 [31:0]);
	 end
	 else begin
	    v1 = zeroExtend (v1 [31:0]);
	    v2 = zeroExtend (v2 [31:0]);
	 end
      end
`endif

      rg_is_OP_not_OP_32 <= is_OP_not_OP_32;
      rg_f3              <= f3;
      rg_v1              <= v1;
      rg_v2              <= v2;

      // MUL, MULH, MULHU, MULHSU
      if (f3 [2] == 1'b0) begin
	 rg_state <= STATE_MUL1;

`ifdef MULT_SERIAL
	 Bool s1, s2;

	 if      (is_OP_not_OP_32     && (f3 == f3_MUL))     begin
	    s1 = False; s2 = False;
	 end
	 else if (is_OP_not_OP_32     && (f3 == f3_MULH))    begin
	    s1 = True; s2 = True;
	 end
	 else if (is_OP_not_OP_32     && (f3 == f3_MULHU))   begin
	    s1 = False; s2 = False;
	 end
	 else if (is_OP_not_OP_32     && (f3 == f3_MULHSU))  begin
	    s1 = True; s2 = False;
	 end
`ifdef RV64
	 else if ((! is_OP_not_OP_32) && (f3 == f3_MUL))     begin
	    // Signed versions of lower 32 bits of v_rs1 and v_rs2
	    v1 = signExtend (v1 [31:0]);
	    v2 = signExtend (v2 [31:0]);
	    s1 = True; s2 = True;
	 end
`endif
	 else begin
	    // This should be Impossible
	    $display ("%0d: ERROR: RISCV_MBox.rl_mul: illegal f3.", cur_cycle);
	    $display ("    f3 0x%0h  v1 0x%0h  v2 0x%0h", f3, v1, v2);
	    $finish (1);    // TODO: illegal instruction; should trap
	    s1 = ?; s2 = ?; // to keep bsc happy
	 end

	 intMul.put_args(s1, v1, s2, v2);
`endif
      end

      // DIV, DIVU, REM, REMU
      else begin
	 rg_state <= STATE_DIV_REM;
	 intDiv.start (is_signed, is_signed);
      end
   endmethod

   // MBox interface: response
   method Bool  valid;
      return dw_valid;
   endmethod

   method WordXL  word;
      return dw_result;
   endmethod
endmodule

// ================================================================

function ActionValue #(WordXL) fav_MUL (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed versions of v_rs1 and v_rs2
      IntXL s_v_rs1 = unpack (v_rs1);
      IntXL s_v_rs2 = unpack (v_rs2);

      WordXL v_rd = pack (s_v_rs1 * s_v_rs2);
      return v_rd;
   endactionvalue
endfunction

function ActionValue #(WordXL) fav_MULH (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed versions of v_rs1 and v_rs2
      IntXL s_v_rs1 = unpack (v_rs1);
      IntXL s_v_rs2 = unpack (v_rs2);

      Int #(XLEN_2) s_v1     = extend (s_v_rs1);
      Int #(XLEN_2) s_v2     = extend (s_v_rs2);
      Int #(XLEN_2) s_result = s_v1 * s_v2;
      WordXL v_rd = pack (s_result) [2 * xlen - 1: xlen];
      return v_rd;
   endactionvalue
endfunction

function ActionValue #(WordXL) fav_MULHU (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      Bit #(XLEN_2) v1     = extend (v_rs1);
      Bit #(XLEN_2) v2     = extend (v_rs2);
      Bit #(XLEN_2) result = v1 * v2;
      WordXL v_rd = result [2 * xlen - 1: xlen];
      return v_rd;
   endactionvalue
endfunction

function ActionValue #(WordXL) fav_MULHSU (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed version of v_rs1
      IntXL s_v_rs1 = unpack (v_rs1);

      Int #(XLEN_2) s_v1     = extend (s_v_rs1);
      Int #(XLEN_2) s_v2     = unpack (extend (v_rs2));
      Int #(XLEN_2) s_result = s_v1 * s_v2;
      WordXL v_rd = pack (s_result) [2 * xlen - 1: xlen];
      return v_rd;
   endactionvalue
endfunction

`ifdef RV64
function ActionValue #(WordXL) fav_MULW (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed versions of lower 32 bits of v_rs1 and v_rs2
      IntXL s_v_rs1 = unpack (signExtend (v_rs1 [31:0]));
      IntXL s_v_rs2 = unpack (signExtend (v_rs2 [31:0]));
      WordXL prod64 = pack (s_v_rs1 * s_v_rs2);

      WordXL v_rd = signExtend (prod64 [31:0]);
      return v_rd;
   endactionvalue
endfunction
`endif

// ================================================================

endpackage

// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved

package RISCV_MBox;

// ================================================================
// This package executes the 'M' extension instructions (MUL/DIV/REM)

// ================================================================
// Exports

export
RISCV_MBox_IFC (..),
mkRISCV_MBox;

// ================================================================
// BSV Library imports

import Assert    :: *;
import ConfigReg :: *;

// ----------------
// BSV additional libs

import Cur_Cycle  :: *;
import GetPut_Aux :: *;

// ================================================================
// Project imports

import ISA_Decls :: *;
import IntMulDiv :: *;

// ================================================================
// MBox interface

interface RISCV_MBox_IFC;
   method Action set_verbosity (Bit #(4) verbosity);

   method Action                   req_reset;
   method ActionValue #(Bit #(0))  rsp_reset;

   // MBox interface: request
   (* always_ready *)
   method Action  req (Bool is_OP_not_OP_32, Bit #(3) f3, WordXL v1, WordXL v2);

   // MBox interface: response
   (* always_ready *)   method Bool    valid;
   (* always_ready *)   method WordXL  word;
endinterface

// ================================================================

typedef enum { STATE_MUL1, STATE_MUL2, STATE_DIV_REM } State
deriving (Bits, Eq, FShow);

(* synthesize *)
module mkRISCV_MBox (RISCV_MBox_IFC);

   Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);

   Reg #(State)     rg_state <- mkRegU;

   Reg #(Bool)      rg_is_OP_not_OP_32 <- mkRegU;
   Reg #(Bit #(3))  rg_f3              <- mkRegU;
   Reg #(WordXL)    rg_v1              <- mkRegU;
   Reg #(WordXL)    rg_v2              <- mkRegU;

   IntDiv_IFC #(XLEN) intDiv <- mkIntDiv (rg_v1, rg_v2);

`ifdef MULT_SERIAL
`ifdef RV64
   IntMul_IFC#(64) intMul <- mkIntMul_64;
`else
   IntMul_IFC#(32) intMul <- mkIntMul_32;
`endif
`endif

   Reg #(Bool)    dw_valid  <- mkDWire (False);
   Reg #(WordXL)  dw_result <- mkDWire (?);

   // ----------------------------------------------------------------
   // MUL family: SYNTH implementation
   // Relies on the fav_MUL/MULH/MULHU/MULHSU/MULW functions later in
   // this package which do multiplication directly with Verilog's '*'
   // and rely on Verilog synthesis to implement the multiplier.
   // (DSPs on FPGAa).

`ifdef MULT_SYNTH

   rule rl_mul (rg_state == STATE_MUL1);
      if (cfg_verbosity > 1)
	 $display ("    RISCV_MBox.rl_mul");

      WordXL result = '1;

      if      (rg_is_OP_not_OP_32     && (rg_f3 == f3_MUL))     result <- fav_MUL (rg_v1, rg_v2);
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULH))    result <- fav_MULH (rg_v1, rg_v2);
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHU))   result <- fav_MULHU (rg_v1, rg_v2);
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHSU))  result <- fav_MULHSU (rg_v1, rg_v2);
`ifdef RV64
      else if ((! rg_is_OP_not_OP_32) && (rg_f3 == f3_MUL))     result <- fav_MULW (rg_v1, rg_v2);
`endif
      else begin
	 // This should be Impossible
	 $display ("%0d: ERROR: RISCV_MBox.rl_mul: illegal f3.", cur_cycle);
	 $display ("    f3 0x%0h  v1 0x%0h  v2 0x%0h", rg_f3, rg_v1, rg_v2);
	 $finish (1);    // TODO: illegal instruction; should trap
      end

      rg_v1 <= result;
      rg_state <= STATE_MUL2;
   endrule

   rule rl_mul2 (rg_state == STATE_MUL2);
      let result = rg_v1;
      dw_valid  <= True;
      dw_result <= result;
   endrule

`endif

   // ----------------------------------------------------------------
   // MUL family: SERIAL implementation
   // Uses the iterative multiplier in the 'IntMulDiv' package.

`ifdef MULT_SERIAL
   rule rl_mul (rg_state == STATE_MUL1 && intMul.result_valid);
      WordXL result;
      if      (rg_is_OP_not_OP_32     && (rg_f3 == f3_MUL))     begin
	 result = (intMul.result_value)[xlen-1:0];
      end
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULH))    begin
	 result = (intMul.result_value)[2 * xlen - 1 : xlen];
      end
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHU))   begin
	 result = (intMul.result_value)[2 * xlen - 1 : xlen];
      end
      else if (rg_is_OP_not_OP_32     && (rg_f3 == f3_MULHSU))  begin
	 result = (intMul.result_value)[2 * xlen - 1 : xlen];
      end
`ifdef RV64
      else if ((! rg_is_OP_not_OP_32) && (rg_f3 == f3_MUL))     begin
	 result = signExtend((intMul.result_value)[31:0]);
      end
`endif
      else begin
	 // This should be Impossible
	 $display ("%0d: ERROR: RISCV_MBox.rl_mul: illegal f3. again", cur_cycle);
	 result = 0; // to keep bsc happy
      end

      dw_valid  <= True;
      dw_result <= result;
   endrule
`endif

   // ----------------------------------------------------------------
   // DIV family and REM family
   // Uses the iterative divider provided in the imported 'IntMulDiv' package.

   rule rg_div_rem ((rg_state == STATE_DIV_REM) && intDiv.result_valid);
      match { .q, .r } = intDiv.result_value;
      WordXL result = ((rg_f3 [1] == 1'b0) ? q : r );

`ifdef RV64
      if (! rg_is_OP_not_OP_32)
	 result = signExtend (result [31:0]);
`endif

      dw_valid  <= True;
      dw_result <= result;
   endrule

   // ================================================================
   // INTERFACE

   method Action set_verbosity (Bit #(4) verbosity);
      cfg_verbosity <= verbosity;
   endmethod

   method Action req_reset;
      noAction;
   endmethod

   method ActionValue #(Bit #(0))  rsp_reset;
      return (?);
   endmethod

   // MBox interface: request
   method Action  req (Bool is_OP_not_OP_32, Bit #(3) f3, WordXL v1, WordXL v2);

      Bool is_signed = (f3 [0] == 1'b0);

`ifdef RV64
      if (! is_OP_not_OP_32) begin
	 // RV64 ops MULW/DIVW/DIVUW/REMW/REMUW)
	 if (is_signed) begin
	    v1 = signExtend (v1 [31:0]);
	    v2 = signExtend (v2 [31:0]);
	 end
	 else begin
	    v1 = zeroExtend (v1 [31:0]);
	    v2 = zeroExtend (v2 [31:0]);
	 end
      end
`endif

      rg_is_OP_not_OP_32 <= is_OP_not_OP_32;
      rg_f3              <= f3;
      rg_v1              <= v1;
      rg_v2              <= v2;

      // MUL, MULH, MULHU, MULHSU
      if (f3 [2] == 1'b0) begin
	 rg_state <= STATE_MUL1;

`ifdef MULT_SERIAL
	 Bool s1, s2;

	 if      (is_OP_not_OP_32     && (f3 == f3_MUL))     begin
	    s1 = False; s2 = False;
	 end
	 else if (is_OP_not_OP_32     && (f3 == f3_MULH))    begin
	    s1 = True; s2 = True;
	 end
	 else if (is_OP_not_OP_32     && (f3 == f3_MULHU))   begin
	    s1 = False; s2 = False;
	 end
	 else if (is_OP_not_OP_32     && (f3 == f3_MULHSU))  begin
	    s1 = True; s2 = False;
	 end
`ifdef RV64
	 else if ((! is_OP_not_OP_32) && (f3 == f3_MUL))     begin
	    // Signed versions of lower 32 bits of v_rs1 and v_rs2
	    v1 = signExtend (v1 [31:0]);
	    v2 = signExtend (v2 [31:0]);
	    s1 = True; s2 = True;
	 end
`endif
	 else begin
	    // This should be Impossible
	    $display ("%0d: ERROR: RISCV_MBox.rl_mul: illegal f3.", cur_cycle);
	    $display ("    f3 0x%0h  v1 0x%0h  v2 0x%0h", f3, v1, v2);
	    $finish (1);    // TODO: illegal instruction; should trap
	    s1 = ?; s2 = ?; // to keep bsc happy
	 end

	 intMul.put_args(s1, v1, s2, v2);
`endif
      end

      // DIV, DIVU, REM, REMU
      else begin
	 rg_state <= STATE_DIV_REM;
	 intDiv.start (is_signed, is_signed);
      end
   endmethod

   // MBox interface: response
   method Bool  valid;
      return dw_valid;
   endmethod

   method WordXL  word;
      return dw_result;
   endmethod
endmodule

// ================================================================

function ActionValue #(WordXL) fav_MUL (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed versions of v_rs1 and v_rs2
      IntXL s_v_rs1 = unpack (v_rs1);
      IntXL s_v_rs2 = unpack (v_rs2);

      WordXL v_rd = pack (s_v_rs1 * s_v_rs2);
      return v_rd;
   endactionvalue
endfunction

function ActionValue #(WordXL) fav_MULH (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed versions of v_rs1 and v_rs2
      IntXL s_v_rs1 = unpack (v_rs1);
      IntXL s_v_rs2 = unpack (v_rs2);

      Int #(XLEN_2) s_v1     = extend (s_v_rs1);
      Int #(XLEN_2) s_v2     = extend (s_v_rs2);
      Int #(XLEN_2) s_result = s_v1 * s_v2;
      WordXL v_rd = pack (s_result) [2 * xlen - 1: xlen];
      return v_rd;
   endactionvalue
endfunction

function ActionValue #(WordXL) fav_MULHU (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      Bit #(XLEN_2) v1     = extend (v_rs1);
      Bit #(XLEN_2) v2     = extend (v_rs2);
      Bit #(XLEN_2) result = v1 * v2;
      WordXL v_rd = result [2 * xlen - 1: xlen];
      return v_rd;
   endactionvalue
endfunction

function ActionValue #(WordXL) fav_MULHSU (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed version of v_rs1
      IntXL s_v_rs1 = unpack (v_rs1);

      Int #(XLEN_2) s_v1     = extend (s_v_rs1);
      Int #(XLEN_2) s_v2     = unpack (extend (v_rs2));
      Int #(XLEN_2) s_result = s_v1 * s_v2;
      WordXL v_rd = pack (s_result) [2 * xlen - 1: xlen];
      return v_rd;
   endactionvalue
endfunction

`ifdef RV64
function ActionValue #(WordXL) fav_MULW (WordXL v_rs1, WordXL v_rs2);
   actionvalue
      // Signed versions of lower 32 bits of v_rs1 and v_rs2
      IntXL s_v_rs1 = unpack (signExtend (v_rs1 [31:0]));
      IntXL s_v_rs2 = unpack (signExtend (v_rs2 [31:0]));
      WordXL prod64 = pack (s_v_rs1 * s_v_rs2);

      WordXL v_rd = signExtend (prod64 [31:0]);
      return v_rd;
   endactionvalue
endfunction
`endif

// ================================================================

endpackage