<|start_filename|>libthymesisflow/unittest/unittest.c<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "client.h"
#include "proto.h"
#include <assert.h>
#include <signal.h>
#include "agent.h"

#define VERIFY(cond)                                                           \
    if (!(cond)) {                                                             \
        printf("\e[31mUnit test failed [ %s ] at %s - line: %d\e[0m\n\n",      \
               __func__, __FILE__, __LINE__);                                  \
        return;                                                                \
    } else {                                                                   \
        printf("\e[32mUnit test passed [ %s ] at %s - line: %d\e[0m\n\n",      \
               __func__, __FILE__, __LINE__);                                  \
    }

#define PASSED                                                                 \
    { printf("\e[32mUnit test [ %s ] passed..\n", __func__); }

void test_hex_string_to_address() {
    const char *hexstring = "0xabcdef0";
    long int number = (int)strtol(hexstring, NULL, 16);
    const char *hexstring2 = "abcdef0";
    log_info("hex representation: hex(%ld):%lx\n", number, number);
    long int number2 = (int)strtol(hexstring2, NULL, 16);
    log_info("hex representation: hex(%ld):%lx\n", number2, number2);
}

void test_connection() {
    connection *conn1 = new_conn("a", "afu1", 10, 0);
    add_conn(conn1);
    VERIFY(conn1->size == 10 && strcmp(conn1->circuit_id, "a") == 0 &&
           strcmp(conn1->afu_name, "afu1") == 0 && conn1->next == NULL);

    connection *conn2 = new_conn("b", "afu2", 10, 0);
    add_conn(conn2);
    VERIFY(clist == conn2 && clist->next == conn1);

    connection *conn3 = new_conn("c", "afu3", 10, 0);
    add_conn(conn3);
    VERIFY(clist == conn3 && clist->next == conn2);

    list_connections();

    connection *conn_ret = get_conn("b");
    log_info("returned conn: %s\n", conn_ret->circuit_id);
    VERIFY(strcmp(conn_ret->circuit_id, "b") == 0);

    del_conn("b");
    VERIFY(clist == conn3 && clist->next == conn1);

    del_conn("a");
    VERIFY(clist == conn3 && clist->next == NULL);

    del_conn("c");
    VERIFY(clist == NULL);
}
void test_iport_marshalling() {

    iport_list *pl = NULL;
    pl = add_port(pl, 1);
    u_int8_t rep = marshal_iports(pl);
    VERIFY(rep == 1);

    pl = add_port(pl, 5);
    rep = marshal_iports(pl);
    VERIFY(rep == 17); // hex(11) == 17 == 2^4 + 2^0
    free_iport_list(pl);
}

void test_iport() {
    u_int8_t port = 1; // expect port 1
    u_int8_t ptest = 0;
    log_info("test - %d ...\n", port);
    iport_list *pl = unmarshal_iports(port);
    cycle_ports(pl);
    free_iport_list(pl);

    port = 3; // expect port 1 and 2
    log_info("test - %d ...\n", port);
    pl = unmarshal_iports(port);
    cycle_ports(pl);
    ptest = marshal_iports(pl);
    log_info("test - serialization %d == %d ...\n", ptest, port);
    VERIFY(ptest == port);
    free_iport_list(pl);

    port = 10; // expect port 2 and 4
    log_info("test - %d ...\n", port);
    pl = unmarshal_iports(port);
    cycle_ports(pl);
    free_iport_list(pl);

    ptest = marshal_iports(pl);
    log_info("test - serialization %d == %d ...\n", ptest, port);
    VERIFY(ptest == port);
    free_iport_list(pl);

    port = 0; // expect port 1
    log_info("test - %d ...\n", port);
    pl = unmarshal_iports(port);
    cycle_ports(pl);
    free_iport_list(pl);

    port = 16; // expect port 5
    log_info("test - %d ...\n", port);
    pl = unmarshal_iports(port);
    cycle_ports(pl);
    free_iport_list(pl);
}

void test_integration() {

#ifdef MOCK
    char *id = "cc592edc-eca6-4e0f-9541-5a3684c37757";
    char *afu = "/dev/ibm-n0";
    uint64_t size = 68719476736;
    int no_hotplug = 1;

    char *sock_path = "/tmp/thymesisflow-test.sock";

    pid_t agent_pid;
    switch (agent_pid = fork()){
      case -1:
        log_error("Error starting agent...\n");
      case 0:
        //child
        log_info("Starting agent...\n");
        run_agent(sock_path);
        exit(0);
    }

    // wait for the agent to start
    sleep(1);

    log_info("Sending mock requests...\n");

    iport_list *plm = NULL;
    plm = add_port(plm, 1);
    // plm = add_port(plm, 3);
    cycle_ports(plm);

    pmessage mresp = send_attach_memory_msg(id, afu, plm, size, sock_path);
    VERIFY(mresp.status == ATTACH_OK);

    pmessage mdresp = send_detach_memory_msg(id, sock_path);
    VERIFY(mdresp.status == DETACH_OK);

    // testing attach_compute with no_hotplug=1
    pmessage cresp =
        send_attach_compute_msg(id, afu, plm, size, mresp.ea, no_hotplug, sock_path);
    VERIFY(cresp.status == ATTACH_OK);

    pmessage cdresp = send_detach_compute_msg(id, sock_path);
    VERIFY(cdresp.status == DETACH_OK);

    // testing attach_compute with no_hotplug=0
    no_hotplug = 0;
    cresp =
        send_attach_compute_msg(id, afu, plm, size, mresp.ea, no_hotplug, sock_path);
    VERIFY(cresp.status == ATTACH_OK);

    cdresp = send_detach_compute_msg(id, sock_path);
    VERIFY(cdresp.status == DETACH_OK);

    free_iport_list(plm);

    //terminate the agent
    kill(agent_pid,SIGTERM);
#else
    log_info("this is an API test, build with MOCK=1\n");
#endif
}

int main(int argc, char const *argv[]) {
#ifdef MOCK
    test_hex_string_to_address();
    test_iport_marshalling();
    test_connection();
    test_integration();
#else
    log_warn("Unit test are available only with MOCK=1\n");
#endif
}


<|start_filename|>libthymesisflow/src/agent.c<|end_filename|>
#include "agent.h"

void handle_request(int cfd) {
    char *msg = read_message(cfd);
    char *response_msg;

    if (msg == NULL) {
        // TODO: return error reading message

        response_msg = new_proto_msg();
        return;
    } else {
        char *msgtype = (char *)malloc(MSGTYPE_SIZE);
        memcpy(msgtype, msg + CIRCUIT_ID_SIZE, MSGTYPE_SIZE);

        if (strncmp(msgtype, MEMORY_ATTACH, MSGTYPE_SIZE) == 0) {
            response_msg = proto_attach_memory(msg);

        } else if (strncmp(msgtype, MEMORY_DETACH, MSGTYPE_SIZE) == 0) {
            response_msg = proto_detach_memory(msg);

        } else if (strncmp(msgtype, COMPUTE_ATTACH, MSGTYPE_SIZE) == 0) {
            response_msg = proto_attach_compute(msg);

        } else if (strncmp(msgtype, COMPUTE_DETACH, MSGTYPE_SIZE) == 0) {
            response_msg = proto_detach_compute(msg);

        } else {
            log_warn("unknown mode %s\n", msgtype);
            response_msg = set_unknown_mode_response(msg);
            // fill error response
        }
        free(msgtype);
    }

    write_message(cfd, response_msg);
    // error checking

    if (msg != NULL)
        free(msg);
    if (response_msg != NULL)
        free(response_msg);
}

void graceful_termination(){
  log_info("Graceful agent termination...\n");
  exit(0);
}


void run_agent(const char* sock_path){

    struct sockaddr_un addr;
    int sfd, cfd;

    if (sock_path == NULL) {
        sock_path = SOCK_PATH;
    }
    log_info("using socket: %s\n", sock_path);

    log_info("starting server with sock_path: %s\n", sock_path);

    // avoid exiting when reading on closed pipe, need better handling
    signal(SIGPIPE, SIG_IGN);
    signal(SIGTERM, graceful_termination);

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd == -1) {
        log_error("error creating socket: %s\n", strerror(errno));
        exit(1);
    }

    if (remove(sock_path) == -1 && errno != ENOENT) {
        log_info("error removing %s.. \n", sock_path);
        exit(2);
    }

    memset(&addr, 0, sizeof(addr.sun_path) - 1);

    addr.sun_family = AF_UNIX; // use unix socket
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (bind(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) {
        log_error("error while binding the socket\n");
        exit(3);
    }

    if (listen(sfd, BACKLOG) == -1) {
        log_error("error during listen\n");
    }

    log_info("Starting thymesisflow server...\n");

    for (;;) {
        log_info("Ready to accept new requests...\n");

        cfd = accept(sfd, NULL, NULL);
        if (cfd == -1) {
            log_info("error during accept\n");
            exit(4);
        }
        handle_request(cfd);

        log_info("closing connection...\n");

        if (close(cfd) == -1) {
            log_error("error during close\n");
        }
    }
}


<|start_filename|>libthymesisflow/include/client.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file client.h
#if !defined(THYMESISFLOW_CLIENT_H)
#define THYMESISFLOW_CLIENT_H

#include "errcode.h"
#include "iport.h"
#include "logger.h"
#include "proto.h"

// fixed afu port in current design
#define AFU_PORT 2

/**
 *  Send setup request to the memory node daemon through the linux socket
 *
 * @param[in] circuit_id: circuit identifier
 * @param[in] afu: AFU name
 * @param[in] iport_list: list of ports to be used for the attachemnt (Currently
 * single port supported)
 * @param[in] size: size of memory to be allocated
 * @param[in] sock_path: path to the linux socket
 * @param[out] pmessage unmarshalled response from the server
 */
pmessage send_attach_memory_msg(const char *circuitid, const char *afu,
                                const iport_list *ports, const uint64_t size,
                                const char *sock_path);

/**
 *  Send setup request to the compute node daemon through the linux socket
 *
 * @param[in] circuit_id: circuit identifier
 * @param[in] afu: AFU name
 * @param[in] iport_list: list of ports to be used for the attachemnt (Currently
 * single port supported)
 * @param[in] size: size of memory to be allocated
 * @param[in] ea: effective address to be passed to the AFU during the setup
 * @param[in] no_hotplug: do not hotploug memory
 * @param[in] sock_path: path to the linux socket
 * @param[out] pmessage unmarshalled response from the server
 */
pmessage send_attach_compute_msg(const char *circuitid, const char *afu,
                                 const iport_list *ports, const uint64_t size,
                                 const uint64_t ea, int no_hotplug, const char *sock_path);

/**
 *  Send detachment request to the memory node daemon through the linux socket
 *
 * @param[in] circuit_id: circuit identifier
 * @param[in] sock_path: path to the linux socket
 * @param[out] pmessage unmarshalled response from the server
 */
pmessage send_detach_memory_msg(const char *circuitid, const char *sock_path);

/**
 *  Send detachment request to the compute node daemon through the linux socket
 *
 * @param[in] circuit_id: circuit identifier
 * @param[in] sock_path: path to the linux socket
 * @param[out] pmessage unmarshalled response from the server
 */
pmessage send_detach_compute_msg(const char *circuitid, const char *sock_path);

#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress_lookup/ocx_memory_egress_lookup_top.cpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>



#include "globals.hpp"

#include "types.hpp"
#include "ocx_flit.hpp"
#include "ocx_cmd_fifo_load.hpp"



void ocx_memory_egress_lookup_top(stream<tlrflit_t> &tl_resp, \
			   /*External BRAM Input Interfaces */
			   tlxscflit_t cmdlookup_in[LOOKUPSIZE],\
                           /*outputs*/
                           count_t &valex_memegress_cmddata_ld_cnt,\
			   stream<resp_combo_t> &tl_fifo_resp_out)
{


#pragma HLS INTERFACE bram register port=cmdlookup_in
#pragma HLS RESOURCE variable=cmdlookup_in core=RAM_1P_BRAM latency=1


#pragma HLS INTERFACE ap_none register port=valex_memegress_cmddata_ld_cnt
#pragma HLS INTERFACE axis register port=tl_fifo_resp_out
#pragma HLS INTERFACE axis register port=tl_resp
#pragma HLS INTERFACE ap_ctrl_none port=return

#pragma HLS dataflow interval=1

/*
 This Fifo Holds Responses coming from the local TL
 We need this Buffer as the Resp State machine will
 might not be ready to pull, spending cycles on 
 rertry CAM updates or data push. We put a generous 8
 depth here, but i think we will not need more than 4.
*/

/*Various State machines Declarations*/
CmdFifoLoad CmdFifold;


/*
   Fifo load for TL cmd
   Input:
     tl_resp comming from TL
   Output: 
     tl_fifo_resp a fifo that feeds Resp egine.
*/

CmdFifold.CmdFifoLoadSM(tl_resp,\
		        cmdlookup_in,\
                valex_memegress_cmddata_ld_cnt,\
		        tl_fifo_resp_out);


}


<|start_filename|>libthymesisflow/include/stats.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef THYMESISSTATS_H
#define THYMESISSTATS_H

#include "logger.h"
#include <fcntl.h>
#include <libocxl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>

#define TX_STATS 0x60
#define RX_STATS 0x68
#define LATENCY_STATS 0x70
#define PERIOD_SEC 1
#define THYMESISCOUNT_PATH "/tmp/thymesispcount"

struct thread_args {
    ocxl_mmio_h global;
    int fd;
    int period;
};

typedef struct thread_args t_args;

// int  tf_init_stats_thread(pthread_t *  tid, int fd, ocxl_mmio_h global, int
// period);
int start_stats_thread(pthread_t **tid, ocxl_mmio_h global);
int stop_stats_thread(pthread_t *tid);

#endif


<|start_filename|>libthymesisflow/include/protoconst.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file protoconst.h
#if !defined(PROTOCONST_H)
#define PROTOCONST_H

/*

Possible messages:

 - | circuitid | memory    | afu | port | size |
 - | circuitid | compute   | afu | port | size | ea | no_hotplug |
 - | circuitid | mresponse | afu |      |      | ea |            | error |
 - | circuitid | cresponse | afu |      | size |    |            | error |

*/

/*! \def    SOCK_PATH
 * \brief default linux socket path used for communication with libthymesisflow
 * server
 */
#define SOCK_PATH "/tmp/thymesisflow.sock"

/*! \def CIRCUIT_ID_SIZE
 * \brief circuit uuid lenght
 */
#define CIRCUIT_ID_SIZE 36

/*! \def MSGTYPE_SIZE
 * \brief maximum size for section identifying the type of message sent/received
 */
#define MSGTYPE_SIZE 16

/*! \def AFUNAME_SIZE
 * \brief maximum size for section identifying the AFU name (or path)
 */
#define AFUNAME_SIZE 256

/*! \def IPORT_SIZE
 * \brief maximum size for section reporting the AFU ports to be used
 * (current maximum is 8 given from the binary representation)
 */
#define IPORT_SIZE sizeof(uint8_t)

/*! \def IPORT_SIZE
 * \brief maximum size for section reporting the remote memory to be attached
 */
#define MEM_SIZE sizeof(uint64_t)

/*! \def EA_SIZE
 * \brief maximum size for sectiction containing the effective address
 */
#define EA_SIZE sizeof(uint64_t)

/*! \def NO_HOTPLUG_SIZE
 * \brief size of the no_hotplug flag field
 */
#define NO_HOTPLUG_SIZE sizeof(int)

/*! \def ERROR_SIZE
 * \brief maximum size for the error section
 */
#define ERROR_SIZE sizeof(uint32_t)

/*! \def MSG_SIZE
 * \brief maximum message size
 */
#define MSG_SIZE                                                               \
    CIRCUIT_ID_SIZE + MSGTYPE_SIZE + AFUNAME_SIZE + IPORT_SIZE + MEM_SIZE +    \
        EA_SIZE + ERROR_SIZE + NO_HOTPLUG_SIZE

#define CIRCUIT_ID_OFFSET 0

#define MSGTYPE_OFFSET CIRCUIT_ID_OFFSET + CIRCUIT_ID_SIZE

#define AFUNAME_OFFSET MSGTYPE_OFFSET + MSGTYPE_SIZE

#define IPORT_OFFSET AFUNAME_OFFSET + AFUNAME_SIZE

#define MEM_SIZE_OFFSET IPORT_OFFSET + IPORT_SIZE

#define EA_OFFSET MEM_SIZE_OFFSET + MEM_SIZE

#define NO_HOTPLUG_OFFSET EA_OFFSET + EA_SIZE

#define ERROR_OFFSET NO_HOTPLUG_OFFSET + NO_HOTPLUG_SIZE

#define MEMORY_ATTACH "memory_attach"

#define COMPUTE_ATTACH "compute_attach"

#define ERROR_ATTACH "error_attach"

#define MRESPONSE_ATTACH "mresponse_attach"

#define CRESPONSE_ATTACH "cresponse_attach"

#define MEMORY_DETACH "memory_detach"

#define COMPUTE_DETACH "compute_detach"

#define ERROR_DETACH "error_detach"

#define MRESPONSE_DETACH "mresponse_detach"

#define CRESPONSE_DETACH "cresponse_detach"

/*! \def    ERR_MSGTYPE
 * \brief message type is not one of the default message types
 * specified (MEMORY_ATTACH/MEMORY_DETACH/COMPUTE_ATTACH/COMPUTE_DETACH)
 */
#define ERR_MSGTYPE -3

/*! \def    ERR_MSGNULL
 * \brief provided a null reference to a message
 */
#define ERR_MSGNULL -2

/*! \def    ERR_NULL_PARAM
 * \brief provided a null reference input parameter
 */
#define ERR_NULL_PARAM -1

/*! \def    ERR_EMPTY_PARAM
 * \brief provided an empty input parameter
 */
#define ERR_EMPTY_PARAM -4

/*! \def    ERR_INT_PARAM
 * \brief provided a negative or zero input parameter
 */
#define ERR_INT_PARAM -5

/*! \def    ERR_MEMBLOCK_SIZE
 * \brief memory hotplugged needs to be a multiple of MEMBLOCK_SIZE
 * (/sys/devices/system/memory/block_size_bytes)
 */
#define ERR_MEMBLOCK_SIZE -5
#endif


<|start_filename|>libthymesisflow/Dockerfile<|end_filename|>
FROM ubuntu:18.04

MAINTAINER <EMAIL>

RUN apt-get update && \
	apt-get install -y libocxl-dev

COPY ./bin/thymesisf-agent /usr/bin/
	
ENTRYPOINT ["/usr/bin/thymesisf-agent"]


<|start_filename|>libthymesisflow/cmd/thymesisf-agent.c<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "proto.h"
#include "agent.h"

#include <getopt.h>

void help() {
    fprintf(stderr, "Usage thymesisf-agent [options]\n\n");
    fprintf(stderr,
            "thymesisf-agent is a server responsible for configuring AFUs\n");
    fprintf(
        stderr,
        "on each node participating in a disaggregated memory connection\n\n");
    fprintf(stderr, "Options (all required):\n\n");
    fprintf(stderr,
            "    -s SOCKET_PATH\n\t\t linux socket fullpath, used by the "
            "server to receive client requests\n");
    fflush(stdout);
}



int main(int argc, char *argv[]) {

    char *sock_path = NULL;


    int opt;

    while ((opt = getopt(argc, argv, ":s")) != -1) {
        switch (opt) {
        case 's':
            sock_path = optarg;
            break;
        case '?':
            help();
            exit(EXIT_FAILURE);
        default:
            help();
            exit(EXIT_FAILURE);
        }
    }
    run_agent(sock_path);

}


<|start_filename|>libthymesisflow/include/iport.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file iport.h
#if !defined(IPORT_H)
#define IPORT_H

#include "logger.h"
#include <stdio.h>
#include <stdlib.h>

struct port_s {
    int nport;
    struct port_s *next;
};

typedef struct port_s iport_list;

/**
 * Print interface (AFU) ports
 *
 * @param[in] iport_list: list of ports passed in the socket request
 */
void cycle_ports(iport_list *pl);

/**
 * Add port to the list
 *
 * @param[in] iport_list: list of ports
 * @param[in] port_number: port number
 */
iport_list *add_port(iport_list *pl, u_int8_t port_number);

/**
 * Convert from binary representation of the ports to list structure
 *
 * @param[in] n: binary representation of the porst.
 */
iport_list *unmarshal_iports(u_int8_t n);

/**
 * Free dynamically allocated list structure
 *
 * @param[in] iport_list: list of port numbers
 */
void free_iport_list(iport_list *pl);

/**
 * Convert port list to binary represetnation
 *
 * @param[in] iport_list: list of port numbers
 * @param[out] binary_rep: binary representation of the ports currently in use
 */
u_int8_t marshal_iports(const iport_list *pl);
#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress_lookup/ocx_cmd_fifo_load.hpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>


#ifndef OCX_CMD_FIFO_LOAD_HH
#define OCX_CMD_FIFO_LOAD_HH

#include "globals.hpp"
#include "types.hpp"
#include "ocx_flit.hpp"

class CmdFifoLoad {


 public:

    CmdFifoLoad();

    void CmdFifoLoadSM(stream<tlrflit_t> &input_fifo,\
    	                tlxscflit_t   cmdlookup[LOOKUPSIZE],\
                        count_t &valex_memegress_cmddata_ld_cnt,\
			stream<resp_combo_t> &output_fifo);
  

};

#endif


<|start_filename|>libthymesisflow/include/errcode.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file errcode.h
#if !defined(THYMESISFLOW_ERR_H)
#define THYMESISFLOW_ERR_H
#define THYMESISFLOW_ERR_H

/*! \def ATTACH_OK
 * \brief Successfully attached memory
 */
#define ATTACH_OK 100

/*! \def ERR_MLOCK
 * \brief Error locking memory
 */
#define ERR_MLOCK 101

/*! \def ERR_AFU_OPEN
 * \brief Error opening AFU
 */
#define ERR_AFU_OPEN 102

/*! \def ERR_AFU_ATTACH
 * \brief Error attaching AFU
 */
#define ERR_AFU_ATTACH 103

/*! \def ERR_MMIO_MAP_GLOBAL
 * \brief Error mapping global memory area
 */
#define ERR_MMIO_MAP_GLOBAL 104

/*! \def ERR_MMIO_MAP_LOCAL
 * \brief Error mapping per process MMIO Area
 */
#define ERR_MMIO_MAP_LOCAL 105

/*! \def ERR_WRITE_CTRL_REGISTER
 * \brief Error writing control register
 */
#define ERR_WRITE_CTRL_REGISTER 106

/*! \def ERR_ENABLING_NETWORK
 * \brief Error enabling network
 */
#define ERR_ENABLING_NETWORK 107

/*! \def ERR_PORT_UNSUPPORTED
 * \brief Only single port setup supported
 */
#define ERR_PORT_UNSUPPORTED 108

/*! \def ERR_AURORA_CHAN
 * \brief Error bringing up the AURORA channel
 */
#define ERR_AURORA_CHAN 109

/*! \def ERR_ATTACH_SEG
 * \brief Error while attaching the memory segment
 */
#define ERR_ATTACH_SEG 110

/*! \def ERR_PROBE
 * \brief Error while probing the memory
 */
#define ERR_PROBE 111

/*! \def    DETACH_OK
 * \brief Successfully detached memory
 */
#define DETACH_OK 200

/*! \def    ERR_REGISTER_DETACH
 * \brief error while updating the internal connection status
 */
#define ERR_REGISTER_DETACH 201

/*! \def    ERR_MISSING_CID
 * \brief Missing connection related to circuit id
 */
#define ERR_MISSING_CID 201

#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress/ocx_flit.cpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>



/* General OCx Flit format to support all transformations

ocxflitbdi_t 

bit rng |---------------------|
512-512 |  BDI BIT            |  optional field 
511-355 |  TL/TLx Cmd Common  |  fields shared between TL/TLx commands
354-313 |  TLx Cmd extras     |  extra TLx fields pasid,actag, etc..
312-297 |  Local CAPPTAG      |  This holds that CAPPTAG to be used for local cmd issue.
313-xxx |  Network Header Id  |  custom network annotation depends on the network used
        |---------------------|  

The BDI is used to trigger SUE errors 

*/

#define TLRESP_CODE_RTY 0x2
#define TLRESP_CODE_PEND 0x4

#include "ocx_flit.hpp"

OCxFlit::OCxFlit()
{
   flit = 0;
   return;
}

void OCxFlit::fromOCxFlit(ocxflit_t fl)
{
   flit.range(511,0) = fl.range(511,0);
   return;
}

ocxflit_t OCxFlit::toOCxFlit(void)
{
   ocxflit_t fl;
 
   fl = flit.range(511,0);
   return fl;
}

void OCxFlit::fromOCxBdiFlit(ocxflitbdi_t fl)
{
   flit = fl;
   return;
}

ocxflitbdi_t OCxFlit::toOCxBdiFlit(void)
{
   return flit;
}

void OCxFlit::setBdi(valid_t bdi)
{
   flit.range(512,512) = bdi;
   return;
}


/* TL RESPONSE CMD FLIT PARSING STARTS HERE */

// TL Response flit to 512 OCXFlit for network transmission
void OCxFlit::fromTLRespData(tlrflit_t fl)
{
   //opcode
   flit.range(511,504) = fl.range(37,30); //8
   //capptag
   flit.range(503,488) = fl.range(29,14); //16
   //respcode
   flit.range(487,484) = fl.range(13,10); //4
   //dl 
   flit.range(483,482) = fl.range(9,8); //2
   //dp 
   flit.range(481,480) = fl.range(7,6); //2
   //pgsize 
   flit.range(479,474) = fl.range(5,0);//6
}

tlrflit_t OCxFlit::toTLRespData(void)
{
   tlrflit_t fl;
   //opcode
   fl.range(37,30) = flit.range(511,504); //8
   //capptag
   fl.range(29,14) = flit.range(503,488); //16
   //respcode
   fl.range(13,10) = flit.range(487,484); //4
   //dl
   fl.range(9,8) = flit.range(483,482); //2
   //dp
   fl.range(7,6) = flit.range(481,480); //2
   //pgsize
   fl.range(5,0) = flit.range(479,474);//6

   return fl;
}

tag_t OCxFlit::getRespCappTag(void)
{ 
  tag_t tag;
 
  tag = flit.range(503,488);

  return tag;
}

dl_t OCxFlit::getTLRespDl(void)
{
  dl_t dl;
 
  dl = flit.range(483,482);
  return dl;
}

dl_t OCxFlit::getTLRespDp(void)
{
  dp_t dp;
 
  dp = flit.range(481,480);
  return dp;
}


void OCxFlit::setRespOrigCappTag(tag_t tag)
{ 
  //set it where tag local is annotated
  flit.range(312,297)  = tag;
  return;
}


tag_t OCxFlit::getRespOrigCappTag(void)
{ 
  tag_t tag;

  tag = flit.range(312,297);  
  return tag;
}


code_t OCxFlit::getRespCode()
{
  code_t code;

  code = flit.range(487,484);
  return code;
}

opcode_t OCxFlit::getRespOpcode(void)
{
  opcode_t opc;
  
  opc = flit.range(511,504);
  return opc;

}

bool OCxFlit::TLRespIsXlateDone(void)
{
	return (flit.range(508,508) & flit.range(507,507));
}

bool OCxFlit::TLRespCodeIsFailure(void)
{
	return flit.range(487,487);
}

// Combinational logic that determines how the response flit should be handled.
sel_t OCxFlit::getTLRespState(void)
{
   sel_t sel;
   bool resp_fail;
   bool resp_rty_only;
   bool resp_rty_pend;

   //Determine if resp _opcodes_ indicate failure:
   resp_fail = flit.range(504,504); //The last opcode bit will be 1 if RD or WD failure
   //Determine if resp _codes_ indicate a command rtry:
   resp_rty_only =  (flit.range(487,484) == TLRESP_CODE_RTY);
   resp_rty_pend = ((flit.range(487,484) == TLRESP_CODE_RTY) || (flit.range(487,484) == TLRESP_CODE_PEND));
   /*Sel is 001 FAILURE_RTY => RTY: The Opcode is either FAIL or RTY with backoff.
     in case of XLATE_DONE the command will be immediately retried.
   */
   sel.range(0,0) = (((resp_fail == 1) && (resp_rty_only == 1)) || (flit.range(511,504) == TL_XLATE_DONE));
   /*010 CMD WITH DATA => NETWORK: The command flit is followed by data.
     Only on read family success
   */
   sel.range(1,1) = flit.range(506,506) & !flit.range(504,504);
   /*100 CMD WITH NO DATA => NETWORK: The command flit is not followed by data.
     Only on write family success OR unrecoverable failures of both read and write.
    */
   //RESP is strictly WRITEOK and if it is fail it is not either a retry or pend code is must be a SUE error code
   sel.range(2,2) =  (flit.range(507,507) & !flit.range(504,504))  | (resp_fail & (!resp_rty_pend));

   //else 000 => resp_pend or code failure only cases not captured.

   return sel;

}

/* TLX CMDFLIT PARSING*/

void OCxFlit::fromTLxCmd(tlxcflit_t fl)
{
    //opcode
    flit.range(511,504) = fl.range(198,191);//8
    //ea
    flit.range(503,440) = fl.range(190,127); //64
    //tag
    flit.range(439,424) = fl.range(126,111); // 16
    //dl 
    flit.range(423,422) = fl.range(110,109);//2
    //pl 
    flit.range(421,419) = fl.range(108,106);//3
    //be 
    flit.range(418,355) = fl.range(105,42);//64
    //actag
    flit.range(354,343) = fl.range(41,30);//12
    //streamid
    flit.range(342,339) = fl.range(29,26); //4 
    //pasid
    flit.range(338,319) = fl.range(25,6);//20
    //pgsize
    flit.range(318,313) = fl.range(5,0);//6
}

void OCxFlit::setTLxCmdRespAnno(code_t cd)
{
  flit.range(318,313) = cd;
}

code_t OCxFlit::getTLxCmdRespAnno(void)
{ 
  code_t cd;

  cd = flit.range(318,313);  
  return cd;
}

/*pulls TLx cmd for final issue*/
tlxcflit_t OCxFlit::toTLxCmdFlit(void)
{
    tlxcflit_t fl;

    //opcode
    fl.range(198,191) = flit.range(511,504);//8
    //ea
    fl.range(190,127) = flit.range(503,440); //64
    //tag -- important this is the local tag to use
    //which lies after pgsize and before netid
    fl.range(126,111) = flit.range(312,297); // 16
    //dl 
    fl.range(110,109) = flit.range(423,422);//2
    //pl 
    fl.range(108,106) = flit.range(421,419);//3
    //be 
    fl.range(105,42) = flit.range(418,355);//64
    //actag
    fl.range(41,30) = flit.range(354,343);//12
    //streamid
    fl.range(29,26) = flit.range(342,339); //4 
    //pasid
    fl.range(25,6) = flit.range(338,319);//20
    //pgsize
    fl.range(5,0) = flit.range(318,313); //6
  
    return fl;

}

//Stores the TLxcommand in a lookup table for retries
void OCxFlit::fromTLxCStore(tlxscflit_t fl)
{
    //This holds the local capptag used
    flit.range(312,297) = fl.range(214,199);//16
    //opcode
    flit.range(511,504) = fl.range(198,191);//8
    //ea
    flit.range(503,440) = fl.range(190,127); //64
    //tag
    flit.range(439,424) = fl.range(126,111); // 16
    //dl 
    flit.range(423,422) = fl.range(110,109);//2
    //pl 
    flit.range(421,419) = fl.range(108,106);//3
    //be 
    flit.range(418,355) = fl.range(105,42);//64
    //actag
    flit.range(354,343) = fl.range(41,30);//12
    //streamid
    flit.range(342,339) = fl.range(29,26); //4 
    //pasid
    flit.range(338,319) = fl.range(25,6);//20
    //netid    
    flit.range(296,291) = fl.range(5,0);//6
}


tlxscflit_t OCxFlit::toTLxCStore(void)
{
    tlxcflit_t fl;

    //This holds the local capptag used
    fl.range(214,199) = flit.range(312,297);//16 
    //opcode
    fl.range(198,191) = flit.range(511,504);//8
    //ea
    fl.range(190,127) = flit.range(503,440); //64
    //tag
    fl.range(126,111) = flit.range(439,424); // 16
    //dl 
    fl.range(110,109) = flit.range(423,422);//2
    //pl 
    fl.range(108,106) = flit.range(421,419);//3
    //be 
    fl.range(105,42) = flit.range(418,355);//64
    //actag
    fl.range(41,30) = flit.range(354,343);//12
    //streamid
    fl.range(29,26) = flit.range(342,339); //4 
    //pasid
    fl.range(25,6) = flit.range(338,319);//20
    //netid
    fl.range(5,0) = flit.range(296,291); //6
  
    return fl;

}


//Check if cmd opcode is write command
bool OCxFlit::TLxCmdIsWrite(void)
{
   //According to Opencapi TLx command codes
   //Write family opcodes have bit 5 high only.
   return flit.range(509,509);
}

//Check if cmd opcode is write command
bool OCxFlit::TLxCmdIsRead(void)
{
   //According to Opencapi TLx command codes
   //Read family opcodes have bit 5 high only and not bit 7 (assign actag)
   return flit.range(508,508);
}

bool OCxFlit::TLxCmdIsAssignActag(void)
{
  return flit.range(510,510);
}

dl_t OCxFlit::getDl(void)
{
  dl_t dl;  

  dl =  flit.range(423,422);
  return dl;
}

void OCxFlit::setDl(dl_t dl)
{
  flit.range(423,422) = dl;
  return;
}

void OCxFlit::setBe(addr_t be)
{
  flit.range(418,355) = be;
  return;
}

void OCxFlit::setOpcode(opcode_t opc)
{
  flit.range(511,504) = opc;
  return;
}

void OCxFlit::setEA(addr_t addr)
{
  flit.range(503,440) = addr;
  return;
}

void OCxFlit::setPasid(pasid_t pasid)
{
  flit.range(338,319) = pasid;
  return;
}

void OCxFlit::setActag(actag_t ac)
{
  flit.range(354,343) = ac;
  return;
}

void OCxFlit::setCappTagLocal(tag_t tag)
{
   flit.range(312,297) = tag;
   return;
}

tag_t OCxFlit::getCappTagLocal(void)
{
  tag_t tag;
  
  tag = flit.range(312,297);
  return tag;
}

tag_t OCxFlit::getCappTagOrig(void)
{
  tag_t tag;

  tag =  flit.range(439,424);
  return tag;
}

void OCxFlit::setCappTagOrig(tag_t tag)
{

  flit.range(439,424) = tag;
  return;
}


/* Network handling function functions*/

//returns the network identifier
nid_t OCxFlit::getNetId(void)
{
   nid_t netid;
 
   netid = flit.range(296,291);
   return netid;
}

//sets the network identifier
void OCxFlit::setNetId(nid_t netid)
{
   flit.range(296,291) = netid;
   return;
}




/*DATA Flit handling same across all ocxflit_t formats */





<|start_filename|>afu/thymesisflow/hls_modules/memory_egress/ocx_resp_eng.hpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>


#ifndef OCX_RESP_ENG_HH
#define OCX_RESP_ENG_HH

#include "globals.hpp"
#include "types.hpp"

#include "ocx_flit.hpp"

class TLRespEng{

 public:
   TLRespEng();
                  //Cmd Response from TL
   void RespEngSM(valid_t &enable,\
		           stream<resp_combo_t> &tlresp_fifo_in, \
                  //Data Response from TL 
                  stream<ocxflitbdi_t> &tlresp_data_in, \
                  ocxflit_t  data0lookup[LOOKUPSIZE],\
                  ocxflit_t  data1lookup[LOOKUPSIZE],\
                  ocxflit_t  data2lookup[LOOKUPSIZE],\
                  ocxflit_t  data3lookup[LOOKUPSIZE],\
                  /*OUTPUTS*/
                  //capptag return..
                  stream<tag_t> &lookup_out,\
                  //rty command out
                  stream<ocxflit_t> &rty_do_cmd_out, \
                  //network command out - should be many
                  stream<ocxflit_t> &network_cmd_out0,\
                  count_t &valex_memegress_cmdf_cnt,\
                  count_t &valex_memegress_data_cnt,\
                  count_t &valex_memegress_cmdf_torty,\
                  count_t &valex_memegress_data_torty);

};



#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress_lookup/ocx_flit.hpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>


#ifndef OCX_FLIT_HH
#define OCX_FLIT_HH

/* This class provides all flit parsing functions
   and preserves the datapath maximum size to 512 
   (standard opencapi flit size) and in some cases
   513 (flit size + Bad data indicator bit).
   The only types used here are:
   ocxflitbdi_t: 513 bits (ocxflit + bdi) 
   ocxflit_t: 512 bits ocxflit
   
   according to context. 
   
 */

#include "globals.hpp"
#include "types.hpp"

class OCxFlit {

    private:
          ocxflitbdi_t flit;

    public:
          OCxFlit();
          void fromOCxFlit(ocxflit_t fl);
          ocxflit_t toOCxFlit(void); 
          void fromOCxBdiFlit(ocxflitbdi_t fl);
          ocxflitbdi_t toOCxBdiFlit(void);
          void setBdi(valid_t bdi);
 
          //TL Response CMD flit parsing
          void fromTLRespData(tlrflit_t fl);
          tlrflit_t toTLRespData(void);
          sel_t getTLRespState(void);
          dl_t getTLRespDl(void);
          dp_t getTLRespDp(void);
          tag_t getRespCappTag(void); 
          void setRespOrigCappTag(tag_t tag); 
          tag_t getRespOrigCappTag(void);      
          code_t getRespCode(void);
          opcode_t getRespOpcode(void);
          bool TLRespIsXlateDone(void);
          bool TLRespCodeIsFailure(void);


          //TLx Command CMD flit parsing
          void fromTLxCmd(tlxcflit_t fl);
          tlxcflit_t toTLxCmdFlit(void);
          void fromTLxCStore(tlxscflit_t fl);
          tlxscflit_t toTLxCStore(void);
          bool TLxCmdIsWrite(void);
          bool TLxCmdIsRead(void);
          bool TLxCmdIsAssignActag(void);
          dl_t getDl(void);
          void setOpcode(opcode_t opc);
          void setDl(dl_t dl);
          void setEA(addr_t addr);
          void setBe(addr_t be);
          void setTLxCmdRespAnno(code_t cd);
          void setActag(actag_t ac);
          void setPasid(pasid_t pasid);
          code_t getTLxCmdRespAnno(void);
          tag_t getCappTagLocal(void);
          void setCappTagLocal(tag_t tag);
          void setCappTagOrig(tag_t tag);
          tag_t getCappTagOrig(void);

          //Network part
          nid_t getNetId(void);
          void setNetId(nid_t netid);
};




#endif



<|start_filename|>afu/thymesisflow/hls_modules/memory_egress_lookup/globals.hpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>

#ifndef GLOBALS_HH
#define GLOBALS_HH

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
#include <stdint.h>
#include <cstdlib>
#include <hls_stream.h>
#include <ap_int.h>

using namespace hls;

#define TL_RD_RESPOK 0x4
#define TL_RD_RESPFAIL 0x5
#define TL_WR_RESPOK 0x8
#define TL_WR_RESPFAIL 0x9
#define TL_XLATE_DONE 0x18


#define TLRESP_DATA  0x2
#define TLRESP_CODE_RTY 0x2
#define TLRESP_CODE_PEND 0x8

#define TLRESP_RTY 0x1
#define TLRESP_DATA 0x2

#define LOOKUPSIZE 512

#endif


<|start_filename|>libthymesisflow/cmd/thymesisf-cli.c<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "client.h"
#include <getopt.h>

void helper_memory_attach() {
    fprintf(stderr, "Usage thymesisf-cli attach-memory [options]\n\n");
    fprintf(stderr, "Options (all required):\n\n");
    fprintf(stderr, "    --afu AFU_NAME \n\t\tName of the Accelerated Function "
                    "Unit (example: IBM,RMEM\n");
    fprintf(stderr, "    --cid CIRCUIT_UUID  \n\t\tCircuit Identifier\n");
    fprintf(stderr,
            "    --size MEMORY_SIZE\n\t\t in bytes (bigger than zero) and "
            "multiple of MEMBLOCK_SIZE (%d)\n",
            MEMBLOCK_SIZE);
    // fprintf(stderr,"  --port PORT_NUMBER\n\t\t AFU port to be used (example:
    // 1 or 2)\n");
}

int valid_mem_size(uint64_t size) { return (size % MEMBLOCK_SIZE == 0); }

int handle_memory_attach(const char *cid, const char *afu, const iport_list *pl,
                         const uint64_t size, const char *sock_path) {
    if (cid == 0 || strcmp(cid, "") == 0 || size == 0 || pl == NULL ||
        strcmp(afu, "") == 0) {
        helper_memory_attach();
        return EXIT_FAILURE;
    }

    if (!valid_mem_size(size)) {
        log_info(
            "Memory allocation needs to be a multiple of MEMBLOCK_SIZE (%d)\n",
            MEMBLOCK_SIZE);
        helper_memory_attach();
        return EXIT_FAILURE;
    }

    log_info("Attaching memory - cid: %s afu: %s:%d - size: %ld\n", cid, afu,
             pl->nport, size);

    pmessage mresp = send_attach_memory_msg(cid, afu, pl, size, sock_path);

    if (mresp.status == 100) {
        log_info("Successfully allocated memory - EA: 0x%lx\n", mresp.ea);
        return 0;
    } else {
        log_error("error allocating memory - status: %d\n", mresp.status);
        return 1;
    }
}

void helper_compute_attach() {
    fprintf(stderr, "Usage thymesisf-cli attach-compute [options]\n\n");
    fprintf(stderr, "Options (all required):\n\n");
    fprintf(stderr, "    --afu AFU_NAME \n\t\tName of the Accelerated Function "
                    "Unit (example: IBM,RMEM\n");
    fprintf(stderr, "    --cid CIRCUIT_UUID  \n\t\tCircuit Identifier\n");
    fprintf(stderr,
            "    --size MEMORY_SIZE\n\t\t in bytes (bigger than zero)\n");
    // fprintf(stderr,"  --port PORT_NUMBER\n\t\t AFU port to be used (example:
    // 1 or 2)\n");
    fprintf(stderr,
            "    --ea EFFECTIVE_ADDRESS\n\t\t effective address printed "
            "by the lender\n");
    fprintf(stderr, "    --no-hotplug\n\t\t attach memory without hotplugging to Linux\n");

}

