diff --git a/ui/devcmd.c b/ui/devcmd.c index 76a27f5..8730161 100644 --- a/ui/devcmd.c +++ b/ui/devcmd.c @@ -50,7 +50,7 @@ int cmd_regs(char **arg) if (device_readmem(regs[0], code, len) < 0) return 0; - disassemble(regs[0], (uint8_t *)code, len); + disassemble(regs[0], (uint8_t *)code, len, device_default->power_buf); return 0; } @@ -324,7 +324,7 @@ int cmd_dis(char **arg) } reader_set_repeat("dis 0x%x 0x%x", offset + length, length); - disassemble(offset, buf, length); + disassemble(offset, buf, length, device_default->power_buf); free(buf); return 0; } diff --git a/ui/rtools.c b/ui/rtools.c index d1b6f54..ad051b5 100644 --- a/ui/rtools.c +++ b/ui/rtools.c @@ -371,7 +371,8 @@ static int do_isearch(address_t addr, address_t len, int count = dis_decode(mbuf + i, addr + i, len - i, &insn); if (count >= 0 && isearch_match(&insn, q)) - disassemble(addr + i, mbuf + i, count); + disassemble(addr + i, mbuf + i, count, + device_default->power_buf); } free(mbuf); diff --git a/util/output_util.c b/util/output_util.c index 36c770b..b9f438c 100644 --- a/util/output_util.c +++ b/util/output_util.c @@ -136,10 +136,10 @@ static int dis_format(const struct msp430_instruction *insn) insn->src_addr, insn->src_reg); - printc(","); + len += printc(","); while (len < 15) len += printc(" "); - printc(" "); + len += printc(" "); } /* Destination operand */ @@ -157,9 +157,12 @@ static int dis_format(const struct msp430_instruction *insn) return len; } -void disassemble(address_t offset, const uint8_t *data, int length) +void disassemble(address_t offset, const uint8_t *data, int length, + powerbuf_t power) { int first_line = 1; + unsigned long long ua_total = 0; + int samples_total = 0; while (length) { struct msp430_instruction insn = {0}; @@ -194,13 +197,39 @@ void disassemble(address_t offset, const uint8_t *data, int length) } if (retval >= 0) - dis_format(&insn); + i = dis_format(&insn); + + if (power) { + unsigned long long ua; + int samples; + + while (i < 40) { + printc(" "); + i++; + } + + samples = powerbuf_get_by_mab(power, offset, &ua); + if (samples) { + printc(" ;; %.01f uA", + (double)ua / (double)samples); + ua_total += ua; + samples_total += samples; + } + } + printc("\n"); offset += count; length -= count; data += count; } + + if (power && samples_total) + printc(";; Total over this block: " + "%.01f uAs in %.01f ms (%.01f uA avg)\n", + (double)(ua_total * power->interval_us) / 1000000.0, + (double)(samples_total * power->interval_us) / 1000.0, + (double)ua_total / (double)samples_total); } void hexdump(address_t addr, const uint8_t *data, int data_len) @@ -256,9 +285,9 @@ void show_regs(const address_t *regs) int print_address(address_t addr, char *out, int max_len) { char name[MAX_SYMBOL_LENGTH]; - address_t offset; + address_t offset; - if (!stab_nearest(addr, name, sizeof(name), &offset)) { + if (!stab_nearest(addr, name, sizeof(name), &offset)) { int len; if (offset) len = snprintf(out, max_len, "%s+0x%x", name, offset); @@ -270,7 +299,7 @@ int print_address(address_t addr, char *out, int max_len) snprintf(out + len, max_len - len, " (%s)", demangled); } return 1; - } + } snprintf(out, max_len, "0x%04x", addr); return 0; diff --git a/util/output_util.h b/util/output_util.h index 05ea8b9..339328c 100644 --- a/util/output_util.h +++ b/util/output_util.h @@ -21,9 +21,11 @@ #include "output.h" #include "util.h" +#include "powerbuf.h" /* Print colorized disassembly on command processor standard output */ -void disassemble(address_t addr, const uint8_t *buf, int len); +void disassemble(address_t addr, const uint8_t *buf, int len, + powerbuf_t power); /* Print colorized hexdump on standard output */ void hexdump(address_t addr, const uint8_t *buf, int len); diff --git a/util/powerbuf.c b/util/powerbuf.c index 17ee55f..ee7113e 100644 --- a/util/powerbuf.c +++ b/util/powerbuf.c @@ -42,6 +42,12 @@ powerbuf_t powerbuf_new(unsigned int max_samples, unsigned int interval_us) pb->mab = malloc(sizeof(pb->mab[0]) * max_samples); if (!pb->mab) { + free(pb->current_ua); + return NULL; + } + + pb->sorted = malloc(sizeof(pb->sorted[0]) * max_samples); + if (!pb->sorted) { free(pb->current_ua); free(pb->mab); return NULL; @@ -60,6 +66,7 @@ void powerbuf_free(powerbuf_t pb) { free(pb->current_ua); free(pb->mab); + free(pb->sorted); free(pb); } @@ -67,6 +74,7 @@ void powerbuf_clear(powerbuf_t pb) { pb->session_head = pb->session_tail = 0; pb->current_head = pb->current_tail = 0; + pb->sort_valid = 0; } static unsigned int session_length(powerbuf_t pb, unsigned int idx) @@ -264,6 +272,8 @@ void powerbuf_add_samples(powerbuf_t pb, unsigned int count, mab += cont_len; count -= cont_len; } + + pb->sort_valid = 0; } address_t powerbuf_last_mab(powerbuf_t pb) @@ -277,3 +287,145 @@ address_t powerbuf_last_mab(powerbuf_t pb) return pb->mab[last]; } + +static void sift_down(powerbuf_t pb, int start, int end) +{ + int root = start; + + while (root * 2 + 1 <= end) { + int left_child = root * 2 + 1; + int biggest = root; + unsigned int temp; + + /* Find the largest of + * (root, left child, right child) + */ + if (pb->mab[pb->sorted[biggest]] < + pb->mab[pb->sorted[left_child]]) + biggest = left_child; + if (left_child + 1 <= end && + (pb->mab[pb->sorted[biggest]] < + pb->mab[pb->sorted[left_child + 1]])) + biggest = left_child + 1; + + /* If no changes are needed, the heap property is ok and + * we can stop. + */ + if (biggest == root) + break; + + /* Swap the root with its largest child */ + temp = pb->sorted[biggest]; + pb->sorted[biggest] = pb->sorted[root]; + pb->sorted[root] = temp; + + /* Continue to push down the old root (now a child) */ + root = biggest; + } +} + +static void heapify(powerbuf_t pb, int num_samples) +{ + int start = (num_samples - 2) / 2; + + while (start >= 0) { + sift_down(pb, start, num_samples - 1); + start--; + } +} + +static void heap_extract(powerbuf_t pb, int num_samples) +{ + int end = num_samples - 1; + + while (end > 0) { + unsigned int temp; + + /* Swap the top of the heap with the end of the array, + * and shrink the heap. + */ + temp = pb->sorted[0]; + pb->sorted[0] = pb->sorted[end]; + pb->sorted[end] = temp; + end--; + + /* Fix up the heap (push down the new root) */ + sift_down(pb, 0, end); + } +} + +void powerbuf_sort(powerbuf_t pb) +{ + const unsigned int num_samples = + (pb->current_head + pb->max_samples - pb->current_tail) % + pb->max_samples; + unsigned int i; + + if (pb->sort_valid) + return; + + /* Prepare an index list */ + for (i = 0; i < num_samples; i++) + pb->sorted[i] = (pb->current_tail + i) % pb->max_samples; + + if (num_samples < 2) { + pb->sort_valid = 1; + return; + } + + heapify(pb, num_samples); + heap_extract(pb, num_samples); + pb->sort_valid = 1; +} + +/* Find the index within the sorted index of the first sample with an + * MAB >= the given mab parameter. + */ +static int find_mab_ge(powerbuf_t pb, address_t mab) +{ + const int num_samples = + (pb->current_head + pb->max_samples - pb->current_tail) % + pb->max_samples; + int low = 0; + int high = num_samples - 1; + + while (low <= high) { + int mid = (low + high) / 2; + + if (pb->mab[pb->sorted[mid]] < mab) + low = mid + 1; + else if ((mid <= 0) || (pb->mab[pb->sorted[mid - 1]] < mab)) + return mid; + else + high = mid - 1; + } + + return -1; +} + +int powerbuf_get_by_mab(powerbuf_t pb, address_t mab, + unsigned long long *sum_ua) +{ + const unsigned int num_samples = + (pb->current_head + pb->max_samples - pb->current_tail) % + pb->max_samples; + int i; + int count = 0; + + if (!pb->sort_valid) + powerbuf_sort(pb); + + i = find_mab_ge(pb, mab); + if (i < 0) + return 0; + + *sum_ua = 0; + + while ((i < num_samples) && (pb->mab[pb->sorted[i]] == mab)) { + *sum_ua += pb->current_ua[pb->sorted[i]]; + count++; + i++; + } + + return count; +} diff --git a/util/powerbuf.h b/util/powerbuf.h index d674d15..4da13e4 100644 --- a/util/powerbuf.h +++ b/util/powerbuf.h @@ -78,6 +78,17 @@ struct powerbuf { address_t *mab; unsigned int current_head; unsigned int current_tail; + + /* Index by MAB. This is a flat array which points to indices + * within current_ua/mab. The indices are sorted in order of + * increasing MAB. + * + * Note that this array is invalidated by any modification to + * the sample buffers. You need to call powerbuf_sort() before + * accessing it. + */ + int sort_valid; + unsigned int *sorted; }; typedef struct powerbuf *powerbuf_t; @@ -120,4 +131,16 @@ void powerbuf_add_samples(powerbuf_t pb, unsigned int count, /* Retrieve the last known MAB for this session, or 0 if none exists. */ address_t powerbuf_last_mab(powerbuf_t pb); +/* Prepare the sorted MAB index. */ +void powerbuf_sort(powerbuf_t pb); + +/* Obtain charge consumption data by MAB over all sessions. This + * automatically calls powerbuf_sort() if necessary. + * + * Returns the number of samples found on success. The sum of all + * current samples is written to the sum_ua argument. + */ +int powerbuf_get_by_mab(powerbuf_t pb, address_t mab, + unsigned long long *sum_ua); + #endif