Bugfix in CPU_Fetch_C to report correct TVAL on compressed instr fetch

In method 'req', when PC is at page-offset 0xFFE (last 2 bytes) and
it's a 32-bit instruction, so we fetch at PC+2, need to set TVAL to PC+2.

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

package CPU_Fetch_C;

// ================================================================
// mkCPU_Fetch_C is an IMem_IFC->Module#(IMem_IFC) wrapper.

// The input parameter interface is for 32-bit-aligned 32-bit instruction-fetches.

// This module completely encapsulates the logic needed to extend it to
// 16-bit "compressed" instructions ('C' extension)
// which then also includes 32-bit instructions which may be only 16-bit-aligned,
// since 32b and 16b instructions can be freely mixed.

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

export mkCPU_Fetch_C;

// ================================================================
// BSV lib imports

import GetPut       :: *;
import ClientServer :: *;

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

import Cur_Cycle :: *;

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

import ISA_Decls    :: *;
import Near_Mem_IFC :: *;

// ================================================================
// Functions concerning address-alignment of instructions.
// 'Even': aligned to an even 16b boundary (so, also aligned to 32b boundary)
// 'Odd':  aligned to an odd  16b boundary (so, not  aligned to 32b boundary)

function Bool is_addr_even16 (WordXL pc);
   return (pc [1:0] == 2'b00);
endfunction

function Bool is_addr_odd16 (WordXL pc);
   return (pc [1:0] != 2'b00);
endfunction

function WordXL fn_to_b32_addr (WordXL addr);
   return ((addr >> 2) << 2);
endfunction

// Equality of 32-bit aligned addresses containing a1 and a2 (i.e., ignoring [1:0])
function Bool eq_b32_addr (WordXL a1, WordXL a2) = ((a1 >> 2) == (a2 >> 2));

// ================================================================
// Functions concerning whether an instr is 32b (RV) or 16b (RVC)

function Bool is_32b_instr (Bit #(n) instr);
   return (instr [1:0] == 2'b11);
endfunction

function Bool is_16b_instr (Bit #(n) instr);
   return (instr [1:0] != 2'b11);
endfunction

// ================================================================
// Wrapper: wraps 32-bit aligned IMem to allow 16-bit instrs and 32-bit instrs,
// aligned to 16b or 32b boundaries.

module mkCPU_Fetch_C #(IMem_IFC  imem32) (IMem_IFC);

   // imem32 is the underlying 32-bit-aligned memory.
   // imem32.req is only given 32-bit aligned addrs,
   // and returns the 32b at that addr.
   // imem32.pc (output pc) is always the last requested address, always 32b-aligned.
   // ( Assert: imem32.is_32b_not_16b == True )

   Integer verbosity = 0;

   // The following hold args of the 'req' method.
   Reg #(Bit #(3))  rg_f3          <- mkRegU;
   Reg #(WordXL)    rg_pc          <- mkRegU;
   Reg #(Priv_Mode) rg_priv        <- mkRegU;
   Reg #(Bit #(1))  rg_sstatus_SUM <- mkRegU;
   Reg #(Bit #(1))  rg_mstatus_MXR <- mkRegU;
   Reg #(WordXL)    rg_satp        <- mkRegU;

   // Holds a faulting address
   Reg #(WordXL)    rg_tval        <- mkRegU;

   // These registers caches the last output of imem32 (imem32.pc, and imem32.instr [31:16])
   Reg #(WordXL)    rg_cache_addr <- mkReg ('1);
   Reg #(Bit #(16)) rg_cache_b16  <- mkRegU;

   // ----------------------------------------------------------------
   // Conditions for selecting 16b and 32b instruction

   // Condition: 32b instr from {imem [15:0], rg_cache_b16}
   Bool cond_i32_odd = (   is_addr_odd16 (rg_pc)
			&& eq_b32_addr (rg_pc, rg_cache_addr)
			&& (imem32.pc == rg_pc + 2)
			&& is_32b_instr (rg_cache_b16));

   // Condition: 32b instr from imem [31:0]
   Bool cond_i32_even = (   is_addr_even16 (rg_pc)
			 && eq_b32_addr (rg_pc, imem32.pc)
			 && is_32b_instr (imem32.instr));

   // Condition: 16b instr from imem [31:16]
   Bool cond_i16_odd  = (   is_addr_odd16 (rg_pc)
			 && (   (   eq_b32_addr (rg_pc, imem32.pc)
				 && is_16b_instr (imem32.instr [31:16]))
			     || (   eq_b32_addr (rg_pc, rg_cache_addr)
				 && is_16b_instr (rg_cache_b16))));

   // Condition: 16b instr from imem [15:0]
   Bool cond_i16_even = (   is_addr_even16 (rg_pc)
			 && eq_b32_addr (rg_pc, imem32.pc)
			 && is_16b_instr (imem32.instr));

   // Condition: 32b instr from { ...next imem [15:0], imem [31:16] }
   Bool cond_i32_odd_fetch_next = (   is_addr_odd16 (rg_pc)
				   && imem32.valid
				   && (! imem32.exc)
				   && eq_b32_addr (rg_pc, imem32.pc)
				   && is_32b_instr (imem32.instr [31:16]));

   // ----------------
   // Compose the 32b output 'instr' (either a 32b instr, or { 16'b0, 16b instr })

   function Bit #(32) fn_instr_out ();
      Bit #(32) instr_out = imem32.instr;
      if (cond_i32_odd)
	 instr_out = { imem32.instr [15:0], rg_cache_b16 };

      else if (cond_i16_even)
	 instr_out = { 16'b0, imem32.instr [15:0] };

      else if (cond_i16_odd) begin
	 if (eq_b32_addr (rg_pc, imem32.pc))
	    instr_out = { 16'b0, imem32.instr [31:16] };
	 else
	    instr_out = { 16'b0, rg_cache_b16 };
      end
      return instr_out;
   endfunction

   // ================================================================
   // Assert: The underlying imem32 only knows about 32-bit aligned words

   rule rl_assert_fail (! imem32.is_i32_not_i16);
      $display ("%0d: ERROR: CPU_Fetch_C: imem32.is_i32_not_i16 is False", cur_cycle);
      $finish (1);
   endrule

   rule rl_debug_conds (False && (verbosity != 0) && imem32.valid);
      $display ("%0d: imem32.pc 0x%0h  pc 0x%0h  rg_f3 %0d  imem32.instr 0x%08h  rg_cache_b16 0x%04h",
		cur_cycle, imem32.pc,  rg_pc,  rg_f3,  imem32.instr,  rg_cache_b16);
      $display ("    cond_i32_odd  = ", fshow (cond_i32_odd));
      $display ("    cond_i32_even = ", fshow (cond_i32_even));
      $display ("    cond_i16_odd  = ", fshow (cond_i16_odd));
      $display ("    cond_i16_even = ", fshow (cond_i16_even));
      $display ("    cond_i32_odd_fetch_next             = ", fshow (cond_i32_odd_fetch_next));
      $display ("    eq_b32_addr (rg_pc, imem32.pc)      = ", fshow (eq_b32_addr (rg_pc, imem32.pc)));
      $display ("    is_addr_odd16 (rg_pc)               = ", fshow (is_addr_odd16 (rg_pc)));
      $display ("    is_32b_instr (imem32.instr [31:16]) = ", fshow (is_32b_instr (imem32.instr [31:16])));
   endrule

   // ================================================================
   // When imem32.instr [31:15] has lower half of 32b instr, cache it and fetch next 32 bits

   (* no_implicit_conditions, fire_when_enabled *)
   rule rl_fetch_next_32b (cond_i32_odd_fetch_next);
      Addr next_b32_addr = imem32.pc + 4;
      imem32.req (rg_f3, next_b32_addr, rg_priv, rg_sstatus_SUM, rg_mstatus_MXR, rg_satp);
      rg_cache_addr <= imem32.pc;
      rg_cache_b16  <= imem32.instr [31:16];
      rg_tval       <= next_b32_addr;

      if (verbosity != 0)
	 $display ("%0d: CPU_Fetch_C.rl_fetch_next_32b:  imem32.pc 0x%0h  next_b32_addr 0x%0h",
		   cur_cycle, imem32.pc, next_b32_addr);
   endrule

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

   // CPU side: IMem request
   method Action  req (Bit #(3)   f3,
		       WordXL     addr,
		       // The following  args for VM
		       Priv_Mode  priv,
		       Bit #(1)   sstatus_SUM,
		       Bit #(1)   mstatus_MXR,
		       WordXL     satp               // { VM_Mode, ASID, PPN_for_page_table }
		       ) if (! cond_i32_odd_fetch_next);
      rg_f3          <= f3;
      rg_pc          <= addr;
      rg_priv        <= priv;
      rg_sstatus_SUM <= sstatus_SUM;
      rg_mstatus_MXR <= mstatus_MXR;
      rg_satp        <= satp;

      // Cache the previous output, if valid
      if (imem32.valid && (! imem32.exc)) begin
	 rg_cache_addr <= imem32.pc;
	 rg_cache_b16  <= imem32.instr [31:16];
      end
      else begin
	 // Invalidate
	 rg_cache_addr <= 'h1;
      end

      WordXL addr_of_b32 = fn_to_b32_addr (addr);
      WordXL tval        = addr;

      // Fetch next 32b word if request is odd-16b aligned, we've already got those 16b, and it's a 32b instr
      // (the 16b we've already got is saved in r16_cache_b16).
      // Note: since we know it's a 32b instr, this next fetch is not speculative, so ok if it page faults.
      if (   is_addr_odd16 (addr)
	  && (imem32.valid && (! imem32.exc))
	  && (addr_of_b32 == imem32.pc)
	  && is_32b_instr (imem32.instr [31:16]))
	 begin
	    addr_of_b32 = addr_of_b32 + 4;
	    tval        = addr_of_b32;
	 end

      rg_tval <= tval;
      imem32.req (f3, addr_of_b32, priv, sstatus_SUM, mstatus_MXR, satp);
      if (verbosity > 0) begin
	 $display ("CPU_Fetch_C.req: addr 0x%0h, addr_of_b32 0x%0h", addr, addr_of_b32);
      end
   endmethod

   // CPU side: IMem response
   method Bool     valid    = (imem32.valid && (   imem32.exc
						|| cond_i32_odd
						|| cond_i32_even
						|| cond_i16_odd
						|| cond_i16_even));

   method Bool     is_i32_not_i16 = (cond_i32_odd || cond_i32_even);

   method WordXL   pc       = rg_pc;
   method Instr    instr    = fn_instr_out ();
   method Bool     exc      = imem32.exc;
   method Exc_Code exc_code = imem32.exc_code;
   method WordXL   tval     = rg_tval;        // Can be different from rg_pc

endmodule

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

endpackage

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

package CPU_Fetch_C;

// ================================================================
// mkCPU_Fetch_C is an IMem_IFC->Module#(IMem_IFC) wrapper.

// The input parameter interface is for 32-bit-aligned 32-bit instruction-fetches.

// This module completely encapsulates the logic needed to extend it to
// 16-bit "compressed" instructions ('C' extension)
// which then also includes 32-bit instructions which may be only 16-bit-aligned,
// since 32b and 16b instructions can be freely mixed.

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

export mkCPU_Fetch_C;

// ================================================================
// BSV lib imports

import GetPut       :: *;
import ClientServer :: *;

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

import Cur_Cycle :: *;

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

import ISA_Decls    :: *;
import Near_Mem_IFC :: *;

// ================================================================
// Functions concerning address-alignment of instructions.
// 'Even': aligned to an even 16b boundary (so, also aligned to 32b boundary)
// 'Odd':  aligned to an odd  16b boundary (so, not  aligned to 32b boundary)

function Bool is_addr_even16 (WordXL pc);
   return (pc [1:0] == 2'b00);
endfunction

function Bool is_addr_odd16 (WordXL pc);
   return (pc [1:0] != 2'b00);
endfunction

function WordXL fn_to_b32_addr (WordXL addr);
   return ((addr >> 2) << 2);
endfunction

// Equality of 32-bit aligned addresses containing a1 and a2 (i.e., ignoring [1:0])
function Bool eq_b32_addr (WordXL a1, WordXL a2) = ((a1 >> 2) == (a2 >> 2));

// ================================================================
// Functions concerning whether an instr is 32b (RV) or 16b (RVC)

function Bool is_32b_instr (Bit #(n) instr);
   return (instr [1:0] == 2'b11);
endfunction

function Bool is_16b_instr (Bit #(n) instr);
   return (instr [1:0] != 2'b11);
endfunction

// ================================================================
// Wrapper: wraps 32-bit aligned IMem to allow 16-bit instrs and 32-bit instrs,
// aligned to 16b or 32b boundaries.

module mkCPU_Fetch_C #(IMem_IFC  imem32) (IMem_IFC);

   // imem32 is the underlying 32-bit-aligned memory.
   // imem32.req is only given 32-bit aligned addrs,
   // and returns the 32b at that addr.
   // imem32.pc (output pc) is always the last requested address, always 32b-aligned.
   // ( Assert: imem32.is_32b_not_16b == True )

   Integer verbosity = 0;

   // The following hold args of the 'req' method.
   Reg #(Bit #(3))  rg_f3          <- mkRegU;
   Reg #(WordXL)    rg_pc          <- mkRegU;
   Reg #(Priv_Mode) rg_priv        <- mkRegU;
   Reg #(Bit #(1))  rg_sstatus_SUM <- mkRegU;
   Reg #(Bit #(1))  rg_mstatus_MXR <- mkRegU;
   Reg #(WordXL)    rg_satp        <- mkRegU;

   // Holds a faulting address
   Reg #(WordXL)    rg_tval        <- mkRegU;

   // These registers caches the last output of imem32 (imem32.pc, and imem32.instr [31:16])
   Reg #(WordXL)    rg_cache_addr <- mkReg ('1);
   Reg #(Bit #(16)) rg_cache_b16  <- mkRegU;

   // ----------------------------------------------------------------
   // Conditions for selecting 16b and 32b instruction

   // Condition: 32b instr from {imem [15:0], rg_cache_b16}
   Bool cond_i32_odd = (   is_addr_odd16 (rg_pc)
			&& eq_b32_addr (rg_pc, rg_cache_addr)
			&& (imem32.pc == rg_pc + 2)
			&& is_32b_instr (rg_cache_b16));

   // Condition: 32b instr from imem [31:0]
   Bool cond_i32_even = (   is_addr_even16 (rg_pc)
			 && eq_b32_addr (rg_pc, imem32.pc)
			 && is_32b_instr (imem32.instr));

   // Condition: 16b instr from imem [31:16]
   Bool cond_i16_odd  = (   is_addr_odd16 (rg_pc)
			 && (   (   eq_b32_addr (rg_pc, imem32.pc)
				 && is_16b_instr (imem32.instr [31:16]))
			     || (   eq_b32_addr (rg_pc, rg_cache_addr)
				 && is_16b_instr (rg_cache_b16))));

   // Condition: 16b instr from imem [15:0]
   Bool cond_i16_even = (   is_addr_even16 (rg_pc)
			 && eq_b32_addr (rg_pc, imem32.pc)
			 && is_16b_instr (imem32.instr));

   // Condition: 32b instr from { ...next imem [15:0], imem [31:16] }
   Bool cond_i32_odd_fetch_next = (   is_addr_odd16 (rg_pc)
				   && imem32.valid
				   && (! imem32.exc)
				   && eq_b32_addr (rg_pc, imem32.pc)
				   && is_32b_instr (imem32.instr [31:16]));

   // ----------------
   // Compose the 32b output 'instr' (either a 32b instr, or { 16'b0, 16b instr })

   function Bit #(32) fn_instr_out ();
      Bit #(32) instr_out = imem32.instr;
      if (cond_i32_odd)
	 instr_out = { imem32.instr [15:0], rg_cache_b16 };

      else if (cond_i16_even)
	 instr_out = { 16'b0, imem32.instr [15:0] };

      else if (cond_i16_odd) begin
	 if (eq_b32_addr (rg_pc, imem32.pc))
	    instr_out = { 16'b0, imem32.instr [31:16] };
	 else
	    instr_out = { 16'b0, rg_cache_b16 };
      end
      return instr_out;
   endfunction

   // ================================================================
   // Assert: The underlying imem32 only knows about 32-bit aligned words

   rule rl_assert_fail (! imem32.is_i32_not_i16);
      $display ("%0d: ERROR: CPU_Fetch_C: imem32.is_i32_not_i16 is False", cur_cycle);
      $finish (1);
   endrule

   rule rl_debug_conds (False && (verbosity != 0) && imem32.valid);
      $display ("%0d: imem32.pc 0x%0h  pc 0x%0h  rg_f3 %0d  imem32.instr 0x%08h  rg_cache_b16 0x%04h",
		cur_cycle, imem32.pc,  rg_pc,  rg_f3,  imem32.instr,  rg_cache_b16);
      $display ("    cond_i32_odd  = ", fshow (cond_i32_odd));
      $display ("    cond_i32_even = ", fshow (cond_i32_even));
      $display ("    cond_i16_odd  = ", fshow (cond_i16_odd));
      $display ("    cond_i16_even = ", fshow (cond_i16_even));
      $display ("    cond_i32_odd_fetch_next             = ", fshow (cond_i32_odd_fetch_next));
      $display ("    eq_b32_addr (rg_pc, imem32.pc)      = ", fshow (eq_b32_addr (rg_pc, imem32.pc)));
      $display ("    is_addr_odd16 (rg_pc)               = ", fshow (is_addr_odd16 (rg_pc)));
      $display ("    is_32b_instr (imem32.instr [31:16]) = ", fshow (is_32b_instr (imem32.instr [31:16])));
   endrule

   // ================================================================
   // When imem32.instr [31:15] has lower half of 32b instr, cache it and fetch next 32 bits

   (* no_implicit_conditions, fire_when_enabled *)
   rule rl_fetch_next_32b (cond_i32_odd_fetch_next);
      Addr next_b32_addr = imem32.pc + 4;
      imem32.req (rg_f3, next_b32_addr, rg_priv, rg_sstatus_SUM, rg_mstatus_MXR, rg_satp);
      rg_cache_addr <= imem32.pc;
      rg_cache_b16  <= imem32.instr [31:16];
      rg_tval       <= next_b32_addr;

      if (verbosity != 0)
	 $display ("%0d: CPU_Fetch_C.rl_fetch_next_32b:  imem32.pc 0x%0h  next_b32_addr 0x%0h",
		   cur_cycle, imem32.pc, next_b32_addr);
   endrule

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

   // CPU side: IMem request
   method Action  req (Bit #(3)   f3,
		       WordXL     addr,
		       // The following  args for VM
		       Priv_Mode  priv,
		       Bit #(1)   sstatus_SUM,
		       Bit #(1)   mstatus_MXR,
		       WordXL     satp               // { VM_Mode, ASID, PPN_for_page_table }
		       ) if (! cond_i32_odd_fetch_next);
      rg_f3          <= f3;
      rg_pc          <= addr;
      rg_priv        <= priv;
      rg_sstatus_SUM <= sstatus_SUM;
      rg_mstatus_MXR <= mstatus_MXR;
      rg_satp        <= satp;
      rg_tval        <= addr;

      // Cache the previous output, if valid
      if (imem32.valid && (! imem32.exc)) begin
	 rg_cache_addr <= imem32.pc;
	 rg_cache_b16  <= imem32.instr [31:16];
      end
      else begin
	 // Invalidate
	 rg_cache_addr <= 'h1;
      end

      WordXL addr_of_b32 = fn_to_b32_addr (addr);

      // Fetch next 32b word if request is odd-16b aligned, we've already got those 16b, and it's a 32b instr
      // (the 16b we've already got is saved in r16_cache_b16).
      // Note: since we know it's a 32b instr, this next fetch is not speculative, so ok if it page faults.
      if (   is_addr_odd16 (addr)
	  && (imem32.valid && (! imem32.exc))
	  && (addr_of_b32 == imem32.pc)
	  && is_32b_instr (imem32.instr [31:16]))
	 begin
	    addr_of_b32 = addr_of_b32 + 4;
	 end

      imem32.req (f3, addr_of_b32, priv, sstatus_SUM, mstatus_MXR, satp);
      if (verbosity > 0) begin
	 $display ("CPU_Fetch_C.req: addr 0x%0h, addr_of_b32 0x%0h", addr, addr_of_b32);
      end
   endmethod

   // CPU side: IMem response
   method Bool     valid    = (imem32.valid && (   imem32.exc
						|| cond_i32_odd
						|| cond_i32_even
						|| cond_i16_odd
						|| cond_i16_even));

   method Bool     is_i32_not_i16 = (cond_i32_odd || cond_i32_even);

   method WordXL   pc       = rg_pc;
   method Instr    instr    = fn_instr_out ();
   method Bool     exc      = imem32.exc;
   method Exc_Code exc_code = imem32.exc_code;
   method WordXL   tval     = rg_tval;        // Can be different from rg_pc

endmodule

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

endpackage


Beginnings of a pipeline.

Beginnings of a pipeline.


everywhere

everywhere

// 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 GetPutF::*;
import RingTypes::*;

module mkNopEngine
 ( ServerF#(Bit#(64), Bit#(64)));
   FIFOF#(Bit#(64)) f_nop <- mkSizedFIFOF(2);

   rule discard;
      let x = f_nop.deq();
      $display("Nop %h\n", x);
   endrule

   interface PutF request = toPutF(f_nop);
   interface GetF response = ?;

endmodule: mkNopEngine

// 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 GetPutF::*;
import RingTypes::*;

module mkNopEngine ( ServerF#(Bit#(64), Bit#(64)));
   FIFOF#(Bit#(64)) f_nop <- mkSizedFIFOF(2);

   rule discard;
      let x = f_nop.deq();
      $display("Nop %h\n", x);
   endrule

   interface PutF request = toPutF(f_nop);
   interface GetF response = ?;

endmodule: mkNopServer


add bitwiseor

add bitwiseor

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

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

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

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

import Vector::*;

function Bool booland(Bool x1, Bool x2); return x1 && x2; endfunction
function Bool boolor(Bool x1, Bool x2); return x1 || x2; endfunction

function Bool eq(a x1, a x2) provisos (Eq#(a)); return x1 == x2; endfunction

function a add(a x1, a x2) provisos (Arith#(a)); return x1 + x2; endfunction
function a mul(a x1, a x2) provisos (Arith#(a)); return x1 * x2; endfunction
function Bit#(b) rshift(Bit#(b) x1, Integer i); return x1 >> i; endfunction
function Vector#(n, a) vadd(Vector#(n, a) x1, Vector#(n, a) x2) provisos (Arith#(a));
   return map(uncurry(add), zip(x1, x2));
endfunction
function Vector#(n, a) vmul(Vector#(n, a) x1, Vector#(n, a) x2) provisos (Arith#(a));
   return map(uncurry(mul), zip(x1, x2));
endfunction
function Vector#(n, Bit#(b)) vrshift(Vector#(n, Bit#(b)) x1, Integer i);
   return map(flip(rshift)(i), x1);
endfunction

function a bitwiseor(a x1, a x2) provisos (Bitwise#(a)); return x1 | x2; endfunction


reverting changes

reverting changes

// Copyright (c) 2014 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.

package DtpTx;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;

typedef 8  CmdLen;
typedef 32 ParamLen;
typedef 4 GLOBAL_DELAY;
typedef 5 RXTX_DELAY;

typedef struct {
   Bit#(CmdLen)   cmd;
   Bit#(ParamLen) param;
} CmdTup deriving (Eq, Bits, FShow);

typedef struct {
   Bool     mux_sel;
   Bit#(53) c_local;
   Bit#(1)  parity;
} TxStageOneBuf deriving (Eq, Bits);

interface DtpTx;
   interface PipeIn#(Bit#(66))  dtpTxIn;
   interface PipeOut#(Bit#(66)) dtpTxOut;
   interface PipeOut#(Bit#(53)) dtpLocalOut;
   interface PipeIn#(Bit#(53))  dtpGlobalIn;
   interface DtpToPhyIfc api;

   interface PipeIn#(DtpEvent) dtpEventIn;
   interface PipeIn#(Bit#(32)) dtpErrCnt;

   (* always_ready, always_enabled *)
   method Action tx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action switch_mode(Bool v);
   (* always_ready, always_enabled *)
   method Action bsync_lock(Bool v);
endinterface

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;

typedef enum {INIT, SENT, SYNC} DtpState
deriving (Bits, Eq);

(* synthesize *)
module mkDtpTxTop(DtpTx);
   DtpTx _a <- mkDtpTx(0, 0);
   return _a;
endmodule

module mkDtpTx#(Integer id, Integer c_local_init)(DtpTx);

   let verbose = True;
   Wire#(Bool) tx_ready_wire <- mkDWire(False);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);
   Wire#(Bool) switch_mode_wire <- mkDWire(False);
   Wire#(Bool) bsync_lock_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpTxInFifo <- mkFIFOF ();

   Reg#(Bool)   is_switch_mode <- mkReg(False); // by default, NIC mode
   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Reg#(DtpState)  curr_state  <- mkReg(INIT);

   Reg#(Bit#(53))  c_local <- mkReg(fromInteger(c_local_init)); //mkReg(0); //fromInteger(c_local_init));
   Reg#(Bit#(53))  c_global <- mkReg(0);
   Reg#(Bit#(53))  delay   <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_init <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_sync <- mkReg(0);
   Reg#(Bit#(64))  jumpCount <- mkReg(0);
   Reg#(Bit#(32))  interval_reg <- mkReg(1000);

   Wire#(Bool) init_rcvd    <- mkDWire(False);
   Wire#(Bool) ack_rcvd     <- mkDWire(False);
   Wire#(Bool) beacon_rcvd  <- mkDWire(False);

   Wire#(Bool) is_idle      <- mkDWire(False);

   Wire#(Bit#(53)) c_local_next <- mkDWire(0);
   FIFOF#(Bit#(2)) txMuxSelFifo <- mkSizedBypassFIFOF(3);

   // Tx Stage 1
   FIFOF#(Bit#(66)) dtpTxInPipelineFifo <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpTxOutFifo <- mkFIFOF;
   FIFOF#(TxStageOneBuf) stageOneFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) initTimestampFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(1)) initParityFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(53)) ackTimestampFifo <- mkBypassFIFOF;

   FIFOF#(Bit#(3))  dtpEventFifo   <- mkFIFOF;
   FIFOF#(Bit#(3))  dtpEventOutputFifo   <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo <- mkFIFOF;
   FIFOF#(DtpEvent) dtpEventInFifo <- mkFIFOF;
   FIFOF#(Bit#(32)) dtpErrCntFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) dtpLocalOutFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) dtpGlobalInFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) localCompareRemoteFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) localCompareGlobalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareGlobalFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareLocalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareRemoteFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareLocalFifo  <- mkFIFOF;

   FIFOF#(Bit#(53)) localOutputFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalOutputFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteOutputFifo <- mkFIFOF;

   FIFOF#(Bool) localLtRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) localGeRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) globalLeRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalGtRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalLeLocalFifo  <- mkFIFOF;
   FIFOF#(Bool) globalGtLocalFifo  <- mkFIFOF;

   FIFOF#(void) cfFifo <- mkFIFOF;
   FIFOF#(void) dmFifo <- mkFIFOF;

   Reg#(Bool)       log_rcvd     <- mkReg(False);
   FIFOF#(Bit#(53)) fromHostFifo <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(53)) toHostFifo   <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(32)) delayFifo    <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) stateFifo     <- mkSizedFIFOF(1);
   FIFOF#(Bit#(64)) jumpCountFifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(53)) cLocalFifo   <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) intervalFifo <- mkSizedFIFOF(1);

//   Wire#(Bit#(53)) dtpGlobal_wires <- mkDWire(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   rule set_switch_mode;
      is_switch_mode <= switch_mode_wire; // 0 for NIC, 1 for switch.
   endrule

   // Setup link first if neither Tx or Rx is ready, bypass DTP.
   rule tx_bypass(!tx_ready_wire || !rx_ready_wire || !bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get;
      dtpTxOutFifo.enq(v);
   endrule

   rule tx_stage1(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get();
      Bit#(1) parity;
      Bool    mux_sel;
      Bit#(53) c_local_out;
      Bit#(53) c_local_next;
      if (is_switch_mode) begin
          c_local_out = c_global + 2;
          c_local_next = c_global+1;
      end
      else begin
          c_local_out = c_local + 2;
          c_local_next = c_local+1;
      end
//      c_local_out = c_local+2; // forward compute parity.
      parity = ^c_local_out[52:0];

      if(v[9:2] == 8'h1e) begin
         mux_sel = True;
         is_idle <= True;
      end
      else begin
         mux_sel = False;
         is_idle <= False;
      end
      //if(verbose) $display("%d: %d dtpTxIn=%h, c_local=%h, is_idle=%h, curr_state=%d", cycle, id, v, c_local, mux_sel, curr_state);
      cfFifo.enq(?);
      dmFifo.enq(?);
      stageOneFifo.enq(TxStageOneBuf{mux_sel: mux_sel,
                                     parity: parity,
                                     c_local: c_local_next});
      dtpTxInPipelineFifo.enq(v);
   endrule

   Probe#(Bit#(53)) debug_from_host <- mkProbe();
   rule tx_stage2(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let val <- toGet(stageOneFifo).get;
      let v <- toGet(dtpTxInPipelineFifo).get();
      let mux_sel = val.mux_sel;
      let c_local = val.c_local;
      let parity = val.parity;

      Bit#(10) block_type;
      Bit#(66) encodeOut;
      Bit#(3) log_type    = fromInteger(valueOf(LOG_TYPE));
      Bit#(2) init_type   = fromInteger(valueOf(INIT_TYPE));
      Bit#(2) ack_type    = fromInteger(valueOf(ACK_TYPE));
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));

      block_type = v[9:0];

      if (mux_sel && fromHostFifo.notEmpty) begin
         let host_data = fromHostFifo.first;
         debug_from_host <= host_data;

         if (host_data[52] == 0) begin
//             Bit#(52) tmp;
//              if (is_switch_mode) begin
//                tmp = c_global[51:0] + 1;
//             end
//             else begin
//                tmp = c_local[51:0] + 1;
//             end
             Bit#(52) tmp = c_local[51:0] + 1;
             encodeOut = {1'b0, tmp, log_type, block_type};
             if(verbose) $display("%d: %d, sending a log message %d", cycle, id, tmp);
         end
         else begin
             encodeOut = {host_data, log_type, block_type};
         end
         fromHostFifo.deq;
      end
      else if (mux_sel && txMuxSelFifo.notEmpty) begin
         let sel = txMuxSelFifo.first;
         if (sel == init_type) begin
            Bit#(53)    tmp = zeroExtend(cycle);
            encodeOut = {tmp+1, parity, init_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing init request %d", cycle, id, tmp+1);
         end
         else if (sel == ack_type) begin
            let init_timestamp <- toGet(initTimestampFifo).get;
            let init_parity <- toGet(initParityFifo).get;
            encodeOut = {init_timestamp, init_parity, ack_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing ack %d", cycle, id, init_timestamp);
         end
         else if (sel == beacon_type) begin
//            Bit#(53) tmp;
//            if (is_switch_mode) begin
//                tmp = c_global + 1;
//                parity = ^tmp[52:0];
//            end
//            else begin
//                tmp = c_local+1;
//            end
            encodeOut = {c_local+1, parity, beacon_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing beacon %d", cycle, id, c_local+1);
         end
         else begin
            encodeOut = v; //should never happen
         end
         txMuxSelFifo.deq;
      end
      else begin
         encodeOut = v;
      end
      //if(verbose) $display("%d: %d dtpTxOut=%h, c_local=%h, encodeOut=%h", cycle, id, encodeOut, c_local, encodeOut[12:10]);
      dtpTxOutFifo.enq(encodeOut);
   endrule

   // delay measurement
   rule delay_measurment(curr_state == INIT || curr_state == SENT);
      let init_timeout = interval_reg._read;
      let init_type = fromInteger(valueOf(INIT_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      dmFifo.deq;
      // Timeout driven output
      if (init_rcvd) begin
         timeout_count_init <= timeout_count_init + 1;
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         if(verbose) $display("%d: %d, send ack, type %d", cycle, id, ack_type);
      end
      else if (timeout_count_init > init_timeout-1) begin
         if (is_idle) begin
            timeout_count_init <= 0;
            if (txMuxSelFifo.notFull) begin
               txMuxSelFifo.enq(init_type);
            end
            if(verbose) $display("%d: %d, init timed_out %d", cycle, id, timeout_count_init);
         end
         else begin
            timeout_count_init <= timeout_count_init + 1;
         end
      end
      else begin
         timeout_count_init <= timeout_count_init + 1;
      end

      // compute delay
      if (ack_rcvd) begin
         let temp <- toGet(ackTimestampFifo).get;
         Bit#(53) tmp2 = zeroExtend(cycle);
         delay <= (tmp2 - temp - 3) >> 1;
         if(verbose) $display("%d: %d update delay=%d, %d, %d", cycle, id, c_local, temp, (tmp2-temp-3)>>1);
      end
   endrule

   // Beacon
   rule beacon(curr_state == SYNC);
      dmFifo.deq;
      let sync_timeout = interval_reg._read;
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      if (timeout_count_sync >= sync_timeout-1) begin
         if (is_idle) begin
            timeout_count_sync <= 0;
         end
         else begin
            timeout_count_sync <= timeout_count_sync + 1;
         end
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(beacon_type);
         end
      end
      else if (init_rcvd) begin
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         timeout_count_sync <= timeout_count_sync + 1;
      end
      else begin
         timeout_count_sync <= timeout_count_sync + 1;
      end
   endrule

   // DTP state machine
   rule state_init (curr_state == INIT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (txMuxSelFifo.notEmpty && is_idle) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= SENT;
         end
      end
      else if (init_rcvd) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= INIT;
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
   endrule

   rule state_sent (curr_state == SENT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SENT;
      end
      else if (ack_rcvd) begin
         curr_state <= SYNC;
      end
      else if (txMuxSelFifo.notEmpty) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= INIT;
         end
      end
      else begin
         curr_state <= SENT;
      end
   endrule

   rule state_sync (curr_state == SYNC);
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SYNC;
      end
      else begin
         curr_state <= SYNC;
      end
   endrule

   rule switch_in_c_local(is_switch_mode);
      //if(verbose) $display("%d: send c_local %h to L2", cycle, c_local);
      dtpLocalOutFifo.enq(c_local);
   endrule

   rule switch_out_c_global;
      let v <- toGet(dtpGlobalInFifo).get;
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      c_global <= v + global_delay + 1;
//      dtpGlobal_wires <= v + global_delay;
      if (is_switch_mode && beacon_rcvd) begin
         if (verbose) $display("%d: received global counter %d", cycle, v);
         globalCompareRemoteFifo.enq(v + 1);
         globalCompareLocalFifo.enq(v + 1);
      end
   endrule

   rule rx_stage1(tx_ready_wire && rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      Bool init_rcvd_next   = False;
      Bool ack_rcvd_next    = False;
      Bool beacon_rcvd_next = False;
      Bool log_rcvd_next    = False;
      if (dtpEventInFifo.notEmpty) begin
         let v <- toGet(dtpEventInFifo).get;
         if ((v.e == init_type)) begin
            let parity = ^(v.t);
            if (initTimestampFifo.notFull && initParityFifo.notFull) begin
               initTimestampFifo.enq(v.t);
               initParityFifo.enq(parity);
            end
            if(verbose) $display("%d: %d DtpTx init_rcvd %h %d", cycle, id, v.e, v.t);
            init_rcvd_next = True;
         end
         else if (v.e == ack_type) begin
            ack_rcvd_next = True;
            // append received timestamp to fifo
            if (ackTimestampFifo.notFull)
               ackTimestampFifo.enq(v.t);
            if(verbose) $display("%d: %d DtpTx ack_rcvd %h %d", cycle, id, v.e, v.t);
         end
         else if (v.e == beacon_type) begin
            beacon_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx beacon_rcvd %h %d %d", cycle, id, v.e, v.t, c_local);
            localCompareRemoteFifo.enq(c_local+1);
            remoteCompareLocalFifo.enq(v.t+1);
            if (is_switch_mode) begin
               localCompareGlobalFifo.enq(c_local+1);
               remoteCompareGlobalFifo.enq(v.t+1);
            end
         end
         else if (v.e == log_type) begin
            log_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx log_rcvd %h %d", cycle, id, v.e, v.t);
            if (toHostFifo.notFull) begin
               toHostFifo.enq(v.t);
            end
         end
         dtpEventFifo.enq(v.e);
      end
      else begin
         dtpEventFifo.enq(3'b0);
      end
      init_rcvd   <= init_rcvd_next;
      ack_rcvd    <= ack_rcvd_next;
      beacon_rcvd <= beacon_rcvd_next;
      log_rcvd    <= log_rcvd_next;
   endrule

   rule rx_stage2;
      let v_local <- toGet(localCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareLocalFifo).get();
      if(verbose) $display("%d: %d, v_local=%d, v_remote=%d, delay=%d", cycle, id, v_local, v_remote, delay);
      if (v_local < v_remote + delay) begin
         localLtRemoteFifo.enq(True);
         localGeRemoteFifo.enq(False);
      end
      else begin
         localLtRemoteFifo.enq(False);
         localGeRemoteFifo.enq(True);
      end
      localOutputFifo.enq(v_local + 1);
      remoteOutputFifo.enq(v_remote + 1);
   endrule

   rule compare_global_remote (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareGlobalFifo).get();
      if (v_global + global_delay <= v_remote + delay) begin
         globalLeRemoteFifo.enq(True);
         globalGtRemoteFifo.enq(False);
      end
      else begin
         globalLeRemoteFifo.enq(False);
         globalGtRemoteFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_remote=%d", cycle, id, v_global, v_remote);
      globalOutputFifo.enq(v_global + 1);
   endrule

   rule compare_global_local (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareLocalFifo).get();
      let v_local <- toGet(localCompareGlobalFifo).get();
      if (v_global + global_delay <= v_local + 1) begin
         globalLeLocalFifo.enq(True);
         globalGtLocalFifo.enq(False);
      end
      else begin
         globalLeLocalFifo.enq(False);
         globalGtLocalFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_local=%d", cycle, id, v_global, v_local);
   endrule

   rule rx_stage2_bypass;
      let v_event <- toGet(dtpEventFifo).get();
      dtpEventOutputFifo.enq(v_event);
   endrule

   rule rx_stage3_nic_mode (!is_switch_mode);
      let vLocal <- toGet(localOutputFifo).get();
      let vRemote <- toGet(remoteOutputFifo).get();
      let useLocal <- toGet(localGeRemoteFifo).get();
      let incrJump <- toGet(localLtRemoteFifo).get();
      if(verbose) $display("%d: %d vLocal=%d", cycle, id, vLocal);
      if(verbose) $display("%d: %d vRemote=%d", cycle, id, vRemote);
      if(verbose) $display("%d: %d delay=%d", cycle, id, delay);
      if (useLocal) begin
         c_local_next <= vLocal + 1;
      end
      else begin
         c_local_next <= vRemote + delay + 1;
      end

      if (incrJump) begin
         jumpCount <= jumpCount + 1;
      end
   endrule

   rule rx_stage3_switch_mode (is_switch_mode);
      let v_local <- toGet(localOutputFifo).get();
      let v_remote <- toGet(remoteOutputFifo).get();
      let v_global <- toGet(globalOutputFifo).get();
      let isGR <- toGet(globalGtRemoteFifo).get();
      let isGL <- toGet(globalGtLocalFifo).get();
      let isLR <- toGet(localGeRemoteFifo).get();
      let isLG <- toGet(globalLeLocalFifo).get();
      let isRG <- toGet(globalLeRemoteFifo).get();
      let isRL <- toGet(localLtRemoteFifo).get();
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let err = False;
      if(verbose) $display("%d: isGR=%d, isGL=%d, isLR=%d, isLG=%d, isRG=%d, isRL=%d", cycle, isGR, isGL, isLR, isLG, isRG, isRL);
      if (isGR && isGL) begin
         c_local_next <= v_global + global_delay;
//        err = True;
      end
      else if (isLR && isLG) begin
         c_local_next <= v_local + 1;
      end
      else if (isRG && isRL) begin
         c_local_next <= v_remote + delay;
         err = True;
      end
      else begin
         c_local_next <= v_local + 1;
//         err = True;
      end

      if (err) begin
         jumpCount <= jumpCount + 1;
      end

      if(verbose && id==1) $display("%d: jumpCount = %d", cycle, jumpCount);
   endrule

   rule rx_stage3;
      let v <- toGet(dtpEventOutputFifo).get();
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));
      if (!rx_ready_wire) begin
         c_local <= 0;
      end
      else if (v == zeroExtend(beacon_type)) begin
         c_local <= c_local_next;
         if(verbose) $display("%d: %d c_local_next = %d", cycle, id, c_local_next);
      end
      else begin
         c_local <= c_local + 1;
      end
   endrule

   rule export_delay;
      delayFifo.enq(truncate(delay));
   endrule

   rule export_state;
      stateFifo.enq(zeroExtend(pack(curr_state)));
   endrule

   rule export_jumpCount;
      jumpCountFifo.enq(jumpCount);
   endrule

   rule export_c_local;
      cLocalFifo.enq(c_local);
   endrule

   rule import_interval(intervalFifo.notEmpty);
      let interval = intervalFifo.first;
      interval_reg <= interval;
      intervalFifo.deq;
   endrule

   method Action tx_ready(Bool v);
      tx_ready_wire <= v;
   endmethod

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   method Action switch_mode(Bool v);
      switch_mode_wire <= v;
   endmethod

   method Action bsync_lock(Bool v);
      bsync_lock_wire <= v;
   endmethod

   interface api = (interface DtpToPhyIfc;
      interface delayOut = toPipeOut(delayFifo);
      interface stateOut = toPipeOut(stateFifo);
      interface jumpCount = toPipeOut(jumpCountFifo);
      interface cLocalOut = toPipeOut(cLocalFifo);
      interface toHost   = toPipeOut(toHostFifo);
      interface fromHost = toPipeIn(fromHostFifo);
      interface interval = toPipeIn(intervalFifo);
      interface dtpErrCnt = toPipeOut(dtpErrCntFifo);
   endinterface);
   interface dtpEventIn = toPipeIn(dtpEventInFifo);
   interface dtpErrCnt = toPipeIn(dtpErrCntFifo);
   interface dtpTxIn = toPipeIn(dtpTxInFifo);
   interface dtpTxOut = toPipeOut(dtpTxOutFifo);
   interface dtpLocalOut = toPipeOut(dtpLocalOutFifo);
   interface dtpGlobalIn = toPipeIn(dtpGlobalInFifo);
endmodule
endpackage

// Copyright (c) 2014 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.

package DtpTx;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;

typedef 8  CmdLen;
typedef 32 ParamLen;
typedef 4 GLOBAL_DELAY;
typedef 5 RXTX_DELAY;

typedef struct {
   Bit#(CmdLen)   cmd;
   Bit#(ParamLen) param;
} CmdTup deriving (Eq, Bits, FShow);

typedef struct {
   Bool     mux_sel;
   Bit#(53) c_local;
   Bit#(1)  parity;
} TxStageOneBuf deriving (Eq, Bits);

interface DtpTx;
   interface PipeIn#(Bit#(66))  dtpTxIn;
   interface PipeOut#(Bit#(66)) dtpTxOut;
   interface PipeOut#(Bit#(53)) dtpLocalOut;
   interface PipeIn#(Bit#(53))  dtpGlobalIn;
   interface DtpToPhyIfc api;

   interface PipeIn#(DtpEvent) dtpEventIn;
   interface PipeIn#(Bit#(32)) dtpErrCnt;

   (* always_ready, always_enabled *)
   method Action tx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action switch_mode(Bool v);
   (* always_ready, always_enabled *)
   method Action bsync_lock(Bool v);
endinterface

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;

typedef enum {INIT, SENT, SYNC} DtpState
deriving (Bits, Eq);

(* synthesize *)
module mkDtpTxTop(DtpTx);
   DtpTx _a <- mkDtpTx(0, 0);
   return _a;
endmodule

module mkDtpTx#(Integer id, Integer c_local_init)(DtpTx);

   let verbose = True;
   Wire#(Bool) tx_ready_wire <- mkDWire(False);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);
   Wire#(Bool) switch_mode_wire <- mkDWire(False);
   Wire#(Bool) bsync_lock_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpTxInFifo <- mkFIFOF ();

   Reg#(Bool)   is_switch_mode <- mkReg(False); // by default, NIC mode
   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Reg#(DtpState)  curr_state  <- mkReg(INIT);

   Reg#(Bit#(53))  c_local <- mkReg(fromInteger(c_local_init)); //mkReg(0); //fromInteger(c_local_init));
   Reg#(Bit#(53))  c_global <- mkReg(0);
   Reg#(Bit#(53))  delay   <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_init <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_sync <- mkReg(0);
   Reg#(Bit#(64))  jumpCount <- mkReg(0);
   Reg#(Bit#(32))  interval_reg <- mkReg(1000);

   Wire#(Bool) init_rcvd    <- mkDWire(False);
   Wire#(Bool) ack_rcvd     <- mkDWire(False);
   Wire#(Bool) beacon_rcvd  <- mkDWire(False);

   Wire#(Bool) is_idle      <- mkDWire(False);

   Wire#(Bit#(53)) c_local_next <- mkDWire(0);
   FIFOF#(Bit#(2)) txMuxSelFifo <- mkSizedBypassFIFOF(3);

   // Tx Stage 1
   FIFOF#(Bit#(66)) dtpTxInPipelineFifo <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpTxOutFifo <- mkFIFOF;
   FIFOF#(TxStageOneBuf) stageOneFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) initTimestampFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(1)) initParityFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(53)) ackTimestampFifo <- mkBypassFIFOF;

   FIFOF#(Bit#(3))  dtpEventFifo   <- mkFIFOF;
   FIFOF#(Bit#(3))  dtpEventOutputFifo   <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo <- mkFIFOF;
   FIFOF#(DtpEvent) dtpEventInFifo <- mkFIFOF;
   FIFOF#(Bit#(32)) dtpErrCntFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) dtpLocalOutFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) dtpGlobalInFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) localCompareRemoteFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) localCompareGlobalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareGlobalFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareLocalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareRemoteFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareLocalFifo  <- mkFIFOF;

   FIFOF#(Bit#(53)) localOutputFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalOutputFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteOutputFifo <- mkFIFOF;

   FIFOF#(Bool) localLtRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) localGeRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) globalLeRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalGtRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalLeLocalFifo  <- mkFIFOF;
   FIFOF#(Bool) globalGtLocalFifo  <- mkFIFOF;

   FIFOF#(void) cfFifo <- mkFIFOF;
   FIFOF#(void) dmFifo <- mkFIFOF;

   Reg#(Bool)       log_rcvd     <- mkReg(False);
   FIFOF#(Bit#(53)) fromHostFifo <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(53)) toHostFifo   <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(32)) delayFifo    <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) stateFifo     <- mkSizedFIFOF(1);
   FIFOF#(Bit#(64)) jumpCountFifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(53)) cLocalFifo   <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) intervalFifo <- mkSizedFIFOF(1);

//   Wire#(Bit#(53)) dtpGlobal_wires <- mkDWire(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   rule set_switch_mode;
      is_switch_mode <= switch_mode_wire; // 0 for NIC, 1 for switch.
   endrule

   // Setup link first if neither Tx or Rx is ready, bypass DTP.
   rule tx_bypass(!tx_ready_wire || !rx_ready_wire || !bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get;
      dtpTxOutFifo.enq(v);
   endrule

   rule tx_stage1(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get();
      Bit#(1) parity;
      Bool    mux_sel;
      Bit#(53) c_local_out;
//      if (is_switch_mode) begin
//          c_local_out = c_global + 2;
//      end
//      else begin
//          c_local_out = c_local + 2;
//      end
      c_local_out = c_local+2; // forward compute parity.
      parity = ^c_local_out[52:0];

      if(v[9:2] == 8'h1e) begin
         mux_sel = True;
         is_idle <= True;
      end
      else begin
         mux_sel = False;
         is_idle <= False;
      end
      //if(verbose) $display("%d: %d dtpTxIn=%h, c_local=%h, is_idle=%h, curr_state=%d", cycle, id, v, c_local, mux_sel, curr_state);
      cfFifo.enq(?);
      dmFifo.enq(?);
      stageOneFifo.enq(TxStageOneBuf{mux_sel: mux_sel,
                                     parity: parity,
                                     c_local: c_local + 1});
      dtpTxInPipelineFifo.enq(v);
   endrule

   Probe#(Bit#(53)) debug_from_host <- mkProbe();
   rule tx_stage2(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let val <- toGet(stageOneFifo).get;
      let v <- toGet(dtpTxInPipelineFifo).get();
      let mux_sel = val.mux_sel;
      let c_local = val.c_local;
      let parity = val.parity;

      Bit#(10) block_type;
      Bit#(66) encodeOut;
      Bit#(3) log_type    = fromInteger(valueOf(LOG_TYPE));
      Bit#(2) init_type   = fromInteger(valueOf(INIT_TYPE));
      Bit#(2) ack_type    = fromInteger(valueOf(ACK_TYPE));
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));

      block_type = v[9:0];

      if (mux_sel && fromHostFifo.notEmpty) begin
         let host_data = fromHostFifo.first;
         debug_from_host <= host_data;

         if (host_data[52] == 0) begin
             Bit#(52) tmp;
             if (is_switch_mode) begin
                tmp = c_global[51:0] + 1;
             end
             else begin
                tmp = c_local[51:0] + 1;
             end
//             Bit#(52) tmp = c_local[51:0] + 1;
             encodeOut = {1'b0, tmp, log_type, block_type};
             if(verbose) $display("%d: %d, sending a log message %d", cycle, id, tmp);
         end
         else begin
             encodeOut = {host_data, log_type, block_type};
         end
         fromHostFifo.deq;
      end
      else if (mux_sel && txMuxSelFifo.notEmpty) begin
         let sel = txMuxSelFifo.first;
         if (sel == init_type) begin
            Bit#(53)    tmp = zeroExtend(cycle);
            encodeOut = {tmp+1, parity, init_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing init request %d", cycle, id, tmp+1);
         end
         else if (sel == ack_type) begin
            let init_timestamp <- toGet(initTimestampFifo).get;
            let init_parity <- toGet(initParityFifo).get;
            encodeOut = {init_timestamp, init_parity, ack_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing ack %d", cycle, id, init_timestamp);
         end
         else if (sel == beacon_type) begin
            Bit#(53) tmp;
            if (is_switch_mode) begin
                tmp = c_global + 1;
                parity = ^tmp[52:0];
            end
            else begin
                tmp = c_local+1;
            end
            encodeOut = {tmp, parity, beacon_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing beacon %d", cycle, id, c_local+1);
         end
         else begin
            encodeOut = v; //should never happen
         end
         txMuxSelFifo.deq;
      end
      else begin
         encodeOut = v;
      end
      //if(verbose) $display("%d: %d dtpTxOut=%h, c_local=%h, encodeOut=%h", cycle, id, encodeOut, c_local, encodeOut[12:10]);
      dtpTxOutFifo.enq(encodeOut);
   endrule

   // delay measurement
   rule delay_measurment(curr_state == INIT || curr_state == SENT);
      let init_timeout = interval_reg._read;
      let init_type = fromInteger(valueOf(INIT_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      dmFifo.deq;
      // Timeout driven output
      if (init_rcvd) begin
         timeout_count_init <= timeout_count_init + 1;
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         if(verbose) $display("%d: %d, send ack, type %d", cycle, id, ack_type);
      end
      else if (timeout_count_init > init_timeout-1) begin
         if (is_idle) begin
            timeout_count_init <= 0;
            if (txMuxSelFifo.notFull) begin
               txMuxSelFifo.enq(init_type);
            end
            if(verbose) $display("%d: %d, init timed_out %d", cycle, id, timeout_count_init);
         end
         else begin
            timeout_count_init <= timeout_count_init + 1;
         end
      end
      else begin
         timeout_count_init <= timeout_count_init + 1;
      end

      // compute delay
      if (ack_rcvd) begin
         let temp <- toGet(ackTimestampFifo).get;
         Bit#(53) tmp2 = zeroExtend(cycle);
         delay <= (tmp2 - temp - 3) >> 1;
         if(verbose) $display("%d: %d update delay=%d, %d, %d", cycle, id, c_local, temp, (tmp2-temp-3)>>1);
      end
   endrule

   // Beacon
   rule beacon(curr_state == SYNC);
      dmFifo.deq;
      let sync_timeout = interval_reg._read;
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      if (timeout_count_sync >= sync_timeout-1) begin
         if (is_idle) begin
            timeout_count_sync <= 0;
         end
         else begin
            timeout_count_sync <= timeout_count_sync + 1;
         end
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(beacon_type);
         end
      end
      else if (init_rcvd) begin
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         timeout_count_sync <= timeout_count_sync + 1;
      end
      else begin
         timeout_count_sync <= timeout_count_sync + 1;
      end
   endrule

   // DTP state machine
   rule state_init (curr_state == INIT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (txMuxSelFifo.notEmpty && is_idle) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= SENT;
         end
      end
      else if (init_rcvd) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= INIT;
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
   endrule

   rule state_sent (curr_state == SENT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SENT;
      end
      else if (ack_rcvd) begin
         curr_state <= SYNC;
      end
      else if (txMuxSelFifo.notEmpty) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= INIT;
         end
      end
      else begin
         curr_state <= SENT;
      end
   endrule

   rule state_sync (curr_state == SYNC);
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SYNC;
      end
      else begin
         curr_state <= SYNC;
      end
   endrule

   rule switch_in_c_local(is_switch_mode);
      //if(verbose) $display("%d: send c_local %h to L2", cycle, c_local);
      dtpLocalOutFifo.enq(c_local);
   endrule

   rule switch_out_c_global;
      let v <- toGet(dtpGlobalInFifo).get;
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      c_global <= v + global_delay + 1;
//      dtpGlobal_wires <= v + global_delay;
      if (is_switch_mode && beacon_rcvd) begin
         if (verbose) $display("%d: received global counter %d", cycle, v);
         globalCompareRemoteFifo.enq(v + 1);
         globalCompareLocalFifo.enq(v + 1);
      end
   endrule

   rule rx_stage1(tx_ready_wire && rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      Bool init_rcvd_next   = False;
      Bool ack_rcvd_next    = False;
      Bool beacon_rcvd_next = False;
      Bool log_rcvd_next    = False;
      if (dtpEventInFifo.notEmpty) begin
         let v <- toGet(dtpEventInFifo).get;
         if ((v.e == init_type)) begin
            let parity = ^(v.t);
            if (initTimestampFifo.notFull && initParityFifo.notFull) begin
               initTimestampFifo.enq(v.t);
               initParityFifo.enq(parity);
            end
            if(verbose) $display("%d: %d DtpTx init_rcvd %h %d", cycle, id, v.e, v.t);
            init_rcvd_next = True;
         end
         else if (v.e == ack_type) begin
            ack_rcvd_next = True;
            // append received timestamp to fifo
            if (ackTimestampFifo.notFull)
               ackTimestampFifo.enq(v.t);
            if(verbose) $display("%d: %d DtpTx ack_rcvd %h %d", cycle, id, v.e, v.t);
         end
         else if (v.e == beacon_type) begin
            beacon_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx beacon_rcvd %h %d %d", cycle, id, v.e, v.t, c_local);
            localCompareRemoteFifo.enq(c_local+1);
            remoteCompareLocalFifo.enq(v.t+1);
            if (is_switch_mode) begin
               localCompareGlobalFifo.enq(c_local+1);
               remoteCompareGlobalFifo.enq(v.t+1);
            end
         end
         else if (v.e == log_type) begin
            log_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx log_rcvd %h %d", cycle, id, v.e, v.t);
            if (toHostFifo.notFull) begin
               toHostFifo.enq(v.t);
            end
         end
         dtpEventFifo.enq(v.e);
      end
      else begin
         dtpEventFifo.enq(3'b0);
      end
      init_rcvd   <= init_rcvd_next;
      ack_rcvd    <= ack_rcvd_next;
      beacon_rcvd <= beacon_rcvd_next;
      log_rcvd    <= log_rcvd_next;
   endrule

   rule rx_stage2;
      let v_local <- toGet(localCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareLocalFifo).get();
      if(verbose) $display("%d: %d, v_local=%d, v_remote=%d, delay=%d", cycle, id, v_local, v_remote, delay);
      if (v_local < v_remote + delay) begin
         localLtRemoteFifo.enq(True);
         localGeRemoteFifo.enq(False);
      end
      else begin
         localLtRemoteFifo.enq(False);
         localGeRemoteFifo.enq(True);
      end
      localOutputFifo.enq(v_local + 1);
      remoteOutputFifo.enq(v_remote + 1);
   endrule

   rule compare_global_remote (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareGlobalFifo).get();
      if (v_global + global_delay <= v_remote + delay) begin
         globalLeRemoteFifo.enq(True);
         globalGtRemoteFifo.enq(False);
      end
      else begin
         globalLeRemoteFifo.enq(False);
         globalGtRemoteFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_remote=%d", cycle, id, v_global, v_remote);
      globalOutputFifo.enq(v_global + 1);
   endrule

   rule compare_global_local (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareLocalFifo).get();
      let v_local <- toGet(localCompareGlobalFifo).get();
      if (v_global + global_delay <= v_local + 1) begin
         globalLeLocalFifo.enq(True);
         globalGtLocalFifo.enq(False);
      end
      else begin
         globalLeLocalFifo.enq(False);
         globalGtLocalFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_local=%d", cycle, id, v_global, v_local);
   endrule

   rule rx_stage2_bypass;
      let v_event <- toGet(dtpEventFifo).get();
      dtpEventOutputFifo.enq(v_event);
   endrule

   rule rx_stage3_nic_mode (!is_switch_mode);
      let vLocal <- toGet(localOutputFifo).get();
      let vRemote <- toGet(remoteOutputFifo).get();
      let useLocal <- toGet(localGeRemoteFifo).get();
      let incrJump <- toGet(localLtRemoteFifo).get();
      if(verbose) $display("%d: %d vLocal=%d", cycle, id, vLocal);
      if(verbose) $display("%d: %d vRemote=%d", cycle, id, vRemote);
      if(verbose) $display("%d: %d delay=%d", cycle, id, delay);
      if (useLocal) begin
         c_local_next <= vLocal + 1;
      end
      else begin
         c_local_next <= vRemote + delay + 1;
      end

      if (incrJump) begin
         jumpCount <= jumpCount + 1;
      end
   endrule

   rule rx_stage3_switch_mode (is_switch_mode);
      let v_local <- toGet(localOutputFifo).get();
      let v_remote <- toGet(remoteOutputFifo).get();
      let v_global <- toGet(globalOutputFifo).get();
      let isGR <- toGet(globalGtRemoteFifo).get();
      let isGL <- toGet(globalGtLocalFifo).get();
      let isLR <- toGet(localGeRemoteFifo).get();
      let isLG <- toGet(globalLeLocalFifo).get();
      let isRG <- toGet(globalLeRemoteFifo).get();
      let isRL <- toGet(localLtRemoteFifo).get();
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let err = False;
      if(verbose) $display("%d: isGR=%d, isGL=%d, isLR=%d, isLG=%d, isRG=%d, isRL=%d", cycle, isGR, isGL, isLR, isLG, isRG, isRL);
      if (isGR && isGL) begin
         c_local_next <= v_global + global_delay;
//        err = True;
      end
      else if (isLR && isLG) begin
         c_local_next <= v_local + 1;
      end
      else if (isRG && isRL) begin
         c_local_next <= v_remote + delay;
         err = True;
      end
      else begin
         c_local_next <= v_local + 1;
//         err = True;
      end

      if (err) begin
         jumpCount <= jumpCount + 1;
      end

      if(verbose && id==1) $display("%d: jumpCount = %d", cycle, jumpCount);
   endrule

   rule rx_stage3;
      let v <- toGet(dtpEventOutputFifo).get();
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));
      if (!rx_ready_wire) begin
         c_local <= 0;
      end
      else if (v == zeroExtend(beacon_type)) begin
         c_local <= c_local_next;
         if(verbose) $display("%d: %d c_local_next = %d", cycle, id, c_local_next);
      end
      else begin
         c_local <= c_local + 1;
      end
   endrule

   rule export_delay;
      delayFifo.enq(truncate(delay));
   endrule

   rule export_state;
      stateFifo.enq(zeroExtend(pack(curr_state)));
   endrule

   rule export_jumpCount;
      jumpCountFifo.enq(jumpCount);
   endrule

   rule export_c_local;
      cLocalFifo.enq(c_local);
   endrule

   rule import_interval(intervalFifo.notEmpty);
      let interval = intervalFifo.first;
      interval_reg <= interval;
      intervalFifo.deq;
   endrule

   method Action tx_ready(Bool v);
      tx_ready_wire <= v;
   endmethod

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   method Action switch_mode(Bool v);
      switch_mode_wire <= v;
   endmethod

   method Action bsync_lock(Bool v);
      bsync_lock_wire <= v;
   endmethod

   interface api = (interface DtpToPhyIfc;
      interface delayOut = toPipeOut(delayFifo);
      interface stateOut = toPipeOut(stateFifo);
      interface jumpCount = toPipeOut(jumpCountFifo);
      interface cLocalOut = toPipeOut(cLocalFifo);
      interface toHost   = toPipeOut(toHostFifo);
      interface fromHost = toPipeIn(fromHostFifo);
      interface interval = toPipeIn(intervalFifo);
      interface dtpErrCnt = toPipeOut(dtpErrCntFifo);
   endinterface);
   interface dtpEventIn = toPipeIn(dtpEventInFifo);
   interface dtpErrCnt = toPipeIn(dtpErrCntFifo);
   interface dtpTxIn = toPipeIn(dtpTxInFifo);
   interface dtpTxOut = toPipeOut(dtpTxOutFifo);
   interface dtpLocalOut = toPipeOut(dtpLocalOutFifo);
   interface dtpGlobalIn = toPipeIn(dtpGlobalInFifo);
endmodule
endpackage


64 -> DmaBusWidth

64 -> DmaBusWidth

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

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

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

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

import Vector::*;
import BuildVector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import ClientServer::*;
import GetPut::*;
import HostInterface::*;
import MemTypes::*;
import MemwriteEngine::*;
import Pipe::*;
import AddressGenerator::*;

typedef TDiv#(DataBusWidth,32) WordsPerBeat;

interface MemwriteRequest;
   method Action startWrite(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) numReqs, Bit#(32) burstLen);
endinterface

interface MemwriteIndication;
   method Action writeDone(Bit#(32) v);
   method Action writeProgress(Bit#(32) v);
endinterface

interface Memwrite;
   interface MemwriteRequest request;
   interface Vector#(1, MemWriteClient#(DataBusWidth)) dmaClients;
endinterface

module  mkMemwrite#(MemwriteIndication indication) (Memwrite);
   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))        numReqs <- mkReg(0);
   Reg#(Bit#(32))        numDone <- mkReg(0);
   Reg#(Bit#(MemOffsetSize)) reqOffset <- mkReg(0);
   Reg#(Bit#(3))                   tag <- mkReg(0);
   Reg#(Bit#(32))             numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   Reg#(Bit#(32))              srcGens <- mkReg(0);

   AddressGenerator#(32, DataBusWidth) addrGenerator <- mkAddressGenerator();
   FIFO#(MemRequest) reqFifo <- mkFIFO();
   FIFO#(PhysMemRequest#(32)) preqFifo <- mkFIFO();
   FIFO#(MemData#(DataBusWidth))   dataFifo <- mkSizedBRAMFIFO(1024);
   FIFO#(Bit#(MemTagSize)) doneFifo <- mkFIFO();

   let verboseProgress = False;

   rule start if (numReqs != 0);
      reqFifo.enq(MemRequest { sglId: pointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });
      preqFifo.enq(PhysMemRequest { addr: 0, burstLen: burstLenBytes, tag: extend(tag) });
      numReqs <= numReqs - 1;
      reqOffset <= reqOffset + extend(burstLenBytes);
      tag <= tag + 1;
      //$display("start numReqs", numReqs);
   endrule

   rule preq;
      let preq <- toGet(preqFifo).get();
      addrGenerator.request.put(preq);
   endrule

   rule finish;
      let donetag <- toGet(doneFifo).get();
      //$display("finished num todo=%d", numDone);
      if (numDone == 1) begin
         indication.writeDone(0);
      end
      numDone <= numDone - 1;
      if (verboseProgress)
	 indication.writeProgress(extend(donetag));
   endrule

   rule src if (numWords != 0);
      let b <- addrGenerator.addrBeat.get();

      function Bit#(32) plusi(Integer i); return srcGens + fromInteger(i); endfunction
      Vector#(WordsPerBeat, Bit#(32)) v = genWith(plusi);
      dataFifo.enq(MemData { data: pack(v), tag: b.tag, last: b.last});
      srcGens <= srcGens+fromInteger(valueOf(WordsPerBeat));
      numWords <= numWords - fromInteger(valueOf(WordsPerBeat));
   endrule

   MemWriteClient#(DataBusWidth) dmaClient = (interface MemWriteClient;
      interface Get writeReq = toGet(reqFifo);
      interface Get writeData = toGet(dataFifo);
      interface Put writeDone = toPut(doneFifo);
   endinterface );

   interface MemwriteRequest request;
       method Action startWrite(Bit#(32) wp, Bit#(32) nw, Bit#(32) nreq, Bit#(32) bl);
	  $dumpvars();
          $display("startWrite pointer=%d numWords=%d (%d) numReqs=%d burstLen=%d", pointer, nw, nreq*bl, nreq, bl);
          pointer <= wp;
          numWords  <= nw;
          burstLenBytes <= truncate(bl);
	  numReqs <= nreq;
	  numDone <= nreq;
       endmethod
   endinterface
   interface dmaClients = vec(dmaClient);

endmodule

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

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

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

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

import Vector::*;
import BuildVector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import ClientServer::*;
import GetPut::*;
import HostInterface::*;
import MemTypes::*;
import MemwriteEngine::*;
import Pipe::*;
import AddressGenerator::*;

typedef TDiv#(DataBusWidth,32) WordsPerBeat;

interface MemwriteRequest;
   method Action startWrite(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) numReqs, Bit#(32) burstLen);
endinterface

interface MemwriteIndication;
   method Action writeDone(Bit#(32) v);
   method Action writeProgress(Bit#(32) v);
endinterface

interface Memwrite;
   interface MemwriteRequest request;
   interface Vector#(1, MemWriteClient#(64)) dmaClients;
endinterface

module  mkMemwrite#(MemwriteIndication indication) (Memwrite);
   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))        numReqs <- mkReg(0);
   Reg#(Bit#(32))        numDone <- mkReg(0);
   Reg#(Bit#(MemOffsetSize)) reqOffset <- mkReg(0);
   Reg#(Bit#(3))                   tag <- mkReg(0);
   Reg#(Bit#(32))             numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   Reg#(Bit#(32))              srcGens <- mkReg(0);

   AddressGenerator#(32, DataBusWidth) addrGenerator <- mkAddressGenerator();
   FIFO#(MemRequest) reqFifo <- mkFIFO();
   FIFO#(PhysMemRequest#(32)) preqFifo <- mkFIFO();
   FIFO#(MemData#(DataBusWidth))   dataFifo <- mkSizedBRAMFIFO(1024);
   FIFO#(Bit#(MemTagSize)) doneFifo <- mkFIFO();

   let verboseProgress = False;

   rule start if (numReqs != 0);
      reqFifo.enq(MemRequest { sglId: pointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });
      preqFifo.enq(PhysMemRequest { addr: 0, burstLen: burstLenBytes, tag: extend(tag) });
      numReqs <= numReqs - 1;
      reqOffset <= reqOffset + extend(burstLenBytes);
      tag <= tag + 1;
      //$display("start numReqs", numReqs);
   endrule

   rule preq;
      let preq <- toGet(preqFifo).get();
      addrGenerator.request.put(preq);
   endrule

   rule finish;
      let donetag <- toGet(doneFifo).get();
      //$display("finished num todo=%d", numDone);
      if (numDone == 1) begin
         indication.writeDone(0);
      end
      numDone <= numDone - 1;
      if (verboseProgress)
	 indication.writeProgress(extend(donetag));
   endrule

   rule src if (numWords != 0);
      let b <- addrGenerator.addrBeat.get();

      function Bit#(32) plusi(Integer i); return srcGens + fromInteger(i); endfunction
      Vector#(WordsPerBeat, Bit#(32)) v = genWith(plusi);
      dataFifo.enq(MemData { data: pack(v), tag: b.tag, last: b.last});
      srcGens <= srcGens+fromInteger(valueOf(WordsPerBeat));
      numWords <= numWords - fromInteger(valueOf(WordsPerBeat));
   endrule

   MemWriteClient#(64) dmaClient = (interface MemWriteClient;
      interface Get writeReq = toGet(reqFifo);
      interface Get writeData = toGet(dataFifo);
      interface Put writeDone = toPut(doneFifo);
   endinterface );

   interface MemwriteRequest request;
       method Action startWrite(Bit#(32) wp, Bit#(32) nw, Bit#(32) nreq, Bit#(32) bl);
	  $dumpvars();
          $display("startWrite pointer=%d numWords=%d (%d) numReqs=%d burstLen=%d", pointer, nw, nreq*bl, nreq, bl);
          pointer <= wp;
          numWords  <= nw;
          burstLenBytes <= truncate(bl);
	  numReqs <= nreq;
	  numDone <= nreq;
       endmethod
   endinterface
   interface dmaClients = vec(dmaClient);

endmodule


connected sda port to top.slave

connected sda port to top.slave

// Copyright (c) 2017 Connectal Project

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

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

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

import ConnectalConfig::*;
import Vector            :: *;
import GetPut::*;
import Connectable::*;
import Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes:: *;
import MMU:: *;
import MemServer:: *;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import SimDma::*;
import IfcNames::*;
import BuildVector::*;
import AxiBits::*;
import FIFOF::*;
import CFFIFO::*;

`include "ConnectalProjectConfig.bsv"

`ifdef PinTypeInclude
import `PinTypeInclude::*;
`endif
`ifdef PinType
typedef `PinType PinType;
`else
typedef Empty PinType;
`endif

(* always_enabled, always_ready *)
interface AwsF1ClSh;
   method Bit#(1) flr_done();
   method Bit#(32) status0();
   method Bit#(32) status1();
   method Bit#(32) id0();
   method Bit#(32) id1();
   method Bit#(16) status_vled();
endinterface

(* always_enabled, always_ready *)
interface AwsF1ShCl;
   (* prefix="" *)
   method Action flr_assert(Bit#(1) flr_assert);
   (* prefix="" *)
   method Action ctl0(Bit#(32) ctl0);
   (* prefix="" *)
   method Action ctl1(Bit#(32) ctl1);
   (* prefix="" *)
   method Action status_vdip(Bit#(16) status_vdip);
   (* prefix="" *)
   method Action pwr_state(Bit#(2) pwr_state);
endinterface

interface AwsF1Top;
   interface PinType pins;
   interface AwsF1ShCl sh_cl;
   interface AwsF1ClSh cl_sh;
   interface Axi4SlaveBits#(64,512,6,Empty) dmasink;
   interface Axi4SlaveLiteBits#(32,32) sda;
   interface Axi4SlaveLiteBits#(32,32) ocl;
   interface Axi4SlaveLiteBits#(32,32) bar1;
endinterface

module mkAxi4SlaveLiteBitsFromPhysMemSlave#(PhysMemSlave#(addrWidth,dataWidth) slave)
       (Axi4SlaveLiteBits#(axiaddrWidth,dataWidth)) provisos (Div#(dataWidth,8,burstLen),Add#(addrWidth,a__,axiaddrWidth));

    let burstLen = fromInteger(valueOf(burstLen));

    Wire#(Bit#(addrWidth)) araddrWire <- mkDWire(0);
    Wire#(Bit#(1)) arvalidWire <- mkDWire(0);
    Wire#(Bit#(1)) rreadyWire <- mkDWire(0);
    Wire#(Bit#(dataWidth)) rdataWire <- mkDWire(0);

    Wire#(Bit#(addrWidth)) awaddrWire <- mkDWire(0);
    Wire#(Bit#(1)) awvalidWire <- mkDWire(0);
    Wire#(Bit#(1)) wvalidWire <- mkDWire(0);
    Wire#(Bit#(dataWidth)) wdataWire <- mkDWire(0);
    Wire#(Bit#(1)) breadyWire <- mkDWire(0);

    FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) arFifo <- mkCFFIFOF();
    FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) awFifo <- mkCFFIFOF();
    FIFOF#(MemData#(dataWidth)) rdataFifo <- mkCFFIFOF();
    FIFOF#(MemData#(dataWidth)) wdataFifo <- mkCFFIFOF();
    FIFOF#(Bit#(MemTagSize)) brespFifo <- mkCFFIFOF();

    rule ar_rule if (arvalidWire == 1 && arFifo.notFull());
       let req = PhysMemRequest {addr: araddrWire, burstLen: burstLen, tag: 0 };
       arFifo.enq(req);
    endrule
    rule ar_to_slave;
       let req <- toGet(arFifo).get();
       slave.read_server.readReq.put(req);
    endrule

    rule aw_rule if (awvalidWire == 1 && awFifo.notFull());
       let req = PhysMemRequest {addr: awaddrWire, burstLen: burstLen, tag: 0 };
       awFifo.enq(req);
    endrule
    rule aw_to_slave;
       let req <- toGet(awFifo).get();
       slave.read_server.readReq.put(req);
    endrule

    rule r_rule if (rreadyWire == 1 && rdataFifo.notEmpty());
       rdataFifo.deq();
    endrule
    rule rdata_from_slave;
       let mdata <- slave.read_server.readData.get();
       rdataFifo.enq(mdata);
    endrule

    rule wdata_rule if (wvalidWire == 1 && wdataFifo.notFull());
       wdataFifo.enq(MemData { data: wdataWire, tag: 0, last: True });
    endrule
    rule wdata_to_slave;
       let mdata <- toGet(wdataFifo).get();
       slave.write_server.writeData.put(mdata);
    endrule

    rule b_rule if (breadyWire == 1 && brespFifo.notEmpty());
       brespFifo.deq();
    endrule
    rule bresp_from_slave;
       let done <- slave.write_server.writeDone.get();
       brespFifo.enq(done);
    endrule

    method Action      araddr(Bit#(axiaddrWidth) v);
       araddrWire <= truncate(v);
    endmethod
    method Bit#(1)     arready();
       return pack(arFifo.notFull());
    endmethod
    method Action      arvalid(Bit#(1) v);
       arvalidWire <= v;
    endmethod
    method Action      awaddr(Bit#(axiaddrWidth) v);
       awaddrWire <= truncate(v);
    endmethod
    method Bit#(1)     awready();
       return pack(awFifo.notFull());
    endmethod
    method Action      awvalid(Bit#(1) v);
       awvalidWire <= v;
    endmethod
    method Action      bready(Bit#(1) v);
       breadyWire <= v;
    endmethod
    method Bit#(2)     bresp();
       return 0; // brespFifo.first();
    endmethod
    method Bit#(1)     bvalid();
       return pack(brespFifo.notEmpty());
    endmethod
    method Bit#(dataWidth)     rdata();
       return rdataFifo.first.data;
    endmethod
    method Action      rready(Bit#(1) v);
       rreadyWire <= v;
    endmethod
    method Bit#(2)     rresp();
       return 0;
    endmethod
    method Bit#(1)     rvalid();
      return pack(rdataFifo.notEmpty);
    endmethod
    method Action      wdata(Bit#(dataWidth) v);
       wdataWire <= v;
    endmethod
    method Bit#(1)     wready();
       return pack(wdataFifo.notFull());
    endmethod
    method Action      wvalid(Bit#(1) v);
       wvalidWire <= v;
    endmethod
endmodule

(* no_default_clock, no_default_reset, clock_prefix="", reset_prefix="" *)
module mkAwsF1Top#(Clock clk_main_a0, Clock clk_extra_a1, Clock clk_extra_a2, Clock clk_extra_a3,
       Clock  clk_extra_b0, Clock clk_extra_b1, Clock clk_extra_c0, Clock clk_extra_c1,
       Reset kernel_rst_n, Reset rst_main_n
       )(AwsF1Top);

   Clock defaultClock = clk_main_a0;
   Reset defaultReset = rst_main_n;
   Clock derivedClock = clk_main_a0;
   Reset derivedReset = rst_main_n;

   XsimHost host <- mkXsimHost(clk_main_a0, rst_main_n, clk_main_a0);
   let top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`else
`ifdef IMPORT_HOST_CLOCKS // enables synthesis boundary
       derivedClock, derivedReset,
`else
// otherwise no params
`endif
`endif
	clocked_by defaultClock, reset_by defaultReset
       );

   MMUIndicationOutput lMMUIndicationOutput <- mkMMUIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MMURequestInput lMMURequestInput <- mkMMURequestInput(clocked_by defaultClock, reset_by defaultReset);
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMMURequestInput.pipes, lMMU.request, clocked_by defaultClock, reset_by defaultReset);

   MemServerIndicationOutput lMemServerIndicationOutput <- mkMemServerIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MemServerRequestInput lMemServerRequestInput <- mkMemServerRequestInput(clocked_by defaultClock, reset_by defaultReset);
   MemServer::MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(top.readers, top.writers, cons(lMMU,nil), lMemServerIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMemServerRequestInput.pipes, lMemServer.request, clocked_by defaultClock, reset_by defaultReset);

   let lMMUIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MMUIndicationH2S)), lMMUIndicationOutput.portalIfc.indications, lMMUIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMMURequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MMURequestS2H)), lMMURequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MemServerIndicationH2S)), lMemServerIndicationOutput.portalIfc.indications, lMemServerIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerRequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MemServerRequestS2H)), lMemServerRequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);

   Axi4SlaveLiteBits#(32,32) sdaSlave <- mkAxi4SlaveLiteBitsFromPhysMemSlave(top.slave, clocked_by defaultClock, reset_by defaultReset);

   interface AwsF1ClSh cl_sh;
      method id0 = 32'hF000_1D0F; // 32'hc100_1be7;
      method id1 = 32'h1D51_FEDD; // 32'hc101_1be7;
   endinterface

   interface sda = sdaSlave;

`ifdef PinType
   interface pins = top.pins;
`endif
endmodule

// Copyright (c) 2017 Connectal Project

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

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

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

import ConnectalConfig::*;
import Vector            :: *;
import GetPut::*;
import Connectable::*;
import Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes:: *;
import MMU:: *;
import MemServer:: *;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import SimDma::*;
import IfcNames::*;
import BuildVector::*;

`include "ConnectalProjectConfig.bsv"

`ifdef PinTypeInclude
import `PinTypeInclude::*;
`endif
`ifdef PinType
typedef `PinType PinType;
`else
typedef Empty PinType;
`endif

(* always_enabled, always_ready *)
interface AwsF1ClSh;
   method Bit#(1) done();
   method Bit#(32) status0();
   method Bit#(32) status1();
   method Bit#(32) id0();
   method Bit#(32) id1();
   method Bit#(16) status_vled();
endinterface

(* always_enabled, always_ready *)
interface AwsF1ShCl;
   (* prefix="" *)
   method Action flr_assert(Bit#(1) flr_assert);
   (* prefix="" *)
   method Action ctl0(Bit#(32) ctl0);
   (* prefix="" *)
   method Action ctl1(Bit#(32) ctl1);
   (* prefix="" *)
   method Action status_vdip(Bit#(16) status_vdip);
   (* prefix="" *)
   method Action pwr_state(Bit#(2) pwr_state);
endinterface

interface AwsF1Top;
   interface PinType pins;
   interface AwsF1ShCl sh_cl;
   interface AwsF1ClSh cl_sh;
endinterface

(* no_default_clock, no_default_reset, clock_prefix="", reset_prefix="" *)
module mkAwsF1Top#(Clock clk_main_a0, Clock clk_extra_a1, Clock clk_extra_a2,
       Clock  clk_extra_b0, Clock clk_extra_b1, Clock clk_extra_c0, Clock clk_extra_c1,
       Reset kernel_rst_n, Reset rst_main_n
       )(AwsF1Top);

   Clock defaultClock = clk_main_a0;
   Reset defaultReset = rst_main_n;
   Clock derivedClock = clk_main_a0;
   Reset derivedReset = rst_main_n;

   XsimHost host <- mkXsimHost(clk_main_a0, rst_main_n, clk_main_a0);
   let top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`else
`ifdef IMPORT_HOST_CLOCKS // enables synthesis boundary
       derivedClock, derivedReset,
`else
// otherwise no params
`endif
`endif
	clocked_by defaultClock, reset_by defaultReset
       );

   MMUIndicationOutput lMMUIndicationOutput <- mkMMUIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MMURequestInput lMMURequestInput <- mkMMURequestInput(clocked_by defaultClock, reset_by defaultReset);
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMMURequestInput.pipes, lMMU.request, clocked_by defaultClock, reset_by defaultReset);

   MemServerIndicationOutput lMemServerIndicationOutput <- mkMemServerIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MemServerRequestInput lMemServerRequestInput <- mkMemServerRequestInput(clocked_by defaultClock, reset_by defaultReset);
   MemServer::MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(top.readers, top.writers, cons(lMMU,nil), lMemServerIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMemServerRequestInput.pipes, lMemServer.request, clocked_by defaultClock, reset_by defaultReset);

   let lMMUIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MMUIndicationH2S)), lMMUIndicationOutput.portalIfc.indications, lMMUIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMMURequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MMURequestS2H)), lMMURequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MemServerIndicationH2S)), lMemServerIndicationOutput.portalIfc.indications, lMemServerIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerRequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MemServerRequestS2H)), lMemServerRequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);

`ifdef PinType
   interface pins = top.pins;
`endif
endmodule