int handle_compute_attach(const char *cid, const char *afu,
                          const iport_list *pl, const uint64_t size,
                          const u_int64_t ea, const char *sock_path, int no_hotplug) {
    if (cid == NULL || strlen(cid) == 0 || size == 0 || pl == NULL ||
        afu == NULL || strlen(afu) == 0 || ea == 0) {
        helper_compute_attach();
        return EXIT_FAILURE;
    }
    if (!valid_mem_size(size)) {
        log_info(
            "Memory allocation needs to be a multiple of MEMBLOCK_SIZE (%u)\n",
            MEMBLOCK_SIZE);
        helper_memory_attach();
        return EXIT_FAILURE;
    }

    log_info("attaching compute - size: %lu - using effective address: %lu\n",
             size, ea);

    pmessage cresp = send_attach_compute_msg(cid, afu, pl, size, ea, no_hotplug, sock_path);

    if (cresp.status == 100) {
        log_info("Successfully attached compute connection\n");
        return 0;
    } else {
        log_info("error allocating memory : %d\n", cresp.status);
        return 1;
    }
}

void helper_memory_detach() {
    fprintf(stderr, "Usage thymesisf-cli detach-memory [options]\n\n");
    fprintf(stderr, "Options (all required):\n\n");
    fprintf(stderr, "    --cid CIRCUIT_UUID  \n\t\tCircuit Identifier\n");
}

int handle_memory_detach(const char *cid, const char *sock_path) {
    if (cid == NULL || strcmp(cid, "") == 0) {
        helper_memory_detach();
        return 1;
    }

    log_info("Detaching memory - cid: %s\n", cid);
    pmessage mresp = send_detach_memory_msg(cid, sock_path);

    if (mresp.status == 200) {
        log_info("Successfully detached memory connection\n");
        return 0;
    } else {
        log_error("Error detaching memory connection - status: %d\n",
                  mresp.status);
        return 1;
    }
}

void helper_compute_detach() {
    fprintf(stderr, "Usage thymesisf-cli detach-compute [options]\n\n");
    fprintf(stderr, "Options (all required):\n\n");
    fprintf(stderr, "    --cid CIRCUIT_UUID  \n\t\tCircuit Identifier\n");
}

int handle_compute_detach(const char *cid, const char *sock_path) {
    if (cid == NULL || strcmp(cid, "") == 0) {
        helper_compute_detach();
        return 1;
    }
    pmessage mresp = send_detach_compute_msg(cid, sock_path);

    if (mresp.status == 200) {
        log_info("Successfully detached compute connection\n");
        return 0;
    } else {
        log_error("Error detaching compute connection - status: %d\n",
                  mresp.status);
        return 1;
    }
}

void common_helper() {
    fprintf(stderr, "Usage thymesisf-cli command [options]\n\n");
    fprintf(stderr, "thymesisf-cli is a command line interface to attach and "
                    "detach disaggregated memory\n\n");
    fprintf(stdout, "Most used commands:\n");
    fprintf(stdout, "    attach-memory - allocate memory on lender machine\n");
    fprintf(stdout,
            "    attach-compute - attach memory on the borrower machine \n");
    fprintf(stdout, "    detach-memory - free memory on lender machine\n");
    fprintf(stdout,
            "    detach-compute - detach memory on the borrower machine\n");
}

void help(const char *command) {

    if (strncmp(command, "attach-memory", MSGTYPE_SIZE))
        helper_memory_attach();
    else if (0 == strncmp(command, "detach-memory", MSGTYPE_SIZE))
        helper_memory_detach();
    else if (0 == strncmp(command, "attach-compute", MSGTYPE_SIZE))
        helper_compute_attach();
    else if (0 == strncmp(command, "detach-compute", MSGTYPE_SIZE))
        helper_compute_detach();
    else
        common_helper();
}

int main(int argc, char **argv) {

    if (argc < 2) {
        common_helper();
        exit(1);
    }

    const char *command = argv[1];

    char *cid = NULL;
    char *afu = NULL;
    uint64_t size = 0;
    uint64_t ea = 0;
    char *sock_path = NULL;
    iport_list *pl = NULL;
    static int no_hotplug = 0;

    static struct option long_options[] = {
        {"size", required_argument, 0, 's'},
        {"afu", required_argument, 0, 'a'},
        {"ea", required_argument, 0, 'e'},
        {"cid", required_argument, 0, 'c'},
        {"no-hotplug", no_argument, &no_hotplug, 1},
        //{"port",required_argument,0,'p'},
    };

    while (1) {
        int option_index = 0;

        int c =
            getopt_long(argc, argv, "s:a:e:c:p:", long_options, &option_index);

        if (c == -1)
            break;

        switch (c) {
        case 's':
            size = strtoull(optarg, NULL, 0);
            break;
        case 'a':
            // afu= (char*)malloc(AFUNAME_SIZE);
            // strcpy(afu , optarg);
            afu = optarg;
            break;
        case 'e':
            ea = strtoull(optarg, NULL, 16);
            break;
        case 'c':
            cid = optarg;
            break;
        }
    }

    // Fixed port 2
    pl = add_port(pl, AFU_PORT);

    if (sock_path == NULL) {
        sock_path = SOCK_PATH;
    }

    if (strcmp("attach-memory", command) == 0) {
        return handle_memory_attach(cid, afu, pl, size, sock_path);
    } else if (strcmp("attach-compute", command) == 0) {
        return handle_compute_attach(cid, afu, pl, size, ea, sock_path, no_hotplug);
    } else if (strcmp("detach-memory", command) == 0) {
        return handle_memory_detach(cid, sock_path);
    } else if (strcmp("detach-compute", command) == 0) {
        return handle_compute_detach(cid, sock_path);
    } else {
        common_helper();
    }
}


<|start_filename|>libthymesisflow/src/iport.c<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file iport.c
#include "iport.h"

void cycle_ports(iport_list *pl) {
    iport_list *plrunner = pl;
    while (plrunner) {
        log_info("selected port: %d\n", plrunner->nport);
        plrunner = plrunner->next;
    }
}

void free_iport_list(iport_list *pl) {

    while (pl) {
        iport_list *pl_next = pl->next;
        free(pl);
        pl = pl_next;
    }
}

iport_list *add_port(iport_list *pl, u_int8_t port_number) {
    if (pl == NULL) {
        pl = (iport_list *)malloc(sizeof(iport_list));
        pl->nport = port_number;
        pl->next = NULL;
        return pl;
    }
    iport_list *new_plhead = (iport_list *)malloc(sizeof(iport_list));
    new_plhead->nport = port_number;
    new_plhead->next = pl;
    return new_plhead;
}

u_int8_t marshal_iports(const iport_list *pl) {

    u_int8_t port_rep = 0;

    const iport_list *plrunner = pl;

    while (plrunner) {
        port_rep += (1 << (plrunner->nport - 1));
        plrunner = plrunner->next;
    }
    return port_rep;
}

iport_list *unmarshal_iports(u_int8_t n) {

    u_int8_t i = 1, pos = 1;

    iport_list *pl = NULL;

    while (i) {

        if (i & n) {
            pl = add_port(pl, pos);
        }

        // Unset current bit and set the next bit in 'i'
        i = i << 1;

        // increment position
        ++pos;
    }

    return pl;
}


<|start_filename|>libthymesisflow/include/agent.h<|end_filename|>
/// @file agent.h
#if !defined(THYMESISFLOW_CMD_H)
#define THYMESISFLOW_CMD_H

#include <sys/socket.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "logger.h"
#include <assert.h>
#include <signal.h>
#include <sys/stat.h>
#include "proto.h"

#ifndef MOCK
#include "stats.h"
#endif

/*! \def BACKLOG
 * \brief max incoming connections
 */
#define BACKLOG 5


void run_agent(const char* sock_path);

#endif


<|start_filename|>libthymesisflow/include/thymesisflow.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file thymesisflow.h
#if !defined(THYMESISFLOW_H)
#define THYMESISFLOW_H

#include "connection.h"
#include "errcode.h"
#include "iport.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//#include "ty_afu.h"

#ifndef MOCK
#include "libocxl.h"
#endif

#define GLOBAL_MMIO_REG_COUNT (0x300 / 8)

#define CTRL_REG 0x000

#define INIT_PROBE_ADDR 0x2000000000000

#define AFU_NAME "IBM,RMEM"

#define MEMBLOCK_SIZE 0x10000000

#define PROBE_PATH "/sys/devices/system/memory/probe"

#define MEMORY_PATH "/sys/devices/system/memory"

#define CACHE_ALIGNMENT 128

/**
 *  Setup AFU and allocate memory
 *  Note: ports are passed but not needed in this current hw implementation
 *
 * @param[in] circuit_id: circuit identifier
 * @param[in] afu_name: AFU name
 * @param[in] iport_list: list of ports to be used for the attachemnt (Currently
 * single port supported)
 * @param[in] size: size of memory to be allocated
 * @param[in] eaptr: effective address to return to the compute node for memory
 * attachment #param[out] error_code
 */
int attach_memory(const char *circuit_id, const char *afu_name,
                  iport_list *ports, const uint64_t size, uint64_t *eaptr);

/**
 *  Setup AFU and attach memory
 *
 * @param[in] circuit_id: circuit identifier
 * @param[in] afu_name: AFU name
 * @param[in] iport_list: list of ports to be used for the attachemnt (Currently
 * single port supported)
 * @param[in] effective_addr: address passed the AFU to attach the remove memory
 * @param[in] size: size of memory to be allocated
 * @param[out] error_code
 */
int attach_compute(const char *circuit_id, const char *afu_name,
                   iport_list *ports, const uint64_t effective_addr,
                   const uint64_t size, int no_hotplug);
/**
 * Disconnect and free allocated memory
 *
 * @param[in] circuit_id: circuit identifier
 * @param[out] error_code
 */
int detach_memory(const char *circuit_id);

/**
 * Register detachment of memory on compute side
 *
 * @param[in] circuit_id: circuit identifier
 * @param[out] error_code
 */
int detach_compute(const char *circuit_id);

#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress_lookup/ocx_cmd_fifo_load.cpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>


#include "ocx_cmd_fifo_load.hpp"
#include "globals.hpp"

CmdFifoLoad::CmdFifoLoad()
{
  return;
}

void CmdFifoLoad::CmdFifoLoadSM(stream<tlrflit_t> &input_fifo,\
		                        tlxscflit_t   cmdlookup[LOOKUPSIZE], \
                                        count_t &valex_memegress_cmddata_ld_cnt,\
					stream<resp_combo_t> &output_fifo)
{
    #pragma HLS pipeline II=1 enable_flush

    OCxFlit tlresp;
    OCxFlit cmdf;
    static count_t valex_memegress_cmddata_ld_cntin = 0x0;
    static resp_combo_t to_send;

    if (!input_fifo.empty()) {
    	      tlresp.fromTLRespData(input_fifo.read());
    	      cmdf.fromTLxCStore(cmdlookup[tlresp.getRespCappTag()]);
              valex_memegress_cmddata_ld_cnt = valex_memegress_cmddata_ld_cntin;
              valex_memegress_cmddata_ld_cntin = valex_memegress_cmddata_ld_cntin + 1;
              to_send.range(252,215) = tlresp.toTLRespData().range(37,0);
              to_send.range(214,0) = cmdf.toTLxCStore().range(214,0);
              output_fifo.write(to_send);
    }

    return;
}




<|start_filename|>afu/thymesisflow/hls_modules/memory_egress/ocx_rty_eng.cpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>


#include "ocx_rty_eng.hpp"


RtyEng::RtyEng()
{
 return;
}


void RtyEng::RtyEngSM(cutimer_t timeout, stream<ocxflit_t> &input_fifo,\
    		       stream<ocxflit_t> &rty_jail,\
                       stream<ocxflit_t> &output_fifo,\
                       count_t &valex_memingress_cmdf_rty_in,\
                       count_t &valex_memingress_cmdf_jail_in,\
                       count_t &valex_memingress_cmdf_rty_out,\
                       count_t &valex_memingress_cmdf_jail_out,\
                       count_t &valex_memingress_data_rty_in,\
                       count_t &valex_memingress_data_rty_out,\
                       count_t &valex_memingress_data_jail_in,\
                       count_t &valex_memingress_data_jail_out)

{


  #pragma HLS pipeline II=1 enable_flush

  static enum State {START = 0,\
	                 DATA,\
                    JAIL_DATA,\
                    } smstate;

  
  static OCxFlit rtycmd;
  static dlsize_t rdata = 0x0;
  ocxflit_t dflt;  
  dl_t fdlt;
  static valid_t xlate_lock = 0x0;
  static cutimer_t timeout_hack = 0x2800;
  static cutimer_t counter = 0x0;
  static valid_t jaildata = 0x0;
  static count_t  valex_memingress_cmdf_rty_inin = 0x0;
  static count_t  valex_memingress_cmdf_jail_inin = 0x0;
  static count_t  valex_memingress_cmdf_rty_outin = 0x0;
  static count_t  valex_memingress_cmdf_jail_outin = 0x0;
  static count_t  valex_memingress_data_rty_inin = 0x0;
  static count_t  valex_memingress_data_rty_outin = 0x0;
  static count_t  valex_memingress_data_jail_inin = 0x0;
  static count_t  valex_memingress_data_jail_outin = 0x0;

  switch(smstate) {

          case START:{
              if (!input_fifo.empty()) {

                  rtycmd.fromOCxFlit(input_fifo.read());
                  valex_memingress_cmdf_rty_in = valex_memingress_cmdf_rty_inin;
                  valex_memingress_cmdf_rty_inin = valex_memingress_cmdf_rty_inin + 1;
                  fdlt = rtycmd.getDl();
                  rdata.range(2,2) = fdlt.range(1,1) & fdlt.range(0,0); //dlt is 11 bit high
                  rdata.range(1,1) = fdlt.range(1,1) & !fdlt.range(0,0);//dlt is 10 bit high
                  rdata.range(0,0) = !fdlt.range(1,1); //It is 01 or 00 then bit high 
                  if ((rtycmd.getTLxCmdRespAnno() == TLRESP_CODE_RTY)) {
                      //Going to jail these flits -- set jail timer if this is the first
                	  //or set the lock for xlate_done
                	  if (xlate_lock == 0x0) {
                		  xlate_lock = 0x1;
                	  }
                	  //send flit to jail
                	  valex_memingress_cmdf_jail_in = valex_memingress_cmdf_jail_inin;
                          valex_memingress_cmdf_jail_inin = valex_memingress_cmdf_jail_inin + 1;
                	  rty_jail.write(rtycmd.toOCxFlit());
                	  if (rtycmd.TLxCmdIsWrite()) {
                		  jaildata = 0x1;
                	      smstate = DATA;
                	  }
                  } else {
                      if (rtycmd.TLxCmdIsWrite()) {
                    	  jaildata = 0x0;
                          smstate = DATA;
                      }//Xlate done arrived - lift lock after this command to re-issue them all.
                       xlate_lock=0x0;
                      //schedule command for re-issue
                       valex_memingress_cmdf_rty_out = valex_memingress_cmdf_rty_outin;
                      valex_memingress_cmdf_rty_outin = valex_memingress_cmdf_rty_outin + 1;
                      output_fifo.write(rtycmd.toOCxFlit());
                  }  //danger here if consequtive page faults some flits might need to wait for another follow up xlate done here.
               } else if (!rty_jail.empty() && /* (counter == 0)*/(xlate_lock == 0x0)) {
            	      //command to exit jail
            	      rtycmd.fromOCxFlit(rty_jail.read());
            	      valex_memingress_cmdf_jail_out = valex_memingress_cmdf_jail_outin;
            	      valex_memingress_cmdf_jail_outin = valex_memingress_cmdf_jail_outin + 1;
                      fdlt = rtycmd.getDl();
            	      rdata.range(2,2) = fdlt.range(1,1) & fdlt.range(0,0); //dlt is 11 bit high
            	      rdata.range(1,1) = fdlt.range(1,1) & !fdlt.range(0,0);//dlt is 10 bit high
            	      rdata.range(0,0) = !fdlt.range(1,1); //It is 01 or 00 then bit high
            	      if (rtycmd.TLxCmdIsWrite()) {
            	         smstate = JAIL_DATA;
            	      }
            	      output_fifo.write(rtycmd.toOCxFlit());
               } 
               break;
           }
           case DATA: {
               if (!input_fifo.empty()) {
                   dflt = input_fifo.read();       
                   if (rdata == 0x1) {
                       smstate = START;
                   } else {
                       rdata = rdata - 1;
                   }
                   valex_memingress_data_rty_in = valex_memingress_data_rty_inin;
                   valex_memingress_data_rty_inin = valex_memingress_data_rty_inin + 1;
                   if(jaildata == 0x1) {
                       valex_memingress_data_jail_in = valex_memingress_data_jail_inin;
                       valex_memingress_data_jail_inin = valex_memingress_data_jail_inin + 1;
                       rty_jail.write(dflt);
                   } else {
                       valex_memingress_data_rty_out = valex_memingress_data_rty_outin + 1;
                       valex_memingress_data_rty_outin = valex_memingress_data_rty_outin + 1;
                       output_fifo.write(dflt);
                   }
                } 
               break;
           }
           case JAIL_DATA: {
                if (!rty_jail.empty()) {
                	if (rdata == 0x1) {
                        smstate = START;
                    } else {
                        rdata = rdata - 1;
                    }
                    valex_memingress_data_jail_out = valex_memingress_data_jail_outin;
                    valex_memingress_data_jail_outin = valex_memingress_data_jail_outin + 1;
                    output_fifo.write(rty_jail.read());
                }
                break;
            }
           default : { break;} 
  }; //end of switch

}


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress/types.hpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>

#ifndef TYPES_HH
#define TYPES_HH

#include <ap_int.h>


typedef ap_uint<253> resp_combo_t; //tlrflit (252:215) + tlxscflit_t (214:0)
typedef ap_uint<32> count_t;
typedef ap_uint<513> ocxflitbdi_t; 
typedef ap_uint<512> ocxflit_t; 
typedef ap_uint<256> ocxflitH_t;
typedef ap_uint<1> valid_t;
typedef ap_uint<199> tlxcflit_t;
typedef ap_uint<38> tlrflit_t;
typedef ap_uint<215> tlxscflit_t;
typedef ap_uint<3> dlsize_t;
typedef ap_uint<36> cutimer_t;
typedef ap_uint<20> pasid_t;
typedef ap_uint<4> stream_t;
typedef ap_uint<12> actag_t;
typedef ap_uint<16> bdf_t;
typedef ap_uint<3> pl_t;
typedef ap_uint<64> addr_t;
typedef ap_uint<4> code_t;
typedef ap_uint<2> dp_t;
typedef ap_uint<1> pad_t;
typedef ap_uint<6> nid_t;
typedef ap_uint<8> opcode_t;
typedef ap_uint<2> dl_t;
typedef ap_uint<16> tag_t;
typedef ap_uint<1> signal_t;
typedef ap_uint<3> sel_t;
typedef ap_uint<10> combo_t;
typedef ap_uint<10> fifocnt_t;
typedef ap_uint<8> token_t;
typedef ap_uint<4> xlatecnt_t;

#endif


<|start_filename|>libthymesisflow/src/client.c<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file client.c
#include "client.h"

pmessage send_cmd(const char *msg, const char *sock_path) {
    int sfd = open_client_connection(sock_path);
    if (write_message(sfd, msg) != 0) {
        log_warn("error sending message\n");
    }

    pmessage rsp;
    read_pmessage(sfd, &rsp);

    if (close(sfd) == -1) {
        log_error("error while closing socket file descriptor\n");
    }
    return rsp;
}

pmessage send_detach_memory_msg(const char *circuitid, const char *sock_path) {
    char *msg = marshal_detach_memory_request(circuitid);

    pmessage rsp = send_cmd(msg, sock_path);

    log_debug("circuitid: %s - type: %s - status: %d\n", rsp.circuitid,
              rsp.msgtype, rsp.status);

    free(msg);
    return rsp;
}

pmessage send_detach_compute_msg(const char *circuitid, const char *sock_path) {
    char *msg = marshal_detach_compute_request(circuitid);

    pmessage rsp = send_cmd(msg, sock_path);

    log_debug("circuitid: %s - type: %s - status: %d\n", rsp.circuitid,
              rsp.msgtype, rsp.status);

    free(msg);
    return rsp;
}

pmessage send_attach_memory_msg(const char *circuitid, const char *afu,
                                const iport_list *ports, const uint64_t size,
                                const char *sock_path) {

    char *msg = marshal_attach_memory_request(circuitid, afu, ports, size);

    pmessage rsp = send_cmd(msg, sock_path);

    log_debug("circuitid: %s - type: %s - afu %s - size %lu  - ea(hex): %lx - "
              "ea(int):%lu - status: %d\n",
              rsp.circuitid, rsp.msgtype, rsp.afu, rsp.size, rsp.ea, rsp.ea,
              rsp.status);

    free(msg);
    return rsp;
}

pmessage send_attach_compute_msg(const char *circuitid, const char *afu,
                                 const iport_list *ports, const uint64_t size,
                                 const uint64_t ea, int no_hotplug, const char *sock_path) {

    char *msg = marshal_attach_compute_request(circuitid, afu, ports, size, ea, no_hotplug);

    pmessage rsp = send_cmd(msg, sock_path);

    log_debug("circuitid: %s - type: %s - afu %s - size %lu  - status: %d\n",
              rsp.circuitid, rsp.msgtype, rsp.afu, rsp.size, rsp.status);

    free(msg);
    return rsp;
}


<|start_filename|>libthymesisflow/src/stats.c<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stats.h"
#include <libocxl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void *_stats_thread(void *arg) {

    uint64_t tx, rx, latency;
    t_args *targs = (t_args *)arg;
    ocxl_err rc;

    int fd = open(THYMESISCOUNT_PATH, O_WRONLY);
    log_info_ext("successfully opened file: %s\n", THYMESISCOUNT_PATH);

    if (targs == NULL) {
        log_warn("%s: thread arguments are null\n", __func__);
        pthread_exit(NULL);
    }
    int cs;

    while (1) {
        if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) {
            log_error("error setting pthread_setcancelstate\n");
            exit(EXIT_FAILURE);
        }

        rc = ocxl_mmio_read64(targs->global, TX_STATS, OCXL_MMIO_LITTLE_ENDIAN,
                              &tx);
        if (rc != OCXL_OK) {
            log_info("Cannot read tx counter, exiting stat thread\n");
            close(fd);
            pthread_exit(NULL);
        }
        rc = ocxl_mmio_read64(targs->global, RX_STATS, OCXL_MMIO_LITTLE_ENDIAN,
                              &rx);
        if (rc != OCXL_OK) {
            log_info("Cannot read rx counter, exiting stat thread\n");
            close(fd);
            pthread_exit(NULL);
        }

        rc = ocxl_mmio_read64(targs->global, LATENCY_STATS,
                              OCXL_MMIO_LITTLE_ENDIAN, &latency);
        if (rc != OCXL_OK) {
            log_info("Cannot read latency counter, exiting stat thread\n");
            close(fd);
            pthread_exit(NULL);
        }

        // latency 64-bit register contains the average
        dprintf(fd, "%ld,%ld,%ld\n", tx, rx,
                (((1UL << 37) - 1) & latency) / (latency >> 37));

        cs = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        if (cs != 0) {
            log_error_ext("error setting pthread_setcancelstate\n");
            close(fd);
            exit(EXIT_FAILURE);
        }
        sleep(targs->period);
    }
}

int tf_init_stats_thread(pthread_t *tid, ocxl_mmio_h global, int period) {

    t_args *targs;

    // Checking values
    if (tid == NULL) {
        fprintf(stderr, "%s: pthread_t is NULL\n", __func__);
        return -1;
    }
    if (global == NULL) {
        fprintf(stderr, "%s: global arg is NULL\n", __func__);
        return -1;
    }
    if (period <= 0) {
        fprintf(stderr, "%s: period is <= 0 \n", __func__);
        return -1;
    }

    targs = malloc(sizeof(t_args));
    if (targs == NULL) {
        fprintf(stderr, "%s: arg allocation failed\n", __func__);
    }

    targs->global = global;
    targs->period = period;

    return pthread_create(tid, NULL, _stats_thread, (void *)targs);
}

int start_stats_thread(pthread_t **tid, ocxl_mmio_h global) {

    unlink(THYMESISCOUNT_PATH);
    log_info_ext("opening thymesisstats file: %s\n", THYMESISCOUNT_PATH);
    int res = mkfifo(THYMESISCOUNT_PATH, 0666);
    if (res != 0) {
        log_error_ext("error opening fifo - err: %d\n", res);
        // set thread it to null so that we don't try to release it during while
        // we delete the connection
        *tid = NULL;
        return -1;
    }
    *tid = (pthread_t *)malloc(sizeof(pthread_t));

    return tf_init_stats_thread(*tid, global, PERIOD_SEC);
}

int stop_stats_thread(pthread_t *tid) {

    if (tid == NULL) {
        log_warn("stat thread reference cannot be null\n");
        return -1;
    }
    void *res;

    int s = pthread_cancel(*tid);
    if (s != 0) {
        log_error("error while cancelling stat thread\n");
        exit(EXIT_FAILURE);
    }

    /* Join with thread to see what its exit status was */
    s = pthread_join(*tid, &res);
    if (s != 0) {
        log_error("error while joining the stat thread");
        exit(EXIT_FAILURE);
    }
    if (res == PTHREAD_CANCELED) {
        log_info("stat thread successfully cancelled\n");
    } else
        log_error("stat thread wasn't cancelled, this should not happen\n");
    free(tid);
    return 0;
}


<|start_filename|>libthymesisflow/src/proto.c<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file proto.c
#include "proto.h"

/**
 * Print serialized message
 *
 * @param[in] msg: serialized proto message
 */
void print_proto_msg(char *msg) {
    for (size_t i = 0; i < MSG_SIZE; i++) {
        // log_info("%c",msg[i]);
        printf("%02x", msg[i]);
    }
    log_info("\n");
}

/**
 * Disconnect and free allocated memory
 *
 * @param[in] msg: serialized proto message
 * @param[out] iport_list: list of AFU ports to be used in the connection
 */
iport_list *get_iports(const char *msg) {
    uint8_t ports = 0;
    memcpy(&ports, msg + IPORT_OFFSET, IPORT_SIZE);
    // log_info("ports hex representation: %x\n", ports);
    return unmarshal_iports(ports);
}

/**
 * Set ports in a serialized message
 *
 * @param[in] msg: serialized proto message
 * @param[out] iport_list: list of AFU ports to be used in the connection
 */
void set_iports(char *msg, const iport_list *ports) {
    uint8_t port_rep = marshal_iports(ports);
    // log_info("setting ports hex rep: %x\n", port_rep);
    memcpy(msg + IPORT_OFFSET, &port_rep, IPORT_SIZE);
}

/**
 * Extract circuit from a serialized message
 *
 * @param[in] msg: serialized proto message
 * @param[in] circuit_id: pointer that will reference a new dynamically
 * allocated array containing the circuit id (remember to free)
 * @param[out] result: 0 for success, -1 in case of error
 */
int get_circuitid(const char *msg, char *circuit_id) {
    // circuit_id needs to be initialized
    if (msg == NULL || circuit_id == NULL) {
        return -1;
    }
    memcpy(circuit_id, msg + CIRCUIT_ID_OFFSET, CIRCUIT_ID_SIZE);
    circuit_id[CIRCUIT_ID_SIZE] = '\0';
    return 0;
}

/**
 * Set circuit id in a message
 *
 * @param[in] msg: serialized proto message
 * @param[in] circtui_id: circuit uuid
 * @param[out] int: status code, 0 if the circuit_id is stored correctly
 */
int set_circuitid(char *msg, const char *circuit_id) {
    if (circuit_id == NULL) {
        return ERR_NULL_PARAM;
    }
    if (msg == NULL) {
        return ERR_MSGNULL;
    }
    memcpy(msg + CIRCUIT_ID_OFFSET, circuit_id, CIRCUIT_ID_SIZE);
    return 0;
}

/**
 * Extract message type pointer from a serialized message
 *
 * @param[in] msg: serialized proto message
 * @param[out] ptr: offset in the message where the circuit_id is stored
 */
int get_msgtype(const char *msg, char *msgtype) {
    if (msg == NULL || msgtype == NULL) {
        return -1;
    }
    memcpy(msgtype, msg + MSGTYPE_OFFSET, MSGTYPE_SIZE);
    msgtype[MSGTYPE_SIZE] = '\0';
    return 0;
}

/**
 * Set message type in a message
 *
 * @param[in] msg: serialized proto message
 * @param[in] msgtype: message type #ATTACH_COMPUTE, #ATTACH_MEMORY,
 * #DETACH_COMPUTE, #DETACH_MEMORY
 * @param[out] int: status code, 0 if the circuit_id is stored correctly
 */
int set_msgtype(char *msg, const char *msgtype) {

    if (msgtype == NULL) {
        return ERR_NULL_PARAM;
    }

    if (msg == NULL) {
        return ERR_MSGNULL;
    }
    if (strcmp(msgtype, COMPUTE_ATTACH) != 0 &&
        strcmp(msgtype, COMPUTE_DETACH) != 0 &&
        strcmp(msgtype, MEMORY_ATTACH) != 0 &&
        strcmp(msgtype, MEMORY_DETACH) != 0 &&
        strcmp(msgtype, CRESPONSE_ATTACH) != 0 &&
        strcmp(msgtype, CRESPONSE_DETACH) != 0 &&
        strcmp(msgtype, MRESPONSE_ATTACH) != 0 &&
        strcmp(msgtype, MRESPONSE_DETACH) != 0) {
        return ERR_MSGTYPE;
    }
    memcpy(msg + MSGTYPE_OFFSET, msgtype, MSGTYPE_SIZE);
    return 0;
}

int get_afu_name(const char *msg, char *afu_name) {
    if (msg == NULL || afu_name == NULL) {
        return -1;
    }
    memcpy(afu_name, msg + AFUNAME_OFFSET, AFUNAME_SIZE);
    afu_name[AFUNAME_SIZE] = '\0';
    return 0;
}

int set_afu(char *msg, const char *afu) {
    if (afu == NULL)
        return ERR_NULL_PARAM;

    if (strlen(afu) == 0)
        return ERR_EMPTY_PARAM;

    if (msg == NULL)
        return ERR_MSGNULL;

    memcpy(msg + AFUNAME_OFFSET, afu, AFUNAME_SIZE);
    return 0;
}

// error if size <=0
uint64_t get_size(const char *msg) {
    if (msg == NULL)
        return ERR_MSGNULL;

    uint64_t size = 0;
    memcpy(&size, msg + MEM_SIZE_OFFSET, MEM_SIZE);
    return size;
}

int set_size(char *msg, uint64_t size) {
    if (msg == NULL)
        return ERR_MSGNULL;
    if (size <= 0)
        return ERR_INT_PARAM;
    if (size % MEMBLOCK_SIZE != 0)
        return ERR_MEMBLOCK_SIZE;

    memcpy(msg + MEM_SIZE_OFFSET, &size, MEM_SIZE);
    return 0;
}

// return effective address
uint64_t get_ea(const char *msg) {
    if (msg == NULL)
        return ERR_MSGNULL;

    uint64_t effective_addr = 0;
    memcpy(&effective_addr, msg + EA_OFFSET, EA_SIZE);
    return effective_addr;
}

int set_ea(char *msg, uint64_t ea) {
    if (msg == NULL)
        return ERR_MSGNULL;
    if (ea == 0)
        return ERR_INT_PARAM;

    memcpy(msg + EA_OFFSET, &ea, EA_SIZE);
    return 0;
}

int set_no_hotplug(char *msg, int no_hotplug) {
    if (msg == NULL)
        return ERR_MSGNULL;
    if (no_hotplug > 1 || no_hotplug < 0)
        return ERR_INT_PARAM;

    memcpy(msg + NO_HOTPLUG_OFFSET, &no_hotplug, NO_HOTPLUG_SIZE);
    return 0;
}

int get_no_hotplug(const char *msg) {
    int no_hotplug = 0;
    memcpy(&no_hotplug, msg + NO_HOTPLUG_OFFSET, NO_HOTPLUG_SIZE);
    return no_hotplug;
}

void set_status(char *msg, int status) {

    log_info("setting status: %d\n", status);
    memcpy(msg + ERROR_OFFSET, &status, ERROR_SIZE);
}

int get_status(const char *msg) {
    int status = 0;
    memcpy(&status, msg + ERROR_OFFSET, ERROR_SIZE);
    return status;
}

char *new_circuitid() {
    return (char *)malloc(sizeof(char) * CIRCUIT_ID_SIZE + 1);
}

char *new_afu_name() { return (char *)malloc(sizeof(char) * AFUNAME_SIZE + 1); }

char *new_msgtype() { return (char *)malloc(sizeof(char) * MSGTYPE_SIZE + 1); }

