Commit e505a960 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'wrpc-dump' into rubi-160120

parents c31bcc0b c06700d8
...@@ -146,6 +146,15 @@ config CHECK_RESET ...@@ -146,6 +146,15 @@ config CHECK_RESET
detects that it is re-executed and dumps a stack trace; it detects that it is re-executed and dumps a stack trace; it
then clears the stack (for next time) and restarts again. then clears the stack (for next time) and restarts again.
config SPLL_FIFO_LOG
depends on DEVELOPER
bool "Add a circular buffer for spll logging, used by tools/wrpc-dump"
help
This option addrs 256 bytes to the wrpc bynary, to log
the DDMTD tags read from the fifos, the interrupts and the
related timing. The information is shown by tools/wrpc-dump
if present, no change/rebuild of the tool is needed.
choice choice
prompt "Implementation of pp_printf" prompt "Implementation of pp_printf"
depends on DEVELOPER && WR_NODE depends on DEVELOPER && WR_NODE
......
...@@ -24,6 +24,7 @@ obj-$(CONFIG_WR_NODE) += wrc_main.o ...@@ -24,6 +24,7 @@ obj-$(CONFIG_WR_NODE) += wrc_main.o
obj-$(CONFIG_WR_SWITCH) += wrs_main.o obj-$(CONFIG_WR_SWITCH) += wrs_main.o
obj-$(CONFIG_WR_SWITCH) += ipc/minipc-mem-server.o ipc/rt_ipc.o obj-$(CONFIG_WR_SWITCH) += ipc/minipc-mem-server.o ipc/rt_ipc.o
obj-y += dump-info.o
# our linker script is preprocessed, so have a rule here # our linker script is preprocessed, so have a rule here
%.ld: %.ld.S $(AUTOCONF) .config %.ld: %.ld.S $(AUTOCONF) .config
$(CC) -include $(AUTOCONF) -E -P $*.ld.S -o $@ $(CC) -include $(AUTOCONF) -E -P $*.ld.S -o $@
...@@ -37,12 +38,15 @@ cflags-$(CONFIG_PPSI) += \ ...@@ -37,12 +38,15 @@ cflags-$(CONFIG_PPSI) += \
-ffreestanding \ -ffreestanding \
-include include/ppsi-wrappers.h \ -include include/ppsi-wrappers.h \
-Iinclude \ -Iinclude \
-I$(PPSI)/include \
-I$(PPSI)/arch-wrpc \ -I$(PPSI)/arch-wrpc \
-I$(PPSI)/arch-wrpc/include \
-I$(PPSI)/proto-ext-whiterabbit \ -I$(PPSI)/proto-ext-whiterabbit \
-Iboards/spec -Iboards/spec
# in order to build tools/wrpc-dump, we need these flags, even for wrs builds
cflags-y += \
-I$(PPSI)/arch-wrpc/include \
-I$(PPSI)/include
obj-ppsi = \ obj-ppsi = \
$(PPSI)/ppsi.o $(PPSI)/ppsi.o
......
This diff is collapsed.
...@@ -84,5 +84,9 @@ SECTIONS ...@@ -84,5 +84,9 @@ SECTIONS
/* First location in stack is highest address in RAM (stack area) */ /* First location in stack is highest address in RAM (stack area) */
PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4); PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4);
/* We have no ppi_static nor fifo_log in wrs builds */
PROVIDE(ppi_static = 0);
PROVIDE(fifo_log = 0);
} }
...@@ -64,4 +64,7 @@ SECTIONS ...@@ -64,4 +64,7 @@ SECTIONS
/* First location in stack is highest address in STACK */ /* First location in stack is highest address in STACK */
PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4); PROVIDE(_fstack = ORIGIN(stack) + LENGTH(stack) - 4);
/* This may be missing, according to .config */
PROVIDE(fifo_log = 0);
} }
...@@ -931,6 +931,92 @@ promgen -w -spi -p mcs -c FF -s 32768 -u 0 <your_bitstream>.bit \ ...@@ -931,6 +931,92 @@ promgen -w -spi -p mcs -c FF -s 32768 -u 0 <your_bitstream>.bit \
After that, you can use the Xilinx JTAG cable and Xilinx ISE Impact tool to After that, you can use the Xilinx JTAG cable and Xilinx ISE Impact tool to
write your @i{output.mcs} file to the Flash memory. write your @i{output.mcs} file to the Flash memory.
@c ##########################################################################
@page
@node wrpc-dump
@appendix wrpc-dump
In December 2015, we added @t{tools/wrpc-dump}. The program accesses
a wrpc memory image (the 128k binary dump) and prints the internal
status of the program.
@c ==========================================================================
@node wrpc-dump with Current Code
@section wrpc-dump with Current Code
@t{wrpc-dump} uses some information that we included at offset 0x80
in the binary, to detect endianness conversions and to find the actual data.
Thus, it only needs to receive the name of the file, either an on-disk file
or the live PCI memory if available (for @i{spec} devices, it's resource 0 of
the PCI space).
@example
tools/wrpc-dump /tmp/logs/vetar-dump-42
tools/wrpc-dump /sys/bus/pci/devices/0000:02:00.0/resource0
@end example
If you built @i{wrpc-sw} with @t{CONFIG_SPLL_FIFO_LOG} (a
``developer'' configuration option), the dump includes the last 16
tags being accessed by @i{softpll}, in relation with interrupts and
timing. Please see @i{sofpll/softpll_ng::_irq_enter} for details.
@c ==========================================================================
@node wrpc-dump with Older WRPC Binaries
@section wrpc-dump with Older WRPC Binaries
The tool has another working mode, that you can use with older
@i{wrpc} builds, where the special table is missing (but please be
aware that the data structures may have changed slightly). In this
mode, you provide the address of the data structure and its name. It
supports the names @i{pll}, @i{fifo} (the circular log described
above), @i{ppg}, @i{ppi}, @i{servo_state}, and @i{ds}. The last name
refers to the PTP data sets, and for this the pointer needed is
@t{ppg} (ppsi global data).
This is an example:
@smallexample
$ ./tools/wrpc-dump dump-file 00015798 servo_state
servo_state at 0x15798
if_name: ""
flags: 1
state: 4
delta_tx_m: 10
delta_rx_m: 174410
delta_tx_s: 0
delta_rx_s: 3200
fiber_fix_alpha: 73622176
clock_period_ps: 8000
t1: correct 1: 1448628309.390213200:0000
t2: correct 1: 1448628309.390213520:2921
t3: correct 1: 1448628310.419072616:0000
t4: correct 1: 1448628310.419073104:6041
[...]
@end smallexample
The address is specified as a hex number, and can be retrieved running
``@t{lm32-elf-nm wrc.elf}''.
Please note that the @i{spec} device has a strange memory mapping, and
it needs a special endian conversion. With current @i{wrpc} it is
autodetected, but if you dump an older binary you'll need to set the
@t{WRPC_SPEC} environment variable (to any value you like) to properly
access the PCI memory or a dump taken from PCI:
@smallexample
$ export WRPC_SPEC=y
@end smallexample
or
@smallexample
$ WRPC_SPEC=y ./tools/wrpc-dump dump-file 00015798 servo_state
@end smallexample
This is not needed if the dump is retrieved using Etherbone.
@c ########################################################################## @c ##########################################################################
@bye @bye
......
#include <sys/types.h>
#include <ppsi/ppsi.h>
#include <softpll_ng.h>
#include "dump-info.h"
struct dump_info dump_info[] = {
/* map for fields of ppsi structures */
#undef DUMP_STRUCT
#define DUMP_STRUCT struct pp_globals
DUMP_HEADER("pp_globals"),
DUMP_FIELD(pointer, pp_instances), /* FIXME: follow this */
DUMP_FIELD(pointer, servo), /* FIXME: follow this */
DUMP_FIELD(pointer, rt_opts),
DUMP_FIELD(pointer, defaultDS),
DUMP_FIELD(pointer, currentDS),
DUMP_FIELD(pointer, parentDS),
DUMP_FIELD(pointer, timePropertiesDS),
DUMP_FIELD(int, ebest_idx),
DUMP_FIELD(int, ebest_updated),
DUMP_FIELD(int, nlinks),
DUMP_FIELD(int, max_links),
//DUMP_FIELD(struct pp_globals_cfg cfg),
DUMP_FIELD(int, rxdrop),
DUMP_FIELD(int, txdrop),
DUMP_FIELD(pointer, arch_data),
DUMP_FIELD(pointer, global_ext_data),
#undef DUMP_STRUCT
#define DUMP_STRUCT DSDefault /* Horrible typedef */
DUMP_HEADER("DSDefault"),
DUMP_FIELD(Boolean, twoStepFlag),
DUMP_FIELD(ClockIdentity, clockIdentity),
DUMP_FIELD(UInteger16, numberPorts),
DUMP_FIELD(ClockQuality, clockQuality),
DUMP_FIELD(UInteger8, priority1),
DUMP_FIELD(UInteger8, priority2),
DUMP_FIELD(UInteger8, domainNumber),
DUMP_FIELD(Boolean, slaveOnly),
#undef DUMP_STRUCT
#define DUMP_STRUCT DSCurrent /* Horrible typedef */
DUMP_HEADER("DSCurrent"),
DUMP_FIELD(UInteger16, stepsRemoved),
DUMP_FIELD(TimeInternal, offsetFromMaster),
DUMP_FIELD(TimeInternal, meanPathDelay), /* oneWayDelay */
DUMP_FIELD(UInteger16, primarySlavePortNumber),
#undef DUMP_STRUCT
#define DUMP_STRUCT DSParent /* Horrible typedef */
DUMP_HEADER("DSParent"),
DUMP_FIELD(PortIdentity, parentPortIdentity),
DUMP_FIELD(UInteger16, observedParentOffsetScaledLogVariance),
DUMP_FIELD(Integer32, observedParentClockPhaseChangeRate),
DUMP_FIELD(ClockIdentity, grandmasterIdentity),
DUMP_FIELD(ClockQuality, grandmasterClockQuality),
DUMP_FIELD(UInteger8, grandmasterPriority1),
DUMP_FIELD(UInteger8, grandmasterPriority2),
#undef DUMP_STRUCT
#define DUMP_STRUCT DSTimeProperties /* Horrible typedef */
DUMP_HEADER("DSTimeProperties"),
DUMP_FIELD(Integer16, currentUtcOffset),
DUMP_FIELD(Boolean, currentUtcOffsetValid),
DUMP_FIELD(Boolean, leap59),
DUMP_FIELD(Boolean, leap61),
DUMP_FIELD(Boolean, timeTraceable),
DUMP_FIELD(Boolean, frequencyTraceable),
DUMP_FIELD(Boolean, ptpTimescale),
DUMP_FIELD(Enumeration8, timeSource),
#undef DUMP_STRUCT
#define DUMP_STRUCT struct wr_servo_state
DUMP_HEADER("servo_state"),
DUMP_FIELD_SIZE(char, if_name, 16),
DUMP_FIELD(unsigned_long, flags),
DUMP_FIELD(int, state),
DUMP_FIELD(Integer32, delta_tx_m),
DUMP_FIELD(Integer32, delta_rx_m),
DUMP_FIELD(Integer32, delta_tx_s),
DUMP_FIELD(Integer32, delta_rx_s),
DUMP_FIELD(Integer32, fiber_fix_alpha),
DUMP_FIELD(Integer32, clock_period_ps),
DUMP_FIELD(TimeInternal, t1),
DUMP_FIELD(TimeInternal, t2),
DUMP_FIELD(TimeInternal, t3),
DUMP_FIELD(TimeInternal, t4),
DUMP_FIELD(Integer32, delta_ms_prev),
DUMP_FIELD(int, missed_iters),
DUMP_FIELD(TimeInternal, mu), /* half of the RTT */
DUMP_FIELD(Integer64, picos_mu),
DUMP_FIELD(Integer32, cur_setpoint),
DUMP_FIELD(Integer32, delta_ms),
DUMP_FIELD(UInteger32, update_count),
DUMP_FIELD(int, tracking_enabled),
DUMP_FIELD_SIZE(char, servo_state_name, 32),
DUMP_FIELD(Integer64, skew),
DUMP_FIELD(Integer64, offset),
DUMP_FIELD(UInteger32, n_err_state),
DUMP_FIELD(UInteger32, n_err_offset),
DUMP_FIELD(UInteger32, n_err_delta_rtt),
#undef DUMP_STRUCT
#define DUMP_STRUCT struct pp_instance
DUMP_HEADER("pp_instance"),
DUMP_FIELD(int, state),
DUMP_FIELD(int, next_state),
DUMP_FIELD(int, next_delay),
DUMP_FIELD(int, is_new_state),
DUMP_FIELD(pointer, arch_data),
DUMP_FIELD(pointer, ext_data),
DUMP_FIELD(unsigned_long, d_flags),
DUMP_FIELD(unsigned_char, flags),
DUMP_FIELD(unsigned_char, role),
DUMP_FIELD(unsigned_char, proto),
DUMP_FIELD(pointer, glbs),
DUMP_FIELD(pointer, n_ops),
DUMP_FIELD(pointer, t_ops),
DUMP_FIELD(pointer, __tx_buffer),
DUMP_FIELD(pointer, __rx_buffer),
DUMP_FIELD(pointer, tx_frame),
DUMP_FIELD(pointer, rx_frame),
DUMP_FIELD(pointer, tx_ptp),
DUMP_FIELD(pointer, rx_ptp),
/* This is a sub-structure */
DUMP_FIELD(int, ch[0].fd),
DUMP_FIELD(pointer, ch[0].custom),
DUMP_FIELD(pointer, ch[0].arch_data),
DUMP_FIELD_SIZE(bina, ch[0].addr, 6),
DUMP_FIELD(int, ch[0].pkt_present),
DUMP_FIELD(int, ch[1].fd),
DUMP_FIELD(pointer, ch[1].custom),
DUMP_FIELD(pointer, ch[1].arch_data),
DUMP_FIELD_SIZE(bina, ch[1].addr, 6),
DUMP_FIELD(int, ch[1].pkt_present),
DUMP_FIELD(ip_address, mcast_addr),
DUMP_FIELD(int, tx_offset),
DUMP_FIELD(int, rx_offset),
DUMP_FIELD_SIZE(bina, peer, 6),
DUMP_FIELD(uint16_t, peer_vid),
DUMP_FIELD(TimeInternal, t1),
DUMP_FIELD(TimeInternal, t2),
DUMP_FIELD(TimeInternal, t3),
DUMP_FIELD(TimeInternal, t4),
DUMP_FIELD(TimeInternal, cField),
DUMP_FIELD(TimeInternal, last_rcv_time),
DUMP_FIELD(TimeInternal, last_snt_time),
DUMP_FIELD(UInteger16, frgn_rec_num),
DUMP_FIELD(Integer16, frgn_rec_best),
//DUMP_FIELD(struct pp_frgn_master frgn_master[PP_NR_FOREIGN_RECORDS]),
DUMP_FIELD(pointer, portDS),
//DUMP_FIELD(unsigned long timeouts[__PP_TO_ARRAY_SIZE]),
DUMP_FIELD(UInteger16, recv_sync_sequence_id),
DUMP_FIELD(Integer8, log_min_delay_req_interval),
//DUMP_FIELD(UInteger16 sent_seq[__PP_NR_MESSAGES_TYPES]),
DUMP_FIELD_SIZE(bina, received_ptp_header, sizeof(MsgHeader)),
//DUMP_FIELD(pointer, iface_name),
//DUMP_FIELD(pointer, port_name),
DUMP_FIELD(int, port_idx),
DUMP_FIELD(int, vlans_array_len),
/* FIXME: array */
DUMP_FIELD(int, nvlans),
/* sub structure */
DUMP_FIELD_SIZE(char, cfg.port_name, 16),
DUMP_FIELD_SIZE(char, cfg.iface_name, 16),
DUMP_FIELD(int, cfg.ext),
DUMP_FIELD(int, cfg.ext),
DUMP_FIELD(unsigned_long, ptp_tx_count),
DUMP_FIELD(unsigned_long, ptp_rx_count),
#undef DUMP_STRUCT
#define DUMP_STRUCT struct softpll_state
DUMP_HEADER("softpll"),
DUMP_FIELD(int, mode),
DUMP_FIELD(int, seq_state),
DUMP_FIELD(int, dac_timeout),
DUMP_FIELD(int, default_dac_main),
DUMP_FIELD(int, delock_count),
DUMP_FIELD(uint32_t, irq_count),
DUMP_FIELD(int, mpll_shift_ps),
DUMP_FIELD(int, helper.p_adder),
DUMP_FIELD(int, helper.p_setpoint),
DUMP_FIELD(int, helper.tag_d0),
DUMP_FIELD(int, helper.ref_src),
DUMP_FIELD(int, helper.sample_n),
DUMP_FIELD(int, helper.delock_count),
/* FIXME: missing helper.pi etc.. */
DUMP_FIELD(int, ext.enabled),
DUMP_FIELD(int, ext.align_state),
DUMP_FIELD(int, ext.align_timer),
DUMP_FIELD(int, ext.align_target),
DUMP_FIELD(int, ext.align_step),
DUMP_FIELD(int, ext.align_shift),
DUMP_FIELD(int, mpll.state),
/* FIXME: mpll.pi etc */
DUMP_FIELD(int, mpll.adder_ref),
DUMP_FIELD(int, mpll.adder_out),
DUMP_FIELD(int, mpll.tag_ref),
DUMP_FIELD(int, mpll.tag_out),
DUMP_FIELD(int, mpll.tag_ref_d),
DUMP_FIELD(int, mpll.tag_out_d),
DUMP_FIELD(uint32_t, mpll.seq_ref),
DUMP_FIELD(int, mpll.seq_out),
DUMP_FIELD(int, mpll.match_state),
DUMP_FIELD(int, mpll.match_seq),
DUMP_FIELD(int, mpll.phase_shift_target),
DUMP_FIELD(int, mpll.phase_shift_current),
DUMP_FIELD(int, mpll.id_ref),
DUMP_FIELD(int, mpll.id_out),
DUMP_FIELD(int, mpll.sample_n),
DUMP_FIELD(int, mpll.delock_count),
DUMP_FIELD(int, mpll.dac_index),
DUMP_FIELD(int, mpll.enabled),
#undef DUMP_STRUCT
#define DUMP_STRUCT struct spll_fifo_log
DUMP_HEADER("pll_fifo"),
DUMP_FIELD(uint32_t, trr),
DUMP_FIELD(uint32_t, tstamp),
DUMP_FIELD(uint32_t, duration),
DUMP_FIELD(uint16_t, irq_count),
DUMP_FIELD(uint16_t, tag_count),
/* FIXME: aux_state and ptracker_state -- variable-len arrays */
DUMP_HEADER("end"),
};
/*
* This header defines structures for dumping other structures from
* binary files. Every arch has a different endianness and alignment/size,
* so we can't just use the structures from the host compiler. It used to
* work for lm32/i386, but it fails with x86-64, so let's change attitude.
*/
#include <stdint.h>
/*
* To ease copying from header files, allow int, char and other known types.
* Please add more type as more structures are included here
*/
enum dump_type {
dump_type_char, /* for zero-terminated strings */
dump_type_bina, /* for binary stull in MAC format */
/* normal types follow */
dump_type_uint32_t,
dump_type_uint16_t,
dump_type_int,
dump_type_unsigned_long,
dump_type_unsigned_char,
dump_type_unsigned_short,
dump_type_double,
dump_type_float,
dump_type_pointer,
/* and strange ones, from IEEE */
dump_type_UInteger64,
dump_type_Integer64,
dump_type_UInteger32,
dump_type_Integer32,
dump_type_UInteger16,
dump_type_Integer16,
dump_type_UInteger8,
dump_type_Integer8,
dump_type_Enumeration8,
dump_type_Boolean,
dump_type_ClockIdentity,
dump_type_PortIdentity,
dump_type_ClockQuality,
/* and this is ours */
dump_type_TimeInternal,
dump_type_ip_address,
};
/* because of the sizeof later on, we need these typedefs */
typedef void * pointer;
typedef unsigned long unsigned_long;
typedef unsigned char unsigned_char;
typedef unsigned short unsigned_short;
typedef struct {unsigned char addr[4];} ip_address;
/*
* This is generated with the target compiler, and then linked
* by the host compiler, so size and alignment must be safe. Then, the
* first structure in each group has the endian flag and the structure name.
* Following ones have zero in endian flag and field name.
*/
#define DUMP_ENDIAN_FLAG 0x12345678
struct dump_info {
uint32_t endian_flag;
uint32_t type;
uint32_t offset;
uint32_t size;
char name[48];
};
extern struct dump_info dump_info[]; /* wrpc-sw/dump-info.c -> bina -> elf */
#define DUMP_HEADER(_struct) { \
.endian_flag = DUMP_ENDIAN_FLAG, \
.name = _struct, \
}
/* The macros below rely on DUMP_STRUCT that must be externally defined */
#define DUMP_FIELD(_type, _fname) { \
.endian_flag = 0, \
.type = dump_type_ ## _type, \
.offset = offsetof(DUMP_STRUCT, _fname),\
.size = sizeof(_type), \
.name = #_fname, \
}
#define DUMP_FIELD_SIZE(_type, _fname, _size) { \
.endian_flag = 0, \
.type = dump_type_ ## _type, \
.offset = offsetof(DUMP_STRUCT, _fname),\
.size = _size, \
.name = #_fname, \
}
...@@ -21,26 +21,20 @@ ...@@ -21,26 +21,20 @@
#include "irq.h" #include "irq.h"
volatile int irq_count = 0; #ifdef CONFIG_SPLL_FIFO_LOG
struct spll_fifo_log fifo_log[FIFO_LOG_LEN];
#define HAS_FIFO_LOG 1
#else
#define HAS_FIFO_LOG 0
extern struct spll_fifo_log *fifo_log;
#endif
volatile struct SPLL_WB *SPLL; volatile struct SPLL_WB *SPLL;
volatile struct PPSG_WB *PPSG; volatile struct PPSG_WB *PPSG;
int spll_n_chan_ref, spll_n_chan_out; int spll_n_chan_ref, spll_n_chan_out;
/*
* The includes below contain code (not only declarations) to enable
* the compiler to inline functions where necessary and save some CPU
* cycles
*/
#include "spll_defs.h"
#include "spll_common.h"
#include "spll_debug.h"
#include "spll_helper.h"
#include "spll_main.h"
#include "spll_ptracker.h"
#include "spll_external.h"
#define MAIN_CHANNEL (spll_n_chan_ref) #define MAIN_CHANNEL (spll_n_chan_ref)
...@@ -60,30 +54,6 @@ int spll_n_chan_ref, spll_n_chan_out; ...@@ -60,30 +54,6 @@ int spll_n_chan_ref, spll_n_chan_out;
#define AUX_ALIGN_PHASE 3 #define AUX_ALIGN_PHASE 3
#define AUX_READY 4 #define AUX_READY 4
struct spll_aux_state {
int seq_state;
int32_t phase_target;
union {
struct spll_main_state dmtd;
/* spll_external_state ch_bb */
} pll;
};
struct softpll_state {
int mode;
int seq_state;
int dac_timeout;
int default_dac_main;
int delock_count;
int32_t mpll_shift_ps;
struct spll_helper_state helper;
struct spll_external_state ext;
struct spll_main_state mpll;
struct spll_aux_state aux[MAX_CHAN_AUX];
struct spll_ptracker_state ptrackers[MAX_PTRACKERS];
};
static const struct stringlist_entry seq_states [] = static const struct stringlist_entry seq_states [] =
{ {
{ SEQ_START_EXT, "start-ext" }, { SEQ_START_EXT, "start-ext" },
...@@ -99,7 +69,7 @@ static const struct stringlist_entry seq_states [] = ...@@ -99,7 +69,7 @@ static const struct stringlist_entry seq_states [] =
{ 0, NULL } { 0, NULL }
}; };
static volatile struct softpll_state softpll; volatile struct softpll_state softpll;
static volatile int ptracker_mask = 0; static volatile int ptracker_mask = 0;
/* fixme: should be done by spll_init() but spll_init is called to /* fixme: should be done by spll_init() but spll_init is called to
...@@ -265,19 +235,43 @@ static inline void update_loops(struct softpll_state *s, int tag_value, int tag_ ...@@ -265,19 +235,43 @@ static inline void update_loops(struct softpll_state *s, int tag_value, int tag_
void _irq_entry(void) void _irq_entry(void)
{ {
struct softpll_state *s = (struct softpll_state *)&softpll; struct softpll_state *s = (struct softpll_state *)&softpll;
uint32_t trr;
int i, tag_source, tag_value;
static uint16_t tag_count;
struct spll_fifo_log *l = NULL;
uint32_t enter_stamp;
/* check if there are more tags in the FIFO */ if (HAS_FIFO_LOG)
enter_stamp = (PPSG->CNTR_NSEC & 0xfffffff);
/* check if there are more tags in the FIFO, and log them if so configured to */
while (!(SPLL->TRR_CSR & SPLL_TRR_CSR_EMPTY)) { while (!(SPLL->TRR_CSR & SPLL_TRR_CSR_EMPTY)) {
trr = SPLL->TRR_R0;
volatile uint32_t trr = SPLL->TRR_R0;
int tag_source = SPLL_TRR_R0_CHAN_ID_R(trr); if (HAS_FIFO_LOG) {
int tag_value = SPLL_TRR_R0_VALUE_R(trr); /* save this to a circular buffer */
i = tag_count % FIFO_LOG_LEN;
l = fifo_log + i;
l->tstamp = (PPSG->CNTR_NSEC & 0xfffffff);
if (!enter_stamp)
enter_stamp = l->tstamp;
l->duration = 0;
l->trr = trr;
l->irq_count = s->irq_count & 0xffff;
l->tag_count = tag_count++;
}
/* And process the values */
tag_source = SPLL_TRR_R0_CHAN_ID_R(trr);
tag_value = SPLL_TRR_R0_VALUE_R(trr);
sequencing_fsm(s, tag_value, tag_source); sequencing_fsm(s, tag_value, tag_source);
update_loops(s, tag_value, tag_source); update_loops(s, tag_value, tag_source);
} }
irq_count++; if (HAS_FIFO_LOG && l)
l->duration = (PPSG->CNTR_NSEC & 0xfffffff) - enter_stamp;
s->irq_count++;
clear_irq(); clear_irq();
} }
...@@ -481,13 +475,16 @@ void spll_get_num_channels(int *n_ref, int *n_out) ...@@ -481,13 +475,16 @@ void spll_get_num_channels(int *n_ref, int *n_out)
void spll_show_stats() void spll_show_stats()
{ {
struct softpll_state *s = (struct softpll_state *)&softpll;
if (softpll.mode > 0) if (softpll.mode > 0)
pp_printf("softpll: irqs %d seq %s mode %d " pp_printf("softpll: irqs %d seq %s mode %d "
"alignment_state %d HL%d ML%d HY=%d MY=%d DelCnt=%d\n", "alignment_state %d HL%d ML%d HY=%d MY=%d DelCnt=%d\n",
irq_count, stringlist_lookup(seq_states, softpll.seq_state), softpll.mode, s->irq_count, stringlist_lookup(seq_states, s->seq_state),
softpll.ext.align_state, softpll.helper.ld.locked, softpll.mpll.ld.locked, s->mode, s->ext.align_state,
softpll.helper.pi.y, softpll.mpll.pi.y, s->helper.ld.locked, s->mpll.ld.locked,
softpll.delock_count); s->helper.pi.y, s->mpll.pi.y,
s->delock_count);
} }
int spll_shifter_busy(int channel) int spll_shifter_busy(int channel)
...@@ -657,7 +654,7 @@ void spll_update() ...@@ -657,7 +654,7 @@ void spll_update()
if (is_wr_switch) { if (is_wr_switch) {
stats.sequence++; stats.sequence++;
stats.mode = softpll.mode; stats.mode = softpll.mode;
stats.irq_cnt = irq_count; stats.irq_cnt = softpll.irq_count;
stats.seq_state = softpll.seq_state; stats.seq_state = softpll.seq_state;
stats.align_state = softpll.ext.align_state; stats.align_state = softpll.ext.align_state;
stats.H_lock = softpll.helper.ld.locked; stats.H_lock = softpll.helper.ld.locked;
......
...@@ -13,6 +13,14 @@ ...@@ -13,6 +13,14 @@
#define __SOFTPLL_NG_H #define __SOFTPLL_NG_H
#include <stdint.h> #include <stdint.h>
#include "spll_defs.h"
#include "spll_common.h"
#include "spll_debug.h"
#include "spll_helper.h"
#include "spll_main.h"
#include "spll_ptracker.h"
#include "spll_external.h"
/* SoftPLL operating modes, for mode parameter of spll_init(). */ /* SoftPLL operating modes, for mode parameter of spll_init(). */
...@@ -155,5 +163,45 @@ struct spll_stats { ...@@ -155,5 +163,45 @@ struct spll_stats {
/* This only exists in wr-switch, but we should use it always */ /* This only exists in wr-switch, but we should use it always */
extern struct spll_stats stats; extern struct spll_stats stats;
/*
* Aux and main state:
* used to be in .c file, but we need it here for memory dumping
*/
struct spll_aux_state {
int seq_state;
int32_t phase_target;
union {
struct spll_main_state dmtd;
/* spll_external_state ch_bb */
} pll;
};
struct softpll_state {
int mode;
int seq_state;
int dac_timeout;
int default_dac_main;
int delock_count;
unsigned irq_count;
int32_t mpll_shift_ps;
struct spll_helper_state helper;
struct spll_external_state ext;
struct spll_main_state mpll;
struct spll_aux_state aux[MAX_CHAN_AUX];
struct spll_ptracker_state ptrackers[MAX_PTRACKERS];
};
struct spll_fifo_log {
uint32_t trr;
uint32_t tstamp;
uint32_t duration;
uint16_t irq_count;
uint16_t tag_count;
};
#define FIFO_LOG_LEN 16
#endif // __SOFTPLL_NG_H #endif // __SOFTPLL_NG_H
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
#include <string.h> #include <string.h>
#include <pp-printf.h> #include <pp-printf.h>
#include "trace.h" #include "trace.h"
#include "spll_defs.h" #include "softpll_ng.h"
#include "spll_common.h"
int pi_update(spll_pi_t *pi, int x) int pi_update(spll_pi_t *pi, int x)
{ {
......
...@@ -12,15 +12,11 @@ ...@@ -12,15 +12,11 @@
#ifndef __SPLL_COMMON_H #ifndef __SPLL_COMMON_H
#define __SPLL_COMMON_H #define __SPLL_COMMON_H
#include <stdint.h>
#include <stdlib.h>
#include <syscon.h> #include <syscon.h>
#include <hw/softpll_regs.h> #include <hw/softpll_regs.h>
#include <hw/pps_gen_regs.h> #include <hw/pps_gen_regs.h>
#include "spll_defs.h"
#define SPLL_LOCKED 1 #define SPLL_LOCKED 1
#define SPLL_LOCKING 0 #define SPLL_LOCKING 0
......
...@@ -10,8 +10,7 @@ ...@@ -10,8 +10,7 @@
/* spll_external.h - implementation of SoftPLL servo for the /* spll_external.h - implementation of SoftPLL servo for the
external (10 MHz - Grandmaster mode) reference channel */ external (10 MHz - Grandmaster mode) reference channel */
#include "spll_external.h" #include "softpll_ng.h"
#include "spll_debug.h"
#include <pp-printf.h> #include <pp-printf.h>
#include "trace.h" #include "trace.h"
......
...@@ -13,9 +13,7 @@ ...@@ -13,9 +13,7 @@
#ifndef __SPLL_EXTERNAL_H #ifndef __SPLL_EXTERNAL_H
#define __SPLL_EXTERNAL_H #define __SPLL_EXTERNAL_H
#include "spll_common.h" #include "softpll_ng.h"
#include "spll_helper.h"
#include "spll_main.h"
struct spll_external_state { struct spll_external_state {
struct spll_helper_state *helper; struct spll_helper_state *helper;
......
...@@ -9,8 +9,7 @@ ...@@ -9,8 +9,7 @@
/* spll_helper.c - implmentation of the Helper PLL servo algorithm. */ /* spll_helper.c - implmentation of the Helper PLL servo algorithm. */
#include "spll_helper.h" #include "softpll_ng.h"
#include "spll_debug.h"
const int helper_precomp_coefs [] = const int helper_precomp_coefs [] =
{ /*b0*/ 60648, { /*b0*/ 60648,
......
...@@ -9,8 +9,7 @@ ...@@ -9,8 +9,7 @@
/* spll_main.c - Implementation of the main DDMTD PLL. */ /* spll_main.c - Implementation of the main DDMTD PLL. */
#include "spll_main.h" #include "softpll_ng.h"
#include "spll_debug.h"
#include <pp-printf.h> #include <pp-printf.h>
#include "trace.h" #include "trace.h"
......
...@@ -13,8 +13,6 @@ ...@@ -13,8 +13,6 @@
#ifndef __SPLL_MAIN_H #ifndef __SPLL_MAIN_H
#define __SPLL_MAIN_H #define __SPLL_MAIN_H
#include "spll_common.h"
/* State of the Main PLL */ /* State of the Main PLL */
struct spll_main_state { struct spll_main_state {
int state; int state;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/* spll_ptracker.c - implementation of phase trackers. */ /* spll_ptracker.c - implementation of phase trackers. */
#include "spll_ptracker.h" #include "softpll_ng.h"
static int tag_ref = -1; static int tag_ref = -1;
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#ifndef __SPLL_PTRACKER_H #ifndef __SPLL_PTRACKER_H
#define __SPLL_PTRACKER_H #define __SPLL_PTRACKER_H
#include "spll_common.h"
struct spll_ptracker_state { struct spll_ptracker_state {
int enabled, id; int enabled, id;
int n_avg, acc, avg_count, preserve_sign; int n_avg, acc, avg_count, preserve_sign;
......
...@@ -9,3 +9,4 @@ sdb-wrpc.bin ...@@ -9,3 +9,4 @@ sdb-wrpc.bin
flash-read flash-read
flash-write flash-write
pfilter-builder pfilter-builder
wrpc-dump
\ No newline at end of file
...@@ -6,6 +6,7 @@ LDFLAGS = -lutil ...@@ -6,6 +6,7 @@ LDFLAGS = -lutil
ALL = genraminit genramvhd genrammif wrpc-uart-sw ALL = genraminit genramvhd genrammif wrpc-uart-sw
ALL += wrpc-w1-read wrpc-w1-write ALL += wrpc-w1-read wrpc-w1-write
ALL += pfilter-builder ALL += pfilter-builder
ALL += wrpc-dump
ifneq ($(EB),no) ifneq ($(EB),no)
ALL += eb-w1-write ALL += eb-w1-write
...@@ -41,5 +42,20 @@ eb-w1-write: eb-w1-write.c ../dev/w1.c ../dev/w1-eeprom.c eb-w1.c ...@@ -41,5 +42,20 @@ eb-w1-write: eb-w1-write.c ../dev/w1.c ../dev/w1-eeprom.c eb-w1.c
sdb-wrpc.bin: sdbfs sdb-wrpc.bin: sdbfs
$(SDBFS)/gensdbfs $< $@ $(SDBFS)/gensdbfs $< $@
wrpc-dump: wrpc-dump.c dump-info-host.o
$(CC) $(CFLAGS) -I../ppsi/include -I../ppsi/arch-wrpc/include \
-I ../softpll \
$^ -o $@
dump-info-host.o: ../dump-info.o
$(CROSS_COMPILE)objcopy --only-section=.data.dump_info \
-O binary $^ dump-info-host.bin
$(AS) makebin.S -o $@
../dump-info.o: ../dump-info.c
$(MAKE) -C .. dump-info.o
clean: clean:
rm -f $(ALL) *.o *~ rm -f $(ALL) *.o *~
/*
* "objcopy -O binary" they say...
* how can I say "spit the default ELF object format"?
*/
.data
.global dump_info
dump_info:
.incbin "dump-info-host.bin"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <arpa/inet.h> /* ntohl */
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <ppsi/ppsi.h>
#include <softpll_ng.h>
#include <dump-info.h>
/* We have a problem: ppsi is built for wrpc, so it has ntoh[sl] wrong */
#undef ntohl
#undef ntohs
#undef ntohll
#define ntohs(x) __do_not_use
#define ntohl(x) __do_not_use
#define ntohll(x) __do_not_use
uint32_t endian_flag; /* from dump_info[0], lazily */
/*
* This picks items from memory, converting as needed. No ntohl any more.
* Next, we'll detect the byte order from the code itself.
*/
static long long wrpc_get_64(void *p)
{
uint64_t *p64 = p;
uint64_t result;
if (endian_flag == DUMP_ENDIAN_FLAG) {
result = *p64 >> 32;
result |= (uint32_t)*p64;
return result;
}
result = __bswap_32((uint32_t)(*p64 >> 32));
result <<= 32;
result |= __bswap_32((uint32_t)*p64);
return result;
}
/* printf complains for i/l mismatch, so get i32 and l32 separately */
static long wrpc_get_l32(void *p)
{
uint32_t *p32 = p;
if (endian_flag == DUMP_ENDIAN_FLAG)
return *p32;
return __bswap_32(*p32);
}
static int wrpc_get_i32(void *p)
{
return wrpc_get_l32(p);
}
static int wrpc_get_16(void *p)
{
uint16_t *p16 = p;
if (endian_flag == DUMP_ENDIAN_FLAG)
return *p16;
return __bswap_16(*p16);
}
void dump_one_field(void *addr, struct dump_info *info)
{
void *p = addr + wrpc_get_i32(&info->offset);
struct TimeInternal *ti = p;
struct PortIdentity *pi = p;
struct ClockQuality *cq = p;
char format[16];
char localname[64];
int i, type, size;
/* now, info may be in wrong-endian. so fix it */
type = wrpc_get_i32(&info->type);
size = wrpc_get_i32(&info->size);
sprintf(localname, "%s:", info->name);
printf(" %-30s ", localname);
switch(type) {
case dump_type_char:
sprintf(format,"\"%%.%is\"\n", size);
printf(format, (char *)p);
break;
case dump_type_bina:
for (i = 0; i < size; i++)
printf("%02x%c", ((unsigned char *)p)[i],
i == size - 1 ? '\n' : ':');
break;
case dump_type_UInteger64:
printf("%lld\n", wrpc_get_64(p));
break;
case dump_type_Integer64:
printf("%lld\n", wrpc_get_64(p));
break;
case dump_type_uint32_t:
printf("0x%08lx\n", wrpc_get_l32(p));
break;
case dump_type_Integer32:
case dump_type_int:
printf("%i\n", wrpc_get_i32(p));
break;
case dump_type_UInteger32:
case dump_type_unsigned_long:
printf("%li\n", wrpc_get_l32(p));
break;
case dump_type_unsigned_char:
case dump_type_UInteger8:
case dump_type_Integer8:
case dump_type_Enumeration8:
case dump_type_Boolean:
printf("%i\n", *(unsigned char *)p);
break;
case dump_type_UInteger16:
case dump_type_uint16_t:
case dump_type_unsigned_short:
printf("%i\n", wrpc_get_16(p));
break;
case dump_type_double:
printf("%lf\n", *(double *)p);
break;
case dump_type_float:
printf("%f\n", *(float *)p);
break;
case dump_type_pointer:
if (size == 4)
printf("%08lx\n", wrpc_get_l32(p));
else
printf("%016llx\n", wrpc_get_64(p));
break;
case dump_type_Integer16:
printf("%i\n", wrpc_get_16(p));
break;
case dump_type_TimeInternal:
printf("correct %i: %10i.%09i:%04i\n",
wrpc_get_i32(&ti->correct),
wrpc_get_i32(&ti->seconds),
wrpc_get_i32(&ti->nanoseconds),
wrpc_get_i32(&ti->phase));
break;
case dump_type_ip_address:
for (i = 0; i < 4; i++)
printf("%02x%c", ((unsigned char *)p)[i],
i == 3 ? '\n' : ':');
break;
case dump_type_ClockIdentity: /* Same as binary */
for (i = 0; i < sizeof(ClockIdentity); i++)
printf("%02x%c", ((unsigned char *)p)[i],
i == sizeof(ClockIdentity) - 1 ? '\n' : ':');
break;
case dump_type_PortIdentity: /* Same as above plus port */
for (i = 0; i < sizeof(ClockIdentity); i++)
printf("%02x%c", ((unsigned char *)p)[i],
i == sizeof(ClockIdentity) - 1 ? '.' : ':');
printf("%04x (%i)\n", pi->portNumber, pi->portNumber);
break;
case dump_type_ClockQuality:
printf("class %i, accuracy %02x (%i), logvariance %i\n",
cq->clockClass, cq->clockAccuracy, cq->clockAccuracy,
wrpc_get_16(&cq->offsetScaledLogVariance));
break;
}
}
void dump_many_fields(void *addr, char *name)
{
struct dump_info *p = dump_info;
/* Look for name */
for (; strcmp(p->name, "end"); p++)
if (!strcmp(p->name, name))
break;
if (!strcmp(p->name, "end")) {
fprintf(stderr, "structure \"%s\" not described\n", name);
return;
}
endian_flag = p->endian_flag;
for (p++; p->endian_flag == 0; p++)
dump_one_field(addr, p);
}
unsigned long wrpc_get_pointer(void *base, char *s_name, char *f_name)
{
struct dump_info *p = dump_info;
int offset;
for (; strcmp(p->name, "end"); p++)
if (!strcmp(p->name, s_name))
break;
if (!strcmp(p->name, "end")) {
fprintf(stderr, "structure \"%s\" not described\n", s_name);
return 0;
}
endian_flag = p->endian_flag;
/* Look for the field: we find the offset, */
for (p++; p->endian_flag == 0; p++) {
if (!strcmp(p->name, f_name)) {
offset = wrpc_get_i32(&p->offset);
return wrpc_get_l32(base + offset);
}
}
fprintf(stderr, "can't find \"%s\" in \"%s\"\n", f_name, s_name);
return 0;
}
/* all of these are 0 by default */
unsigned long spll_off, fifo_off, ppi_off, ppg_off, servo_off, ds_off;
/* Use: wrs_dump_memory <file> <hex-offset> <name> */
int main(int argc, char **argv)
{
int fd;
void *mapaddr;
unsigned long offset;
struct stat st;
char *dumpname = "";
char c;
if (argc != 4 && argc != 2) {
fprintf(stderr, "%s: use \"%s <file> <offset> <name>\n",
argv[0], argv[0]);
fprintf(stderr,
"\"name\" is one of pll, fifo, ppg, ppi, servo_state"
" or ds for data-sets. \"ds\" gets a ppg offset\n");
fprintf(stderr, "But with a new binary, just pass <file>\n");
exit(1);
}
fd = open(argv[1], O_RDONLY | O_SYNC);
if (fd < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], argv[1], strerror(errno));
exit(1);
}
if (fstat(fd, &st) < 0) {
fprintf(stderr, "%s: stat(%s): %s\n",
argv[0], argv[1], strerror(errno));
exit(1);
}
if (!S_ISREG(st.st_mode)) { /* FIXME: support memory */
fprintf(stderr, "%s: %s not a regular file\n",
argv[0], argv[1]);
exit(1);
}
if (st.st_size > 128 * 1024) /* support /sys/..../resource0 */
st.st_size = 128 * 1024;
if (argc == 4 && sscanf(argv[2], "%lx%c", &offset, &c) != 1) {
fprintf(stderr, "%s: \"%s\" not a hex offset\n", argv[0],
argv[2]);
exit(1);
}
mapaddr = mmap(0, st.st_size, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_PRIVATE, fd, 0);
if (mapaddr == MAP_FAILED) {
fprintf(stderr, "%s: mmap(%s): %s\n",
argv[0], argv[1], strerror(errno));
exit(1);
}
/* In case we have a "new" binary file, use such information */
if (!strncmp(mapaddr + 0x80, "CPRW", 4))
setenv("WRPC_SPEC", "yes", 1);
/* If the dump file needs "spec" byte order, fix it all */
if (getenv("WRPC_SPEC")) {
uint32_t *p = mapaddr;
int i;
for (i = 0; i < st.st_size / 4; i++, p++)
*p = __bswap_32(*p);
}
if (argc == 4)
dumpname = argv[3];
/* If we have a new binary file, pick the pointers */
if (!strncmp(mapaddr + 0x80, "WRPC----", 8)) {
spll_off = wrpc_get_l32(mapaddr + 0x90);
fifo_off = wrpc_get_l32(mapaddr + 0x94);
ppi_off = wrpc_get_l32(mapaddr + 0x98);
if (ppi_off) { /* This is 0 for wrs */
ppg_off = wrpc_get_pointer(mapaddr + ppi_off,
"pp_instance", "glbs");
servo_off = wrpc_get_pointer(mapaddr + ppg_off,
"pp_globals", "global_ext_data");
ds_off = ppg_off;
}
}
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
/* Now check the "name" to be dumped */
if (!strcmp(dumpname, "pll"))
spll_off = offset;
if (spll_off) {
printf("pll at 0x%lx\n", spll_off);
dump_many_fields(mapaddr + spll_off, "softpll");
}
if (!strcmp(dumpname, "fifo"))
fifo_off = offset;
if (fifo_off) {
int i;
printf("fifo log at 0x%lx\n", fifo_off);
for (i = 0; i < FIFO_LOG_LEN; i++)
dump_many_fields(mapaddr + fifo_off
+ i * sizeof(struct spll_fifo_log),
"pll_fifo");
}
if (!strcmp(dumpname, "ppg"))
ppg_off = offset;
if (ppg_off) {
printf("ppg at 0x%lx\n", ppg_off);
dump_many_fields(mapaddr + ppg_off, "pp_globals");
}
if (!strcmp(dumpname, "ppi"))
ppi_off = offset;
if (ppi_off) {
printf("ppi at 0x%lx\n", ppi_off);
dump_many_fields(mapaddr + ppi_off, "pp_instance");
}
if (!strcmp(dumpname, "servo_state"))
servo_off = offset;
if (servo_off) {
printf("servo_state at 0x%lx\n", servo_off);
dump_many_fields(mapaddr + servo_off, "servo_state");
}
/* This "all" gets the ppg pointer. It's not really all: no pll */
if (!strcmp(dumpname, "ds"))
ds_off = offset;
if (ds_off) {
unsigned long newoffset;
ppg_off = ds_off;
newoffset = wrpc_get_pointer(mapaddr + ppg_off,
"pp_globals", "defaultDS");
printf("DSDefault at 0x%lx\n", newoffset);
dump_many_fields(mapaddr + newoffset, "DSDefault");
newoffset = wrpc_get_pointer(mapaddr + ppg_off,
"pp_globals", "currentDS");
printf("DSCurrent at 0x%lx\n", newoffset);
dump_many_fields(mapaddr + newoffset, "DSCurrent");
newoffset = wrpc_get_pointer(mapaddr + ppg_off,
"pp_globals", "parentDS");
dump_many_fields(mapaddr + newoffset, "DSParent");
newoffset = wrpc_get_pointer(mapaddr + ppg_off,
"pp_globals", "timePropertiesDS");
printf("DSTimeProperties at 0x%lx\n", newoffset);
dump_many_fields(mapaddr + newoffset, "DSTimeProperties");
}
exit(0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment