1 /* DYNGUI.C (c) Copyright "Fish" (David B. Trout), 2003-2014 */
2 /* Hercules External GUI Interface DLL */
3
4 #include "hstdinc.h"
5 #include "hercules.h" // (#includes "config." w/#define for VERSION)
6
7 #ifdef EXTERNALGUI
8
9 #if defined(OPTION_DYNAMIC_LOAD)
10
11 #include "devtype.h"
12 #include "opcode.h"
13
14 ///////////////////////////////////////////////////////////////////////////////
15 // Some handy macros... (feel free to add these to hercules.h)
16
17 #ifndef BOOL
18 #define BOOL BYTE
19 #endif
20 #ifndef FALSE
21 #define FALSE 0
22 #endif
23 #ifndef TRUE
24 #define TRUE 1
25 #endif
26
27 ///////////////////////////////////////////////////////////////////////////////
28 // Our global variables... (initialized by our "Initialize" function)
29
30 #define INPUT_STREAM_FILE_PTR ( stdin )
31 #define OUTPUT_STREAM_FILE_PTR ( stdout )
32 #define STATUS_STREAM_FILE_PTR ( stderr )
33 #define MAX_COMMAND_LEN ( 1024 )
34 #define DEF_MAXRATES_RPT_INTVL ( 1440 )
35
36 #if defined( WIN32 ) && !defined( HDL_USE_LIBTOOL )
37 #if !defined( _MSVC_ )
38 SYSBLK *psysblk; // (ptr to Herc's SYSBLK structure)
39 #define sysblk (*psysblk)
40 #endif
41 #endif
42
43 static FILE* fOutputStream = NULL; // (stdout stream)
44 static FILE* fStatusStream = NULL; // (stderr stream)
45 static int nInputStreamFileNum = -1; // (file descriptor for stdin stream)
46 static int gui_nounload = 1; // (nounload indicator)
47
48 // The device query buffer SHOULD be the maximum device filename length
49 // plus the maximum descriptive length of any/all options for the device,
50 // but there is no #define for either so we have no choice but to impose
51 // our own maximum.
52
53 #define MAX_DEVICEQUERY_LEN ( 1024 + 256 )
54
55 ///////////////////////////////////////////////////////////////////////////////
56 // Some forward references... (our own functions that we call)
57
58 void Initialize ();
59 void ProcessingLoop ();
60 void Cleanup ();
61 void UpdateTargetCPU ();
62 void ReadInputData (int nTimeoutMillsecs);
63 void ProcessInputData ();
64 void* gui_panel_command (char* pszCommand);
65 void UpdateStatus ();
66 void HandleForcedRefresh();
67 void UpdateCPUStatus ();
68 void UpdateRegisters ();
69 void UpdateDeviceStatus ();
70 void NewUpdateDevStats ();
71
72 void gui_fprintf( FILE* stream, const char* pszFormat, ... );
73
74 ///////////////////////////////////////////////////////////////////////////////
75 // Our main processing loop...
76
77 BOOL bDoneProcessing = FALSE; // (set to TRUE to exit)
78
ProcessingLoop()79 void ProcessingLoop()
80 {
81 // Notify logger_thread we're in control
82
83 sysblk.panel_init = 1;
84
85 // Our main purpose in life: read input stream and process
86 // any commands that may be entered, and send periodic status
87 // information back to the external gui via its status stream.
88
89 // Note we only exit whenever our bDoneProcessing flag is set
90 // which is normally not done until just before Herc unloads
91 // us which is normally not done until immediately before it
92 // terminates.
93
94 // Also note we re-retrieve sysblk.panrate each iteration
95 // since it could change from one iteration to the next as a result
96 // of the Hercules "panrate" command being entered and processed.
97
98 while (!bDoneProcessing)
99 {
100 UpdateTargetCPU(); // ("cpu" command could have changed it)
101 UpdateStatus(); // (keep sending status back to gui...)
102
103 ReadInputData( sysblk.panrate );
104
105 ProcessInputData(); // (if there even is any of course...)
106 }
107 }
108
109 ///////////////////////////////////////////////////////////////////////////////
110
111 int pcpu = INT_MAX; // target cpu# for commands and displays
112 REGS* pTargetCPU_REGS = NULL; // pointer to target cpu REGS
113
114 int prev_pcpu = INT_MAX; // (previous value)
115 REGS* pPrevTargetCPU_REGS = NULL; // (previous value)
116
117 REGS copyregs; // (copy of active cpu's REGS)
118 REGS copysieregs; // (same but when in SIE mode)
119 REGS* CopyREGS( int cpu ); // (fwd ref)
120
121 ///////////////////////////////////////////////////////////////////////////////
122
UpdateTargetCPU()123 void UpdateTargetCPU ()
124 {
125 if (!sysblk.shutdown)
126 pTargetCPU_REGS = CopyREGS( pcpu = sysblk.pcpu );
127 }
128
129 ///////////////////////////////////////////////////////////////////////////////
130 // (get non-moving/non-dynamic working copy of active cpu's register context)
131
CopyREGS(int cpu)132 REGS* CopyREGS( int cpu ) // (same logic as in panel.c)
133 {
134 REGS* regs;
135
136 if (cpu < 0 || cpu >= sysblk.maxcpu)
137 cpu = 0;
138
139 obtain_lock( &sysblk.cpulock[cpu] );
140
141 if (!(regs = sysblk.regs[cpu]))
142 {
143 release_lock( &sysblk.cpulock[cpu] );
144 return &sysblk.dummyregs;
145 }
146
147 memcpy( ©regs, regs, sysblk.regs_copy_len );
148
149 if (!copyregs.hostregs)
150 {
151 release_lock(&sysblk.cpulock[cpu]);
152 return &sysblk.dummyregs;
153 }
154
155 #if defined(_FEATURE_SIE)
156 if (regs->sie_active)
157 {
158 memcpy( ©sieregs, regs->guestregs, sysblk.regs_copy_len );
159 copyregs.guestregs = ©sieregs;
160 copysieregs.hostregs = ©regs;
161 regs = ©sieregs;
162 }
163 else
164 #endif
165 regs = ©regs;
166
167 SET_PSW_IA( regs );
168
169 release_lock( &sysblk.cpulock[cpu] );
170 return regs;
171 }
172
173 ///////////////////////////////////////////////////////////////////////////////
174
175 char* pszInputBuff = NULL; // ptr to buffer
176 int nInputBuffSize = (MAX_COMMAND_LEN+1); // how big the buffer is
177 int nInputLen = 0; // amount of data it's holding
178
179 ///////////////////////////////////////////////////////////////////////////////
180
ReadInputData(int nTimeoutMillsecs)181 void ReadInputData ( int nTimeoutMillsecs )
182 {
183 size_t nMaxBytesToRead;
184 int nBytesRead;
185 char* pReadBuffer;
186
187 // Wait for keyboard input data to arrive...
188
189 #if !defined( _MSVC_ )
190
191 fd_set input_fd_set;
192 struct timeval wait_interval_timeval;
193 int rc;
194
195 FD_ZERO ( &input_fd_set );
196 FD_SET ( nInputStreamFileNum, &input_fd_set );
197
198 wait_interval_timeval.tv_sec = nTimeoutMillsecs / 1000;
199 wait_interval_timeval.tv_usec = (nTimeoutMillsecs % 1000) * 1000;
200
201 if ((rc = select( nInputStreamFileNum+1, &input_fd_set, NULL, NULL, &wait_interval_timeval )) < 0)
202 {
203 if (HSO_EINTR == HSO_errno)
204 return; // (we were interrupted by a signal)
205
206 // A bona fide error occurred; abort...
207
208 logmsg
209 (
210 _("HHCDG003S select failed on input stream: %s\n")
211
212 ,strerror(HSO_errno)
213 );
214
215 bDoneProcessing = TRUE; // (force main loop to exit)
216 return;
217 }
218
219 // Has keyboard input data indeed arrived yet?
220
221 if (!FD_ISSET( nInputStreamFileNum, &input_fd_set ))
222 return; // (nothing for us to do...)
223
224 #endif // !defined( _MSVC_ )
225
226 // Ensure our buffer never overflows... (-2 because
227 // we need room for at least 1 byte + NULL terminator)
228
229 MINMAX(nInputLen,0,(nInputBuffSize-2));
230
231 // Read input data into next available buffer location...
232 // (nMaxBytesToRead-1 == room for NULL terminator)
233
234 pReadBuffer = (pszInputBuff + nInputLen);
235 nMaxBytesToRead = (nInputBuffSize - nInputLen) - 1;
236
237 #if !defined( _MSVC_ )
238
239 if ((nBytesRead = read( nInputStreamFileNum, pReadBuffer, nMaxBytesToRead )) < 0)
240 {
241 if (EINTR == errno)
242 return; // (we were interrupted by a signal)
243
244 // A bona fide error occurred; abort...
245
246 logmsg
247 (
248 _("HHCDG004S read failed on input stream: %s\n")
249
250 ,strerror(errno)
251 );
252
253 bDoneProcessing = TRUE; // (force main loop to exit)
254 return;
255 }
256
257 #else // defined( _MSVC_ )
258
259 if ( ( nBytesRead = w32_get_stdin_char( pReadBuffer, nTimeoutMillsecs ) ) <= 0 )
260 return;
261
262 #endif // !defined( _MSVC_ )
263
264 // Update amount of input data we have and
265 // ensure that it's always NULL terminated...
266
267 MINMAX(nBytesRead,0,nInputBuffSize);
268 nInputLen += nBytesRead;
269 MINMAX(nInputLen,0,(nInputBuffSize-1));
270 *(pszInputBuff + nInputLen) = 0;
271 }
272
273 ///////////////////////////////////////////////////////////////////////////////
274
275 char* pszCommandBuff = NULL; // ptr to buffer
276 int nCommandBuffSize = (MAX_COMMAND_LEN+1); // how big the buffer is
277 int nCommandLen = 0; // amount of data it's holding
278
279 ///////////////////////////////////////////////////////////////////////////////
280 // Process the data we just read from the input stream...
281
ProcessInputData()282 void ProcessInputData ()
283 {
284 char* pNewLineChar;
285
286 // Ensure our buffer is NULL terminated...
287
288 MINMAX(nInputLen,0,(nInputBuffSize-1));
289 *(pszInputBuff + nInputLen) = 0;
290
291 // Input commands are delimited by newline characters...
292
293 while (nInputLen && (pNewLineChar = strchr(pszInputBuff,'\n')) != NULL)
294 {
295 // Extract command from input buffer
296 // into our command processing buffer...
297
298 nCommandLen = (pNewLineChar - pszInputBuff);
299 MINMAX(nCommandLen,0,(nCommandBuffSize-1));
300 memcpy(pszCommandBuff, pszInputBuff, nCommandLen);
301 *(pszCommandBuff + nCommandLen) = 0;
302
303 // Process the extracted command...
304
305 // Note that we always call the registered "panel_command" function
306 // rather than call our "gui_panel_command" function directly. This
307 // is in case some other DLL has overridden OUR command handler...
308
309 panel_command ( pszCommandBuff ); // (call registered handler)
310
311 // Shift remaining data back to beginning of input buffer...
312
313 nInputLen = ((pszInputBuff + nInputLen) - (pNewLineChar+1));
314 MINMAX(nInputLen,0,(nInputBuffSize-1));
315 memmove(pszInputBuff,pNewLineChar+1,nInputLen);
316 *(pszInputBuff + nInputLen) = 0;
317 }
318 }
319
320 ///////////////////////////////////////////////////////////////////////////////
321 // (These are actually boolean flags..)
322
323 double gui_version = 0.0; // (version of HercGUI we're talking to)
324
325 BYTE gui_forced_refresh = 1; // (force initial update refresh)
326
327 BYTE gui_wants_gregs = 0;
328 BYTE gui_wants_gregs64 = 0;
329 BYTE gui_wants_cregs = 0;
330 BYTE gui_wants_cregs64 = 0;
331 BYTE gui_wants_aregs = 0;
332 BYTE gui_wants_fregs = 0;
333 BYTE gui_wants_fregs64 = 0;
334 BYTE gui_wants_devlist = 0;
335 BYTE gui_wants_new_devlist = 1; // (should always be initially on)
336 #if defined(OPTION_MIPS_COUNTING)
337 BYTE gui_wants_aggregates = 1;
338 BYTE gui_wants_cpupct = 0;
339 BYTE gui_wants_cpupct_all = 0;
340 int prev_cpupct [ MAX_CPU_ENGINES ];
341 U32 prev_mips_rate = 0;
342 U32 prev_sios_rate = 0;
343 #endif // defined(OPTION_MIPS_COUNTING)
344
345 ///////////////////////////////////////////////////////////////////////////////
346 // Our Hercules "panel_command" override...
347
gui_panel_command(char * pszCommand)348 void* gui_panel_command (char* pszCommand)
349 {
350 void* (*next_panel_command_handler)(char* pszCommand);
351
352 // Special GUI commands start with ']'. At the moment, all these special
353 // gui commands tell us is what status information it's interested in...
354
355 if ( ']' != *pszCommand )
356 goto NotSpecialGUICommand;
357
358 gui_forced_refresh = 1; // (forced update refresh)
359
360 pszCommand++; // (bump past ']')
361
362 if (strncasecmp(pszCommand,"VERS=",5) == 0)
363 {
364 gui_version = atof(pszCommand+5);
365 return NULL;
366 }
367
368 if (strncasecmp(pszCommand,"SCD=",4) == 0)
369 {
370 // (set current directory)
371 if (chdir(pszCommand+4) != 0)
372 {
373 // (inform gui of error)
374 char *cwd = getcwd( NULL, 0 );
375 if (cwd)
376 {
377 debug_cd_cmd( cwd );
378 free( cwd );
379 }
380 }
381 return NULL;
382 }
383
384 if (strncasecmp(pszCommand,"GREGS=",6) == 0)
385 {
386 gui_wants_gregs = atoi(pszCommand+6);
387 return NULL;
388 }
389
390 if (strncasecmp(pszCommand,"GREGS64=",8) == 0)
391 {
392 gui_wants_gregs64 = atoi(pszCommand+8);
393 return NULL;
394 }
395
396 if (strncasecmp(pszCommand,"CREGS=",6) == 0)
397 {
398 gui_wants_cregs = atoi(pszCommand+6);
399 return NULL;
400 }
401
402 if (strncasecmp(pszCommand,"CREGS64=",8) == 0)
403 {
404 gui_wants_cregs64 = atoi(pszCommand+8);
405 return NULL;
406 }
407
408 if (strncasecmp(pszCommand,"AREGS=",6) == 0)
409 {
410 gui_wants_aregs = atoi(pszCommand+6);
411 return NULL;
412 }
413
414 if (strncasecmp(pszCommand,"FREGS=",6) == 0)
415 {
416 gui_wants_fregs = atoi(pszCommand+6);
417 return NULL;
418 }
419
420 if (strncasecmp(pszCommand,"FREGS64=",8) == 0)
421 {
422 gui_wants_fregs64 = atoi(pszCommand+8);
423 return NULL;
424 }
425
426 if (strncasecmp(pszCommand,"DEVLIST=",8) == 0)
427 {
428 gui_wants_devlist = atoi(pszCommand+8);
429 if ( gui_wants_devlist )
430 gui_wants_new_devlist = 0;
431 return NULL;
432 }
433
434 if (strncasecmp(pszCommand,"NEWDEVLIST=",11) == 0)
435 {
436 gui_wants_new_devlist = atoi(pszCommand+11);
437 if ( gui_wants_new_devlist )
438 gui_wants_devlist = 0;
439 return NULL;
440 }
441
442 if (strncasecmp(pszCommand,"MAINSTOR=",9) == 0)
443 {
444 gui_fprintf(fStatusStream,"MAINSTOR=%"UINT_PTR_FMT"d\n",(uintptr_t)pTargetCPU_REGS->mainstor);
445
446 // Here's a trick! Hercules reports its version number to the GUI
447 // by means of the MAINSIZE value! Later releases of HercGUI know
448 // to interpret mainsizes less than 1000 as Hercule's version number.
449 // Earlier versions of HercGUI will simply try to interpret it as
450 // the actual mainsize, but no real harm is done since we immediately
451 // send it the CORRECT mainsize immediately afterwards. This allows
452 // future versions of HercGUI to know whether the version of Hercules
453 // that it's talking to supports a given feature or not. Slick, eh? :)
454 gui_fprintf(fStatusStream,"MAINSIZE=%s\n",VERSION);
455
456 if (gui_version < 1.12)
457 gui_fprintf(fStatusStream,"MAINSIZE=%d\n",(U32)sysblk.mainsize);
458 else
459 gui_fprintf(fStatusStream,"MAINSIZE=%"UINT_PTR_FMT"d\n",(uintptr_t)sysblk.mainsize);
460 return NULL;
461 }
462
463 #if defined(OPTION_MIPS_COUNTING)
464 if (strncasecmp(pszCommand,"CPUPCT=",7) == 0)
465 {
466 gui_wants_cpupct = atoi(pszCommand+7);
467 return NULL;
468 }
469 if (strncasecmp(pszCommand,"CPUPCTALL=",10) == 0)
470 {
471 if (!(gui_wants_cpupct_all = atoi(pszCommand+10)))
472 memset( &prev_cpupct[0], 0xFF, sizeof(prev_cpupct) );
473 return NULL;
474 }
475 if (strncasecmp(pszCommand,"AGGREGATE=",10) == 0)
476 {
477 gui_wants_aggregates = atoi(pszCommand+10);
478 gui_forced_refresh = 1;
479 return NULL;
480 }
481 #endif
482
483 // Silently ignore any unrecognized special GUI commands...
484
485 return NULL; // (silently ignore it)
486
487 NotSpecialGUICommand:
488
489 // Ignore "commands" that are actually just comments (start with '*' or '#')
490
491 if ('*' == pszCommand[0] || '#' == pszCommand[0])
492 {
493 if ('*' == pszCommand[0]) // (LOUD comment?)
494 logmsg("%s\n",pszCommand); // (then log to console)
495 return NULL; // (and otherwise ignore it)
496 }
497
498 // Otherwise it's not a command that we handle. Call the next higher
499 // level command handler which, under normal circumstances SHOULD be
500 // Hercules's "panel_command" function, but which MAY have been over-
501 // ridden by yet some OTHER dynamically loaded command handler...
502
503 next_panel_command_handler = HDL_FINDNXT( gui_panel_command );
504
505 if (!next_panel_command_handler) // (extremely unlikely!)
506 return (char *)-1; // (extremely unlikely!)
507
508 return next_panel_command_handler( pszCommand );
509 }
510
511 ///////////////////////////////////////////////////////////////////////////////
512 // Status updating control fields...
513
514 QWORD psw, prev_psw;
515 BYTE wait_bit;
516 BYTE prev_cpustate = 0xFF;
517 U64 prev_instcount = 0;
518
519 U32 prev_gr [16];
520 U64 prev_gr64 [16];
521
522 U32 prev_cr [16];
523 U64 prev_cr64 [16];
524
525 U32 prev_ar [16];
526
527 U32 prev_fpr [8*2];
528 U32 prev_fpr64[16*2];
529
530 ///////////////////////////////////////////////////////////////////////////////
531 // Send status information messages back to the gui...
532
UpdateStatus()533 void UpdateStatus ()
534 {
535 BOOL bStatusChanged = FALSE; // (whether or not anything has changed)
536
537 if (sysblk.shutdown) return;
538
539 copy_psw(pTargetCPU_REGS, psw);
540 wait_bit = (psw[1] & 0x02);
541
542 // The SYS light and %CPU-Utilization
543 // information we send *ALL* the time...
544
545 if (!(0
546 || CPUSTATE_STOPPING == pTargetCPU_REGS->cpustate
547 || CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate
548 ))
549 {
550 gui_fprintf(fStatusStream,
551
552 "SYS=%c\n"
553
554 ,wait_bit ? '0' : '1'
555 );
556 }
557
558 #if defined(OPTION_MIPS_COUNTING)
559 if (gui_wants_cpupct)
560 {
561 if (gui_wants_aggregates)
562 {
563 int cpu, cpupct = 0, started = 0;
564 for (cpupct=0, cpu=0; cpu < sysblk.maxcpu; cpu++)
565 {
566 if (1
567 && IS_CPU_ONLINE( cpu )
568 && CPUSTATE_STARTED == sysblk.regs[ cpu ]->cpustate
569 )
570 {
571 started++;
572 cpupct += sysblk.regs[ cpu ]->cpupct;
573 }
574 }
575 gui_fprintf(fStatusStream,
576
577 "CPUPCT=%d\n"
578
579 ,started ? (cpupct / started) : 0
580 );
581 }
582 else
583 {
584 gui_fprintf(fStatusStream,
585
586 "CPUPCT=%d\n"
587
588 ,pTargetCPU_REGS->cpupct
589 );
590 }
591 }
592 if (gui_wants_cpupct_all)
593 {
594 int i, cpupct;
595
596 for (i = 0; i < sysblk.hicpu; i++)
597 {
598 if (0
599 || !IS_CPU_ONLINE(i)
600 || CPUSTATE_STARTED != sysblk.regs[i]->cpustate
601 )
602 cpupct = 0;
603 else
604 cpupct = sysblk.regs[i]->cpupct;
605
606 if (cpupct != prev_cpupct[i])
607 {
608 prev_cpupct[i] = cpupct;
609 gui_fprintf( fStatusStream, "CPUPCT%02d=%d\n", i, cpupct );
610 }
611 }
612 }
613 #endif
614
615 // Determine if we need to inform the GUI of anything...
616
617 bStatusChanged = FALSE; // (whether or not anything has changed)
618
619 if (0
620 || gui_forced_refresh
621 || pTargetCPU_REGS != pPrevTargetCPU_REGS
622 || pcpu != prev_pcpu
623 || memcmp(prev_psw, psw, sizeof(prev_psw)) != 0
624 || prev_cpustate != pTargetCPU_REGS->cpustate
625 || prev_instcount != INSTCOUNT(pTargetCPU_REGS)
626 )
627 {
628 bStatusChanged = TRUE; // (something has indeed changed...)
629
630 if (gui_forced_refresh) // (forced refresh?)
631 HandleForcedRefresh(); // (reset all prev values)
632
633 // Save new values for next time...
634
635 pPrevTargetCPU_REGS = pTargetCPU_REGS;
636 prev_pcpu = pcpu;
637 memcpy(prev_psw, psw, sizeof(prev_psw));
638 prev_cpustate = pTargetCPU_REGS->cpustate;
639 prev_instcount = INSTCOUNT(pTargetCPU_REGS);
640 }
641
642 // If anything has changed, inform the GUI...
643
644 if (bStatusChanged)
645 {
646 UpdateCPUStatus(); // (update the status line info...)
647 UpdateRegisters(); // (update the registers display...)
648 }
649
650 // PROGRAMMING NOTE: my original [rather poorly designed I admit] logic
651 // sent device status messages to the GUI *continuously* (i.e. all the
652 // time), even when both Herc and the channel subsystem was idle. This
653 // proved to be terribly inefficient, causing the GUI to consume *FAR*
654 // too much valuable CPU cycles parsing all of those messages.
655
656 // Thus, starting with this version of dyngui, we now only send device
657 // status messages to the GUI only whenever the device's status actually
658 // changes, but only if it (the GUI) specifically requests such notifi-
659 // cations of course (via the new "]NEWDEVLIST=" special message).
660
661 // The new(er) version of HercGUI understands (and thus requests) these
662 // newer format device status messages, but older versions of HercGUI
663 // of course do not. Thus in order to remain compatible with the current
664 // (older) version of the GUI, we still need to support the inefficient
665 // technique of constantly sending a constant stream of device status
666 // messages.
667
668 // Eventually at some point this existing original inefficient technique
669 // logic will be removed (once everyone has had time to upgrade to the
670 // newer version of HercGUI), but for now, at least for the next couple
671 // of HercGUI release cycles, we need to keep it.
672
673 if (gui_wants_devlist) // (if the device list is visible)
674 UpdateDeviceStatus(); // (update the list of devices...)
675
676 else // (the two options are mutually exclusive from one another)
677
678 if (gui_wants_new_devlist) // (if the device list is visible)
679 NewUpdateDevStats(); // (update the list of devices...)
680
681 gui_forced_refresh = 0; // (reset switch; must follow devlist update)
682 }
683
684 ///////////////////////////////////////////////////////////////////////////////
685 // Forced GUI Refresh: reset all "previous" values to force update...
686
HandleForcedRefresh()687 void HandleForcedRefresh()
688 {
689 #ifdef OPTION_MIPS_COUNTING
690 prev_mips_rate = INT_MAX;
691 prev_sios_rate = INT_MAX;
692 #endif
693 prev_instcount = ULLONG_MAX;
694 prev_pcpu = INT_MAX;
695 pPrevTargetCPU_REGS = NULL;
696 prev_cpustate = 0xFF;
697 memset( prev_psw, 0xFF, sizeof(prev_psw) );
698
699 memset( &prev_gr [0], 0xFF,
700 sizeof(prev_gr) );
701
702 memset( &prev_cr [0], 0xFF,
703 sizeof(prev_cr) );
704
705 memset( &prev_ar [0], 0xFF,
706 sizeof(prev_ar) );
707
708 memset( &prev_fpr [0], 0xFF,
709 sizeof(prev_fpr) );
710
711 memset( &prev_gr64 [0], 0xFF,
712 sizeof(prev_gr64) );
713
714 memset( &prev_cr64 [0], 0xFF,
715 sizeof(prev_cr64) );
716
717 memset( &prev_fpr64[0], 0xFF,
718 sizeof(prev_fpr64) );
719
720 #if defined(OPTION_MIPS_COUNTING)
721 memset( &prev_cpupct [0], 0xFF,
722 sizeof(prev_cpupct ) );
723 #endif
724 }
725
726 ///////////////////////////////////////////////////////////////////////////////
727 // Send status information messages back to the gui...
728
UpdateCPUStatus()729 void UpdateCPUStatus ()
730 {
731 if (sysblk.shutdown) return;
732
733 if (pTargetCPU_REGS == &sysblk.dummyregs)
734 {
735 // pTargetCPU_REGS == &sysblk.dummyregs; cpu is offline
736
737 gui_fprintf(fStatusStream, "STATUS="
738
739 "%s%02X (((((((((((((((((((((((( OFFLINE ))))))))))))))))))))))))\n",
740
741 PTYPSTR(pcpu) ,pcpu);
742 }
743 else // pTargetCPU_REGS != &sysblk.dummyregs; cpu is online
744 {
745 // CPU status line... (PSW, status indicators, and instruction count)
746
747 gui_fprintf(fStatusStream, "STATUS="
748
749 "%s%02X "
750
751 "PSW=%2.2X%2.2X%2.2X%2.2X "
752 "%2.2X%2.2X%2.2X%2.2X "
753 "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X "
754
755 "%c%c%c%c%c%c%c%c "
756
757 "instcount=%" I64_FMT "u\n"
758
759 ,PTYPSTR(pTargetCPU_REGS->cpuad), pTargetCPU_REGS->cpuad
760
761 ,psw[0], psw[1], psw[2], psw[3]
762 ,psw[4], psw[5], psw[6], psw[7]
763 ,psw[8], psw[9], psw[10], psw[11], psw[12], psw[13], psw[14], psw[15]
764
765 ,CPUSTATE_STOPPED == pTargetCPU_REGS->cpustate ? 'M' : '.'
766 ,sysblk.inststep ? 'T' : '.'
767 ,wait_bit ? 'W' : '.'
768 ,pTargetCPU_REGS->loadstate ? 'L' : '.'
769 ,pTargetCPU_REGS->checkstop ? 'C' : '.'
770 ,PROBSTATE(&pTargetCPU_REGS->psw) ? 'P' : '.'
771 ,
772 #if defined(_FEATURE_SIE)
773 SIE_MODE(pTargetCPU_REGS) ? 'S' : '.'
774 #else // !defined(_FEATURE_SIE)
775 '.'
776 #endif // defined(_FEATURE_SIE)
777 ,
778 #if defined(_900)
779 ARCH_900 == pTargetCPU_REGS->arch_mode ? 'Z' : '.'
780 #else // !defined(_900)
781 '.'
782 #endif // defined(_900)
783 ,(U64)INSTCOUNT(pTargetCPU_REGS)
784 );
785
786 } // endif cpu is online/offline
787
788 #if defined(OPTION_MIPS_COUNTING)
789
790 // MIPS rate and SIOS rate...
791 {
792 U32* mipsrate;
793 U32* siosrate;
794
795 if (gui_wants_aggregates)
796 {
797 mipsrate = &sysblk.mipsrate;
798 siosrate = &sysblk.siosrate;
799 }
800 else
801 {
802 mipsrate = &pTargetCPU_REGS->mipsrate;
803 siosrate = &pTargetCPU_REGS->siosrate;
804 }
805
806 if (*mipsrate != prev_mips_rate)
807 {
808 gui_fprintf( fStatusStream,
809
810 "MIPS=%4d.%2.2d\n"
811
812 , *mipsrate / 1000000
813 ,(*mipsrate % 1000000) / 10000
814 );
815
816 prev_mips_rate = *mipsrate;
817 }
818
819 if (*siosrate != prev_sios_rate)
820 {
821 gui_fprintf( fStatusStream,
822
823 "SIOS=%4d\n"
824
825 ,*siosrate
826 );
827
828 prev_sios_rate = *siosrate;
829 }
830 }
831
832 update_maxrates_hwm(); // (update high-water-mark values)
833
834 #endif // defined(OPTION_MIPS_COUNTING)
835 }
836
837 ///////////////////////////////////////////////////////////////////////////////
838 // Send status information messages back to the gui...
839
840 #define REG32FMT "%8.8"I32_FMT"X"
841 #define REG64FMT "%16.16"I64_FMT"X"
842
UpdateRegisters()843 void UpdateRegisters ()
844 {
845 if (sysblk.shutdown) return;
846
847 if (gui_wants_gregs)
848 {
849 if (0
850 || prev_gr[0] != pTargetCPU_REGS->GR_L(0)
851 || prev_gr[1] != pTargetCPU_REGS->GR_L(1)
852 || prev_gr[2] != pTargetCPU_REGS->GR_L(2)
853 || prev_gr[3] != pTargetCPU_REGS->GR_L(3)
854 )
855 {
856 prev_gr[0] = pTargetCPU_REGS->GR_L(0);
857 prev_gr[1] = pTargetCPU_REGS->GR_L(1);
858 prev_gr[2] = pTargetCPU_REGS->GR_L(2);
859 prev_gr[3] = pTargetCPU_REGS->GR_L(3);
860
861 gui_fprintf(fStatusStream,
862
863 "GR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
864
865 ,pTargetCPU_REGS->GR_L(0)
866 ,pTargetCPU_REGS->GR_L(1)
867 ,pTargetCPU_REGS->GR_L(2)
868 ,pTargetCPU_REGS->GR_L(3)
869 );
870 }
871
872 if (0
873 || prev_gr[4] != pTargetCPU_REGS->GR_L(4)
874 || prev_gr[5] != pTargetCPU_REGS->GR_L(5)
875 || prev_gr[6] != pTargetCPU_REGS->GR_L(6)
876 || prev_gr[7] != pTargetCPU_REGS->GR_L(7)
877 )
878 {
879 prev_gr[4] = pTargetCPU_REGS->GR_L(4);
880 prev_gr[5] = pTargetCPU_REGS->GR_L(5);
881 prev_gr[6] = pTargetCPU_REGS->GR_L(6);
882 prev_gr[7] = pTargetCPU_REGS->GR_L(7);
883
884 gui_fprintf(fStatusStream,
885
886 "GR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
887
888 ,pTargetCPU_REGS->GR_L(4)
889 ,pTargetCPU_REGS->GR_L(5)
890 ,pTargetCPU_REGS->GR_L(6)
891 ,pTargetCPU_REGS->GR_L(7)
892 );
893 }
894
895 if (0
896 || prev_gr[8] != pTargetCPU_REGS->GR_L(8)
897 || prev_gr[9] != pTargetCPU_REGS->GR_L(9)
898 || prev_gr[10] != pTargetCPU_REGS->GR_L(10)
899 || prev_gr[11] != pTargetCPU_REGS->GR_L(11)
900 )
901 {
902 prev_gr[8] = pTargetCPU_REGS->GR_L(8);
903 prev_gr[9] = pTargetCPU_REGS->GR_L(9);
904 prev_gr[10] = pTargetCPU_REGS->GR_L(10);
905 prev_gr[11] = pTargetCPU_REGS->GR_L(11);
906
907 gui_fprintf(fStatusStream,
908
909 "GR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
910
911 ,pTargetCPU_REGS->GR_L(8)
912 ,pTargetCPU_REGS->GR_L(9)
913 ,pTargetCPU_REGS->GR_L(10)
914 ,pTargetCPU_REGS->GR_L(11)
915 );
916 }
917
918 if (0
919 || prev_gr[12] != pTargetCPU_REGS->GR_L(12)
920 || prev_gr[13] != pTargetCPU_REGS->GR_L(13)
921 || prev_gr[14] != pTargetCPU_REGS->GR_L(14)
922 || prev_gr[15] != pTargetCPU_REGS->GR_L(15)
923 )
924 {
925 prev_gr[12] = pTargetCPU_REGS->GR_L(12);
926 prev_gr[13] = pTargetCPU_REGS->GR_L(13);
927 prev_gr[14] = pTargetCPU_REGS->GR_L(14);
928 prev_gr[15] = pTargetCPU_REGS->GR_L(15);
929
930 gui_fprintf(fStatusStream,
931
932 "GRC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
933
934 ,pTargetCPU_REGS->GR_L(12)
935 ,pTargetCPU_REGS->GR_L(13)
936 ,pTargetCPU_REGS->GR_L(14)
937 ,pTargetCPU_REGS->GR_L(15)
938 );
939 }
940 }
941
942 if (gui_wants_gregs64)
943 {
944 if (0
945 || prev_gr64[0] != pTargetCPU_REGS->GR_G(0)
946 || prev_gr64[1] != pTargetCPU_REGS->GR_G(1)
947 )
948 {
949 prev_gr64[0] = pTargetCPU_REGS->GR_G(0);
950 prev_gr64[1] = pTargetCPU_REGS->GR_G(1);
951
952 gui_fprintf(fStatusStream,
953
954 "64_GR0-1="REG64FMT" "REG64FMT"\n"
955
956 ,pTargetCPU_REGS->GR_G(0)
957 ,pTargetCPU_REGS->GR_G(1)
958 );
959 }
960
961 if (0
962 || prev_gr64[2] != pTargetCPU_REGS->GR_G(2)
963 || prev_gr64[3] != pTargetCPU_REGS->GR_G(3)
964 )
965 {
966 prev_gr64[2] = pTargetCPU_REGS->GR_G(2);
967 prev_gr64[3] = pTargetCPU_REGS->GR_G(3);
968
969 gui_fprintf(fStatusStream,
970
971 "64_GR2-3="REG64FMT" "REG64FMT"\n"
972
973 ,pTargetCPU_REGS->GR_G(2)
974 ,pTargetCPU_REGS->GR_G(3)
975 );
976 }
977
978 if (0
979 || prev_gr64[4] != pTargetCPU_REGS->GR_G(4)
980 || prev_gr64[5] != pTargetCPU_REGS->GR_G(5)
981 )
982 {
983 prev_gr64[4] = pTargetCPU_REGS->GR_G(4);
984 prev_gr64[5] = pTargetCPU_REGS->GR_G(5);
985
986 gui_fprintf(fStatusStream,
987
988 "64_GR4-5="REG64FMT" "REG64FMT"\n"
989
990 ,pTargetCPU_REGS->GR_G(4)
991 ,pTargetCPU_REGS->GR_G(5)
992 );
993 }
994
995 if (0
996 || prev_gr64[6] != pTargetCPU_REGS->GR_G(6)
997 || prev_gr64[7] != pTargetCPU_REGS->GR_G(7)
998 )
999 {
1000 prev_gr64[6] = pTargetCPU_REGS->GR_G(6);
1001 prev_gr64[7] = pTargetCPU_REGS->GR_G(7);
1002
1003 gui_fprintf(fStatusStream,
1004
1005 "64_GR6-7="REG64FMT" "REG64FMT"\n"
1006
1007 ,pTargetCPU_REGS->GR_G(6)
1008 ,pTargetCPU_REGS->GR_G(7)
1009 );
1010 }
1011
1012 if (0
1013 || prev_gr64[8] != pTargetCPU_REGS->GR_G(8)
1014 || prev_gr64[9] != pTargetCPU_REGS->GR_G(9)
1015 )
1016 {
1017 prev_gr64[8] = pTargetCPU_REGS->GR_G(8);
1018 prev_gr64[9] = pTargetCPU_REGS->GR_G(9);
1019
1020 gui_fprintf(fStatusStream,
1021
1022 "64_GR8-9="REG64FMT" "REG64FMT"\n"
1023
1024 ,pTargetCPU_REGS->GR_G(8)
1025 ,pTargetCPU_REGS->GR_G(9)
1026 );
1027 }
1028
1029 if (0
1030 || prev_gr64[10] != pTargetCPU_REGS->GR_G(10)
1031 || prev_gr64[11] != pTargetCPU_REGS->GR_G(11)
1032 )
1033 {
1034 prev_gr64[10] = pTargetCPU_REGS->GR_G(10);
1035 prev_gr64[11] = pTargetCPU_REGS->GR_G(11);
1036
1037 gui_fprintf(fStatusStream,
1038
1039 "64_GRA-B="REG64FMT" "REG64FMT"\n"
1040
1041 ,pTargetCPU_REGS->GR_G(10)
1042 ,pTargetCPU_REGS->GR_G(11)
1043 );
1044 }
1045
1046 if (0
1047 || prev_gr64[12] != pTargetCPU_REGS->GR_G(12)
1048 || prev_gr64[13] != pTargetCPU_REGS->GR_G(13)
1049 )
1050 {
1051 prev_gr64[12] = pTargetCPU_REGS->GR_G(12);
1052 prev_gr64[13] = pTargetCPU_REGS->GR_G(13);
1053
1054 gui_fprintf(fStatusStream,
1055
1056 "64_GRC-D="REG64FMT" "REG64FMT"\n"
1057
1058 ,pTargetCPU_REGS->GR_G(12)
1059 ,pTargetCPU_REGS->GR_G(13)
1060 );
1061 }
1062
1063 if (0
1064 || prev_gr64[14] != pTargetCPU_REGS->GR_G(14)
1065 || prev_gr64[15] != pTargetCPU_REGS->GR_G(15)
1066 )
1067 {
1068 prev_gr64[14] = pTargetCPU_REGS->GR_G(14);
1069 prev_gr64[15] = pTargetCPU_REGS->GR_G(15);
1070
1071 gui_fprintf(fStatusStream,
1072
1073 "64_GRE-F="REG64FMT" "REG64FMT"\n"
1074
1075 ,pTargetCPU_REGS->GR_G(14)
1076 ,pTargetCPU_REGS->GR_G(15)
1077 );
1078 }
1079 }
1080
1081 if (gui_wants_cregs)
1082 {
1083 if (0
1084 || prev_cr[0] != pTargetCPU_REGS->CR_L(0)
1085 || prev_cr[1] != pTargetCPU_REGS->CR_L(1)
1086 || prev_cr[2] != pTargetCPU_REGS->CR_L(2)
1087 || prev_cr[3] != pTargetCPU_REGS->CR_L(3)
1088 )
1089 {
1090 prev_cr[0] = pTargetCPU_REGS->CR_L(0);
1091 prev_cr[1] = pTargetCPU_REGS->CR_L(1);
1092 prev_cr[2] = pTargetCPU_REGS->CR_L(2);
1093 prev_cr[3] = pTargetCPU_REGS->CR_L(3);
1094
1095 gui_fprintf(fStatusStream,
1096
1097 "CR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1098
1099 ,pTargetCPU_REGS->CR_L(0)
1100 ,pTargetCPU_REGS->CR_L(1)
1101 ,pTargetCPU_REGS->CR_L(2)
1102 ,pTargetCPU_REGS->CR_L(3)
1103 );
1104 }
1105
1106 if (0
1107 || prev_cr[4] != pTargetCPU_REGS->CR_L(4)
1108 || prev_cr[5] != pTargetCPU_REGS->CR_L(5)
1109 || prev_cr[6] != pTargetCPU_REGS->CR_L(6)
1110 || prev_cr[7] != pTargetCPU_REGS->CR_L(7)
1111 )
1112 {
1113 prev_cr[4] = pTargetCPU_REGS->CR_L(4);
1114 prev_cr[5] = pTargetCPU_REGS->CR_L(5);
1115 prev_cr[6] = pTargetCPU_REGS->CR_L(6);
1116 prev_cr[7] = pTargetCPU_REGS->CR_L(7);
1117
1118 gui_fprintf(fStatusStream,
1119
1120 "CR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1121
1122 ,pTargetCPU_REGS->CR_L(4)
1123 ,pTargetCPU_REGS->CR_L(5)
1124 ,pTargetCPU_REGS->CR_L(6)
1125 ,pTargetCPU_REGS->CR_L(7)
1126 );
1127 }
1128
1129 if (0
1130 || prev_cr[8] != pTargetCPU_REGS->CR_L(8)
1131 || prev_cr[9] != pTargetCPU_REGS->CR_L(9)
1132 || prev_cr[10] != pTargetCPU_REGS->CR_L(10)
1133 || prev_cr[11] != pTargetCPU_REGS->CR_L(11)
1134 )
1135 {
1136 prev_cr[8] = pTargetCPU_REGS->CR_L(8);
1137 prev_cr[9] = pTargetCPU_REGS->CR_L(9);
1138 prev_cr[10] = pTargetCPU_REGS->CR_L(10);
1139 prev_cr[10] = pTargetCPU_REGS->CR_L(10);
1140
1141 gui_fprintf(fStatusStream,
1142
1143 "CR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1144
1145 ,pTargetCPU_REGS->CR_L(8)
1146 ,pTargetCPU_REGS->CR_L(9)
1147 ,pTargetCPU_REGS->CR_L(10)
1148 ,pTargetCPU_REGS->CR_L(11)
1149 );
1150 }
1151
1152 if (0
1153 || prev_cr[12] != pTargetCPU_REGS->CR_L(12)
1154 || prev_cr[13] != pTargetCPU_REGS->CR_L(13)
1155 || prev_cr[14] != pTargetCPU_REGS->CR_L(14)
1156 || prev_cr[15] != pTargetCPU_REGS->CR_L(15)
1157 )
1158 {
1159 prev_cr[12] = pTargetCPU_REGS->CR_L(12);
1160 prev_cr[13] = pTargetCPU_REGS->CR_L(13);
1161 prev_cr[14] = pTargetCPU_REGS->CR_L(14);
1162 prev_cr[15] = pTargetCPU_REGS->CR_L(15);
1163
1164 gui_fprintf(fStatusStream,
1165
1166 "CRC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1167
1168 ,pTargetCPU_REGS->CR_L(12)
1169 ,pTargetCPU_REGS->CR_L(13)
1170 ,pTargetCPU_REGS->CR_L(14)
1171 ,pTargetCPU_REGS->CR_L(15)
1172 );
1173 }
1174 }
1175
1176 if (gui_wants_cregs64)
1177 {
1178 if (0
1179 || prev_cr64[0] != pTargetCPU_REGS->CR_G(0)
1180 || prev_cr64[1] != pTargetCPU_REGS->CR_G(1)
1181 )
1182 {
1183 prev_cr64[0] = pTargetCPU_REGS->CR_G(0);
1184 prev_cr64[1] = pTargetCPU_REGS->CR_G(1);
1185
1186 gui_fprintf(fStatusStream,
1187
1188 "64_CR0-1="REG64FMT" "REG64FMT"\n"
1189
1190 ,pTargetCPU_REGS->CR_G(0)
1191 ,pTargetCPU_REGS->CR_G(1)
1192 );
1193 }
1194
1195 if (0
1196 || prev_cr64[2] != pTargetCPU_REGS->CR_G(2)
1197 || prev_cr64[3] != pTargetCPU_REGS->CR_G(3)
1198 )
1199 {
1200 prev_cr64[2] = pTargetCPU_REGS->CR_G(2);
1201 prev_cr64[3] = pTargetCPU_REGS->CR_G(3);
1202
1203 gui_fprintf(fStatusStream,
1204
1205 "64_CR2-3="REG64FMT" "REG64FMT"\n"
1206
1207 ,pTargetCPU_REGS->CR_G(2)
1208 ,pTargetCPU_REGS->CR_G(3)
1209 );
1210 }
1211
1212 if (0
1213 || prev_cr64[4] != pTargetCPU_REGS->CR_G(4)
1214 || prev_cr64[5] != pTargetCPU_REGS->CR_G(5)
1215 )
1216 {
1217 prev_cr64[4] = pTargetCPU_REGS->CR_G(4);
1218 prev_cr64[5] = pTargetCPU_REGS->CR_G(5);
1219
1220 gui_fprintf(fStatusStream,
1221
1222 "64_CR4-5="REG64FMT" "REG64FMT"\n"
1223
1224 ,pTargetCPU_REGS->CR_G(4)
1225 ,pTargetCPU_REGS->CR_G(5)
1226 );
1227 }
1228
1229 if (0
1230 || prev_cr64[6] != pTargetCPU_REGS->CR_G(6)
1231 || prev_cr64[7] != pTargetCPU_REGS->CR_G(7)
1232 )
1233 {
1234 prev_cr64[6] = pTargetCPU_REGS->CR_G(6);
1235 prev_cr64[7] = pTargetCPU_REGS->CR_G(7);
1236
1237 gui_fprintf(fStatusStream,
1238
1239 "64_CR6-7="REG64FMT" "REG64FMT"\n"
1240
1241 ,pTargetCPU_REGS->CR_G(6)
1242 ,pTargetCPU_REGS->CR_G(7)
1243 );
1244 }
1245
1246 if (0
1247 || prev_cr64[8] != pTargetCPU_REGS->CR_G(8)
1248 || prev_cr64[9] != pTargetCPU_REGS->CR_G(9)
1249 )
1250 {
1251 prev_cr64[8] = pTargetCPU_REGS->CR_G(8);
1252 prev_cr64[9] = pTargetCPU_REGS->CR_G(9);
1253
1254 gui_fprintf(fStatusStream,
1255
1256 "64_CR8-9="REG64FMT" "REG64FMT"\n"
1257
1258 ,pTargetCPU_REGS->CR_G(8)
1259 ,pTargetCPU_REGS->CR_G(9)
1260 );
1261 }
1262
1263 if (0
1264 || prev_cr64[10] != pTargetCPU_REGS->CR_G(10)
1265 || prev_cr64[11] != pTargetCPU_REGS->CR_G(11)
1266 )
1267 {
1268 prev_cr64[10] = pTargetCPU_REGS->CR_G(10);
1269 prev_cr64[11] = pTargetCPU_REGS->CR_G(11);
1270
1271 gui_fprintf(fStatusStream,
1272
1273 "64_CRA-B="REG64FMT" "REG64FMT"\n"
1274
1275 ,pTargetCPU_REGS->CR_G(10)
1276 ,pTargetCPU_REGS->CR_G(11)
1277 );
1278 }
1279
1280 if (0
1281 || prev_cr64[12] != pTargetCPU_REGS->CR_G(12)
1282 || prev_cr64[13] != pTargetCPU_REGS->CR_G(13)
1283 )
1284 {
1285 prev_cr64[12] = pTargetCPU_REGS->CR_G(12);
1286 prev_cr64[13] = pTargetCPU_REGS->CR_G(13);
1287
1288 gui_fprintf(fStatusStream,
1289
1290 "64_CRC-D="REG64FMT" "REG64FMT"\n"
1291
1292 ,pTargetCPU_REGS->CR_G(12)
1293 ,pTargetCPU_REGS->CR_G(13)
1294 );
1295 }
1296
1297 if (0
1298 || prev_cr64[14] != pTargetCPU_REGS->CR_G(14)
1299 || prev_cr64[15] != pTargetCPU_REGS->CR_G(15)
1300 )
1301 {
1302 prev_cr64[14] = pTargetCPU_REGS->CR_G(14);
1303 prev_cr64[15] = pTargetCPU_REGS->CR_G(15);
1304
1305 gui_fprintf(fStatusStream,
1306
1307 "64_CRE-F="REG64FMT" "REG64FMT"\n"
1308
1309 ,pTargetCPU_REGS->CR_G(14)
1310 ,pTargetCPU_REGS->CR_G(15)
1311 );
1312 }
1313 }
1314
1315 if (gui_wants_aregs)
1316 {
1317 if (0
1318 || prev_ar[0] != pTargetCPU_REGS->AR(0)
1319 || prev_ar[1] != pTargetCPU_REGS->AR(1)
1320 || prev_ar[2] != pTargetCPU_REGS->AR(2)
1321 || prev_ar[3] != pTargetCPU_REGS->AR(3)
1322 )
1323 {
1324 prev_ar[0] = pTargetCPU_REGS->AR(0);
1325 prev_ar[1] = pTargetCPU_REGS->AR(1);
1326 prev_ar[2] = pTargetCPU_REGS->AR(2);
1327 prev_ar[3] = pTargetCPU_REGS->AR(3);
1328
1329 gui_fprintf(fStatusStream,
1330
1331 "AR0-3="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1332
1333 ,pTargetCPU_REGS->AR(0)
1334 ,pTargetCPU_REGS->AR(1)
1335 ,pTargetCPU_REGS->AR(2)
1336 ,pTargetCPU_REGS->AR(3)
1337 );
1338 }
1339
1340 if (0
1341 || prev_ar[4] != pTargetCPU_REGS->AR(4)
1342 || prev_ar[5] != pTargetCPU_REGS->AR(5)
1343 || prev_ar[6] != pTargetCPU_REGS->AR(6)
1344 || prev_ar[7] != pTargetCPU_REGS->AR(7)
1345 )
1346 {
1347 prev_ar[4] = pTargetCPU_REGS->AR(4);
1348 prev_ar[5] = pTargetCPU_REGS->AR(5);
1349 prev_ar[6] = pTargetCPU_REGS->AR(6);
1350 prev_ar[7] = pTargetCPU_REGS->AR(7);
1351
1352 gui_fprintf(fStatusStream,
1353
1354 "AR4-7="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1355
1356 ,pTargetCPU_REGS->AR(4)
1357 ,pTargetCPU_REGS->AR(5)
1358 ,pTargetCPU_REGS->AR(6)
1359 ,pTargetCPU_REGS->AR(7)
1360 );
1361 }
1362
1363 if (0
1364 || prev_ar[8] != pTargetCPU_REGS->AR(8)
1365 || prev_ar[9] != pTargetCPU_REGS->AR(9)
1366 || prev_ar[10] != pTargetCPU_REGS->AR(10)
1367 || prev_ar[11] != pTargetCPU_REGS->AR(11)
1368 )
1369 {
1370 prev_ar[8] = pTargetCPU_REGS->AR(8);
1371 prev_ar[9] = pTargetCPU_REGS->AR(9);
1372 prev_ar[10] = pTargetCPU_REGS->AR(10);
1373 prev_ar[11] = pTargetCPU_REGS->AR(11);
1374
1375 gui_fprintf(fStatusStream,
1376
1377 "AR8-B="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1378
1379 ,pTargetCPU_REGS->AR(8)
1380 ,pTargetCPU_REGS->AR(9)
1381 ,pTargetCPU_REGS->AR(10)
1382 ,pTargetCPU_REGS->AR(11)
1383 );
1384 }
1385
1386 if (0
1387 || prev_ar[12] != pTargetCPU_REGS->AR(12)
1388 || prev_ar[13] != pTargetCPU_REGS->AR(13)
1389 || prev_ar[14] != pTargetCPU_REGS->AR(14)
1390 || prev_ar[15] != pTargetCPU_REGS->AR(15)
1391 )
1392 {
1393 prev_ar[12] = pTargetCPU_REGS->AR(12);
1394 prev_ar[13] = pTargetCPU_REGS->AR(13);
1395 prev_ar[14] = pTargetCPU_REGS->AR(14);
1396 prev_ar[15] = pTargetCPU_REGS->AR(15);
1397
1398 gui_fprintf(fStatusStream,
1399
1400 "ARC-F="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1401
1402 ,pTargetCPU_REGS->AR(12)
1403 ,pTargetCPU_REGS->AR(13)
1404 ,pTargetCPU_REGS->AR(14)
1405 ,pTargetCPU_REGS->AR(15)
1406 );
1407 }
1408 }
1409
1410 if (gui_wants_fregs)
1411 {
1412 if (0
1413 || prev_fpr[0] != pTargetCPU_REGS->fpr[0]
1414 || prev_fpr[1] != pTargetCPU_REGS->fpr[1]
1415 || prev_fpr[2] != pTargetCPU_REGS->fpr[2]
1416 || prev_fpr[3] != pTargetCPU_REGS->fpr[3]
1417 )
1418 {
1419 prev_fpr[0] = pTargetCPU_REGS->fpr[0];
1420 prev_fpr[1] = pTargetCPU_REGS->fpr[1];
1421 prev_fpr[2] = pTargetCPU_REGS->fpr[2];
1422 prev_fpr[3] = pTargetCPU_REGS->fpr[3];
1423
1424 gui_fprintf(fStatusStream,
1425
1426 "FR0-2="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1427
1428 ,pTargetCPU_REGS->fpr[0]
1429 ,pTargetCPU_REGS->fpr[1]
1430 ,pTargetCPU_REGS->fpr[2]
1431 ,pTargetCPU_REGS->fpr[3]
1432 );
1433 }
1434
1435 if (0
1436 || prev_fpr[4] != pTargetCPU_REGS->fpr[4]
1437 || prev_fpr[5] != pTargetCPU_REGS->fpr[5]
1438 || prev_fpr[6] != pTargetCPU_REGS->fpr[6]
1439 || prev_fpr[7] != pTargetCPU_REGS->fpr[7]
1440 )
1441 {
1442 prev_fpr[4] = pTargetCPU_REGS->fpr[4];
1443 prev_fpr[5] = pTargetCPU_REGS->fpr[5];
1444 prev_fpr[6] = pTargetCPU_REGS->fpr[6];
1445 prev_fpr[7] = pTargetCPU_REGS->fpr[7];
1446
1447 gui_fprintf(fStatusStream,
1448
1449 "FR4-6="REG32FMT" "REG32FMT" "REG32FMT" "REG32FMT"\n"
1450
1451 ,pTargetCPU_REGS->fpr[4]
1452 ,pTargetCPU_REGS->fpr[5]
1453 ,pTargetCPU_REGS->fpr[6]
1454 ,pTargetCPU_REGS->fpr[7]
1455 );
1456 }
1457 }
1458
1459 if (gui_wants_fregs64)
1460 {
1461 if (0
1462 || prev_fpr64[0] != pTargetCPU_REGS->fpr[0]
1463 || prev_fpr64[1] != pTargetCPU_REGS->fpr[1]
1464 || prev_fpr64[2] != pTargetCPU_REGS->fpr[2]
1465 || prev_fpr64[3] != pTargetCPU_REGS->fpr[3]
1466 )
1467 {
1468 prev_fpr64[0] = pTargetCPU_REGS->fpr[0];
1469 prev_fpr64[1] = pTargetCPU_REGS->fpr[1];
1470 prev_fpr64[2] = pTargetCPU_REGS->fpr[2];
1471 prev_fpr64[3] = pTargetCPU_REGS->fpr[3];
1472
1473 gui_fprintf(fStatusStream,
1474
1475 "64_FR0-1="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1476
1477 ,pTargetCPU_REGS->fpr[0] ,pTargetCPU_REGS->fpr[1]
1478 ,pTargetCPU_REGS->fpr[2] ,pTargetCPU_REGS->fpr[3]
1479 );
1480 }
1481
1482 if (0
1483 || prev_fpr64[4] != pTargetCPU_REGS->fpr[4]
1484 || prev_fpr64[5] != pTargetCPU_REGS->fpr[5]
1485 || prev_fpr64[6] != pTargetCPU_REGS->fpr[6]
1486 || prev_fpr64[7] != pTargetCPU_REGS->fpr[7]
1487 )
1488 {
1489 prev_fpr64[4] = pTargetCPU_REGS->fpr[4];
1490 prev_fpr64[5] = pTargetCPU_REGS->fpr[5];
1491 prev_fpr64[6] = pTargetCPU_REGS->fpr[6];
1492 prev_fpr64[7] = pTargetCPU_REGS->fpr[7];
1493
1494 gui_fprintf(fStatusStream,
1495
1496 "64_FR2-3="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1497
1498 ,pTargetCPU_REGS->fpr[4] ,pTargetCPU_REGS->fpr[5]
1499 ,pTargetCPU_REGS->fpr[6] ,pTargetCPU_REGS->fpr[7]
1500 );
1501 }
1502
1503 if (0
1504 || prev_fpr64[8] != pTargetCPU_REGS->fpr[8]
1505 || prev_fpr64[9] != pTargetCPU_REGS->fpr[9]
1506 || prev_fpr64[10] != pTargetCPU_REGS->fpr[10]
1507 || prev_fpr64[11] != pTargetCPU_REGS->fpr[11]
1508 )
1509 {
1510 prev_fpr64[8] = pTargetCPU_REGS->fpr[8];
1511 prev_fpr64[9] = pTargetCPU_REGS->fpr[9];
1512 prev_fpr64[10] = pTargetCPU_REGS->fpr[10];
1513 prev_fpr64[11] = pTargetCPU_REGS->fpr[11];
1514
1515 gui_fprintf(fStatusStream,
1516
1517 "64_FR4-5="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1518
1519 ,pTargetCPU_REGS->fpr[8] ,pTargetCPU_REGS->fpr[9]
1520 ,pTargetCPU_REGS->fpr[10] ,pTargetCPU_REGS->fpr[11]
1521
1522 );
1523 }
1524
1525 if (0
1526 || prev_fpr64[12] != pTargetCPU_REGS->fpr[12]
1527 || prev_fpr64[13] != pTargetCPU_REGS->fpr[13]
1528 || prev_fpr64[14] != pTargetCPU_REGS->fpr[14]
1529 || prev_fpr64[15] != pTargetCPU_REGS->fpr[15]
1530 )
1531 {
1532 prev_fpr64[12] = pTargetCPU_REGS->fpr[12];
1533 prev_fpr64[13] = pTargetCPU_REGS->fpr[13];
1534 prev_fpr64[14] = pTargetCPU_REGS->fpr[14];
1535 prev_fpr64[15] = pTargetCPU_REGS->fpr[15];
1536
1537 gui_fprintf(fStatusStream,
1538
1539 "64_FR6-7="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1540
1541 ,pTargetCPU_REGS->fpr[12] ,pTargetCPU_REGS->fpr[13]
1542 ,pTargetCPU_REGS->fpr[14] ,pTargetCPU_REGS->fpr[15]
1543
1544 );
1545 }
1546
1547 if (0
1548 || prev_fpr64[16] != pTargetCPU_REGS->fpr[16]
1549 || prev_fpr64[17] != pTargetCPU_REGS->fpr[17]
1550 || prev_fpr64[18] != pTargetCPU_REGS->fpr[18]
1551 || prev_fpr64[19] != pTargetCPU_REGS->fpr[19]
1552 )
1553 {
1554 prev_fpr64[16] = pTargetCPU_REGS->fpr[16];
1555 prev_fpr64[17] = pTargetCPU_REGS->fpr[17];
1556 prev_fpr64[18] = pTargetCPU_REGS->fpr[18];
1557 prev_fpr64[19] = pTargetCPU_REGS->fpr[19];
1558
1559 gui_fprintf(fStatusStream,
1560
1561 "64_FR8-9="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1562
1563 ,pTargetCPU_REGS->fpr[16] ,pTargetCPU_REGS->fpr[17]
1564 ,pTargetCPU_REGS->fpr[18] ,pTargetCPU_REGS->fpr[19]
1565 );
1566 }
1567
1568 if (0
1569 || prev_fpr64[20] != pTargetCPU_REGS->fpr[20]
1570 || prev_fpr64[21] != pTargetCPU_REGS->fpr[21]
1571 || prev_fpr64[22] != pTargetCPU_REGS->fpr[22]
1572 || prev_fpr64[23] != pTargetCPU_REGS->fpr[23]
1573 )
1574 {
1575 prev_fpr64[20] = pTargetCPU_REGS->fpr[20];
1576 prev_fpr64[21] = pTargetCPU_REGS->fpr[21];
1577 prev_fpr64[22] = pTargetCPU_REGS->fpr[22];
1578 prev_fpr64[23] = pTargetCPU_REGS->fpr[23];
1579
1580 gui_fprintf(fStatusStream,
1581
1582 "64_FRA-B="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1583
1584 ,pTargetCPU_REGS->fpr[20] ,pTargetCPU_REGS->fpr[21]
1585 ,pTargetCPU_REGS->fpr[22] ,pTargetCPU_REGS->fpr[23]
1586 );
1587 }
1588
1589 if (0
1590 || prev_fpr64[24] != pTargetCPU_REGS->fpr[24]
1591 || prev_fpr64[25] != pTargetCPU_REGS->fpr[25]
1592 || prev_fpr64[26] != pTargetCPU_REGS->fpr[26]
1593 || prev_fpr64[27] != pTargetCPU_REGS->fpr[27]
1594 )
1595 {
1596 prev_fpr64[24] = pTargetCPU_REGS->fpr[24];
1597 prev_fpr64[25] = pTargetCPU_REGS->fpr[25];
1598 prev_fpr64[26] = pTargetCPU_REGS->fpr[26];
1599 prev_fpr64[27] = pTargetCPU_REGS->fpr[27];
1600
1601 gui_fprintf(fStatusStream,
1602
1603 "64_FRC-D="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1604
1605 ,pTargetCPU_REGS->fpr[24] ,pTargetCPU_REGS->fpr[25]
1606 ,pTargetCPU_REGS->fpr[26] ,pTargetCPU_REGS->fpr[27]
1607 );
1608 }
1609
1610 if (0
1611 || prev_fpr64[28] != pTargetCPU_REGS->fpr[28]
1612 || prev_fpr64[29] != pTargetCPU_REGS->fpr[29]
1613 || prev_fpr64[30] != pTargetCPU_REGS->fpr[30]
1614 || prev_fpr64[31] != pTargetCPU_REGS->fpr[31]
1615 )
1616 {
1617 prev_fpr64[28] = pTargetCPU_REGS->fpr[28];
1618 prev_fpr64[29] = pTargetCPU_REGS->fpr[29];
1619 prev_fpr64[30] = pTargetCPU_REGS->fpr[30];
1620 prev_fpr64[31] = pTargetCPU_REGS->fpr[31];
1621
1622 gui_fprintf(fStatusStream,
1623
1624 "64_FRE-F="REG32FMT""REG32FMT" "REG32FMT""REG32FMT"\n"
1625
1626 ,pTargetCPU_REGS->fpr[28] ,pTargetCPU_REGS->fpr[29]
1627 ,pTargetCPU_REGS->fpr[30] ,pTargetCPU_REGS->fpr[31]
1628 );
1629 }
1630 }
1631 }
1632
1633 ///////////////////////////////////////////////////////////////////////////////
1634
1635 char szQueryDeviceBuff[ MAX_DEVICEQUERY_LEN + 1 ]; // (always +1 for safety!)
1636
1637 ///////////////////////////////////////////////////////////////////////////////
1638 // Send status information messages back to the gui... (VERY inefficient!)
1639
UpdateDeviceStatus()1640 void UpdateDeviceStatus ()
1641 {
1642 DEVBLK* pDEVBLK;
1643 char* pDEVClass;
1644 BYTE chOnlineStat, chBusyStat, chPendingStat, chOpenStat;
1645
1646 if (sysblk.shutdown) return;
1647
1648 // Process ALL the devices in the entire configuration each time...
1649
1650 for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev)
1651 {
1652 // Does this device actually exist in the configuration?
1653
1654 if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V))
1655 continue; // (no, skip)
1656
1657 // Retrieve this device's filename and optional settings parameter values...
1658
1659 szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra)
1660
1661 (pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff);
1662
1663 if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN]) // (buffer overflow?)
1664 {
1665 logmsg
1666 (
1667 _("HHCDG005E Device query buffer overflow! (device=%4.4X)\n")
1668
1669 ,pDEVBLK->devnum
1670
1671 );
1672 }
1673
1674 szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (enforce NULL termination)
1675
1676 // Device status flags...
1677 chOnlineStat =
1678 chBusyStat =
1679 chPendingStat =
1680 chOpenStat = '0';
1681
1682 if ((!pDEVBLK->console && pDEVBLK->fd >= 0) ||
1683 ( pDEVBLK->console && pDEVBLK->connected)) chOnlineStat = '1';
1684 if (pDEVBLK->busy) chBusyStat = '1';
1685 if (IOPENDING(pDEVBLK)) chPendingStat = '1';
1686 if (pDEVBLK->fd > MAX(STDIN_FILENO,MAX(STDOUT_FILENO,STDERR_FILENO))) chOpenStat = '1';
1687
1688 // Send status message back to gui...
1689
1690 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1691 if (pDEVBLK == sysblk.sysgdev)
1692 {
1693 gui_fprintf( fStatusStream,
1694
1695 "DEV=0000 SYSG %-4.4s %c%c%c%c %s\n"
1696
1697 ,pDEVClass
1698
1699 ,chOnlineStat
1700 ,chBusyStat
1701 ,chPendingStat
1702 ,chOpenStat
1703
1704 ,szQueryDeviceBuff
1705 );
1706 }
1707 else
1708 #endif // defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1709 gui_fprintf(fStatusStream,
1710
1711 "DEV=%4.4X %4.4X %-4.4s %c%c%c%c %s\n"
1712
1713 ,pDEVBLK->devnum
1714 ,pDEVBLK->devtype
1715 ,pDEVClass
1716
1717 ,chOnlineStat
1718 ,chBusyStat
1719 ,chPendingStat
1720 ,chOpenStat
1721
1722 ,szQueryDeviceBuff
1723 );
1724 }
1725
1726 // Since the device list can be in any order and devices can be added
1727 // and/or removed at any time, the GUI needs to know "That's all the
1728 // devices there are" so that it can detect when devices are removed...
1729
1730 gui_fprintf(fStatusStream, "DEV=X\n"); // (indicates end of list)
1731 }
1732
1733 ///////////////////////////////////////////////////////////////////////////////
1734 // Send device status msgs to the gui IF NEEDED... (slightly more efficient)
1735
NewUpdateDevStats()1736 void NewUpdateDevStats ()
1737 {
1738 DEVBLK* pDEVBLK;
1739 GUISTAT* pGUIStat;
1740 char* pDEVClass;
1741 BYTE chOnlineStat, chBusyStat, chPendingStat, chOpenStat;
1742 BOOL bUpdatesSent = FALSE;
1743 static BOOL bFirstBatch = TRUE;
1744
1745 if (sysblk.shutdown) return;
1746
1747 // Process ALL the devices in the entire configuration each time...
1748
1749 // (But only send device status messages to the GUI only when the
1750 // device's status actually changes and not continuously like before)
1751
1752 for (pDEVBLK = sysblk.firstdev; pDEVBLK != NULL; pDEVBLK = pDEVBLK->nextdev)
1753 {
1754 pGUIStat = pDEVBLK->pGUIStat;
1755
1756 // Does this device exist in the configuration?
1757
1758 if (!pDEVBLK->allocated || !(pDEVBLK->pmcw.flag5 & PMCW5_V))
1759 {
1760 // This device no longer exists in the configuration...
1761 // If we haven't yet notified the GUI about this device
1762 // being deleted from the configuration, then do so at
1763 // this time...
1764
1765 if (*pGUIStat->pszNewStatStr)
1766 {
1767 // Send "device deleted" message...
1768
1769 gui_fprintf ( fStatusStream, "DEVD=%4.4X\n", pDEVBLK->devnum );
1770 bUpdatesSent = TRUE;
1771
1772 *pGUIStat->pszNewStatStr = 0; // (prevent re-reporting it)
1773 *pGUIStat->pszOldStatStr = 0; // (prevent re-reporting it)
1774 }
1775
1776 continue; // (go on to next device)
1777 }
1778
1779 // Retrieve this device's filename and optional settings parameter values...
1780
1781 szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (buffer allows room for 1 extra)
1782
1783 (pDEVBLK->hnd->query)(pDEVBLK, &pDEVClass, MAX_DEVICEQUERY_LEN, szQueryDeviceBuff);
1784
1785 if (0 != szQueryDeviceBuff[MAX_DEVICEQUERY_LEN]) // (buffer overflow?)
1786 {
1787 logmsg
1788 (
1789 _("HHCDG005E Device query buffer overflow! (device=%4.4X)\n")
1790
1791 ,pDEVBLK->devnum
1792 );
1793 }
1794
1795 szQueryDeviceBuff[MAX_DEVICEQUERY_LEN] = 0; // (enforce NULL termination)
1796
1797 // Device status flags...
1798 chOnlineStat =
1799 chBusyStat =
1800 chPendingStat =
1801 chOpenStat = '0';
1802
1803 if ((!pDEVBLK->console && pDEVBLK->fd >= 0) ||
1804 ( pDEVBLK->console && pDEVBLK->connected)) chOnlineStat = '1';
1805 if (pDEVBLK->busy) chBusyStat = '1';
1806 if (IOPENDING(pDEVBLK)) chPendingStat = '1';
1807 if (pDEVBLK->fd > MAX(STDIN_FILENO,MAX(STDOUT_FILENO,STDERR_FILENO))) chOpenStat = '1';
1808
1809 // Build a new "device added" or "device changed"
1810 // status string for this device...
1811
1812 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1813 if (pDEVBLK == sysblk.sysgdev)
1814 {
1815 snprintf( pGUIStat->pszNewStatStr, GUI_STATSTR_BUFSIZ,
1816
1817 "DEV%c=0000 SYSG %-4.4s %c%c%c%c %s"
1818
1819 ,*pGUIStat->pszOldStatStr ? 'C' : 'A'
1820 ,pDEVClass
1821
1822 ,chOnlineStat
1823 ,chBusyStat
1824 ,chPendingStat
1825 ,chOpenStat
1826
1827 ,szQueryDeviceBuff
1828 );
1829 }
1830 else
1831 #endif // defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1832 snprintf( pGUIStat->pszNewStatStr, GUI_STATSTR_BUFSIZ,
1833
1834 "DEV%c=%4.4X %4.4X %-4.4s %c%c%c%c %s"
1835
1836 ,*pGUIStat->pszOldStatStr ? 'C' : 'A'
1837 ,pDEVBLK->devnum
1838 ,pDEVBLK->devtype
1839 ,pDEVClass
1840
1841 ,chOnlineStat
1842 ,chBusyStat
1843 ,chPendingStat
1844 ,chOpenStat
1845
1846 ,szQueryDeviceBuff
1847 );
1848
1849 *(pGUIStat->pszNewStatStr + GUI_STATSTR_BUFSIZ - 1) = 0;
1850
1851 // If the new status string is different from the old one,
1852 // then send the new one to the GUI and swap buffer ptrs
1853 // for next time. In this way we only send device status
1854 // msgs to the GUI only when the status actually changes...
1855
1856 if (strcmp( pGUIStat->pszNewStatStr, pGUIStat->pszOldStatStr ))
1857 {
1858 gui_fprintf ( fStatusStream, "%s\n", pGUIStat->pszNewStatStr );
1859 bUpdatesSent = TRUE;
1860 {
1861 register char*
1862 pszSavStatStr = pGUIStat->pszNewStatStr;
1863 pGUIStat->pszNewStatStr = pGUIStat->pszOldStatStr;
1864 pGUIStat->pszOldStatStr = pszSavStatStr;
1865 }
1866 }
1867 }
1868
1869 // Only send End-of-Batch indicator if we sent any updates or
1870 // if this is the first device-list update since powering on.
1871
1872 if ( bUpdatesSent || bFirstBatch )
1873 {
1874 bFirstBatch = FALSE;
1875 gui_fprintf(fStatusStream, "DEVX=\n"); // (send end-of-batch indicator)
1876 }
1877 }
1878
1879 ///////////////////////////////////////////////////////////////////////////////
1880 // Our Hercules "debug_cpu_state" override...
1881 //
1882 // Hercules calls the following function from several different places to fix
1883 // an unintentional problem caused by the new logger mechanism (wherein stdout
1884 // and stderr now point to the same stream) due to a oversight (bug) on my part
1885 // wherein the 'LOAD' and 'MAN' messages are being [mistakenly] written to stdout
1886 // instead of stderr (where they normally should be). The current version of
1887 // the gui expects both messages to come in on the stdout stream, but due to the
1888 // recent logger changes, they now come in on the stderr stream instead (because
1889 // stdout was duped to stderr by the new logger logic) thus causing the gui to
1890 // miss seeing them without the below fix. The below fix simply corrects for the
1891 // problem by simply writing the two messages to the stdout stream where older
1892 // versions of the gui expect to see them.
1893
gui_debug_cpu_state(REGS * pREGS)1894 void* gui_debug_cpu_state ( REGS* pREGS )
1895 {
1896 void *(*next_debug_call)(REGS *);
1897
1898 static BOOL bLoading = FALSE;
1899 static BOOL bStopped = FALSE;
1900
1901 if (sysblk.shutdown) return NULL;
1902
1903 if (pTargetCPU_REGS && pREGS != pTargetCPU_REGS)
1904 return NULL;
1905
1906 if (bLoading != (pREGS->loadstate ? TRUE : FALSE))
1907 {
1908 bLoading = (pREGS->loadstate ? TRUE : FALSE);
1909 gui_fprintf(stdout,"LOAD=%c\n", bLoading ? '1' : '0');
1910 }
1911
1912 if (bStopped != ((CPUSTATE_STOPPED == pREGS->cpustate) ? TRUE : FALSE))
1913 {
1914 bStopped = ((CPUSTATE_STOPPED == pREGS->cpustate) ? TRUE : FALSE);
1915 gui_fprintf(stdout,"MAN=%c\n", bStopped ? '1' : '0');
1916 }
1917
1918 if((next_debug_call = HDL_FINDNXT( gui_debug_cpu_state )))
1919 return next_debug_call( pREGS );
1920
1921 return NULL; // (I have no idea why this is a void* func)
1922 }
1923
1924 ///////////////////////////////////////////////////////////////////////////////
1925 // Our Hercules "debug_cd_cmd" hook...
1926 //
1927 // The following function is called by the 'cd_cmd' panel command to notify
1928 // the GUI of what the new current directory was just changed to...
1929
gui_debug_cd_cmd(char * pszCWD)1930 void* gui_debug_cd_cmd( char* pszCWD )
1931 {
1932 ASSERT( pszCWD );
1933 if (gui_version >= 1.12)
1934 gui_fprintf( fStatusStream, "]CWD=%s\n", pszCWD );
1935 return NULL;
1936 }
1937
1938 ///////////////////////////////////////////////////////////////////////////////
1939 // Streams 'fprintf' function to prevent interleaving collision problem...
1940
1941 LOCK gui_fprintf_lock;
1942
gui_fprintf(FILE * stream,const char * pszFormat,...)1943 void gui_fprintf( FILE* stream, const char* pszFormat, ... )
1944 {
1945 va_list vl;
1946 va_start( vl, pszFormat );
1947 obtain_lock ( &gui_fprintf_lock );
1948 vfprintf( stream, pszFormat, vl );
1949 fflush( stream );
1950 release_lock( &gui_fprintf_lock );
1951 }
1952
1953 ///////////////////////////////////////////////////////////////////////////////
1954 // Acquire any resources we need in order to operate...
1955 // (called by 'gui_panel_display' before main loop initiates...)
1956
Initialize()1957 void Initialize ()
1958 {
1959 // Initialize streams...
1960
1961 fOutputStream = OUTPUT_STREAM_FILE_PTR;
1962 fStatusStream = STATUS_STREAM_FILE_PTR;
1963
1964 nInputStreamFileNum = fileno( INPUT_STREAM_FILE_PTR );
1965
1966 // Allocate input stream buffer...
1967
1968 if (!(pszInputBuff = (char *) malloc( nInputBuffSize )))
1969 {
1970 fprintf(stderr,
1971 _("HHCDG006S malloc pszInputBuff failed: %s\n")
1972 ,strerror(errno));
1973 exit(0);
1974 }
1975
1976 memset(pszInputBuff, 0, nInputBuffSize);
1977 nInputLen = 0;
1978
1979 // Allocate command processing buffer...
1980
1981 if (!(pszCommandBuff = (char *) malloc( nCommandBuffSize )))
1982 {
1983 fprintf(stderr,
1984 _("HHCDG007S malloc pszCommandBuff failed: %s\n")
1985 ,strerror(errno));
1986 exit(0);
1987 }
1988
1989 memset(pszCommandBuff, 0, nCommandBuffSize);
1990 nCommandLen = 0;
1991
1992 // Initialize some variables...
1993
1994 HandleForcedRefresh();
1995 }
1996
1997 ///////////////////////////////////////////////////////////////////////////////
1998 // Release any resources we acquired in order to operate...
1999 // (called by 'gui_panel_display' when main loop terminates...)
2000
Cleanup()2001 void Cleanup()
2002 {
2003 if (pszInputBuff)
2004 free(pszInputBuff);
2005
2006 if (pszCommandBuff)
2007 free(pszCommandBuff);
2008 }
2009
2010 ///////////////////////////////////////////////////////////////////////////////
2011 // Hercules "daemon_task" -or- "panel_display" override...
2012
gui_panel_display()2013 void gui_panel_display ()
2014 {
2015 static char *DisQuietCmd[] = { "$zapcmd", "quiet", "NoCmd" };
2016
2017 SET_THREAD_NAME("dyngui");
2018
2019 ProcessConfigCommand(3,DisQuietCmd,NULL); // Disable the quiet command
2020
2021 if ( !bDoneProcessing )
2022 {
2023 logmsg(_("HHCDG001I dyngui.dll initiated\n"));
2024 Initialize(); // (allocate buffers, etc)
2025 ProcessingLoop(); // (primary processing loop)
2026 logmsg(_("HHCDG002I dyngui.dll terminated\n"));
2027 Cleanup(); // (de-allocate resources)
2028 }
2029 }
2030
2031 /*****************************************************************************\
2032 Hercules Dynamic Loader control sections...
2033 \*****************************************************************************/
2034 /*
2035 Note that ALL of the below "sections" are actually just simple functions
2036 that Hercules's dynamic loader logic calls, thus allowing you to insert
2037 whatever 'C' code you may need directly into any of the below sections.
2038 */
2039 ///////////////////////////////////////////////////////////////////////////////
2040 // HDL_DEPENDENCY_SECTION
2041 // The following are the various Hercules structures whose layout this module
2042 // depends on. The layout of the following structures (size and version) MUST
2043 // match the layout that was used to build Hercules with. If the size/version
2044 // of any of the following structures changes (and a new version of Hercules
2045 // is built using the new layout), then THIS module must also be built with
2046 // the new layout as well. The layout (size/version) of the structure as it
2047 // was when Hercules was built MUST MATCH the layout as it was when THIS DLL
2048 // was built)
2049
2050 /* Libtool static name colision resolution */
2051 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
2052 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
2053 #define hdl_ddev dyngui_LTX_hdl_ddev
2054 #define hdl_depc dyngui_LTX_hdl_depc
2055 #define hdl_reso dyngui_LTX_hdl_reso
2056 #define hdl_init dyngui_LTX_hdl_init
2057 #define hdl_fini dyngui_LTX_hdl_fini
2058 #endif
2059
2060 HDL_DEPENDENCY_SECTION; // (define module dependencies)
2061
2062 HDL_DEPENDENCY ( HERCULES ); // Hercules itself
2063 HDL_DEPENDENCY ( SYSBLK ); // Master control block
2064 HDL_DEPENDENCY ( REGS ); // CPU regs and such
2065 HDL_DEPENDENCY ( DEVBLK ); // Device info block
2066
2067 END_DEPENDENCY_SECTION
2068
2069 ///////////////////////////////////////////////////////////////////////////////
2070 // HDL_REGISTER_SECTION
2071 // The following section defines the entry points within Hercules that THIS
2072 // module is overriding (replacing). That is to say, THIS module's functions
2073 // will be called by Hercules instead of the normal Hercules function (if any).
2074 // The functions defined below thus provide additional/different functionality
2075 // above/beyond the functionality normally provided by Hercules. (Of course,
2076 // yet OTHER dlls may have further overridden whatever overrides we register
2077 // here, such as would likely be the case for panel command overrides).
2078
2079 HDL_REGISTER_SECTION; // ("Register" our entry-points)
2080 {
2081 // Perform static module initialization...
2082
2083 gui_nounload = 1; // (reject any unload attempt)
2084 initialize_lock( &gui_fprintf_lock ); // (initialize GUI fprintf LOCK)
2085
2086 // Register all of our override entry-points...
2087
2088 // Hercules's Our
2089 // registered overriding
2090 // entry-point entry-point
2091 // name value
2092 HDL_REGISTER ( panel_display, gui_panel_display );// (Yep! We override EITHER!)
2093 HDL_REGISTER ( daemon_task, gui_panel_display );// (Yep! We override EITHER!)
2094 HDL_REGISTER ( debug_cpu_state, gui_debug_cpu_state );
2095 HDL_REGISTER ( debug_cd_cmd, gui_debug_cd_cmd );
2096 HDL_REGISTER ( panel_command, gui_panel_command );
2097 }
2098 END_REGISTER_SECTION
2099
2100 #if defined( WIN32 ) && !defined( HDL_USE_LIBTOOL )
2101 #if !defined( _MSVC_ )
2102 #undef sysblk
2103 #endif
2104 ///////////////////////////////////////////////////////////////////////////////
2105 // HDL_RESOLVER_SECTION
2106 // The following section "resolves" entry-points that this module needs. The
2107 // below HDL_RESOLVE entries define the names of Hercules's registered entry-
2108 // points that we need "imported" to us (so that we may call those functions
2109 // directly ourselves). The HDL_RESOLVE_PTRVAR entries set the named pointer
2110 // variable value (i.e. the name of OUR pointer variable) to the registered
2111 // entry-point value that was registered by Hercules or some other DLL.
2112
2113 HDL_RESOLVER_SECTION; // ("Resolve" needed entry-points)
2114 {
2115 // Registered
2116 // entry-points
2117 // that we call
2118 HDL_RESOLVE ( panel_command );
2119
2120 #if !defined( _MSVC_ )
2121 // Our pointer- Registered entry-
2122 // variable name point value name
2123 HDL_RESOLVE_PTRVAR ( psysblk, sysblk );
2124 #endif
2125 }
2126 END_RESOLVER_SECTION
2127 #endif
2128
2129 ///////////////////////////////////////////////////////////////////////////////
2130 // HDL_FINAL_SECTION
2131 // The following section defines what should be done immediately before this
2132 // module is unloaded. It is nothing more than a function that is called by
2133 // Hercules just before your module is unloaded. You can do anything you want
2134 // but the normal thing to do is release any resources that were acquired when
2135 // your module was loaded (e.g. release memory that was malloc'ed, etc).
2136
2137 HDL_FINAL_SECTION;
2138 {
2139 bDoneProcessing = TRUE; // (tell main loop to stop processing)
2140
2141 usleep(100000); // (brief delay to give GUI time
2142 // to display ALL shutdown msgs)
2143 return gui_nounload; // (reject unloads when activated)
2144 }
2145 END_FINAL_SECTION
2146
2147 ///////////////////////////////////////////////////////////////////////////////
2148
2149 #endif /*defined(OPTION_DYNAMIC_LOAD)*/
2150
2151 #endif // EXTERNALGUI
2152