char *set_unknown_mode_response(char *msg) {
    char *response_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    char *circuit_id = (char *)malloc(sizeof(char) * CIRCUIT_ID_SIZE + 1);
    if (get_circuitid(msg, circuit_id) != 0) {
        log_warn("error fetching circuit from message\n");
    }

    if (set_circuitid(response_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    char *afu_name = new_afu_name();
    if (get_afu_name(msg, afu_name) != 0) {
        log_warn("error fetching afu_name\n");
    }
    set_afu(response_msg, afu_name);
    free(circuit_id);
    free(afu_name);
    return response_msg;
}

char *proto_attach_memory(const char *msg) {
    log_info("allocating memory side...\n");

    char *circuit_id = new_circuitid();
    if (get_circuitid(msg, circuit_id) != 0) {
        log_warn("error fetching circuit from message\n");
    }

    char *afu_name = new_afu_name();
    if (get_afu_name(msg, afu_name) != 0) {
        log_warn("error fetching afu_name\n");
    }
    iport_list *ports = get_iports(msg);

    uint64_t size = get_size(msg);

    log_info("circuit: %s - allocating %lu bytes using afu: %s...\n",
             circuit_id, size, afu_name);

    uint64_t effective_address;

    int res =
        attach_memory(circuit_id, afu_name, ports, size, &effective_address);

    // CHECK ERROR

    log_info("returing effective address: %lx\n", effective_address);

    char *response_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    if (set_circuitid(response_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    if (set_msgtype(response_msg, MRESPONSE_ATTACH) < 0) {
        log_warn("error setting message type \n");
    }
    set_afu(response_msg, afu_name);
    set_iports(response_msg, ports);
    set_size(response_msg, size);
    set_ea(response_msg, effective_address);
    set_status(response_msg, res);

    free_iport_list(ports);
    free(circuit_id);
    free(afu_name);
    return response_msg;
}

char *proto_attach_compute(const char *msg) {

    log_info("allocating compute side...\n");

    char *circuit_id = new_circuitid();
    if (get_circuitid(msg, circuit_id) != 0) {
        log_warn("error fetching circuit from message\n");
    }

    char *afu_name = new_afu_name();
    if (get_afu_name(msg, afu_name) != 0) {
        log_warn("error fetching afu_name\n");
    }

    iport_list *ports = get_iports(msg);

    uint64_t size = get_size(msg);

    uint64_t ea = get_ea(msg);

    int no_hotplug = get_no_hotplug(msg);

    // uint64_t memsize = get_size(msg);

    log_info("requested compute mode - size %lu - effective address: %lu \n",
             size, ea);

    int err = attach_compute(circuit_id, afu_name, ports, ea, size, no_hotplug);

    // error check
    char *response_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    if (set_circuitid(response_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    if (set_msgtype(response_msg, CRESPONSE_ATTACH) < 0) {
        log_warn("error setting message type \n");
    }
    set_size(response_msg, size);
    set_afu(response_msg, afu_name);
    set_iports(response_msg, ports);
    set_status(response_msg, err);
    free_iport_list(ports);

    free(circuit_id);
    free(afu_name);
    return response_msg;
}

char *proto_detach_compute(const char *msg) {
    char *response_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    char *circuit_id = new_circuitid();
    if (get_circuitid(msg, circuit_id) != 0) {
        log_warn("error fetching circuit from message\n");
    }

    log_info("deleting compute connection- cid: %s \n", circuit_id);

    if (set_circuitid(response_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    int err = detach_compute(circuit_id);
    if (set_msgtype(response_msg, CRESPONSE_DETACH) < 0) {
        log_warn("error setting message type \n");
    }
    set_status(response_msg, err);

    free(circuit_id);

    return response_msg;
}

char *proto_detach_memory(const char *msg) {
    if (msg == NULL) {
        log_warn("message should not be NULL\n");
    }
    char *response_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    char *circuit_id = new_circuitid();
    if (get_circuitid(msg, circuit_id) != 0) {
        log_warn("error fetching circuit from message\n");
    }

    log_info("deleting memory connection - cid: %s \n", circuit_id);

    if (set_circuitid(response_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    if (set_msgtype(response_msg, MRESPONSE_DETACH) < 0) {
        log_warn("error setting message type \n");
    }
    int err = detach_memory(circuit_id);
    set_status(response_msg, err);
    free(circuit_id);

    return response_msg;
}

char *new_proto_msg() {
    char *response_msg = (char *)malloc(sizeof(char) * MSG_SIZE);
    // fill with error message
    return response_msg;
}

char *marshal_detach_memory_request(const char *circuit_id) {
    char *request_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    if (set_circuitid(request_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    if (set_msgtype(request_msg, MEMORY_DETACH) < 0) {
        log_warn("error setting message type \n");
    }

    return request_msg;
}

char *marshal_detach_compute_request(const char *circuit_id) {
    char *request_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    if (set_circuitid(request_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    if (set_msgtype(request_msg, COMPUTE_DETACH) < 0) {
        log_warn("error setting message type \n");
    }

    return request_msg;
}

char *marshal_attach_memory_request(const char *circuit_id, const char *afu,
                                    const iport_list *ports,
                                    const uint64_t memsize) {
    char *request_msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    if (set_circuitid(request_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");

    if (set_msgtype(request_msg, MEMORY_ATTACH) < 0) {
        log_warn("error setting message type \n");
    }
    set_afu(request_msg, afu);
    set_iports(request_msg, ports);
    set_size(request_msg, memsize);
    return request_msg;
}

char *marshal_attach_compute_request(const char *circuit_id, const char *afu,
                                     const iport_list *ports,
                                     const uint64_t memsize,
                                     const uint64_t ea,
                                     int no_hotplug) {
    char *request_msg = (char *)malloc(sizeof(char) * MSG_SIZE);
    if (set_circuitid(request_msg, circuit_id) < 0)
        log_warn("error setting message circuit id\n");
    if (set_msgtype(request_msg, COMPUTE_ATTACH) < 0) {
        log_warn("error setting message type \n");
    }
    set_afu(request_msg, afu);
    set_iports(request_msg, ports);
    set_size(request_msg, memsize);
    set_ea(request_msg, ea);
    set_no_hotplug(request_msg, no_hotplug);
    return request_msg;
}

void unmarshal_response(char *msg, pmessage *rsp) {

    char *circuit_id = new_circuitid();
    if (get_circuitid(msg, circuit_id) != 0) {
        log_warn("error fetching circuit from message\n");
    }
    strncpy(rsp->circuitid, circuit_id, CIRCUIT_ID_SIZE + 1);
    // log_info("circuitid: %s\n", rsp->circuitid);

    char *afu_name = new_afu_name();
    if (get_afu_name(msg, afu_name) != 0) {
        log_warn("error fetching afu_name\n");
    }
    strncpy(rsp->afu, afu_name, AFUNAME_SIZE + 1);
    // log_info("afu_name: %s\n", rsp->afu);

    char *msgtype = new_msgtype();
    if (get_msgtype(msg, msgtype) != 0) {
        log_warn("error fetching msgtype\n");
    }
    strncpy(rsp->msgtype, msgtype, MSGTYPE_SIZE + 1);
    // log_info("msgtype: %s\n", rsp->circuitid);

    free(msgtype);
    rsp->size = get_size(msg);
    rsp->ea = get_ea(msg);
    rsp->status = get_status(msg);
    rsp->no_hotplug = get_no_hotplug(msg);
    free(afu_name);
    free(circuit_id);
}

char *read_message(int fd) {
    char *msg = (char *)malloc(sizeof(char) * MSG_SIZE);

    for (size_t i = 0; i < MSG_SIZE; i++) {
        int num_read = recv(fd, msg + i, MSG_SIZE, 0);
        i += num_read;
    }

    return msg;
}

int read_pmessage(int fd, pmessage *resp) {

    char *resp_msg = read_message(fd);

    if (resp_msg == NULL) {
        return -1;
    }
    unmarshal_response(resp_msg, resp);

    free(resp_msg);

    return 0;
}

int write_message(int fd, const char *msg) {
    for (size_t i = 0; i < MSG_SIZE; i++) {
        int num_read = write(fd, msg, MSG_SIZE);
        i += num_read;
    }

    return 0;
}

int open_client_connection(const char *sock_path) {
    if (sock_path == NULL || 0 == strlen(sock_path))
        return -1;

    struct sockaddr_un addr;
    int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd == -1) {
        log_info("error creating socket\n");
        return -1;
    }
    memset(&addr, 0, sizeof(addr.sun_path) - 1);

    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);

    if (connect(sfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) ==
        -1)
        return -1;
    return sfd;
}


<|start_filename|>libthymesisflow/include/connection.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file connection.h
#if !defined(CONNECTION_H)
#define CONNECTION_H

#include "errcode.h"
#include "iport.h"
#include "logger.h"
#include "protoconst.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef MOCK
#include "libocxl.h"

#define AURORA_CTRL 0x78

#define AURORA_CHAN 0x02

#define MEM_SEG0_CONFIG 0x20

#define MEM_SEG0_OFFSET 0x0

#define MEM_SEG1_CONFIG 0x28

#define MEM_SEG1_OFFSET (1UL << 40)
#include "stats.h"

typedef union {
    struct {
        unsigned int test_enable : 1;
        unsigned int trigger_sfw_intrp : 1;
        unsigned int ignore_nomatch_on_read : 1;
        unsigned int unassigned1 : 1;
        unsigned int enable_pipeline : 1;
    } reg;
    uint64_t val;
} global_mmio_control;

#endif

/**
 * Contains all variables related to an active remote memory allocation
 */
struct connection_s {
    char circuit_id[CIRCUIT_ID_SIZE + 1];
    char afu_name[AFUNAME_SIZE];
    uint64_t size;
    unsigned char *ea;
    struct connection_s *next;
    int no_hotplug;

#ifndef MOCK
    ocxl_afu_h afu;
    pthread_t *stat_tid;
    ocxl_mmio_h global;
    ocxl_mmio_h pp_mmio;
#endif
};

typedef struct connection_s connection;

connection *clist;

/**
 * Add a new connection
 *
 * @param[in] connection: connection to be added
 * @param[out] outcome: 0 if operations finished with success
 */
int add_conn(connection *conn);

/**
 * Get connection from circuit_id
 *
 * @param[in] circuit_id: circuit identifier
 * @param[out] connection: first connection having the specified circuit id
 */
connection *get_conn(const char *circuit_id);

/**
 * Delete first circuit matching cirguit_id
 *
 * @param[in] circuit_id: circuit identifier
 * @param[out] outcome: 0 if operations finished with success
 */
int del_conn(const char *circuit_id);

/**
 * List all active connections
 */
void list_connections();

/**
 * Free dynamically allocated connection struc
 *
 * @param[in] connection: connection to be freed
 * @param[out] outcome: 0 if operations finished with success
 */
int free_conn(connection *conn);

/**
 * Dynamically allocate a new connection
 *
 * @param[in] circuit_id: circuit identifier
 * @param[in] afu_name: AFU to be used
 * @param[in] size: disaggregated memory size
 * @param[in] no_hotplug: no_hotplug flag value
 * @param[out] connection: connection to be freed
 */
connection *new_conn(const char *circuit_id, const char *afu_name,
                     const uint64_t size, int no_hotplug);

int setup_afu_compute(connection *conn, uint64_t effective_addr,
                      iport_list *ports);

int setup_afu_memory(connection *conn);

#define CONN_SUCCESS 0

#define CONN_DUP 1
#define CONN_NULL 2

#define CONN_NOT_FOUND 3

#endif


<|start_filename|>libthymesisflow/include/logger.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file logger.h

#ifndef LOGGER_H
#define LOGGER_H

#include <libgen.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define ERROR_TAG "ERROR"
#define WARN_TAG "WARN"
#define INFO_TAG "INFO"
#define DEBUG_TAG "DEBUG"

/**
 * Get current time
 *
 * @param[out] time_string: string reporting the time as %Y-%m-%d %H:%M:%S
 */
static inline char *current_time() {
    static char time_string[64];
    time_t rawtime;
    struct tm *timeinfo;

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    strftime(time_string, 64, "%Y-%m-%d %H:%M:%S", timeinfo);

    return time_string;
}

static inline void print_log(const char *tag, const char *curr_time,
                             const char *message, va_list args) {
    printf("%s [%s] ", curr_time, tag);
    vprintf(message, args);
    fflush(stdout); // printf("\n");
}

static inline void log_info(char *message, ...) {
    va_list args;
    va_start(args, message);
    print_log(INFO_TAG, current_time(), message, args);
    va_end(args);
}
static inline void log_debug(char *message, ...) {
    va_list args;
    va_start(args, message);
    print_log(DEBUG_TAG, current_time(), message, args);
    va_end(args);
}

static inline void log_warn(char *message, ...) {
    va_list args;
    va_start(args, message);
    print_log(WARN_TAG, current_time(), message, args);
    va_end(args);
}

static inline void log_error(char *message, ...) {
    va_list args;
    va_start(args, message);
    print_log(ERROR_TAG, current_time(), message, args);
    va_end(args);
}

static inline void print_log_ext(const char *tag, const char *curr_time,
                                 const char *filename, int line,
                                 const char *message, ...) {
    va_list args;
    va_start(args, message);
    printf("%s [%s] %s:%d, ", curr_time, tag, filename, line);
    vprintf(message, args);
    va_end(args);
    fflush(stdout);
}

#define log_info_ext(message, args...)                                         \
    print_log_ext(INFO_TAG, current_time(), basename(__FILE__), __LINE__,      \
                  message, ##args)

#define log_debug_ext(message, args...)                                        \
    print_log_ext(DEBUG_TAG, current_time(), basename(__FILE__), __LINE__,     \
                  message, ##args)

#define log_warn_ext(message, args...)                                         \
    print_log_ext(WARN_TAG, current_time(), basename(__FILE__), __LINE__,      \
                  message, ##args)

#define log_error_ext(message, args...)                                        \
    print_log_ext(ERROR_TAG, current_time(), basename(__FILE__), __LINE__,     \
                  message, ##args)

#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress/ocx_resp_eng.cpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *!
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org.
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME> <EMAIL>, <NAME>



#include "ocx_resp_eng.hpp"

TLRespEng::TLRespEng()
{
  return;
}


void TLRespEng::RespEngSM( valid_t &enable,\
		           stream<resp_combo_t> &tlresp_fifo_in,\
                           stream<ocxflitbdi_t> &tlresp_data_in,\
			   ocxflit_t  data0lookup[LOOKUPSIZE],\
			   ocxflit_t  data1lookup[LOOKUPSIZE],\
			   ocxflit_t  data2lookup[LOOKUPSIZE],\
			   ocxflit_t  data3lookup[LOOKUPSIZE],\
                           /*OUTPUTS*/
                           stream<tag_t> &lookup_out,\
                           stream<ocxflit_t> &rtry_do_cmd_out,\
                           //1 interfaces for now - that should be preprocessor scalable
                           stream<ocxflit_t> &network_cmd_out0,\
                           count_t &valex_memegress_cmdf_cnt,\
                           count_t &valex_memegress_data_cnt,\
                           count_t &valex_memegress_cmdf_torty,\
                           count_t &valex_memegress_data_torty)
{

  #pragma HLS pipeline II=1 enable_flush


  static enum State { INIT = 0, GET_CMD , GET_DATA} smstate;



  OCxFlit cmdf;
  OCxFlit dataf;
  ocxflit_t datar;
  static OCxFlit tlresp;
  static OCxFlit tlrespw;
  static OCxFlit tlrespw1;
  static tag_t capptag_count = 0x1;
  dl_t cdlt;
  dl_t fdlt;
  dl_t respdl;
  dl_t origdl;
  dp_t respdp;
  static valid_t keeplookupentry = 0x0;
  static valid_t respdataflag = 0x0;
  static tag_t localtag = 0x0;
  static dlsize_t cdata = 0x0;
  static dlsize_t cdata_count = 0x0;
  nid_t outnid;
  tag_t origtag;
  resp_combo_t tlresp_combo;
  tlrflit_t tlrespflit_received;
  tlxscflit_t tlxcmd_store_received;

  static count_t valex_memegress_cmdf_cntin = 0x0;
  static count_t valex_memegress_data_cntin = 0x0;
  static count_t valex_memegress_cmdf_tortyin = 0x0;
  static count_t valex_memegress_data_tortyin = 0x0;

  switch(smstate) {
        /*INIT loads CAPPTAG FIFO with tokens at initialization */
        case INIT: {
           if (enable == 0x1) {
              if (capptag_count == 0x200) {
                 smstate = GET_CMD;
              }
              lookup_out.write(capptag_count);
              capptag_count = capptag_count + 1;
           }
           break;
        }
        case GET_CMD: {
           if(!tlresp_fifo_in.empty() /*&& (enable == 0x1)*/) {
               //pull new response flit from fifo
        	   valex_memegress_cmdf_cnt  = valex_memegress_cmdf_cntin;
               valex_memegress_cmdf_cntin = valex_memegress_cmdf_cntin + 1;
               //Get Combo flit
               tlresp_combo = tlresp_fifo_in.read();
		       tlrespflit_received.range(37,0) = tlresp_combo.range(252,215);
		       tlxcmd_store_received.range(214,0) = tlresp_combo.range(214,0);
               tlresp.fromTLRespData(tlrespflit_received);
               cmdf.fromTLxCStore(tlxcmd_store_received);
               //Store Orig tag in case it will be needed later.
               localtag = tlresp.getRespCappTag();
               //Store response dl and cmd dl
               respdl = tlresp.getTLRespDl();
               //store original dl to work with the dp trick...
               origdl = cmdf.getDl();
               //get dp
               respdp = tlresp.getTLRespDp();
               /* NOTE: This is P9 specific here
				* and this behaviour is copied from memcpy3
				* design. For 256B requests only the host
				* might respond with 2 seperate 128B requests
				* instead of a single 256B one. It will use DP
				* to designate the second response (i.e. dp=1).
				* So if we receive a response with DL that does
				* not match the original command we assert keeplookup
				* to prevent eviction from lookuptables later. OpenCAPI
				* v3.0 spec allows any combination for dl/dp - but if
				* we check them currently this might hinder  timing closure.
                */
               keeplookupentry = (respdl != origdl) && (respdp == 0x0);
               //prepare flit for pushing further
               origtag = cmdf.getCappTagOrig();
               tlresp.setRespOrigCappTag(origtag);
               outnid = cmdf.getNetId();
               tlresp.setNetId(outnid);
               //TL Resp command handling below
               if (tlresp.getTLRespState().range(0,0)) {
                   //Annotating Resp code in the pgsize field -- which is not _currently_ used
            	   if(tlresp.TLRespIsXlateDone()) {
            	       cmdf.setTLxCmdRespAnno(0x0);
            	   } else {
                       cmdf.setTLxCmdRespAnno(tlresp.getRespCode());
            	   }
                   /* Remark: Rewriting the command capptag as it seems that it fails in generated verilog simulation
                    * to get written to BRAM during cmd issue step. The rest of the
                    * fields seem to be available correctly.
					*/
                   cmdf.setCappTagLocal(tlresp.getRespCappTag());
                   /* Write rty_cmd out to retry command
                    * Check if you will be pulling flits.
					*/
                   cdata.range(2,2) = origdl.range(1,1) & origdl.range(0,0); //dlt is 11 bit high
                   cdata.range(1,1) = origdl.range(1,1) & !origdl.range(0,0);//dlt is 10 bit high
                   cdata.range(0,0) = !origdl.range(1,1); //It is 01 or 00 then bit high
                   cdata_count = 0x1; //Initialize counter
                   valex_memegress_cmdf_torty = valex_memegress_cmdf_tortyin;
                   valex_memegress_cmdf_tortyin = valex_memegress_cmdf_tortyin + 1;
                   rtry_do_cmd_out.write(cmdf.toOCxFlit());
                   if(cmdf.TLxCmdIsWrite()) {
                       respdataflag = 0; //Don't pull flits from host data will come from ltables
                       smstate = GET_DATA;
                   }
               } else if (tlresp.getTLRespState().range(1,1)) {
                   //prepare state machine to pull flits
                   respdataflag = 1;
                   //Get information from response.
                   cdata.range(2,2) = respdl.range(1,1) & respdl.range(0,0); //dlt is 11 bit high
                   cdata.range(1,1) = respdl.range(1,1) & !respdl.range(0,0);//dlt is 10 bit high
                   cdata.range(0,0) = !respdl.range(1,1); //It is 01 or 00 then bit high
                   cdata_count = 0x1; //Initialize counter
                   smstate = GET_DATA;
                   network_cmd_out0.write(tlresp.toOCxFlit());
               } else if (tlresp.getTLRespState().range(2,2)) { //Flit with nodata (i.e WR_OK) or unrecoverable error.
                   //crossbar here -- WOK or others return capptag
            	   lookup_out.write(tlresp.getRespCappTag());
                   network_cmd_out0.write(tlresp.toOCxFlit());
               }

             }
             break;
        }
        case GET_DATA: {
            /* if respdataflag is set we are serving
             * fresh response data that come from the host.
             */
            if(respdataflag) {
                 if(!tlresp_data_in.empty()) {
                     if (cdata != 0x1) {
                         cdata = cdata - 1;
                     } else {
                         //Return capptag if allowed
                         if (!keeplookupentry) {
                             lookup_out.write(localtag);
                         }
                         smstate = GET_CMD;
                     }
                     valex_memegress_data_cnt = valex_memegress_data_cntin;
                     valex_memegress_data_cntin = valex_memegress_data_cntin + 1;
                     network_cmd_out0.write(tlresp_data_in.read());
                 }
             } else {
            	  valex_memegress_data_torty = valex_memegress_data_tortyin;
                  valex_memegress_data_tortyin = valex_memegress_data_tortyin + 1;
                  //Pulling dataflits from local store first flit at datalookup0
                  if (cdata_count == 0x1) {
                	 datar = data0lookup[(localtag/*^ADDR_MASK*/)];
                     rtry_do_cmd_out.write(datar);
                  } else if (cdata_count == 0x2) {
                	 datar = data1lookup[(localtag/*^ADDR_MASK*/)];
                     rtry_do_cmd_out.write(datar);
                  } else if (cdata_count == 0x3) {
                	 datar = data2lookup[(localtag/*^ADDR_MASK*/)];
                     rtry_do_cmd_out.write(datar);
                  } else { //cdata_count 0x4
                	 datar = data3lookup[(localtag/*^ADDR_MASK*/)];
                     rtry_do_cmd_out.write(datar);
                  }
                  if (cdata_count == cdata) {
                      //Done jump to GET_CMD again
                      smstate = GET_CMD;
                  }
                  cdata_count = cdata_count + 1;
             }
            break;
        }

        default: {break;}
   }; //end of switch

}





<|start_filename|>libthymesisflow/Makefile<|end_filename|>
CC=gcc
CCFLAGS=-fPIC -Wall 
#LDFLAGS=-shared
#LIBOCXL_DIR=../libocxl/lib

# mock thymesisflow backend
MOCK ?=0

IDIR=include
ODIR=obj
BINDIR=bin
LIB_DIR=lib
TESTBIN_DIR=testbin

OUT_DIRS= $(ODIR) $(BINDIR) $(LIB_DIR) $(TESTBIN_DIR)

CCFLAGS+=-I $(IDIR)/
CCFLAGS+= -I/usr/include/


CORE_SRCS := $(wildcard src/*.c)
CORE_OBJ:= $(addprefix $(ODIR)/,$(notdir $(CORE_SRCS:.c=.o)))

TEST_SRCS := $(wildcard unittest/*.c)
TEST_BIN:= $(addprefix $(TESTBIN_DIR)/,$(notdir $(TEST_SRCS:.c=)))

CMD_SRCS := $(wildcard cmd/*.c)
CMD_BIN:= $(addprefix $(BINDIR)/,$(notdir $(CMD_SRCS:.c=)))


VPATH= src cmd unittest

GIT_VERSION=`git rev-parse --abbrev-ref HEAD`

ifeq ($(DEBUG),1)
	CCFLAGS+= -g -O0
else
	CCFLAGS+= -O2
endif

ifeq ($(MOCK),1)
	CCFLAGS+= -DMOCK
else
	LDFLAGS+= -L$(LIBOCXL_DIR) -locxl -lpthread -locxl
endif

ifeq ($(PREFIX),)
	PREFIX := /usr/local
endif

all: make_dirs libthymesisflow cmds

make_dirs: 
	$(info making output directories: $(OUT_DIRS))
	mkdir -p $(OUT_DIRS)

$(ODIR)/%.o: %.c 
	$(CC) $(CCFLAGS) -c -o $@ $< $(LDFLAGS)

libthymesisflow: $(CORE_OBJ)
	ar rcs lib/$@.a $(CORE_OBJ)


$(TESTBIN_DIR)/%: $(ODIR)/%.o
	$(CC) $(CCFLAGS) -o $@ $^ -L$(LIB_DIR) -lthymesisflow $(LDFLAGS)

tests: $(TEST_BIN)


$(BINDIR)/%: $(ODIR)/%.o
	$(CC) $(CCFLAGS) -o $@ $^ -L$(LIB_DIR) -lthymesisflow $(LDFLAGS)

cmds: $(CMD_BIN) 

docker:
	docker build --network=host -t thymesisflow:$(GIT_VERSION) .


.PHONY: all clean clean_tests cmds tests docs

cscope:
	find ./* -type f \( -name \*.c -o -name \*.h \) > ./cscope.files
	cscope -b -q

clean:
	rm -rf $(OUT_DIRS)
	rm -rf cscope.files
	rm -rf cscope.in.out
	rm -rf cscope.out
	rm -rf cscope.po.out



<|start_filename|>libthymesisflow/include/proto.h<|end_filename|>
/*
 * Copyright 2019 International Business Machines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/// @file proto.h
#if !defined(THYMESISFLOW_PROTO_H)
#define THYMESISFLOW_PROTO_H

#include "errcode.h"
#include "iport.h"
#include "logger.h"
#include "protoconst.h"
#include "thymesisflow.h"
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>

typedef struct proto_response {
    char circuitid[CIRCUIT_ID_SIZE + 1];
    char msgtype[MSGTYPE_SIZE + 1];
    char afu[AFUNAME_SIZE + 1];
    int status;
    uint64_t size;
    uint64_t ea;
    int no_hotplug;
} pmessage;

/**
 * Open linux socket connection towards the server
 *
 * @param[in] circuit_id: circuit identifier
 * @param[out] sfd: socket file descriptor if success, -1 if failure
 */
int open_client_connection(const char *sock_path);

/**
 * Print the content of the a message sent on the socket. Used for DEBUG
 * purposes
 *
 * @param[in] msg: message sent through the socket
 */
void print_proto_msg(char *msg);

/**
 * Print the content of the a message sent on the socket. Used for DEBUG
 * purposes
 *
 * @param[in] msg: message sent through the socket
 * @param[in] rsp: pointer to data struct that will contain the unmarshalled
 * response
 */
void unmarshal_response(char *msg, pmessage *rsp);

/**
 * Read message from from the socket connection and unmarshal the content
 *
 * @param[in] cfd: socket connection
 * @param[in] rsp: pointer to data struct that will contain the unmarshalled
 * response
 */
int read_pmessage(int cfd, pmessage *rsp);

/**
 * Read message from the socket connection
 *
 * @param[in] cfd: socket connection
 * @param[in] msg: array containing the marshalled response
 */
char *read_message(int cfd);

/**
 * Write message on a socket connection
 *
 * @param[in] fd: socket connection
 * @param[in] msg: array containing the marshalled response
 * @param[out] result: 0 if success, -1 if error in writing the message
 */
int write_message(int fd, const char *msg);

/**
 * Marshal request to setup new thymesisflow on memory-stealing node
 *
 * @param[in] circuitid: circuit uuid
 * @param[in] afu: name of the Accelerated Function Unit
 * @param[in] ports: AFU port to be used
 * @param[in] size: memory allocation size (in bytes)
 * @param[out] msg: array containing the marshalled request
 */
char *marshal_attach_memory_request(const char *circuitid, const char *afu,
                                    const iport_list *ports,
                                    const uint64_t size);

/**
 * Marshal request to setup new thymesisflow on memory-stealing node
 *
 * @param[in] circuitid: circuit uuid
 * @param[in] afu: name of the Accelerated Function Unit
 * @param[in] ports: AFU port to be used
 * @param[in] size: memory allocation size (in bytes)
 * @param[in] ea: effective address used for memory access translation
 * @param[in] no_hotplug: don't hoplug memory
 * @param[out] msg: array containing the marshalled request
 */
char *marshal_attach_compute_request(const char *circuitid, const char *afu,
                                     const iport_list *ports,
                                     const uint64_t memsize, const uint64_t ea, int no_hotplug);

/**
 * Marshal request to tear down a thymesisflow on memory-stealing node
 *
 * @param[in] circuitid: circuit uuid associate to the connection to tear down
 * @param[out] msg: array containing the marshalled request
 */
char *marshal_detach_memory_request(const char *circuitid);

/**
 * Marshal request to tear down a thymesisflow on comute node
 *
 * @param[in] circuitid: circuit uuid associate to the connection to tear down
 * @param[out] msg: array containing the marshalled request
 */
char *marshal_detach_compute_request(const char *circuitid);

/**
 * Perform the steps required to setup a new thymesisflow on the compute node
 *
 * @param[in] msg: array containing the marshalled request
 * @param[out] msg: array containing the marshalled response
 */
char *proto_attach_compute(const char *msg);

/**
 * Perform the steps required to setup a new thymesisflow on the memory-stealing
 * node
 *
 * @param[in] msg: array containing the marshalled request
 * @param[out] msg: array containing the marshalled response
 */
char *proto_attach_memory(const char *msg);

/**
 * Perform the steps required to tear down a thymesisflow on the memory-stealing
 * node
 *
 * @param[in] msg: array containing the marshalled request
 * @param[out] msg: array containing the marshalled response
 */
char *proto_detach_memory(const char *msg);

/**
 * Perform the steps required to setup a new thymesisflow on the compute node
 *
 * @param[in] msg: array containing the marshalled request
 * @param[out] msg: array containing the marshalled response
 */
char *proto_detach_compute(const char *msg);

/**
 * Return error message if the message type is not recognized
 *
 * @param[in] msg: array containing the marshalled request
 * @param[out] msg: array containing the marshalled response
 */
char *set_unknown_mode_response(char *msg);

/**
 * Dynamically allocate memory for a protocol message
 *
 * @param[out] ptr: return a pointer to newly allocated memory
 */
char *new_proto_msg();

#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress/ocx_rty_eng.hpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>


#ifndef OCX_RTY_ENG_HH
#define OCX_RTY_ENG_HH

#include "globals.hpp"
#include "types.hpp"

#include "ocx_flit.hpp"

class RtyEng {

   public:
          
      RtyEng();
       //Get Input from Retry engine and accordingly forwards to command engine
      void  RtyEngSM(cutimer_t timeout,\
                       stream<ocxflit_t> &input_fifo, \
		       stream<ocxflit_t> &rty_jail,\
                       stream<ocxflit_t> &output_fifo,
                       count_t &valex_memingress_cmdf_rty_in,\
                       count_t &valex_memingress_cmdf_jail_in,\
                       count_t &valex_memingress_cmdf_rty_out,\
                       count_t &valex_memingress_cmdf_jail_out,\
                       count_t &valex_memingress_data_rty_in,\
                       count_t &valex_memingress_data_rty_out,\
                       count_t &valex_memingress_data_jail_in,\
                       count_t &valex_memingress_data_jail_out); 



};





#endif


<|start_filename|>afu/thymesisflow/hls_modules/memory_egress/ocx_memory_egress_top.cpp<|end_filename|>
// *!***************************************************************************
// *! Copyright 2019 International Business Machines
// *!
// *! Licensed under the Apache License, Version 2.0 (the "License");
// *! you may not use this file except in compliance with the License.
// *! You may obtain a copy of the License at
// *! http://www.apache.org/licenses/LICENSE-2.0 
// *!
// *! The patent license granted to you in Section 3 of the License, as applied
// *! to the "Work," hereby includes implementations of the Work in physical form.  
// *!
// *! Unless required by applicable law or agreed to in writing, the reference design
// *! distributed under the License is distributed on an "AS IS" BASIS,
// *! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// *! See the License for the specific language governing permissions and
// *! limitations under the License.
// *! 
// *! The background Specification upon which this is based is managed by and available from
// *! the OpenCAPI Consortium.  More information can be found at https://opencapi.org. 
// *!***************************************************************************
// Module designer: <NAME>
// Backup: <NAME>, <NAME>

#include "globals.hpp"

#include "types.hpp"
#include "ocx_flit.hpp"
#include "ocx_resp_eng.hpp"
#include "ocx_rty_eng.hpp"


                         /*Inputs*/
void ocx_memory_egress_top(cutimer_t &rtry_timeout,\
		                    valid_t &enable,\
                           stream<resp_combo_t> tl_fifo_resp,\
                           stream<ocxflitbdi_t> &tl_fifo_data,\
                           /*External BRAM Input Interfaces */
			   ocxflit_t data0lookup_in[LOOKUPSIZE],\
			   ocxflit_t data1lookup_in[LOOKUPSIZE],\
			   ocxflit_t data2lookup_in[LOOKUPSIZE],\
			   ocxflit_t data3lookup_in[LOOKUPSIZE],\
                           /*outputs*/
                           stream<tag_t> &capptag_fifo_out,\
                           stream<ocxflit_t> &rty_issue_fifo_out,\
			   stream<ocxflit_t> &net_resp_out,\
                           count_t &valex_memegress_cmdf_cnt,\
                           count_t &valex_memegress_data_cnt,\
                           count_t &valex_memegress_cmdf_torty,\
                           count_t &valex_memegress_data_torty,\
                           count_t &valex_memingress_cmdf_rty_in,\
                           count_t &valex_memingress_cmdf_jail_in,\
                           count_t &valex_memingress_cmdf_rty_out,\
                           count_t &valex_memingress_cmdf_jail_out,\
                           count_t &valex_memingress_data_rty_in,\
                           count_t &valex_memingress_data_rty_out,\
                           count_t &valex_memingress_data_jail_in,\
                           count_t &valex_memingress_data_jail_out)
{


#pragma HLS INTERFACE ap_none register port=rtry_timeout
#pragma HLS INTERFACE ap_none register port=enable

#pragma HLS INTERFACE bram register port=data0lookup_in
#pragma HLS RESOURCE variable=data0lookup_in core=RAM_1P_BRAM latency=1

#pragma HLS INTERFACE bram register port=data1lookup_in
#pragma HLS RESOURCE variable=data1lookup_in core=RAM_1P_BRAM latency=1

#pragma HLS INTERFACE bram register port=data2lookup_in
#pragma HLS RESOURCE variable=data2lookup_in core=RAM_1P_BRAM latency=1

#pragma HLS INTERFACE bram register port=data3lookup_in
#pragma HLS RESOURCE variable=data3lookup_in core=RAM_1P_BRAM latency=1

#pragma HLS INTERFACE axis register port=tl_fifo_resp

#pragma HLS INTERFACE axis register port=tl_fifo_data
#pragma HLS INTERFACE axis register port=capptag_fifo_out
#pragma HLS INTERFACE axis register port=rty_issue_fifo_out
#pragma HLS INTERFACE axis register port=net_resp_out

#pragma HLS INTERFACE ap_none register port=valex_memegress_cmddata_ld_cnt
#pragma HLS INTERFACE ap_none register port=valex_memegress_cmdf_cnt
#pragma HLS INTERFACE ap_none register port=valex_memegress_data_cnt
#pragma HLS INTERFACE ap_none register port=valex_memegress_cmdf_torty
#pragma HLS INTERFACE ap_none register port=&valex_memegress_data_torty
#pragma HLS INTERFACE ap_none register port=valex_memingress_cmdf_rty_in
#pragma HLS INTERFACE ap_none register port=valex_memingress_cmdf_jail_in
#pragma HLS INTERFACE ap_none register port=valex_memingress_cmdf_rty_out
#pragma HLS INTERFACE ap_none register port=valex_memingress_cmdf_jail_out
#pragma HLS INTERFACE ap_none register port=valex_memingress_data_rty_in
#pragma HLS INTERFACE ap_none register port=valex_memingress_data_rty_out
#pragma HLS INTERFACE ap_none register port=valex_memingress_data_jail_in
#pragma HLS INTERFACE ap_none register port=valex_memingress_data_jail_out

#pragma HLS INTERFACE ap_ctrl_none port=return

#pragma HLS dataflow interval=1

/*
 This Fifo Holds Responses coming from the local TL
 We need this Buffer as the Resp State machine will
 might not be ready to pull, spending cycles on 
 rertry CAM updates or data push. We put a generous 8
 depth here, but i think we will not need more than 4.
*/


/*Various State machines Declarations*/


TLRespEng TlResp;
RtyEng Rtyeng;


static stream<ocxflit_t> rty_unit_fifo_in("rty_unit_fifo_in");
#pragma HLS STREAM variable=rty_unit_fifo_in depth=128

static stream<ocxflit_t> rty_jail("rty_jail");
#pragma HLS STREAM variable=rty_jail depth=512

/*Response Issue Engine
  Inputs:
   resp fifo comes from TL
   resp data comes from TL
   rty_cmd_fifo comes from Cmd Issue Eng,
  Outputs:
   capptag fifo
   rty_cmd_fifo_retry goes to rtry timeout unit
   resp to network
*/

TlResp.RespEngSM(enable,\
		 tl_fifo_resp, \
                 tl_fifo_data, \
                 data0lookup_in,\
                 data1lookup_in,\
                 data2lookup_in,\
                 data3lookup_in,\
                 capptag_fifo_out, \
                 rty_unit_fifo_in, \
                 net_resp_out,\
                 valex_memegress_cmdf_cnt,\
                 valex_memegress_data_cnt,\
                 valex_memegress_cmdf_torty,\
                 valex_memegress_data_torty);


Rtyeng.RtyEngSM(rtry_timeout, \
                rty_unit_fifo_in,\
                rty_jail,\
                rty_issue_fifo_out,\
                valex_memingress_cmdf_rty_in,\
                valex_memingress_cmdf_jail_in,\
                valex_memingress_cmdf_rty_out,\
                valex_memingress_cmdf_jail_out,\
                valex_memingress_data_rty_in,\
                valex_memingress_data_rty_out,\
                valex_memingress_data_jail_in,\
                valex_memingress_data_jail_out);


}
