11#include " tracer.moc"
22Tracer *tracer;
33
4+ #include " w32_socket.cpp"
5+
6+ // TODO: demo only: make these checkboxes in the UI or config options
7+
8+ // tracer output info format
9+ // false: binary format (small/faster),
10+ // true: text format (easier to parse / but slower and HUGE))
11+ const bool traceOutputFormatIsText = false ;
12+
13+ // where trace output will be sent
14+ // true: listen on a socket port and stream data to a client
15+ // false: output via a logfile on disk
16+ const bool traceOutputMediumIsSocket = true ;
17+
18+ #define DEFAULT_TRACE_SERVER_LISTEN_PORT " 27015"
19+
20+ void Tracer::outputTrace (const char * buf, int len) {
21+ outputTraceToFile (buf, len);
22+ outputTraceToSocket (buf, len);
23+ }
24+
25+ void Tracer::outputTraceToFile (const char *buf, int len) {
26+ if (!tracefile.open ())
27+ return ;
28+
29+ // perf: without trask masking, this is SUPER SLOW, grinds the emulation to 2FPS when enabled.
30+ // TODO: there's probably some easy way to improve performance here, like buffering and async IO calls.
31+ // this chews on gigs of data quickly, so whatever you do, be mindful of performance.
32+ //
33+ tracefile.write (reinterpret_cast <const uint8_t *>(buf), len);
34+ if (traceOutputFormatIsText)
35+ tracefile.print (" \n " );
36+ }
37+
38+ void Tracer::outputTraceToSocket (const char *buf, int len) {
39+ if (!traceServer.IsInitialized ())
40+ return ;
41+
42+ traceServer.Push ((const uint8_t *)buf, len);
43+ }
44+
45+ void Tracer::outputCpuTrace () {
46+ char buf[256 ]; int len; // TODO: bounds check buf/len, make sure we don't overflow
47+ if (traceOutputFormatIsText) {
48+ SNES::cpu.disassemble_opcode (buf, SNES::cpu.regs .pc , config ().debugger .showHClocks ); // text
49+ len = strlen (buf) + 1 ; // null terminator
50+ } else {
51+ SNES::cpu.disassemble_opcode_bin (buf, SNES::cpu.regs .pc , len); // binary
52+ }
53+ outputTrace (buf, len);
54+ }
55+
56+ void Tracer::outputSmpTrace () {
57+ char buf[256 ]; int len;
58+ if (traceOutputFormatIsText) {
59+ SNES::smp.disassemble_opcode (buf, SNES::cpu.regs .pc );
60+ len = strlen (buf) + 1 ; // byte size = string + null term
61+ } else {
62+ // TODO: implement // SNES::smp.disassemble_opcode_bin(buf, SNES::cpu.regs.pc, len); // binary
63+ return ; // TODO: not supported just yet
64+ }
65+ outputTrace (buf, len);
66+ }
67+
68+ void Tracer::outputSa1Trace () {
69+ char buf[256 ]; int len;
70+ if (traceOutputFormatIsText) {
71+ SNES::sa1.disassemble_opcode (buf, SNES::cpu.regs .pc , config ().debugger .showHClocks );
72+ len = strlen (buf) + 1 ; // byte size = string + null term
73+ } else {
74+ // TODO: implement // SNES::sa1.disassemble_opcode_bin(buf, SNES::cpu.regs.pc, config().debugger.showHClocks, len); // binary
75+ return ; // TODO: not supported just yet
76+ }
77+ outputTrace (buf, len);
78+ }
79+
80+ void Tracer::outputSfxTrace () {
81+ char buf[256 ]; int len;
82+ if (traceOutputFormatIsText) {
83+ SNES::superfx.disassemble_opcode (buf, SNES::cpu.regs .pc );
84+ len = strlen (buf) + 1 ; // byte size = string + null term
85+ } else {
86+ // TODO: implement // SNES::superfx.disassemble_opcode_bin(buf, SNES::cpu.regs.pc, len); // binary
87+ return ; // TODO: not supported just yet
88+ }
89+ outputTrace (buf, len);
90+ }
91+
92+ void Tracer::outputSgbTrace () {
93+ char buf[256 ]; int len;
94+ if (traceOutputFormatIsText) {
95+ SNES::supergameboy.disassemble_opcode (buf, SNES::cpu.regs .pc );
96+ len = strlen (buf) + 1 ; // byte size = string + null term
97+ } else {
98+ // TODO: implement // SNES::supergameboy.disassemble_opcode_bin(buf, SNES::cpu.regs.pc, len); // binary
99+ return ; // TODO: not supported just yet
100+ }
101+ outputTrace (buf, len);
102+ }
103+
4104void Tracer::stepCpu () {
5105 if (traceCpu) {
6106 unsigned addr = SNES::cpu.regs .pc ;
7107 if (!traceMask || !(traceMaskCPU[addr >> 3 ] & (0x80 >> (addr & 7 )))) {
8- char text[256 ];
9- SNES::cpu.disassemble_opcode (text, addr, config ().debugger .showHClocks );
10- tracefile.print (string () << text << " \n " );
108+ outputCpuTrace ();
11109 }
12110 traceMaskCPU[addr >> 3 ] |= 0x80 >> (addr & 7 );
13111 }
@@ -17,9 +115,7 @@ void Tracer::stepSmp() {
17115 if (traceSmp) {
18116 unsigned addr = SNES::smp.regs .pc ;
19117 if (!traceMask || !(traceMaskSMP[addr >> 3 ] & (0x80 >> (addr & 7 )))) {
20- char text[256 ];
21- SNES::smp.disassemble_opcode (text, addr);
22- tracefile.print (string () << text << " \n " );
118+ outputSmpTrace ();
23119 }
24120 traceMaskSMP[addr >> 3 ] |= 0x80 >> (addr & 7 );
25121 }
@@ -29,9 +125,7 @@ void Tracer::stepSa1() {
29125 if (traceSa1) {
30126 unsigned addr = SNES::sa1.regs .pc ;
31127 if (!traceMask || !(traceMaskSA1[addr >> 3 ] & (0x80 >> (addr & 7 )))) {
32- char text[256 ];
33- SNES::sa1.disassemble_opcode (text, addr, config ().debugger .showHClocks );
34- tracefile.print (string () << text << " \n " );
128+ outputSa1Trace ();
35129 }
36130 traceMaskSA1[addr >> 3 ] |= 0x80 >> (addr & 7 );
37131 }
@@ -41,9 +135,7 @@ void Tracer::stepSfx() {
41135 if (traceSfx) {
42136 unsigned addr = SNES::superfx.opcode_pc ;
43137 if (!traceMask || !(traceMaskSFX[addr >> 3 ] & (0x80 >> (addr & 7 )))) {
44- char text[256 ];
45- SNES::superfx.disassemble_opcode (text, addr);
46- tracefile.print (string () << text << " \n " );
138+ outputSfxTrace ();
47139 }
48140 traceMaskSFX[addr >> 3 ] |= 0x80 >> (addr & 7 );
49141 }
@@ -53,30 +145,51 @@ void Tracer::stepSgb() {
53145 if (traceSgb) {
54146 unsigned addr = SNES::supergameboy.opcode_pc ;
55147 if (!traceMask || !(traceMaskSGB[addr >> 3 ] & (0x80 >> (addr & 7 )))) {
56- char text[256 ];
57- SNES::supergameboy.disassemble_opcode (text, addr);
58- tracefile.print (string () << text << " \n " );
148+ outputSgbTrace ();
59149 }
60150 traceMaskSGB[addr >> 3 ] |= 0x80 >> (addr & 7 );
61151 }
62152}
63153
64154void Tracer::resetTraceState () {
65155 tracefile.close ();
156+ traceServer.Shutdown ();
157+
66158 setTraceState (traceCpu || traceSmp || traceSa1 || traceSfx || traceSgb);
67159
68160 // reset trace masks
69161 if (traceMask)
70162 setTraceMaskState (true );
71163}
72164
165+ void Tracer::ensureTraceOutputReady () {
166+ if (!traceOutputMediumIsSocket && !tracefile.open ()) {
167+ string name = filepath (nall::basename (cartridge.fileName ), config ().path .data );
168+ name << " -trace.log" ;
169+ tracefile.open (name, file::mode::write);
170+ }
171+
172+ if (traceOutputMediumIsSocket && !traceServer.IsInitialized ()) {
173+ // demo: this blocks the entire UI while waiting for a client to connect (not great, better ways to handle)
174+ traceServer.Init (DEFAULT_TRACE_SERVER_LISTEN_PORT);
175+ }
176+ }
177+
178+ void Tracer::ensureTraceOutputShutdown () {
179+ if (tracefile.open ()) {
180+ tracefile.close ();
181+ }
182+
183+ if (traceServer.IsInitialized ()) {
184+ traceServer.Shutdown ();
185+ }
186+ }
187+
73188void Tracer::setTraceState (bool state) {
74- if (state && !tracefile.open () && SNES::cartridge.loaded ()) {
75- string name = filepath (nall::basename (cartridge.fileName ), config ().path .data );
76- name << " -trace.log" ;
77- tracefile.open (name, file::mode::write);
78- } else if (!traceCpu && !traceSmp && !traceSa1 && !traceSfx && !traceSgb && tracefile.open ()) {
79- tracefile.close ();
189+ if (state && SNES::cartridge.loaded ()) {
190+ ensureTraceOutputReady ();
191+ } else if (!traceCpu && !traceSmp && !traceSa1 && !traceSfx && !traceSgb) {
192+ ensureTraceOutputShutdown ();
80193 }
81194}
82195
@@ -146,3 +259,7 @@ Tracer::~Tracer() {
146259 delete[] traceMaskSGB;
147260 if (tracefile.open ()) tracefile.close ();
148261}
262+
263+ void Tracer::flushTraceOutput () {
264+ traceServer.FlushWorkingBuffer ();
265+ }
0 commit comments