forked from cores/microwatt
Add core logging
This logs 256 bits of data per cycle to a ring buffer in BRAM. The data collected can be read out through 2 new SPRs or through the debug interface. The new SPRs are LOG_ADDR (724) and LOG_DATA (725). LOG_ADDR contains the buffer write pointer in the upper 32 bits (in units of entries, i.e. 32 bytes) and the read pointer in the lower 32 bits (in units of doublewords, i.e. 8 bytes). Reading LOG_DATA gives the doubleword from the buffer at the read pointer and increments the read pointer. Setting bit 31 of LOG_ADDR inhibits the trace log system from writing to the log buffer, so the contents are stable and can be read. There are two new debug addresses which function similarly to the LOG_ADDR and LOG_DATA SPRs. The log is frozen while either or both of the LOG_ADDR SPR bit 31 or the debug LOG_ADDR register bit 31 are set. The buffer defaults to 2048 entries, i.e. 64kB. The size is set by the LOG_LENGTH generic on the core_debug module. Software can determine the length of the buffer because the length is ORed into the buffer write pointer in the upper 32 bits of LOG_ADDR. Hence the length of the buffer can be calculated as 1 << (31 - clz(LOG_ADDR)). There is a program to format the log entries in a somewhat readable fashion in scripts/fmt_log/fmt_log.c. The log_entry struct in that file describes the layout of the bits in the log entries. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>jtag-port
parent
aab84acda8
commit
49a4d9f67a
@ -0,0 +1,12 @@
|
||||
CFLAGS = -O2 -g -Wall -std=c99
|
||||
|
||||
all: fmt_log
|
||||
|
||||
fmt_log: fmt_log.c
|
||||
$(CC) -o $@ $^ $(CFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f fmt_log
|
||||
distclean:
|
||||
rm -f *~
|
||||
|
@ -0,0 +1,235 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned long long u64;
|
||||
|
||||
struct log_entry {
|
||||
u64 nia_lo: 42;
|
||||
u64 nia_hi: 1;
|
||||
u64 ic_ra_valid: 1;
|
||||
u64 ic_access_ok: 1;
|
||||
u64 ic_is_miss: 1;
|
||||
u64 ic_is_hit: 1;
|
||||
u64 ic_way: 3;
|
||||
u64 ic_state: 1;
|
||||
u64 ic_part_nia: 4;
|
||||
u64 ic_fetch_failed: 1;
|
||||
u64 ic_stall_out: 1;
|
||||
u64 ic_wb_stall: 1;
|
||||
u64 ic_wb_cyc: 1;
|
||||
u64 ic_wb_stb: 1;
|
||||
u64 ic_wb_adr: 3;
|
||||
u64 ic_wb_ack: 1;
|
||||
|
||||
u64 ic_insn: 32;
|
||||
u64 ic_valid: 1;
|
||||
u64 d1_valid: 1;
|
||||
u64 d1_unit: 2;
|
||||
u64 d1_part_nia: 4;
|
||||
u64 d1_insn_type: 6;
|
||||
u64 d2_bypass_a: 1;
|
||||
u64 d2_bypass_b: 1;
|
||||
u64 d2_bypass_c: 1;
|
||||
u64 d2_stall_out: 1;
|
||||
u64 d2_stopped_out: 1;
|
||||
u64 d2_valid: 1;
|
||||
u64 d2_part_nia: 4;
|
||||
u64 e1_flush_out: 1;
|
||||
u64 e1_stall_out: 1;
|
||||
u64 e1_redirect: 1;
|
||||
u64 e1_valid: 1;
|
||||
u64 e1_write_enable: 1;
|
||||
u64 e1_unused: 3;
|
||||
|
||||
u64 e1_irq_state: 1;
|
||||
u64 e1_irq: 1;
|
||||
u64 e1_exception: 1;
|
||||
u64 e1_msr_dr: 1;
|
||||
u64 e1_msr_ir: 1;
|
||||
u64 e1_msr_pr: 1;
|
||||
u64 e1_msr_ee: 1;
|
||||
u64 pad1: 5;
|
||||
u64 ls_state: 3;
|
||||
u64 ls_dw_done: 1;
|
||||
u64 ls_min_done: 1;
|
||||
u64 ls_do_valid: 1;
|
||||
u64 ls_mo_valid: 1;
|
||||
u64 ls_lo_valid: 1;
|
||||
u64 ls_eo_except: 1;
|
||||
u64 ls_stall_out: 1;
|
||||
u64 pad2: 2;
|
||||
u64 dc_state: 3;
|
||||
u64 dc_ra_valid: 1;
|
||||
u64 dc_tlb_way: 3;
|
||||
u64 dc_stall_out: 1;
|
||||
u64 dc_op: 3;
|
||||
u64 dc_do_valid: 1;
|
||||
u64 dc_do_error: 1;
|
||||
u64 dc_wb_cyc: 1;
|
||||
u64 dc_wb_stb: 1;
|
||||
u64 dc_wb_ack: 1;
|
||||
u64 dc_wb_stall: 1;
|
||||
u64 dc_wb_adr: 3;
|
||||
u64 cr_wr_mask: 8;
|
||||
u64 cr_wr_data: 4;
|
||||
u64 cr_wr_enable: 1;
|
||||
u64 reg_wr_reg: 6;
|
||||
u64 reg_wr_enable: 1;
|
||||
|
||||
u64 reg_wr_data;
|
||||
};
|
||||
|
||||
#define FLAG(i, y) (log.i? y: ' ')
|
||||
#define FLGA(i, y, z) (log.i? y: z)
|
||||
#define PNIA(f) (full_nia[log.f] & 0xff)
|
||||
|
||||
const char *units[4] = { "--", "al", "ls", "?3" };
|
||||
const char *ops[64] =
|
||||
{
|
||||
"illegal", "nop ", "add ", "and ", "attn ", "b ", "bc ", "bcreg ",
|
||||
"bperm ", "cmp ", "cmpb ", "cmpeqb ", "cmprb ", "cntz ", "crop ", "darn ",
|
||||
"dcbf ", "dcbst ", "dcbt ", "dcbtst ", "dcbz ", "div ", "dive ", "exts ",
|
||||
"extswsl", "icbi ", "icbt ", "isel ", "isync ", "ld ", "st ", "maddhd ",
|
||||
"maddhdu", "maddld ", "mcrxr ", "mcrxrx ", "mfcr ", "mfmsr ", "mfspr ", "mod ",
|
||||
"mtcrf ", "mtmsr ", "mtspr ", "mull64 ", "mulh64 ", "mulh32 ", "or ", "popcnt ",
|
||||
"prty ", "rfid ", "rlc ", "rlcl ", "rlcr ", "sc ", "setb ", "shl ",
|
||||
"shr ", "sync ", "tlbie ", "trap ", "xor ", "ffail ", "?62 ", "?63 "
|
||||
};
|
||||
|
||||
const char *spr_names[13] =
|
||||
{
|
||||
"lr ", "ctr", "sr0", "sr1", "hr0", "hr1", "sg0", "sg1",
|
||||
"sg2", "sg3", "hg0", "hg1", "xer"
|
||||
};
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct log_entry log;
|
||||
u64 full_nia[16];
|
||||
long int lineno = 1;
|
||||
FILE *f;
|
||||
const char *filename;
|
||||
int i;
|
||||
long int ncompl = 0;
|
||||
|
||||
if (ac != 1 && ac != 2) {
|
||||
fprintf(stderr, "Usage: %s [filename]\n", av[0]);
|
||||
exit(1);
|
||||
}
|
||||
f = stdin;
|
||||
if (ac == 2) {
|
||||
filename = av[1];
|
||||
f = fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 15; ++i)
|
||||
full_nia[i] = i << 2;
|
||||
|
||||
while (fread(&log, sizeof(log), 1, f) == 1) {
|
||||
full_nia[log.nia_lo & 0xf] = (log.nia_hi? 0xc000000000000000: 0) |
|
||||
(log.nia_lo << 2);
|
||||
if (lineno % 20 == 1) {
|
||||
printf(" fetch1 NIA icache decode1 decode2 execute1 loadstore dcache CR GSPR\n");
|
||||
printf(" ---------------- TAHW S -WB-- pN --insn-- pN un op pN byp FR IIE MSR WC SD MM CE SRTO DE -WB-- c ms reg val\n");
|
||||
printf(" LdMy t csnSa IA IA it IA abc le srx EPID em tw rd mx tAwp vr csnSa 0 k\n");
|
||||
}
|
||||
printf("%4ld %c0000%.11llx %c ", lineno,
|
||||
(log.nia_hi? 'c': '0'),
|
||||
(unsigned long long)log.nia_lo << 2,
|
||||
FLAG(ic_stall_out, '|'));
|
||||
printf("%c%c%c%d %c %c%c%d%c%c %.2llx ",
|
||||
FLGA(ic_ra_valid, ' ', 'T'),
|
||||
FLGA(ic_access_ok, ' ', 'X'),
|
||||
FLGA(ic_is_hit, 'H', FLGA(ic_is_miss, 'M', ' ')),
|
||||
log.ic_way,
|
||||
FLAG(ic_state, 'W'),
|
||||
FLAG(ic_wb_cyc, 'c'),
|
||||
FLAG(ic_wb_stb, 's'),
|
||||
log.ic_wb_adr,
|
||||
FLAG(ic_wb_stall, 'S'),
|
||||
FLAG(ic_wb_ack, 'a'),
|
||||
PNIA(ic_part_nia));
|
||||
if (log.ic_valid)
|
||||
printf("%.8x", log.ic_insn);
|
||||
else if (log.ic_fetch_failed)
|
||||
printf("!!!!!!!!");
|
||||
else
|
||||
printf("--------");
|
||||
printf(" %c%c %.2llx ",
|
||||
FLAG(ic_valid, '>'),
|
||||
FLAG(d2_stall_out, '|'),
|
||||
PNIA(d1_part_nia));
|
||||
if (log.d1_valid)
|
||||
printf("%s %s",
|
||||
units[log.d1_unit],
|
||||
ops[log.d1_insn_type]);
|
||||
else
|
||||
printf("-- -------");
|
||||
printf(" %c%c ",
|
||||
FLAG(d1_valid, '>'),
|
||||
FLAG(d2_stall_out, '|'));
|
||||
printf("%.2llx %c%c%c %c%c ",
|
||||
PNIA(d2_part_nia),
|
||||
FLAG(d2_bypass_a, 'a'),
|
||||
FLAG(d2_bypass_b, 'b'),
|
||||
FLAG(d2_bypass_c, 'c'),
|
||||
FLAG(d2_valid, '>'),
|
||||
FLAG(e1_stall_out, '|'));
|
||||
printf("%c%c %c%c%c %c%c%c%c %c%c ",
|
||||
FLAG(e1_flush_out, 'F'),
|
||||
FLAG(e1_redirect, 'R'),
|
||||
FLAG(e1_irq_state, 'w'),
|
||||
FLAG(e1_irq, 'I'),
|
||||
FLAG(e1_exception, 'X'),
|
||||
FLAG(e1_msr_ee, 'E'),
|
||||
FLGA(e1_msr_pr, 'u', 's'),
|
||||
FLAG(e1_msr_ir, 'I'),
|
||||
FLAG(e1_msr_dr, 'D'),
|
||||
FLAG(e1_write_enable, 'W'),
|
||||
FLAG(e1_valid, 'C'));
|
||||
printf("%c %d%d %c%c %c%c %c ",
|
||||
FLAG(ls_stall_out, '|'),
|
||||
log.ls_state,
|
||||
log.ls_dw_done,
|
||||
FLAG(ls_mo_valid, 'M'),
|
||||
FLAG(ls_min_done, 'm'),
|
||||
FLAG(ls_lo_valid, 'C'),
|
||||
FLAG(ls_eo_except, 'X'),
|
||||
FLAG(ls_do_valid, '>'));
|
||||
printf("%d%c%d%d %c%c %c%c%d%c%c ",
|
||||
log.dc_state,
|
||||
FLAG(dc_ra_valid, 'R'),
|
||||
log.dc_tlb_way,
|
||||
log.dc_op,
|
||||
FLAG(dc_do_valid, 'V'),
|
||||
FLAG(dc_do_error, 'E'),
|
||||
FLAG(dc_wb_cyc, 'c'),
|
||||
FLAG(dc_wb_stb, 's'),
|
||||
log.dc_wb_adr,
|
||||
FLAG(dc_wb_stall, 'S'),
|
||||
FLAG(dc_wb_ack, 'a'));
|
||||
if (log.cr_wr_enable)
|
||||
printf("%x>%.2x ", log.cr_wr_data, log.cr_wr_mask);
|
||||
else
|
||||
printf(" ");
|
||||
if (log.reg_wr_enable) {
|
||||
if (log.reg_wr_reg < 32 || log.reg_wr_reg > 44)
|
||||
printf("r%02d", log.reg_wr_reg);
|
||||
else
|
||||
printf("%s", spr_names[log.reg_wr_reg - 32]);
|
||||
printf("=%.16llx", log.reg_wr_data);
|
||||
}
|
||||
printf("\n");
|
||||
++lineno;
|
||||
if (log.ls_lo_valid || log.e1_valid)
|
||||
++ncompl;
|
||||
}
|
||||
printf("%ld instructions completed, %.2f CPI\n", ncompl,
|
||||
(double)(lineno - 1) / ncompl);
|
||||
exit(0);
|
||||
}
|
Loading…
Reference in New Issue