Commit ad27d165 authored by Christian Eichler's avatar Christian Eichler
Browse files

Merge branch 'dev' into 'master'

dev -> master

See merge request gene/xmc4500-relax-linux!1
parents 14b8e467 22d5c131
.PHONY: flash/ids_% flash/bch_% reset_%
.PHONY: reset_%
.SECONDARY: $(bin/*.axf)
#### Setup ####
XMC = $(shell pwd)/XMC
......@@ -16,19 +17,19 @@ LIBS = $(CMSIS)/Lib/GCC/libarm_cortexM4lf_math.a
LINKER_FILE = $(CMSIS)/Infineon/$(UC)_series/Source/GCC/XMC4500x1024.ld
CMSIS_SRC += $(CMSIS)/Infineon/$(UC)_series/Source/System_$(UC).c
JLINK = JLinkExe
SYSCC = $(TOOLCHAIN)-gcc
CC = patmos-clang
CP = $(TOOLCHAIN)-objcopy
OD = $(TOOLCHAIN)-objdump
GDB = $(TOOLCHAIN)-gdb
#STACK_SIZE?=2048
STACK_SIZE?=16384
JLINK = JLinkExe
JLFLAGS = -device XMC4500-1024 -if SWD -speed 900
CFLAGS = -target armv6m--none-eabi -mcpu=cortex-m4 -mthumb -integrated-as -ccc-gcc-name arm-none-eabi-gcc
CFLAGS = -mcpu=cortex-m4 -target armv7m-none-eabi -msoft-float
CFLAGS+= -integrated-as -ccc-gcc-name arm-none-eabi-gcc
CFLAGS+= -fno-builtin
CFLAGS+= -Os -ffunction-sections -fdata-sections
CFLAGS+= -MD -std=c99 -Wall
......@@ -36,6 +37,7 @@ CFLAGS+= -DUC_ID=$(UC_ID) -DARM_MATH_CM4 -DINTERRUPT_CONTROL_ENDPOINT
CFLAGS+= -DXMC4500_F100x1024
CFLAGS+= -I$(CMSIS)/Include -I$(CMSIS)/Infineon/$(UC)_series/Include
CFLAGS+= -Ilib/LUFA -I$(XMC)/XMCLib/inc
CFLAGS+= $(CFLAGS_GENE)
ASFLAGS = -target armv6m--none-eabi -mcpu=cortex-m4 -marm -mthumb
ASFLAGS+= -O0 -ffunction-sections -fdata-sections
......@@ -60,7 +62,7 @@ OBJS += src/System_$(UC).o
OBJS_MAIN = $(OBJS) $(SRC_MAIN:.c=.o)
#### Rules ####
all: $(OBJS) bin/xmc.bin xmccomm
all: $(OBJS)
src/System_$(UC).o: $(CMSIS_SRC)
$(CC) -c $(CFLAGS) $< -o $@
......@@ -88,24 +90,10 @@ bin/ids_%.axf: $(OBJS) bin/startup_XMC4500.o bin/ids_%.o
%.bin: %.axf
$(CP) $(CPFLAGS) $^ $@
flash/ids_%: bin/ids_%.bin
echo "connect\n\
loadbin $< 0x8000000\n\
r\n\
g\n\
exit\n" | $(JLINK) $(JLFLAGS) -SelectEmuBySN $*
flash/bch_%: bin/xmc.bin
echo "connect\n\
loadbin bin/xmc.bin 0x8000000\n\
r\n\
g\n\
exit\n" | $(JLINK) $(JLFLAGS) -SelectEmuBySN $*
bin/xmc.axf: $(OBJS_MAIN) bin/startup_XMC4500.o gene.o
bin/system_%.axf: $(OBJS_MAIN) bin/startup_XMC4500.o %.o
mkdir -p bin
@echo LD $<
@$(CC) -T $(LINKER_FILE) $(LFLAGS) -o bin/xmc.axf $^ $(LIBS)
@echo LD $@
@$(CC) -T $(LINKER_FILE) $(LFLAGS) -o $@ $^ $(LIBS)
reset_%:
echo "connect\n\
......@@ -124,8 +112,7 @@ fastgdb:
sleep 1
make gdb
xmccomm: xmccomm.c
gcc -std=c99 -g xmccomm.c -o xmccomm
clean:
rm -f src/*.o src/*.d bin/*
print-% : ; @echo $* = $($*)
......@@ -59,6 +59,9 @@ The **bch** supports the following requests:
* `eic`: enable instruction cache
* `bch`: run benchmark
Building the **bch** system requires a prior execution of GenE to generate
the file containing the actual benchmark (`gene.o`).
Usage: Communicate with the System
----------------------------------
......
......@@ -11,7 +11,7 @@
#include "timer.h"
#endif /* ifndef ID_SYSTEM */
#define IHANDLER __attribute__ ((naked))
#define IHANDLER
#define xstr(s) str(s)
#define str(s) #s
......@@ -22,9 +22,32 @@
#define SERIALSTR "<none>"
#endif
#define VOID_ARG_TYPE 1
#define UINT32_ARG_TYPE 2
#ifndef BENCHMARK_MAIN
#if defined(BENCHMARK_ARG) || defined(BENCHMARK_INIT)
#error BENCHMARK_MAIN, BENCHMARK_ARG, BENCHMARK_INIT must be defined
#endif
#define BENCHMARK_MAIN gene_main
#define BENCHMARK_ARG uint32_t
#define ARG_TYPE UINT32_ARG_TYPE
#define BENCHMARK_INIT gene_init
#endif
// use void as default
#ifndef BENCHMARK_ARG
#define ARG_TYPE VOID_ARG_TYPE
#define BENCHMARK_ARG void
#endif
void BENCHMARK_MAIN(BENCHMARK_ARG);
void BENCHMARK_INIT(void);
extern int errno;
void _init() {}
void _sbrk() {}
/* Clock configuration */
XMC_SCU_CLOCK_CONFIG_t clock_config =
......@@ -58,10 +81,7 @@ void SystemCoreClockSetup(void)
SystemCoreClockUpdate();
}
void gene_main(uint32_t);
void gene_init(void);
/*** Begin: Interrupt Handlers ***/
IHANDLER void PendSV_Handler() { P1_1_set(); while(1) {} }
IHANDLER void SysTick_Handler() { P1_1_set(); while(1) {} }
IHANDLER void SVC_Handler() { P1_1_set(); while(1) {} }
......@@ -70,6 +90,8 @@ IHANDLER void NMI_Handler() { P1_1_set(); while(1) {} }
IHANDLER void MemManage_Handler() { P1_1_set(); while(1) {} }
IHANDLER void UsageFault_Handler() { P1_1_set(); while(1) {} }
IHANDLER void BusFault_Handler() { P1_1_set(); while(1) {} }
/*** End: Interrupt Handlers ***/
static void uint64_to_string(char *buf, uint64_t value) {
if(0 == value) {
......@@ -85,62 +107,87 @@ static void uint64_to_string(char *buf, uint64_t value) {
}
}
/*** Begin: USB helper functions ***/
static void usb_send(const char *str) {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, str);
}
static void usb_send2(const char *str1, const char *str2) {
usb_send(str1);
usb_send(str2);
}
static void usb_send3(const char *str1, const char *str2, const char *str3) {
usb_send(str1);
usb_send(str2);
usb_send(str3);
}
static void usb_flush() { CDC_Device_Flush(&VirtualSerial_CDC_Interface); }
/*** End: USB helper functions ***/
#ifndef ID_SYSTEM
static void command_bch(char *arg) {
errno = 0;
unsigned long long val = strtoull(arg, NULL, 10);
if(0 != errno || val > (unsigned long long) UINT32_MAX) {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:ov\n");
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_send("e:ov\n");
usb_flush();
return;
}
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:start\r");
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_send("o:start\r");
usb_flush();
P1_0_toggle();
uint32_t old_basepri = __get_BASEPRI();
__set_BASEPRI(1 << (8 - __NVIC_PRIO_BITS));
gene_init();
BENCHMARK_INIT();
// flush instruction cache prior to executing the benchmark to
// ensure a "clean" system state
XMC_PREFETCH_InvalidateInstructionBuffer();
timer_reset();
P5_7_set();
timer_start();
gene_main(val);
#if ARG_TYPE == VOID_ARG_TYPE
BENCHMARK_MAIN();
#else
BENCHMARK_MAIN(val);
#endif
timer_stop();
P5_7_reset();
uint64_t cycles = timer_get();
__set_BASEPRI(old_basepri);
P1_0_toggle();
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:end ");
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
char buf[64] = {0};
uint64_to_string(buf, cycles);
CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf);
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "\n");
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_send3("o:end ", buf, "\n");
usb_flush();
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
}
static void command_dic(char *arg) {
XMC_PREFETCH_DisableInstructionBuffer();
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o\n");
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_send("o\n");
usb_flush();
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
}
static void command_eic(char *arg) {
XMC_PREFETCH_EnableInstructionBuffer();
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o\n");
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_send("o\n");
usb_flush();
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
}
......@@ -159,50 +206,36 @@ static void command_inf(char *arg) {
// send FREQUENCY
char buf[128] = {0};
uint64_to_string(buf, SystemCoreClock);
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:freq ");
CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf);
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "\r");
usb_send3("o:freq ", buf, "\r");
// send PFLASH
{
char buf[128] = {0};
uint64_to_string(buf, (FLASH0->FCON & (uint32_t)FLASH_FCON_WSPFLASH_Msk) >> FLASH_FCON_WSPFLASH_Pos);
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:wspflash ");
CDC_Device_SendString(&VirtualSerial_CDC_Interface, buf);
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "\r");
usb_send3("o:wspflash ", buf, "\r");
}
// send DWT status
switch(DWT->CTRL & 0xFF000000) {
case 0x40000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:4wt\r"); break;
case 0x4F000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:4w\r"); break;
case 0x10000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:1wt\r"); break;
case 0x1F000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:1w\r"); break;
case 0x00000000: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:0\r"); break;
default: CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:v\r"); break;
case 0x40000000: usb_send("o:4wt\r"); break;
case 0x4F000000: usb_send("o:4w\r"); break;
case 0x10000000: usb_send("o:1wt\r"); break;
case 0x1F000000: usb_send("o:1w\r"); break;
case 0x00000000: usb_send("o:0\r"); break;
default: usb_send("e:v\r"); break;
}
#ifndef ID_SYSTEM
if(timer_has_overflow_detection()) {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ov e\r");
} else {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ov d\r");
}
usb_send(timer_has_overflow_detection() ? "o:ov e\r" : "o:ov d\r");
#endif /* ifndef ID_SYSTEM */
usb_send((PREF->PCON & PREF_PCON_IBYP_Msk) ? "o:ic d\n" : "o:ic e\n");
if(PREF->PCON & PREF_PCON_IBYP_Msk) {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ic d\n");
} else {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "o:ic e\n");
}
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_flush();
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
}
void* __aeabi_memset(void *s, int c, size_t n){
size_t i;
for (i = 0; i < n; i++) {
void* __aeabi_memset(void *s, int c, size_t n) {
for(size_t i = 0; i < n; i++) {
((char *)s)[i] = (char)c;
}
return s;
......@@ -216,12 +249,12 @@ int main(void) {
P1_1_set_mode(OUTPUT_PP_GP);
P1_1_set_driver_strength(STRONG);
#define BUFFER_SIZE 32
char buffer[BUFFER_SIZE + 1];
buffer[BUFFER_SIZE] = '\0';
P5_7_set_mode(OUTPUT_PP_GP);
P5_7_set_driver_strength(WEAK);
#define BUFFER_SIZE 32
uint8_t pos = 0;
char buffer[BUFFER_SIZE + 1] = {0};
// enable monitor debugging
CoreDebug->DHCSR = 0xA05F << CoreDebug_DHCSR_DBGKEY_Pos;
......@@ -270,8 +303,8 @@ int main(void) {
#undef COMMAND
if(!handled) {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:uc\n");
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_send("e:uc\n");
usb_flush();
}
pos = 0;
......@@ -283,8 +316,8 @@ int main(void) {
buffer[pos] = byte;
++pos;
} else {
CDC_Device_SendString(&VirtualSerial_CDC_Interface, "e:OVERFLOW IN COMMAND BUFFER\n");
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
usb_send("e:ov\n");
usb_flush();
pos = 0;
}
......
#define _POSIX_C_SOURCE 199309L
#define _XOPEN_SOURCE 500
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#define SHELL_ESC "\x1b"
#define streq(A,B) (!strcmp(A,B))
// stty -F /dev/ttyACM0 115200
static void print_ok() {
printf(SHELL_ESC"[;32;02m[ok] "SHELL_ESC"[m");
}
static void print_er() {
printf(SHELL_ESC"[;31;02m[ER] "SHELL_ESC"[m");
}
static void print_vb(char *msg) {
fprintf(stderr, SHELL_ESC"[;36;02m[vb] "SHELL_ESC"[m%s", msg);
}
static bool recv_response(FILE *fh, char *buf, size_t buf_size) {
int pos = 0;
while(pos < buf_size) {
int c = fgetc(fh);
if(EOF != c) {
if('\n' == c) {
buf[pos] = '\0';
return true;
} else if('\r' == c) {
buf[pos] = '\0';
return false;
} else {
buf[pos] = c;
++pos;
}
} else {
if(ferror(fh)) {
perror("fgetc(TTY)");
exit(EXIT_FAILURE);
} else {
fprintf(stderr, "Unexpected EOF\n");
exit(EXIT_FAILURE);
}
}
}
}
static int connect_tty(char *tty) {
bool exists = false;
unsigned retry = 0;
do {
print_vb("");
fprintf(stderr, "open('%s') try %u\n", tty, retry);
++retry;
struct stat sbuf;
int res = stat(tty, &sbuf);
exists = (0 == res);
if(!exists) {
usleep(500 * 1000);
}
} while(!exists && errno != EACCES && retry < 10);
int fd = open(tty, O_RDWR | O_NOCTTY);
if(-1 == fd) {
perror("open(TTY)");
if(EACCES == errno) {
fprintf(stderr, "Make sure current user `%s` is in group `dialout`\n", getlogin());
}
exit(EXIT_FAILURE);
} else {
print_vb(""); fprintf(stderr, "%s successfully opened\n", tty);
}
// setup control structure
struct termios toptions;
if(0 != tcgetattr(fd, &toptions)) { perror("tcgetattr"); }
if(0 != cfsetispeed(&toptions, B115200)) { perror("cfsetispeed"); }
if(0 != cfsetospeed(&toptions, B115200)) { perror("cfsetospeed"); }
toptions.c_cflag &= ~PARENB; // no parity bit
toptions.c_cflag &= ~CSTOPB; // no stop bits
toptions.c_cflag &= ~CSIZE; // char. size
toptions.c_cflag |= CS8; // 8 bits
/* enable receiver, ignore status lines */
toptions.c_cflag |= CREAD | CLOCAL;
/* disable input/output flow control, disable restart chars */
toptions.c_iflag &= ~(IXON | IXOFF | IXANY);
/* disable canonical input, disable echo,
disable visually erase chars,
disable terminal-generated signals */
toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
toptions.c_oflag &= ~OPOST; // disable postprocessing
if(0 != tcsetattr(fd, TCSANOW, &toptions)) { perror("tcsetattr"); }
if(0 != tcflush(fd, TCIFLUSH)) { perror("tcflush"); }
return fd;
}
static char* strsw(char *str, char *start) {
const uint32_t N = strlen(start);
if(!strncmp(str, start, N)) {
return &str[N];
}
return NULL;
}
uint32_t remote_frequency = 0;
static void resp_inf(bool success, char *resp) {
char *rem = NULL;
if(streq(resp, "4wt")) { printf("DWT: 4 comparators for watchpoints+triggers available"); }
else if(streq(resp, "4w" )) { printf("DWT: 4 comparators for watchpoints available"); }
else if(streq(resp, "1wt")) { printf("DWT: 1 comparator for watchpoints+triggers available"); }
else if(streq(resp, "1w" )) { printf("DWT: 1 comparator for watchpoints available"); }
else if(streq(resp, "0" )) { printf("DWT: NOT AVAILABLE"); }
else if(streq(resp, "v" )) { printf("Unexpected value ain DWT->CTRL"); }
else if(rem = strsw(resp, "freq ")) {
remote_frequency = strtoull(rem, NULL, 10);
char prefixes[] = { ' ', 'k', 'M', 'G' };
double freq_dbl = remote_frequency;
int idx = 0;
while(freq_dbl > 500) {
++idx;
freq_dbl /= 1000.;
}
printf("Frequency: %.2f%cHz", freq_dbl, prefixes[idx]);
} else if(rem = strsw(resp, "ic ")) {
printf("Instruction Cache: Currently %s", ('e' == *rem) ? "enabled" : "disabled");
} else if(rem = strsw(resp, "ov ")) {
printf("Timer Overflow Detection: Currently %s", ('e' == *rem) ? "enabled" : "disabled");
} else if(rem = strsw(resp, "id ")) {
printf("Device ID: %s", rem);
} else if(rem = strsw(resp, "wspflash ")) {
printf("Flash Wait States: %s", rem);
} else {
printf("Unparsed: %s", resp);
}
}
static void resp_bch(bool success, char *resp) {
char *rem = NULL;
if(streq(resp, "start")) {
printf("Benchmark started...");
} else if(rem = strsw(resp, "end ")) {
printf("Benchmark done: ");
uint64_t cycles = strtoull(rem, NULL, 10);
printf("%lu cy / %0.2f s", cycles, (double)cycles / remote_frequency);
} else if(rem = strsw(resp, "ov")) {
printf("Overflow in input data");
} else {
printf("Unparsed: %s", resp);
}
}
static void resp_dic(bool success, char *resp) {
printf("Instruction Cache now disabled!");
}
static void resp_eic(bool success, char *resp) {
printf("Instruction Cache now enabled!");
}
static void response_loop(FILE *fh, void (*cb)(bool, char*)) {
bool done = false;
char buf[128];
while(!done) {
done = recv_response(fh, buf, 128);
bool success;
switch(buf[0]) {
case 'o':
success = true;
print_ok();
break;
case 'e':
success = false;
print_er();
break;
default:
printf(SHELL_ESC"[;31;02m[ER] Invalid response!");
return;
}
char *rem = NULL;
if(rem = strsw(buf, "e:uc")) {
printf("Command not known to device; are you trying to benchmark on an IDS?\n");
exit(EXIT_FAILURE);
} else {
cb(success, '\0' != &buf[1] ? &buf[2] : NULL);
}
printf(SHELL_ESC"[m\n");
fflush(stdout);
}
}
struct command {
char *cmd;
uint32_t nparam;
void (*callback)(bool, char*);
};
static struct command commands[] = {
{"bch", 1, resp_bch},
{"dic", 0, resp_dic},
{"eic", 0, resp_eic},
{"inf", 0, resp_inf},
{"rst", 0, NULL}
};
static const size_t commands_count = sizeof(commands)/sizeof(struct command);
int main(int argc, char *argv[]) {
if(2 != argc) {
fprintf(stderr, "Usage: %s <tty> \n", argv[0]);
return EXIT_FAILURE;
}
int fd = connect_tty(argv[1]);
FILE *fh = fdopen(fd, "r+");
if(fh == NULL) {
perror("fdopen(TTY)");
return EXIT_FAILURE;
}
print_vb("Requesting device info...\n");
fprintf(fh, "inf \n");
fflush(fh);
response_loop(fh, resp_inf);
print_vb("Sending user commands...\n");
char input[512];
while(NULL != fgets(input, sizeof(input), stdin)) {
struct command *cmd = NULL;
input[strlen(input) - 1] = '\0';