INTRA32 Version 4, Supported mode[1-34]

INTRA32 Version 4, Supported mode[1-34]

// Copyright (c) 2016 Min Chen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import BuildVector::*;
import Connectable::*;
import Vector::*;
import GetPut::*;
import ConfigReg::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Utils::*;

typedef struct {
   Vector#(64, Bit#(8)) left;
   Vector#(65, Bit#(8)) top;
} IntraRef_t deriving(Bits);

interface IIntra32;
   interface Put#(IntraRef_t) io_in;
   interface Get#(Vector#( 32, Bit#(8))) io_out;
endinterface

Integer mapTbl[16][32] = {
   { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},   // Mode  2
   { 0,  1,  2,  3,  4,  4,  5,  6,  7,  8,  8,  9, 10, 11, 12, 13, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 26},   // Mode  3
   { 0,  1,  1,  2,  3,  3,  4,  5,  5,  6,  7,  7,  8,  9,  9, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 21},   // Mode  4
   { 0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 17},   // Mode  5
   { 0,  0,  1,  1,  2,  2,  2,  3,  3,  4,  4,  4,  5,  5,  6,  6,  6,  7,  7,  8,  8,  8,  9,  9, 10, 10, 10, 11, 11, 12, 12, 13},   // Mode  6
   { 0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9},   // Mode  7
   { 0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  4,  5},   // Mode  8
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2},   // Mode  9
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   //*Mode 10
   { 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   // Mode 11
   { 4,  4,  4,  4,  4,  4,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0},   // Mode 12
   { 8,  8,  8,  7,  7,  7,  7,  6,  6,  6,  5,  5,  5,  5,  4,  4,  4,  3,  3,  3,  3,  2,  2,  2,  1,  1,  1,  1,  0,  0,  0,  0},   // Mode 13
   {12, 12, 11, 11, 10, 10, 10,  9,  9,  8,  8,  8,  7,  7,  6,  6,  6,  5,  5,  4,  4,  4,  3,  3,  2,  2,  2,  1,  1,  0,  0,  0},   // Mode 14
   {16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10,  9,  9,  8,  7,  7,  6,  6,  5,  5,  4,  4,  3,  3,  2,  2,  1,  1,  0,  0},   // Mode 15
   {20, 19, 19, 18, 17, 17, 16, 15, 15, 14, 13, 13, 12, 11, 11, 10,  9,  9,  8,  7,  7,  6,  4,  5,  5,  3,  3,  2,  1,  1,  0,  0},   // Mode 16
   {25, 24, 23, 22, 21, 21, 20, 19, 18, 17, 17, 16, 15, 14, 13, 13, 12, 11, 10,  9,  8,  8,  7,  6,  5,  4,  4,  3,  2,  1,  0,  0}    // Mode 17

};
Integer facTbl[16][32] = {
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   // Mode  2, 34, 18
   {26, 20, 14,  8,  2, 28, 22, 16, 10,  4, 30, 24, 18, 12,  6,  0, 26, 20, 14,  8,  2, 28, 22, 16, 10,  4, 30, 24, 18, 12,  6,  0},   // Mode  3, 33
   {21, 10, 31, 20,  9, 30, 19,  8, 29, 18,  7, 28, 17,  6, 27, 16,  5, 26, 15,  4, 25, 14,  3, 24, 13,  2, 23, 12,  1, 22, 11,  0},   // Mode  4, 32
   {17,  2, 19,  4, 21,  6, 23,  8, 25, 10, 27, 12, 29, 14, 31, 16,  1, 18,  3, 20,  5, 22,  7, 24,  9, 26, 11, 28, 13, 30, 15,  0},   // Mode  5, 31
   {13, 26,  7, 20,  1, 14, 27,  8, 21,  2, 15, 28,  9, 22,  3, 16, 29, 10, 23,  4, 17, 30, 11, 24,  5, 18, 31, 12, 25,  6, 19,  0},   // Mode  6, 30
   { 9, 18, 27,  4, 13, 22, 31,  8, 17, 26,  3, 12, 21, 30,  7, 16, 25,  2, 11, 20, 29,  6, 15, 24,  1, 10, 19, 28,  5, 14, 23,  0},   // Mode  7, 29
   { 5, 10, 15, 20, 25, 30,  3,  8, 13, 18, 23, 28,  1,  6, 11, 16, 21, 26, 31,  4,  9, 14, 19, 24, 29,  2,  7, 12, 17, 22, 27,  0},   // Mode  8, 28
   { 2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,  0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,  0},   // Mode  9, 27
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   //*Mode 10, 26,  1
   {30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10,  8,  6,  4,  2,  0, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10,  8,  6,  4,  2,  0},   // Mode 11, 25
   {27, 22, 17, 12,  7,  2, 29, 24, 19, 14,  9,  4, 31, 26, 21, 16, 11,  6,  1, 28, 23, 18, 13,  8,  3, 30, 25, 20, 15, 10,  5,  0},   // Mode 12, 24
   {23, 14,  5, 28, 19, 10,  1, 24, 15,  6, 29, 20, 11,  2, 25, 16,  7, 30, 21, 12,  3, 26, 17,  8, 31, 22, 13,  4, 27, 18,  9,  0},   // Mode 13, 23
   {19,  6, 25, 12, 31, 18,  5, 24, 11, 30, 17,  4, 23, 10, 29, 16,  3, 22,  9, 28, 15,  2, 21,  8, 27, 14,  1, 20,  7, 26, 13,  0},   // Mode 14, 22
   {15, 30, 13, 28, 11, 26,  9, 24,  7, 22,  5, 20,  3, 18,  1, 16, 31, 14, 29, 12, 27, 10, 25,  8, 23,  6, 21,  4, 19,  2, 17,  0},   // Mode 15, 21
   {11, 22,  1, 12, 23,  2, 13, 24,  3, 14, 25,  4, 15, 26,  5, 16, 27,  6, 17, 28,  7, 18, 29,  8, 19, 30,  9, 20, 31, 10, 21,  0},   // Mode 16, 20
   { 6, 12, 18, 24, 30,  4, 10, 16, 22, 28,  2,  8, 14, 20, 26,  0,  6, 12, 18, 24, 30,  4, 10, 16, 22, 28,  2,  8, 14, 20, 26,  0}    // Mode 17, 19
};

