Commit b89ccf99 authored by Jens Korinth's avatar Jens Korinth

Cleanup kernels: remove unused/broken code

parent e8e1b0e9
HWSWCOSIM ?= ../../hwswcosim
CC ?= gcc
CFLAGS += -O3 -g -I$(HWSWCOSIM)/include -pedantic -Wall -Werror -std=gnu99
LDFLAGS += -L$(HWSWCOSIM)/lib -lrcu-client
.PHONY: clean
rcu-client: client.c kernel_desc.c
$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $^
clean:
rm -rf rcu-client
HWSWCOSIM ?= "/scratch/jk/rcu/hwswcosim"
TARGETNAME ?= client
$(TARGETNAME)-rcu: $(TARGETSRCS) $(COMMONDIR)/client.c
$(CC) $(CFLAGS) -I$(HWSWCOSIM)/include -L$(HWSWCOSIM)/lib -lrcu-client -o $(TARGETNAME)-rcu $^
//
// Copyright (C) 2014 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <errno.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libgen.h>
#include <assert.h>
#include "rcu_client.h"
#include "rcu_api.h"
#include "kernel_desc.h"
#ifndef NDEBUG
#define DBG(...) \
do { \
fprintf(stdout, "client (%s): ", __func__); \
fprintf(stdout, __VA_ARGS__); \
fprintf(stdout, "\n"); \
} while (0)
#else
#define DBG(...) (void)0
#endif
#define DO_OR_DIE(stmt, ...) \
do { \
if (! (stmt)) { \
fprintf(stderr, "FATAL: "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
rcu_deinit(); \
exit(EXIT_FAILURE); \
} \
} while (0)
static off_t load_file(const char *fn, char **data) {
DBG("fn = %s", fn);
int fd = open(fn, O_RDONLY);
if (! fd) return 0;
const off_t sz = lseek(fd, 0, SEEK_END); DBG("sz = %zd", sz);
*data = (char *)malloc(sz);
lseek(fd, 0, SEEK_SET);
off_t n = 0;
ssize_t status;
do {
status = read(fd, &(*data)[n], sz - n);
if (status > 0) n += status;
} while (status > 0 && n < sz);
DO_OR_DIE(status >= 0, "error reading %s: %s", fn, strerror(errno));
return n;
}
int main(int argc, char **argv) {
DO_OR_DIE(argc == 2, "Expected exactly one argument: kernel description file");
int sock, i;
/*****************************************************************************/
DBG("reading kernel description %s ...", argv[1]);
kernel_desc_t *kd = kd_read_from_file(argv[1]);
// DO_OR_DIE(kd->base_addr_cnt, "expected at least one base address!");
DBG("kernel description read");
const char *kernel_dir = dirname(argv[1]);
const uint32_t ns = strlen(kernel_dir) + strlen("/input.data") + 1;
char *fn = (char *)malloc(ns);
/*****************************************************************************/
DBG("loading input data ...");
char *input = NULL;
snprintf(fn, ns, "%s/input.data", kernel_dir);
off_t input_sz = load_file(fn, &input);
char *input_data = input;
off_t direct_in_size = 0;
for (i = 0; i < kd->simple_arg_cnt; ++i)
direct_in_size += kd->simple_arg_sz[i];
input_data += direct_in_size;
input_sz -= direct_in_size;
/*****************************************************************************/
DBG("loading check data ...");
char *check = NULL;
snprintf(fn, ns, "%s/check.data", kernel_dir);
off_t check_sz = load_file(fn, &check);// - (kd->ret_sz << 2);
char *check_data = check;// + (kd->ret_sz << 2);
off_t direct_ret_size = kd->ret_sz << 2;
if (direct_ret_size < direct_in_size)
direct_ret_size = direct_in_size;
check_sz -= direct_ret_size;
check_data += direct_ret_size;
free(fn);
DBG("simple_arg_cnt = %d, input_sz = %zd, check_sz = %zd",
kd->simple_arg_cnt, input_sz, check_sz);
DO_OR_DIE(input_sz == check_sz, "input size does not match check size");
DBG("reading done");
/*****************************************************************************/
// connect to sim and setup the system
DBG("connecting to simulator....");
DO_OR_DIE(sock = rcu_init(), "could not connect to simulator");
DBG("connected to simulator");
DO_OR_DIE(rcu_setup_system(1), "setup failed");
if (kd->base_addr_cnt) {
// load input to memory
DBG("writing %zd bytes of input data to simulator memory ...", input_sz);
DO_OR_DIE(rcu_write_mem(kd->base_addr[0], input_sz, input_data),
"failed to write input data");
DBG("writing %zd bytes done", input_sz);
DBG("setting %u base addresses ...", kd->base_addr_cnt);
for (int i = 0; i < kd->base_addr_cnt; ++i) {
const uint32_t base_addr = i > 0 ? kd->base_addr[0] + kd->base_addr[i]
: kd->base_addr[0];
DBG("base address #%d = 0x%08x", i, base_addr);
DO_OR_DIE(rcu_set_base(0, i, base_addr),
"failed setting base #%d of instances #%d to 0x%08x",
i, 0, base_addr);
}
}
/*****************************************************************************/
if (kd->simple_arg_cnt) {
char *argp = input;
if (! kd->simple_arg_sz)
fprintf(stderr, "WARNING: no sizes for simple args, assuming 32bit each.\n");
for (int i = 0; i < kd->simple_arg_cnt; ++i) {
const uint32_t sz = kd->simple_arg_sz ? kd->simple_arg_sz[i] : 4;
switch (sz) {
case 8: {
uint64_t v = *(uint64_t *)argp;
DBG("setting 64bit reg #%d to %lu", i, v);
DO_OR_DIE(rcu_set_arg64(0, i, v), "failed to set arg #%d of inst #%d to "
"0x%lx (%lu)", i, 0, v, v);
} break;
case 4: {
const uint32_t v = *(uint32_t *)argp;
DBG("setting 32bit reg #%d to %u", i, v);
DO_OR_DIE(rcu_set_arg32(0, i, v), "failed to set arg #%d of inst #%d to "
"0x%x (%u)", i, 0, v, v);
} break;
default: DO_OR_DIE(0, "unsupported size: %d", sz);
}
argp += sz;
}
}
int irqs = 0;
int64_t start = 0, stop = 0;
DO_OR_DIE(rcu_get_time(&start), "failed to get start time");
DBG("start time = %ld", start);
DBG("launching kernel ...");
DO_OR_DIE(rcu_launch_kernel(0, &irqs), "failed to launch kernel");
DBG("kernel done");
DO_OR_DIE(rcu_get_time(&stop), "failed to get stop time");
DBG("stop time = %ld", stop);
/*****************************************************************************/
int ok = 1;
switch (kd->ret_sz) {
case RET_SZ_32BIT: {
int ret = 0, resp = 0;
int exp = *((int *)check); // expect first entry to be expected ret val
DO_OR_DIE(rcu_read_kernel_reg(0, 4, &ret, &resp),
"failed to read return register");
DBG("return reg = 0x%x (%d), expected = 0x%x (%d)", ret, ret, exp, exp);
ok = ok && ret == exp;
} break;
case RET_SZ_64BIT: {
int ret0, ret1, resp;
const int64_t exp = *((int64_t *)check);
DO_OR_DIE(rcu_read_kernel_reg(0, 4, &ret0, &resp),
"failed to read return register");
DO_OR_DIE(rcu_read_kernel_reg(0, 5, &ret1, &resp),
"failed to read return register");
const uint32_t r0 = (uint32_t)ret0;
const uint32_t r1 = (uint32_t)ret1;
DBG("ret0 = %u, ret1 = %u", r0, r1);
const int64_t ret = ((uint64_t)ret1 << 32) | (uint64_t)r0;
DBG("return reg = 0x%lx (%ld), expected = 0x%lx (%ld)", ret, ret, exp, exp);
ok = ok && ret == exp;
} break;
default:
DBG("no return value expected");
break;
}
if (kd->base_addr_cnt && check_sz == input_sz) {
DBG("reading results ...");
DO_OR_DIE(rcu_read_mem(kd->base_addr[0], input_sz, input_data),
"failed to read output data");
DBG("results read, checking ...");
if (check_sz == input_sz && memcmp(input_data, check_data, input_sz) != 0) {
int i = 0;
int *ptr = (int *)input_data;
int *cptr = (int *)check_data;
for (; i < input_sz >> 2; ++i, ++ptr, ++cptr) {
if (*ptr != *cptr) {
fprintf(stderr, "ERROR: output[%d] = 0x%08x (%u), check[%d] = 0x%08x (%u)\n",
i, *ptr, *ptr, i, *cptr, *cptr);
}
}
} else {
DBG("yay, data ok!");
}
ok = ok && ! memcmp(input_data, check_data, input_sz);
DBG("results checked, %s", ok ? "ok" : "not ok");
}
DBG("stopping simulation ...");
DO_OR_DIE(rcu_stop(ok), "stop failed");
rcu_deinit();
DBG("simulation stopped, disconnected");
DBG("client finished!");
free(input);
free(check);
kd_destroy(kd);
printf("Total kernel execution time: %ld\n", stop - start);
return ok ? 0 : 1;
}
//
// Copyright (C) 2014 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
/* some common routines */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include "common.h"
void dump_file(const char *fn, char *data, const size_t sz) {
int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH);
if (fd <= 0)
fprintf(stderr, "could not write to %s: %s\n",
fn, strerror(errno));
assert(fd > 0);
size_t n = 0;
while (n < sz) {
ssize_t status = write(fd, data, sz - n);
if (status < 0)
fprintf(stderr, "could not write to %s: %s\n",
fn, strerror(errno));
assert(status >= 0);
n += status;
}
close(fd);
printf("dumped %zd byte to %s.\n", sz, fn);
}
//
// Copyright (C) 2014 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef __RCU_COMMON_H__
#define __RCU_COMMON_H__
#include <stddef.h>
#ifdef __cplus_plus
extern "C" {
#endif
void dump_file(const char *fn, char *data, const size_t sz);
#ifdef __cplus_plus
} /* extern "C" */
#endif
#endif /* __RCU_COMMON_H__ */
//
// Copyright (C) 2014 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "kernel_desc.h"
#ifndef NDEBUG
#define DBG(...) do { \
if (getenv("KD_LIB_DEBUG")) { \
fprintf(stderr, "%s: ", __func__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} \
} while (0)
#else
#define DBG(...)
#endif
#define KNOWN_KEYS \
_X("BaseAddresses", KT_BASE_ADDRESSES, parse_base_addresses) \
_X("SimpleArgs", KT_SIMPLE_ARGS, parse_simple_args) \
_X("SimpleArgSizes", KT_SIMPLE_ARG_SIZES, parse_simple_arg_sizes) \
_X("ReturnSize", KT_RETURN_VAL_SZ, parse_return_value_size)
typedef enum {
KT_INVALID,
#define _X(name, val, func) val,
KNOWN_KEYS
#undef _X
} kd_key_t;
typedef struct pp_t {
kernel_desc_t *kd;
const char *start;
off_t sz;
char *p;
off_t curr;
} pp_t;
static inline void skip_ws(pp_t *pp) {
while (pp->curr < pp->sz && (*pp->p == ' ' || *pp->p == '\n' || *pp->p == '\t')) {
++(pp->p);
++(pp->curr);
}
}
static inline void skip_ws_nn(pp_t *pp) {
while (pp->curr < pp->sz && (*pp->p == ' ' || *pp->p == '\t')) {
++(pp->p);
++(pp->curr);
}
}
static inline void skip_char(pp_t *pp, const char c) {
while (pp->curr < pp->sz && *pp->p == c) {
++(pp->p);
++(pp->curr);
}
}
static inline void skip_until(pp_t *pp, const char c) {
while (pp->curr < pp->sz && *pp->p != c) {
++(pp->p);
++(pp->curr);
}
}
static inline void skip_until_ws(pp_t *pp) {
while (pp->curr < pp->sz && *pp->p != ' ' && *pp->p != '\n' && *pp->p != '\t') {
++(pp->p);
++(pp->curr);
}
}
static inline uint32_t count_elems(pp_t *pp) {
uint32_t cnt = 0;
skip_ws_nn(pp);
while (pp->curr < pp->sz && *pp->p != '\n') {
skip_ws_nn(pp);
++cnt;
skip_until_ws(pp);
}
DBG("count = %u", cnt);
return cnt;
}
static char *load_file(const char *fn, off_t *off) {
int fd = open(fn, O_RDONLY);
assert(fd);
*off = lseek(fd, 0, SEEK_END);
DBG("file = %s, size = %zd bytes", fn, *off);
lseek(fd, 0, SEEK_SET);
char *res = (char *)malloc(*off);
assert(res);
off_t n = *off; int status = 1;
while (n > 0 && (status = read(fd, &res[*off - n], n))) {
if (status < 0) {
fprintf(stderr, "failed to read: %s", strerror(errno));
exit(errno);
}
n -= status;
}
close(fd);
return res;
}
static kd_key_t parse_key(pp_t *pp) {
skip_ws(pp);
#define _X(name, val, func) \
if (strlen(name) <= pp->sz - pp->curr && !strncmp(pp->p, name, strlen(name))) { \
pp->p += strlen(name); \
pp->curr += strlen(name); \
skip_ws(pp); skip_char(pp, '=');\
return val; \
}
KNOWN_KEYS
#undef _X
// unknown key, consume line
skip_until(pp, '\n');
skip_ws(pp);
return KT_INVALID;
}
static void parse_base_addresses(pp_t *pp) {
uint32_t b[320];
uint32_t b_c = 0;
while (*pp->p != '\n' && pp->curr < pp->sz) {
skip_ws(pp);
skip_char(pp, '"');
// first absolute, others relative to first
b[b_c] = strtoul(pp->p, NULL, 0) - (b_c > 0 ? b[0] : 0x0);
if (errno == 0) {
DBG("found base: 0x%x", b[b_c]);
++b_c;
}
skip_until_ws(pp);
}
assert(pp->kd);
if (b_c) {
pp->kd->base_addr = (uint32_t *)malloc(b_c * sizeof(b[0]));
assert(pp->kd->base_addr);
memcpy(pp->kd->base_addr, b, b_c * sizeof(b[0]));
}
pp->kd->base_addr_cnt = b_c;
}
static void parse_simple_arg_sizes(pp_t *pp) {
uint32_t sz[1024];
uint32_t sz_c = 0;
while (*pp->p != '\n' && pp->curr < pp->sz) {
skip_ws(pp);
skip_char(pp, '"');
// first absolute, others relative to first
sz[sz_c] = strtoul(pp->p, NULL, 0);
if (errno == 0) {
DBG("found size: %d", sz[sz_c]);
++sz_c;
}
skip_until_ws(pp);
}
assert(pp->kd);
if (sz_c) {
pp->kd->simple_arg_sz = (uint32_t *)malloc(sz_c * sizeof(sz[0]));
assert(pp->kd->simple_arg_sz);
memcpy(pp->kd->simple_arg_sz, sz, sz_c * sizeof(sz[0]));
}
}
static void parse_simple_args(pp_t *pp) {
pp->kd->simple_arg_cnt = count_elems(pp);
}
static void parse_return_value_size(pp_t *pp) {
skip_ws(pp);
uint32_t sz = strtoul(pp->p, NULL, 0);
pp->kd->ret_sz = RET_SZ_32BIT;
if (! errno) {
switch (sz) {
case 8: pp->kd->ret_sz = RET_SZ_64BIT; break;
case 4: pp->kd->ret_sz = RET_SZ_32BIT; break;
default:
fprintf(stderr, "WARNING: found invalid return size %d, assuming 32bit.", sz);
break;
}
} else {
fprintf(stderr, "WARNING: invalid return size value, assuming 32bit.");
}
DBG("return value size: %s", pp->kd->ret_sz == RET_SZ_64BIT ? "64bit" : "32bit");
}
kernel_desc_t *kd_read_from_file(const char *fn) {
off_t sz;
char *raw = load_file(fn, &sz);
kd_key_t key;
pp_t pp;
pp.kd = (kernel_desc_t *)calloc(sizeof(kernel_desc_t), 1);
pp.start = raw;
pp.sz = sz;
pp.p = raw;
pp.curr = 0;
DBG("opening file %s", fn);
do {
key = parse_key(&pp);
switch (key) {
#define _X(name, val, func) \
case val: \
DBG("found %s", name); \
func(&pp); \
break;
KNOWN_KEYS
#undef _X
case KT_INVALID:
default:
break;
}
} while (pp.curr < pp.sz);
free(raw);
// warn if sizes are missing
if (pp.kd->simple_arg_cnt && !pp.kd->simple_arg_sz)
fprintf(stderr, "WARNING: simple args specified, but not their sizes!\n");
return pp.kd;
}
void kd_destroy(kernel_desc_t *kd) {
free(kd->simple_arg_sz);
free(kd->base_addr);
free(kd);
}
//
// Copyright (C) 2014 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef __KERNEL_DESC_H__
#define __KERNEL_DESC_H__
#include <stdint.h>
#ifdef __cplus_plus
extern "C" {
#endif
typedef enum { RET_SZ_NA, RET_SZ_32BIT, RET_SZ_64BIT } ret_sz_t;
typedef struct kernel_desc_t {
uint32_t *base_addr;
uint32_t base_addr_cnt;
uint32_t simple_arg_cnt;
uint32_t *simple_arg_sz;
ret_sz_t ret_sz;
} kernel_desc_t;
kernel_desc_t *kd_read_from_file(const char *fn);
void kd_destroy(kernel_desc_t *kd);
#ifdef __cplus_plus
} /* extern "C" */
#endif
#endif /* __KERNEL_DESC_H__ */
//
// Copyright (C) 2014 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
//! @file countdown.c
//! @brief A hardware kernel that counts down a 64-bit register.
//! @authors J. Korinth, TU Darmstadt (jk@esa.cs.tu-darmstadt.de)
//!
#include "countdown.h"
uint32_t countdown(volatile uint32_t v)
{
while (v) {
v -= 1;
}
return v;
}
//
// Copyright (C) 2014 Jens Korinth, TU Darmstadt
//
// This file is part of Tapasco (TPC).
//
// Tapasco is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tapasco is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tapasco. If not, see <http://www.gnu.org/licenses/>.
//
//! @file countdown.h
//! @brief A hardware kernel that counts down a 64-bit register.
//! @authors J. Korinth, TU Darmstadt (jk@esa.cs.tu-darmstadt.de)
//!
#ifndef __COUNTDOWN_H__
#define __COUNTDOWN_H__
#include <stdint.h>
uint32_t countdown(volatile uint32_t v);
#endif /* __COUNTDOWN_H__ */
{
"Description" : "Countdown kernel: programmable runtime kernel.",
"Name" : "countdown",