diff --git a/src/main.c b/src/main.c index cdb304dda1..1af1b0f3a0 100644 --- a/src/main.c +++ b/src/main.c @@ -36,7 +36,9 @@ void TOUCH_Handler(); // temporarily in main() void VIDEO_Update(); void PAGE_Test(); -int main() __attribute__((weak)); +#if defined (TEST) || defined (PROFILE) +#define main _main +#endif #ifndef DUMP_BOOTLOADER int main() { diff --git a/src/target/qemu/.target_main.c.swp b/src/target/qemu/.target_main.c.swp deleted file mode 100644 index f1daae7ac5..0000000000 Binary files a/src/target/qemu/.target_main.c.swp and /dev/null differ diff --git a/src/target/qemu/Makefile.inc b/src/target/qemu/Makefile.inc index c62bd53034..b3af4d79e5 100644 --- a/src/target/qemu/Makefile.inc +++ b/src/target/qemu/Makefile.inc @@ -27,7 +27,7 @@ SRC_C := $(wildcard $(SDIR)/target/$(TARGET)/*.c) \ SRC_C := $(filter-out $(SDIR)/target/common/stm32/spi_flash.c, $(SRC_C)) -CFLAGS = -D"assert_param(x)=" -DSTM32F10X_HD -DSTM32F1 -mcpu=cortex-m3 -mthumb -mfix-cortex-m3-ldrd -fdata-sections -ffunction-sections -I$(SDIR)/target/common/devo/msc2/lib -I$(SDIR)/target/common/devo/msc2 -I$(SDIR)/libopencm3/include -I$(SDIR)/target/common/filesystems -fno-builtin-printf -Os --specs=nano.specs +CFLAGS = -DPROFILE -D"assert_param(x)=" -DSTM32F10X_HD -DSTM32F1 -mcpu=cortex-m3 -mthumb -mfix-cortex-m3-ldrd -fdata-sections -ffunction-sections -I$(SDIR)/target/common/devo/msc2/lib -I$(SDIR)/target/common/devo/msc2 -I$(SDIR)/libopencm3/include -I$(SDIR)/target/common/filesystems -fno-builtin-printf -Os --specs=nano.specs MODULE_FLAGS = -fno-builtin LFLAGS = -nostartfiles -Wl,-gc-sections -Wl,-Map=$(TARGET).map,--cref -lc -lnosys -L$(SDIR) -Lobjs/$(TARGET) diff --git a/src/target/qemu/target_main.c b/src/target/qemu/target_main.c index c23b3dff29..9662876a0d 100644 --- a/src/target/qemu/target_main.c +++ b/src/target/qemu/target_main.c @@ -1,18 +1,51 @@ #include #include #include +#include #include "common.h" +#include "mixer.h" +#include "config/tx.h" +#include "config/model.h" #include "../common/devo/devo.h" +void run_profile(); +void init_profile(); int main() { SCB_VTOR = VECTOR_TABLE_LOCATION; SCB_SCR &= ~SCB_SCR_SLEEPONEXIT; //sleep immediate on WFI rcc_clock_setup_in_hse_8mhz_out_72mhz(); + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + systick_set_reload(0x00FFFFFF); + systick_counter_enable(); rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN); gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); gpio_clear(GPIOC, GPIO12); gpio_set(GPIOC, GPIO12); gpio_clear(GPIOC, GPIO12); + + init_profile(); + run_profile(); +} + +void init_profile() { + for (int i = 0; i < INP_HAS_CALIBRATION; i++) + { + Transmitter.calibration[i].min = CHAN_MIN_VALUE; + Transmitter.calibration[i].max = CHAN_MAX_VALUE; + Transmitter.calibration[i].zero = 0; + } + memset(Model.mixers, 0, sizeof(Model.mixers)); + for (unsigned i = 0; i < 1; i++) { + Model.mixers[i].src = 1; + Model.mixers[i].dest = (2 + i) % 5; + Model.mixers[i].scalar = 100; + Model.mixers[i].flags = MUX_REPLACE; + } + Model.num_channels = 12; +} + +void __attribute__ ((noinline)) run_profile() { + MIXER_CalcChannels(); } diff --git a/utils/qemu.py b/utils/qemu.py new file mode 100644 index 0000000000..23df920209 --- /dev/null +++ b/utils/qemu.py @@ -0,0 +1,89 @@ +# This script will profile the qemu.bin build and produce a calltrace log +# It is meant to be loaded from within gdb via: +# arm-none-eabi-gdb-py +# source gdb +# profile +# An STM32 QEMU is needed (either docker or natively compiled): https://github.com/beckus/qemu_stm32 +# QEMU is started before running gdb via: +# qemu-system-arm -S -s -M stm32-p103 -kernel qemu.bin + +import gdb + +compress = True + +class func: + def __init__(self, parent, pc, lr, name): + self.exclusive = 0 + self.parent = parent + self.pc = pc + self.lr = lr + self.children = [] + self.name = name + def newchild(self, pc, lr, name): + if compress: + for child in self.children: + if child.pc == pc: + child.lr = lr + return child + newfunc = func(self, pc, lr, name) + self.children.append(newfunc) + return newfunc + +def printstack(trace, depth=""): + inclusive = trace.exclusive + childstr = "" + for child in trace.children: + _str, incl = printstack(child, depth + " ") + childstr += _str + inclusive += incl + childstr = "{}{} 0x{:02x} (ex:{} inc:{})\n".format(depth, trace.name, trace.pc, trace.exclusive, inclusive) + childstr + if depth == "": + print childstr + else: + return childstr, inclusive + +topfunc = func(None, 0, 0, None) + +class Profile(gdb.Command): + def __init__(self): + # This registers our class as "simple_command" + super(Profile, self).__init__("profile", gdb.COMMAND_DATA) + gdb.execute("file qemu.elf") + gdb.execute("target remote localhost:1234") + gdb.execute("set pagination off") + self.trace = topfunc + + def invoke(self, arg, from_tty): + # When we call "simple_command" from gdb, this is the method + # that will be called. + #gdb.execute("set logging file /dev/null") + #gdb.execute("set logging redirect on") + #gdb.execute("set logging on") + gdb.execute("b run_profile") + gdb.execute("c") + gdb.execute("disable") + stop_pc = gdb.newest_frame().older().pc() + + last_lr = int(gdb.parse_and_eval('$lr'))-1 + while True: + frame = gdb.newest_frame() + pc = frame.pc() + lr = int(gdb.parse_and_eval('$lr'))-1 + if pc == self.trace.lr: + print "Returned from {:02x}".format(self.trace.pc) + self.trace = self.trace.parent + #return + elif lr != last_lr: + self.trace = self.trace.newchild(pc, lr, frame.name()) + print "Called {}{:02x} (return: {:02x})".format(frame.name(), pc, lr) + #return + if pc == 0 or pc == stop_pc: + break; + self.trace.exclusive += 1 + last_lr = lr + gdb.execute("si") + #gdb.execute("set logging off") + #gdb.execute("display") + printstack(topfunc) + +Profile()