Bit#(1) mapShift[16][31] = {   // 0-Keep, 1-Shift
//  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
   {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},     // Mode 34
   {1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1},     // Mode 33
   {1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1},     // Mode 32
   {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1},     // Mode 31
   {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},     // Mode 30
   {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1},     // Mode 29
   {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1},     // Mode 28
   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},     // Mode 27
   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},     // Mode 26,  1
   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},     // Mode 25
   {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},     // Mode 24
   {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},     // Mode 23
   {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0},     // Mode 22
   {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0},     // Mode 21
   {1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0},     // Mode 20
   {1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}      // Mode 19
};

(* synthesize *)
module mkIntra32(IIntra32);
   Reg#(Maybe#(IntraRef_t))                     reg_i    <- mkReg(tagged Invalid);
   FIFOF#(Vector#(32, Bit#(8)))                 fifo_o   <- mkPipelineFIFOF;
   Reg#(Bit#(6))                                mode     <- mkReg(0);            // 0-Mode2, 1-Mode3..., 15-Mode17, 16-Mode34, 17-Mode33..., 32-Mode18
   Reg#(Bit#(6))                                moded1   <- mkRegU;
   Reg#(Maybe#(Vector#(64, Bit#(8))))           stage0   <- mkReg(tagged Invalid);
   FIFOF#(Tuple3#(Bit#(4), Vector#(32, Bit#( 8)), Vector#(32, Bit#( 8)))) stage1 <- mkPipelineFIFOF;
   FIFOF#(Vector#(2, (Vector#(32, Bit#(13)))))  stage2   <- mkPipelineFIFOF;
   Reg#(Vector#(32, Bit#(8)))                   pixd1    <- mkRegU;
   Reg#(Bit#(6))                                cnt1     <- mkReg(0);
   Reg#(Bit#(8))                                dcVal    <- mkRegU;

   Integer chen_debug = 0;

   rule do_stage0(!isValid(stage0) &&& reg_i matches tagged Valid .x);
      let xL = cons(?, x.left);
      let xT = x.top;
      Vector#(64, Bit#(8)) y = ?;

      case(mode)
         0: begin
            y = unpack({?,         xL[64], xL[63], xL[62], xL[61], xL[60], xL[59], xL[58],
                           xL[57], xL[56], xL[55], xL[54], xL[53], xL[52], xL[51], xL[50],
                           xL[49], xL[48], xL[47], xL[46], xL[45], xL[44], xL[43], xL[42],
                           xL[41], xL[40], xL[39], xL[38], xL[37], xL[36], xL[35], xL[34],
                           xL[33], xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26],
                           xL[25], xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18],
                           xL[17], xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10],
                           xL[ 9], xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2]
                        });
         end
          1,  2,  3,  4,  5,  6,  7, 8: begin
            y = unpack({?,                                                         xL[57],
                           xL[56], xL[55], xL[54], xL[53], xL[52], xL[51], xL[50], xL[49],
                           xL[48], xL[47], xL[46], xL[45], xL[44], xL[43], xL[42], xL[41],
                           xL[40], xL[39], xL[38], xL[37], xL[36], xL[35], xL[34], xL[33],
                           xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1]
                        });
         end
          9: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[16]
                        });
         end
        10: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 6], xT[13], xT[19], xT[26]
                        });
         end
        11: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 4], xT[ 7], xT[11], xT[14], xT[18], xT[21], xT[25],
                           xT[28]
                        });
         end
        12: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 2], xT[ 5], xT[ 7], xT[10], xT[12], xT[15], xT[17],
                           xT[20], xT[22], xT[25], xT[27], xT[30]
                        });
         end
        13: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 2], xT[ 4], xT[ 6], xT[ 8], xT[ 9], xT[11], xT[13],
                           xT[15], xT[17], xT[19], xT[21], xT[23], xT[24], xT[26], xT[28],
                           xT[30]
                        });
         end
        14: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 2], xT[ 3], xT[ 5], xT[ 6], xT[ 8], xT[ 9], xT[11],
                           xT[12], xT[14], xT[15], xT[17], xT[18], xT[20], xT[21], xT[23],
                           xT[24], xT[26], xT[27], xT[29], xT[30]
                        });
         end
        15: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 1], xT[ 2], xT[ 4], xT[ 5], xT[ 6], xT[ 7], xT[ 9],
                           xT[10], xT[11], xT[12], xT[14], xT[15], xT[16], xT[17], xT[18],
                           xT[20], xT[21], xT[22], xT[23], xT[25], xT[26], xT[27], xT[28],
                           xT[30], xT[31]
                        });
         end

         // Vertical
        16: begin
            y = unpack({?,
                                   xT[64], xT[63], xT[62], xT[61], xT[60], xT[59], xT[58],
                           xT[57], xT[56], xT[55], xT[54], xT[53], xT[52], xT[51], xT[50],
                           xT[49], xT[48], xT[47], xT[46], xT[45], xT[44], xT[43], xT[42],
                           xT[41], xT[40], xT[39], xT[38], xT[37], xT[36], xT[35], xT[34],
                                                                                xT[33],
                           xT[33], xT[32], xT[31], xT[30], xT[29], xT[28], xT[27], xT[26],
                           xT[25], xT[24], xT[23], xT[22], xT[21], xT[20], xT[19], xT[18],
                           xT[17], xT[16], xT[15], xT[14], xT[13], xT[12], xT[11], xT[10],
                           xT[ 9], xT[ 8], xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2]
                        });
         end
        17, 18, 19, 20, 21, 22, 23, 24: begin
            y = unpack({?,                                                         xT[58],
                           xT[57], xT[56], xT[55], xT[54], xT[53], xT[52], xT[51], xT[50],
                           xT[49], xT[48], xT[47], xT[46], xT[45], xT[44], xT[43], xT[42],
                           xT[41], xT[40], xT[39], xT[38], xT[37], xT[36], xT[35], xT[34],
                                                                                xT[33],
                           xT[32], xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25],
                           xT[24], xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17],
                           xT[16], xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9],
                           xT[ 8], xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1]
                        });
         end
        25: begin
            y = unpack({?,                                                         xL[16],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        26: begin
            y = unpack({?,                                 xL[26], xL[19], xL[13], xL[ 6],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        27: begin
            y = unpack({?, xL[28], xL[25], xL[21], xL[18], xL[14], xL[11], xL[ 7], xL[ 4],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        28: begin
            y = unpack({?,                                 xL[30], xL[27], xL[25], xL[22],
                           xL[20], xL[17], xL[15], xL[12], xL[10], xL[ 7], xL[ 5], xL[ 2],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        29: begin
            y = unpack({?, xL[30], xL[28], xL[26], xL[24], xL[23], xL[21], xL[19], xL[17],
                           xL[15], xL[13], xL[11], xL[ 9], xL[ 8], xL[ 6], xL[ 4], xL[ 2],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        30: begin
            y = unpack({?,                                 xL[30], xL[29], xL[27], xL[26],
                           xL[24], xL[23], xL[21], xL[20], xL[18], xL[17], xL[15], xL[14],
                           xL[12], xL[11], xL[ 9], xL[ 8], xL[ 6], xL[ 5], xL[ 3], xL[ 2],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        31: begin
            y = unpack({?,                                                         xL[31],
                           xL[30], xL[28], xL[27], xL[26], xL[25], xL[23], xL[22], xL[21],
                           xL[20], xL[18], xL[17], xL[16], xL[15], xL[14], xL[12], xL[11],
                           xL[10], xL[ 9], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 2], xL[ 1],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        32: begin
            y = unpack({?,         xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25],
                           xT[24], xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17],
                           xT[16], xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9],
                           xT[ 8], xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1],
                                                                                xT[33],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
         33: begin
            Bit#(8) dc = truncate(dcVal >> 6);
            y = unpack({?,
                           dc, dc, dc, dc, dc, dc, dc, dc,
                           dc, dc, dc, dc, dc, dc, dc, dc,
                           dc, dc, dc, dc, dc, dc, dc, dc,
                           dc, dc, dc, dc, dc, dc, dc, dc
                        });
         end
      endcase

      // swap Top and Left on Horizon/Vertical mode edge
      Vector#(64, Bit#(8)) tmpLeft = x.left;
      Vector#(65, Bit#(8)) tmpTop = x.top;
      if (mode == 15) begin
         tmpLeft = takeAt(1, x.top);
         tmpTop  = cons(x.top[0], x.left);
      end
      reg_i  <= (mode == 33) ? (tagged Invalid) : (tagged Valid IntraRef_t {left:tmpLeft, top:tmpTop});

      moded1 <= (mode == 33) ? 24 : mode;
      mode   <= mode + 1;
      stage0 <= tagged Valid y;
      cnt1   <= (mode < 16) ? ~0 : 0;

      if (chen_debug == 1) begin
         if (mode == 2)
            $finish;
      end
   endrule

   rule do_stage1(stage0 matches tagged Valid .x);
      Vector#(33, Bit#(8)) y0 = take(x);
      Vector#(31, Bit#(8)) y1 = takeAt(33, x);
      let modeX = moded1[3:0];
      let fac = facTbl[modeX][cnt1];

      Vector#(32, Bit#(8)) m = take    (y0);
      Vector#(32, Bit#(8)) n = takeTail(y0);
      let shiftIdx = modeX;

      if (moded1 < 16) begin
         m = pixd1;
         for(Integer i = 0; i < 32; i = i + 1) begin
            n[i] = x[mapTbl[modeX][i]];
         end
         shiftIdx = 0;
      end

      pixd1 <= n;

      // Prediction
      if (cnt1[5] != 0) begin
         stage1.enq(tuple3(modeX, m, n));
      end

      // next row
      cnt1 <= cnt1 + 1;
      if (cnt1 == 31) begin
         stage0 <= tagged Invalid;
      end
      else if (mapShift[shiftIdx][cnt1] == 1) begin
         y0 = ((moded1 >= 24 && moded1 <= 31) ? shiftInAt0(y0, y1[0]) : shiftInAtN(y0, y1[0]));
         y1 = shiftOutFrom0(?, y1, 1);
         stage0 <= tagged Valid append(y0, y1);
      end
   endrule

   rule do_stage2;
      let x = stage1.first;
      let modeX = tpl_1(x);
      let y0 = tpl_2(x);
      let y1 = tpl_3(x);
      stage1.deq;

      Vector#(32, Bit#(13)) xm;
      Vector#(32, Bit#(13)) xn;
      for(Integer i = 0; i < 32; i = i + 1) begin
         let fac = facTbl[modeX][i];
         xm[i] = (fromInteger(32 - fac) * zeroExtend(y0[i]));
         xn[i] = (fromInteger(     fac) * zeroExtend(y1[i]));
      end
      stage2.enq(vec(xm, xn));
   endrule

   rule do_stage3;
      let x = stage2.first;
      Vector#(32, Bit#(8)) y;
      for(Integer i = 0; i < 32; i = i + 1) begin
         y[i] = roundN((x[0][i] + x[1][i]), 5);
      end
      fifo_o.enq(y);
   endrule

   interface io_in  =  interface Put;
                           method Action put(IntraRef_t x) if (!isValid(reg_i));
                              reg_i <= tagged Valid x;
                              Bit#(14) sum = 0;
                              for(Integer i = 0; i < 32; i = i + 1) begin
                                 sum = sum + zeroExtend(x.left[i]) + zeroExtend(x.top[1+i]);
                              end
                              dcVal <= truncate(sum >> 6);
                           endmethod
                      endinterface;
   interface io_out = toGet(fifo_o);
endmodule : mkIntra32

`ifdef TEST_BENCH_mkIntra32
(* synthesize *)
module mkTb(Empty);
   FIFOF#(IntraRef_t)   fifo_in  <- mkPipelineFIFOF;
   Reg#(Bit#(16))       cycles   <- mkReg(0);
   IIntra32             dut      <- mkIntra32;

   mkConnection(toGet(fifo_in), dut.io_in);

   rule do_cycles;
      cycles <= cycles + 1;
   endrule

   rule do_input;
      Vector#(64, Bit#(8)) xL;
      Vector#(65, Bit#(8)) xT;
      for(Integer i=0; i<64; i=i+1)
         xL[i] = fromInteger(-(i+1));

      for(Integer i=0; i<65; i=i+1)
         xT[i] = fromInteger(i);

      fifo_in.enq(IntraRef_t {left:xL, top:xT});
   endrule

endmodule

`endif

// Copyright (c) 2016 Min Chen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import BuildVector::*;
import Connectable::*;
import Vector::*;
import GetPut::*;
import ConfigReg::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Utils::*;

typedef struct {
   Vector#(64, Bit#(8)) left;
   Vector#(65, Bit#(8)) top;
} IntraRef_t deriving(Bits);

interface IIntra32;
   interface Put#(IntraRef_t) io_in;
   interface Get#(Vector#( 32, Bit#(8))) io_out;
endinterface

Integer mapTbl[16][32] = {
   { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},   // Mode  2
   { 0,  1,  2,  3,  4,  4,  5,  6,  7,  8,  8,  9, 10, 11, 12, 13, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 26},   // Mode  3
   { 0,  1,  1,  2,  3,  3,  4,  5,  5,  6,  7,  7,  8,  9,  9, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 21},   // Mode  4
   { 0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  6,  7,  7,  8,  9,  9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 17},   // Mode  5
   { 0,  0,  1,  1,  2,  2,  2,  3,  3,  4,  4,  4,  5,  5,  6,  6,  6,  7,  7,  8,  8,  8,  9,  9, 10, 10, 10, 11, 11, 12, 12, 13},   // Mode  6
   { 0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9},   // Mode  7
   { 0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  4,  5},   // Mode  8
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2},   // Mode  9
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   //*Mode 10
   { 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   // Mode 11
   { 4,  4,  4,  4,  4,  4,  3,  3,  3,  3,  3,  3,  2,  2,  2,  2,  2,  2,  2,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0},   // Mode 12
   { 8,  8,  8,  7,  7,  7,  7,  6,  6,  6,  5,  5,  5,  5,  4,  4,  4,  3,  3,  3,  3,  2,  2,  2,  1,  1,  1,  1,  0,  0,  0,  0},   // Mode 13
   {12, 12, 11, 11, 10, 10, 10,  9,  9,  8,  8,  8,  7,  7,  6,  6,  6,  5,  5,  4,  4,  4,  3,  3,  2,  2,  2,  1,  1,  0,  0,  0},   // Mode 14
   {16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10,  9,  9,  8,  7,  7,  6,  6,  5,  5,  4,  4,  3,  3,  2,  2,  1,  1,  0,  0},   // Mode 15
   {20, 19, 19, 18, 17, 17, 16, 15, 15, 14, 13, 13, 12, 11, 11, 10,  9,  9,  8,  7,  7,  6,  4,  5,  5,  3,  3,  2,  1,  1,  0,  0},   // Mode 16
   {25, 24, 23, 22, 21, 21, 20, 19, 18, 17, 17, 16, 15, 14, 13, 13, 12, 11, 10,  9,  8,  8,  7,  6,  5,  4,  4,  3,  2,  1,  0,  0}    // Mode 17

};
Integer facTbl[16][32] = {
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   // Mode  2, 34, 18
   {26, 20, 14,  8,  2, 28, 22, 16, 10,  4, 30, 24, 18, 12,  6,  0, 26, 20, 14,  8,  2, 28, 22, 16, 10,  4, 30, 24, 18, 12,  6,  0},   // Mode  3, 33
   {21, 10, 31, 20,  9, 30, 19,  8, 29, 18,  7, 28, 17,  6, 27, 16,  5, 26, 15,  4, 25, 14,  3, 24, 13,  2, 23, 12,  1, 22, 11,  0},   // Mode  4, 32
   {17,  2, 19,  4, 21,  6, 23,  8, 25, 10, 27, 12, 29, 14, 31, 16,  1, 18,  3, 20,  5, 22,  7, 24,  9, 26, 11, 28, 13, 30, 15,  0},   // Mode  5, 31
   {13, 26,  7, 20,  1, 14, 27,  8, 21,  2, 15, 28,  9, 22,  3, 16, 29, 10, 23,  4, 17, 30, 11, 24,  5, 18, 31, 12, 25,  6, 19,  0},   // Mode  6, 30
   { 9, 18, 27,  4, 13, 22, 31,  8, 17, 26,  3, 12, 21, 30,  7, 16, 25,  2, 11, 20, 29,  6, 15, 24,  1, 10, 19, 28,  5, 14, 23,  0},   // Mode  7, 29
   { 5, 10, 15, 20, 25, 30,  3,  8, 13, 18, 23, 28,  1,  6, 11, 16, 21, 26, 31,  4,  9, 14, 19, 24, 29,  2,  7, 12, 17, 22, 27,  0},   // Mode  8, 28
   { 2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,  0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,  0},   // Mode  9, 27
   { 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0},   //*Mode 10, 26
   {30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10,  8,  6,  4,  2,  0, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10,  8,  6,  4,  2,  0},   // Mode 11, 25
   {27, 22, 17, 12,  7,  2, 29, 24, 19, 14,  9,  4, 31, 26, 21, 16, 11,  6,  1, 28, 23, 18, 13,  8,  3, 30, 25, 20, 15, 10,  5,  0},   // Mode 12, 24
   {23, 14,  5, 28, 19, 10,  1, 24, 15,  6, 29, 20, 11,  2, 25, 16,  7, 30, 21, 12,  3, 26, 17,  8, 31, 22, 13,  4, 27, 18,  9,  0},   // Mode 13, 23
   {19,  6, 25, 12, 31, 18,  5, 24, 11, 30, 17,  4, 23, 10, 29, 16,  3, 22,  9, 28, 15,  2, 21,  8, 27, 14,  1, 20,  7, 26, 13,  0},   // Mode 14, 22
   {15, 30, 13, 28, 11, 26,  9, 24,  7, 22,  5, 20,  3, 18,  1, 16, 31, 14, 29, 12, 27, 10, 25,  8, 23,  6, 21,  4, 19,  2, 17,  0},   // Mode 15, 21
   {11, 22,  1, 12, 23,  2, 13, 24,  3, 14, 25,  4, 15, 26,  5, 16, 27,  6, 17, 28,  7, 18, 29,  8, 19, 30,  9, 20, 31, 10, 21,  0},   // Mode 16, 20
   { 6, 12, 18, 24, 30,  4, 10, 16, 22, 28,  2,  8, 14, 20, 26,  0,  6, 12, 18, 24, 30,  4, 10, 16, 22, 28,  2,  8, 14, 20, 26,  0}    // Mode 17, 19
};

Bit#(1) mapShift[16][31] = {   // 0-Shift, 1-Keep
//  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
   {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},     // Mode 34
   {1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1},     // Mode 33
   {1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1},     // Mode 32
   {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1},     // Mode 31
   {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},     // Mode 30
   {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1},     // Mode 29
   {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1},     // Mode 28
   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},     // Mode 27
   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},     // Mode 26
   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},     // Mode 25
   {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},     // Mode 24
   {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},     // Mode 23
   {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0},     // Mode 22
   {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0},     // Mode 21
   {1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0},     // Mode 20
   {1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0}      // Mode 19
};

(* synthesize *)
module mkIntra32(IIntra32);
   Reg#(Maybe#(IntraRef_t))                     reg_i    <- mkReg(tagged Invalid);
   FIFOF#(Vector#(32, Bit#(8)))                 fifo_o   <- mkPipelineFIFOF;
   Reg#(Bit#(6))                                mode     <- mkReg(0);            // 0-Mode2, 1-Mode3..., 15-Mode17, 16-Mode34, 17-Mode33..., 32-Mode18
   Reg#(Bit#(6))                                moded1   <- mkRegU;
   Reg#(Maybe#(Vector#(64, Bit#(8))))           stage0   <- mkReg(tagged Invalid);
   FIFOF#(Tuple3#(Bit#(4), Vector#(32, Bit#( 8)), Vector#(32, Bit#( 8)))) stage1 <- mkPipelineFIFOF;
   FIFOF#(Vector#(2, (Vector#(32, Bit#(13)))))  stage2   <- mkPipelineFIFOF;
   Reg#(Vector#(32, Bit#(8)))                   pixd1    <- mkRegU;
   Reg#(Bit#(6))                                cnt1     <- mkReg(0);

   Integer chen_debug = 0;

   rule do_stage0(!isValid(stage0) &&& reg_i matches tagged Valid .x);
      let xL = cons(?, x.left);
      let xT = x.top;
      Vector#(64, Bit#(8)) y = ?;

      case(mode)
         0: begin
            y = unpack({?,         xL[64], xL[63], xL[62], xL[61], xL[60], xL[59], xL[58],
                           xL[57], xL[56], xL[55], xL[54], xL[53], xL[52], xL[51], xL[50],
                           xL[49], xL[48], xL[47], xL[46], xL[45], xL[44], xL[43], xL[42],
                           xL[41], xL[40], xL[39], xL[38], xL[37], xL[36], xL[35], xL[34],
                           xL[33], xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26],
                           xL[25], xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18],
                           xL[17], xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10],
                           xL[ 9], xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2]
                        });
         end
          1,  2,  3,  4,  5,  6,  7, 8: begin
            y = unpack({?,                                                         xL[57],
                           xL[56], xL[55], xL[54], xL[53], xL[52], xL[51], xL[50], xL[49],
                           xL[48], xL[47], xL[46], xL[45], xL[44], xL[43], xL[42], xL[41],
                           xL[40], xL[39], xL[38], xL[37], xL[36], xL[35], xL[34], xL[33],
                           xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1]
                        });
         end
          9: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[16]
                        });
         end
        10: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 6], xT[13], xT[19], xT[26]
                        });
         end
        11: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 4], xT[ 7], xT[11], xT[14], xT[18], xT[21], xT[25],
                           xT[28]
                        });
         end
        12: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 2], xT[ 5], xT[ 7], xT[10], xT[12], xT[15], xT[17],
                           xT[20], xT[22], xT[25], xT[27], xT[30]
                        });
         end
        13: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 2], xT[ 4], xT[ 6], xT[ 8], xT[ 9], xT[11], xT[13],
                           xT[15], xT[17], xT[19], xT[21], xT[23], xT[24], xT[26], xT[28],
                           xT[30]
                        });
         end
        14: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 2], xT[ 3], xT[ 5], xT[ 6], xT[ 8], xT[ 9], xT[11],
                           xT[12], xT[14], xT[15], xT[17], xT[18], xT[20], xT[21], xT[23],
                           xT[24], xT[26], xT[27], xT[29], xT[30]
                        });
         end
        15: begin
            y = unpack({?, xL[32], xL[31], xL[30], xL[29], xL[28], xL[27], xL[26], xL[25],
                           xL[24], xL[23], xL[22], xL[21], xL[20], xL[19], xL[18], xL[17],
                           xL[16], xL[15], xL[14], xL[13], xL[12], xL[11], xL[10], xL[ 9],
                           xL[ 8], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 3], xL[ 2], xL[ 1],
                           xT[ 0], xT[ 1], xT[ 2], xT[ 4], xT[ 5], xT[ 6], xT[ 7], xT[ 9],
                           xT[10], xT[11], xT[12], xT[14], xT[15], xT[16], xT[17], xT[18],
                           xT[20], xT[21], xT[22], xT[23], xT[25], xT[26], xT[27], xT[28],
                           xT[30], xT[31]
                        });
         end

         // Vertical
        16: begin
            y = unpack({?,
                                   xT[64], xT[63], xT[62], xT[61], xT[60], xT[59], xT[58],
                           xT[57], xT[56], xT[55], xT[54], xT[53], xT[52], xT[51], xT[50],
                           xT[49], xT[48], xT[47], xT[46], xT[45], xT[44], xT[43], xT[42],
                           xT[41], xT[40], xT[39], xT[38], xT[37], xT[36], xT[35], xT[34],
                                                                                xT[33],
                           xT[33], xT[32], xT[31], xT[30], xT[29], xT[28], xT[27], xT[26],
                           xT[25], xT[24], xT[23], xT[22], xT[21], xT[20], xT[19], xT[18],
                           xT[17], xT[16], xT[15], xT[14], xT[13], xT[12], xT[11], xT[10],
                           xT[ 9], xT[ 8], xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2]
                        });
         end
        17, 18, 19, 20, 21, 22, 23, 24: begin
            y = unpack({?,                                                         xT[58],
                           xT[57], xT[56], xT[55], xT[54], xT[53], xT[52], xT[51], xT[50],
                           xT[49], xT[48], xT[47], xT[46], xT[45], xT[44], xT[43], xT[42],
                           xT[41], xT[40], xT[39], xT[38], xT[37], xT[36], xT[35], xT[34],
                                                                                xT[33],
                           xT[32], xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25],
                           xT[24], xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17],
                           xT[16], xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9],
                           xT[ 8], xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1]
                        });
         end
        25: begin
            y = unpack({?,                                                         xL[16],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        26: begin
            y = unpack({?,                                 xL[26], xL[19], xL[13], xL[ 6],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        27: begin
            y = unpack({?, xL[28], xL[25], xL[21], xL[18], xL[14], xL[11], xL[ 7], xL[ 4],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        28: begin
            y = unpack({?,                                 xL[30], xL[27], xL[25], xL[22],
                           xL[20], xL[17], xL[15], xL[12], xL[10], xL[ 7], xL[ 5], xL[ 2],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        29: begin
            y = unpack({?, xL[30], xL[28], xL[26], xL[24], xL[23], xL[21], xL[19], xL[17],
                           xL[15], xL[13], xL[11], xL[ 9], xL[ 8], xL[ 6], xL[ 4], xL[ 2],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        30: begin
            y = unpack({?,                                 xL[30], xL[29], xL[27], xL[26],
                           xL[24], xL[23], xL[21], xL[20], xL[18], xL[17], xL[15], xL[14],
                           xL[12], xL[11], xL[ 9], xL[ 8], xL[ 6], xL[ 5], xL[ 3], xL[ 2],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        31: begin
            y = unpack({?,                                                         xL[31],
                           xL[30], xL[28], xL[27], xL[26], xL[25], xL[23], xL[22], xL[21],
                           xL[20], xL[18], xL[17], xL[16], xL[15], xL[14], xL[12], xL[11],
                           xL[10], xL[ 9], xL[ 7], xL[ 6], xL[ 5], xL[ 4], xL[ 2], xL[ 1],
                                                                                xT[32],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
        32: begin
            y = unpack({?,         xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25],
                           xT[24], xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17],
                           xT[16], xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9],
                           xT[ 8], xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1],
                                                                                xT[33],
                           xT[31], xT[30], xT[29], xT[28], xT[27], xT[26], xT[25], xT[24],
                           xT[23], xT[22], xT[21], xT[20], xT[19], xT[18], xT[17], xT[16],
                           xT[15], xT[14], xT[13], xT[12], xT[11], xT[10], xT[ 9], xT[ 8],
                           xT[ 7], xT[ 6], xT[ 5], xT[ 4], xT[ 3], xT[ 2], xT[ 1], xT[ 0]
                        });
         end
      endcase

      // swap Top and Left on Horizon/Vertical mode edge
      Vector#(64, Bit#(8)) tmpLeft = x.left;
      Vector#(65, Bit#(8)) tmpTop = x.top;
      if (mode == 15) begin
         tmpLeft = takeAt(1, x.top);
         tmpTop  = cons(x.top[0], x.left);
      end
      reg_i  <= (mode == 32) ? (tagged Invalid) : (tagged Valid IntraRef_t {left:tmpLeft, top:tmpTop});

      moded1 <= mode;
      mode   <= mode + 1;
      stage0 <= tagged Valid y;
      cnt1   <= (mode < 16) ? ~0 : 0;

      if (chen_debug == 1) begin
         if (mode == 2)
            $finish;
      end
   endrule

   rule do_stage1(stage0 matches tagged Valid .x);
      Vector#(33, Bit#(8)) y0 = take(x);
      Vector#(31, Bit#(8)) y1 = takeAt(33, x);
      let modeX = moded1[3:0];
      let fac = facTbl[modeX][cnt1];

      Vector#(32, Bit#(8)) m = take    (y0);
      Vector#(32, Bit#(8)) n = takeTail(y0);
      let shiftIdx = modeX;

      if (moded1 < 16) begin
         m = pixd1;
         for(Integer i = 0; i < 32; i = i + 1) begin
            n[i] = x[mapTbl[modeX][i]];
         end
         shiftIdx = 0;
      end

      pixd1 <= n;

      // Prediction
      if (cnt1[5] != 0) begin
         stage1.enq(tuple3(modeX, m, n));
      end

      // next row
      cnt1 <= cnt1 + 1;
      if (cnt1 == 31) begin
         stage0 <= tagged Invalid;
      end
      else if (mapShift[shiftIdx][cnt1] == 1) begin
         y0 = ((moded1 >= 24 && moded1 <= 31) ? shiftInAt0(y0, y1[0]) : shiftInAtN(y0, y1[0]));
         y1 = shiftOutFrom0(?, y1, 1);
         stage0 <= tagged Valid append(y0, y1);
      end
   endrule

   rule do_stage2;
      let x = stage1.first;
      let modeX = tpl_1(x);
      let y0 = tpl_2(x);
      let y1 = tpl_3(x);
      stage1.deq;

      Vector#(32, Bit#(13)) xm;
      Vector#(32, Bit#(13)) xn;
      for(Integer i = 0; i < 32; i = i + 1) begin
         let fac = facTbl[modeX][i];
         xm[i] = (fromInteger(32 - fac) * zeroExtend(y0[i]));
         xn[i] = (fromInteger(     fac) * zeroExtend(y1[i]));
      end
      stage2.enq(vec(xm, xn));
   endrule

   rule do_stage3;
      let x = stage2.first;
      Vector#(32, Bit#(8)) y;
      for(Integer i = 0; i < 32; i = i + 1) begin
         y[i] = roundN((x[0][i] + x[1][i]), 5);
      end
      fifo_o.enq(y);
   endrule

   interface io_in  =  interface Put;
                           method Action put(IntraRef_t x) if (!isValid(reg_i));
                              reg_i <= tagged Valid x;
                           endmethod
                      endinterface;
   interface io_out = toGet(fifo_o);
endmodule : mkIntra32

`ifdef TEST_BENCH_mkIntra32
(* synthesize *)
module mkTb(Empty);
   FIFOF#(IntraRef_t)   fifo_in  <- mkPipelineFIFOF;
   Reg#(Bit#(16))       cycles   <- mkReg(0);
   IIntra32             dut      <- mkIntra32;

   mkConnection(toGet(fifo_in), dut.io_in);

   rule do_cycles;
      cycles <= cycles + 1;
   endrule

   rule do_input;
      Vector#(64, Bit#(8)) xL;
      Vector#(65, Bit#(8)) xT;
      for(Integer i=0; i<64; i=i+1)
         xL[i] = fromInteger(-(i+1));

      for(Integer i=0; i<65; i=i+1)
         xT[i] = fromInteger(i);

      fifo_in.enq(IntraRef_t {left:xL, top:xT});
   endrule

endmodule

`endif


added interface MemClient

added interface MemClient

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

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

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

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

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

`include "ConnectalProjectConfig.bsv"

typedef Bit#(32) SGLId;
typedef 44 MemOffsetSize;
`ifdef MemTagSize
typedef `MemTagSize MemTagSize;
`else
typedef 6 MemTagSize;
`endif
typedef `BurstLenSize BurstLenSize;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

`include "ConnectalProjectConfig.bsv"

typedef Bit#(32) SGLId;
typedef 44 MemOffsetSize;
`ifdef MemTagSize
typedef `MemTagSize MemTagSize;
`else
typedef 6 MemTagSize;
`endif
typedef `BurstLenSize BurstLenSize;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


pure BSV version of SyncBits

pure BSV version of SyncBits

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

module mkSyncBits#(a initValue, Clock sClkIn, Reset sRst, Clock dClkIn, Reset dRst)(SyncBitIfc#(a))
   provisos (Bits#(a,awidth));

   Reg#(a) ff0 <- mkReg(initValue, clocked_by sClkIn, reset_by sRst);
   Reg#(a) ff1 <- mkReg(initValue, clocked_by dClkIn, reset_by dRst);
   Reg#(a) ff2 <- mkReg(initValue, clocked_by dClkIn, reset_by dRst);

   ReadOnly#(a) ff0cross <- mkNullCrossingWire(dClkIn, ff0);

   rule update;
      ff1 <= ff0cross;
      ff2 <= ff1;
   endrule

   method a read();
      return ff2;
   endmethod: read

   method Action send(a value);
      ff0 <= value;
   endmethod: send
endmodule

module mkSyncBitsFromCC#(a initValue, Clock dClkIn, Reset dRst)(SyncBitIfc#(a))
   provisos (Bits#(a,awidth));
   Clock sClkIn <- exposeCurrentClock();
   Reset sRst <- exposeCurrentReset();
   SyncBitIfc#(a) syncbits <- mkSyncBits(initValue, sClkIn, sRst, dClkIn, dRst);
   return syncbits;
endmodule

module mkSyncBitsToCC#(a initValue, Clock sClkIn, Reset sRst)(SyncBitIfc#(a))
   provisos (Bits#(a,awidth));
   Clock dClkIn <- exposeCurrentClock();
   Reset dRst <- exposeCurrentReset();
   SyncBitIfc#(a) syncbits <- mkSyncBits(initValue, sClkIn, sRst, dClkIn, dRst);
   return syncbits;
endmodule

module mkSyncBits128#(Clock sClkIn, Reset sRst, Clock dClkIn, Reset dRst)(SyncBitIfc#(Bit#(128)));
   SyncBitIfc#(Bit#(128)) sbits <- mkSyncBits(0, sClkIn, sRst, dClkIn, dRst);
   method read = sbits.read;
   method send = sbits.send;
endmodule: mkSyncBits128

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

module mkSyncBits#(Clock sClkIn, Reset sRst, Clock dClkIn)(SyncBitIfc#(a))
   provisos (Bits#(a,awidth));
   Vector#(awidth, SyncBitIfc#(Bit#(1))) bits <- replicateM(mkSyncBit(sClkIn, sRst, dClkIn));

   method a read();
      function Bit#(1) readBit(SyncBitIfc#(Bit#(1)) syncBit); return syncBit.read(); endfunction
      return unpack(pack(map(readBit, bits)));
   endmethod: read
   method Action send(a value);
      Bit#(awidth) abits = pack(value);
      for (Integer i = 0; i < valueOf(awidth); i = i + 1) begin
	 bits[i].send(abits[i]);
      end
   endmethod: send
endmodule

module mkSyncBitsFromCC#(Clock dClkIn)(SyncBitIfc#(a))
   provisos (Bits#(a,awidth));
   Clock sClkIn <- exposeCurrentClock();
   Reset sRst <- exposeCurrentReset();
   SyncBitIfc#(a) syncbits <- mkSyncBits(sClkIn, sRst, dClkIn);
   return syncbits;
endmodule

module mkSyncBitsToCC#(Clock sClkIn, Reset sRst)(SyncBitIfc#(a))
   provisos (Bits#(a,awidth));
   Clock dClkIn <- exposeCurrentClock();
   SyncBitIfc#(a) syncbits <- mkSyncBits(sClkIn, sRst, dClkIn);
   return syncbits;
endmodule


Fixed whichServer logic for RV32IM_3stage

// Copyright (c) 2016 Massachusetts Institute of Technology

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

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

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

import BuildVector::*;
import ClientServer::*;
import FIFO::*;
import GetPut::*;
import Vector::*;

import PrintTrace::*;
import ServerUtil::*;

import Abstraction::*;
import BasicMemorySystemBlocks::*;
import BRAMTightlyCoupledMemory::*;
import RVTypes::*;

interface TightlyCoupledMemorySystem;
    interface Server#(RVIMemReq, RVIMemResp) ifetch;
    interface Server#(RVDMemReq, RVDMemResp) dmem;
    interface UncachedMemClient mmio;
    interface Server#(GenericMemReq#(XLEN), GenericMemResp#(XLEN)) ext;
endinterface

module mkTightlyCoupledMemorySystem(TightlyCoupledMemorySystem);
    Bool verbose = False;
    File tracefile = verbose ? stdout : tagged InvalidFile;

    // uncached port -- works on XLEN-bit words
    FIFO#(UncachedMemReq) uncachedReqFIFO <- mkFIFO;
    FIFO#(UncachedMemResp) uncachedRespFIFO <- mkFIFO;
    let uncachedMemClient = toGPClient(uncachedReqFIFO, uncachedRespFIFO);
    let mmio_server <- mkUncachedConverter(toGPServer(uncachedReqFIFO, uncachedRespFIFO));

    // Shared I/D Memory
    let sram <- mkBramIDExtMem;

    // address decoding the dmem port of the sram for uncachedMemClient
    function Bit#(1) whichServer(RVDMemReq r);
        return (r.addr >= 'h4000_0000) ? 1 : 0;
    endfunction
    function Bool getsResponse(RVDMemReq r);
        return r.op != tagged Mem St;
    endfunction
    let proc_dmem <- mkServerJoiner(whichServer, getsResponse, 2, vec(sram.dmem, mmio_server));

    interface Server ifetch = fprintTrace(tracefile, "Proc-IMem", sram.imem);
    interface Server dmem = fprintTrace(tracefile, "Proc-DMem", proc_dmem);

    interface Client mmio = uncachedMemClient;

    // External memory requests and responses
    interface Server ext = fprintTrace(tracefile, "ExtMem", sram.ext);
endmodule

// Copyright (c) 2016 Massachusetts Institute of Technology

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

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

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

import BuildVector::*;
import ClientServer::*;
import FIFO::*;
import GetPut::*;
import Vector::*;

import PrintTrace::*;
import ServerUtil::*;

import Abstraction::*;
import BasicMemorySystemBlocks::*;
import BRAMTightlyCoupledMemory::*;
import RVTypes::*;

interface TightlyCoupledMemorySystem;
    interface Server#(RVIMemReq, RVIMemResp) ifetch;
    interface Server#(RVDMemReq, RVDMemResp) dmem;
    interface UncachedMemClient mmio;
    interface Server#(GenericMemReq#(XLEN), GenericMemResp#(XLEN)) ext;
endinterface

module mkTightlyCoupledMemorySystem(TightlyCoupledMemorySystem);
    Bool verbose = False;
    File tracefile = verbose ? stdout : tagged InvalidFile;

    // uncached port -- works on XLEN-bit words
    FIFO#(UncachedMemReq) uncachedReqFIFO <- mkFIFO;
    FIFO#(UncachedMemResp) uncachedRespFIFO <- mkFIFO;
    let uncachedMemClient = toGPClient(uncachedReqFIFO, uncachedRespFIFO);
    let mmio_server <- mkUncachedConverter(toGPServer(uncachedReqFIFO, uncachedRespFIFO));

    // Shared I/D Memory
    let sram <- mkBramIDExtMem;

    // address decoding the dmem port of the sram for uncachedMemClient
    function Bit#(1) whichServer(RVDMemReq r);
        return (r.addr > 'h4000_0000) ? 1 : 0;
    endfunction
    function Bool getsResponse(RVDMemReq r);
        return r.op != tagged Mem St;
    endfunction
    let proc_dmem <- mkServerJoiner(whichServer, getsResponse, 2, vec(sram.dmem, mmio_server));

    interface Server ifetch = fprintTrace(tracefile, "Proc-IMem", sram.imem);
    interface Server dmem = fprintTrace(tracefile, "Proc-DMem", proc_dmem);

    interface Client mmio = uncachedMemClient;

    // External memory requests and responses
    interface Server ext = fprintTrace(tracefile, "ExtMem", sram.ext);
endmodule