1 /* PANEL.C (c) Copyright Roger Bowler, 1999-2010 */
2 /* Hercules Control Panel Commands */
3
4 /* Modified for New Panel Display =NP= */
5 /*-------------------------------------------------------------------*/
6 /* This module is the control panel for the ESA/390 emulator. */
7 /* It provides a command interface into hercules, and it displays */
8 /* messages that are issued by various hercules components. */
9 /*-------------------------------------------------------------------*/
10
11 /*-------------------------------------------------------------------*/
12 /* Additional credits: */
13 /* breakpoint command contributed by Dan Horak */
14 /* devinit command contributed by Jay Maynard */
15 /* New Panel Display contributed by Dutch Owen */
16 /* HMC system console commands contributed by Jan Jaeger */
17 /* Set/reset bad frame indicator command by Jan Jaeger */
18 /* attach/detach/define commands by Jan Jaeger */
19 /* Panel refresh rate triva by Reed H. Petty */
20 /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2007 */
21 /* 64-bit address support by Roger Bowler */
22 /* Display subchannel command by Nobumichi Kozawa */
23 /* External GUI logic contributed by "Fish" (David B. Trout) */
24 /* Socket Devices originally designed by Malcolm Beattie; */
25 /* actual implementation by "Fish" (David B. Trout). */
26 /*-------------------------------------------------------------------*/
27
28 #include "hstdinc.h"
29
30 #define _PANEL_C_
31 #define _HENGINE_DLL_
32
33 #include "hercules.h"
34 #include "devtype.h"
35 #include "opcode.h"
36 #include "history.h"
37 // #include "inline.h"
38 #include "fillfnam.h"
39 #include "hconsole.h"
40
41 #define DISPLAY_INSTRUCTION_OPERANDS
42
43 #define PANEL_MAX_ROWS (256)
44 #define PANEL_MAX_COLS (256)
45
46 int redraw_msgs; /* 1=Redraw message area */
47 int redraw_cmd; /* 1=Redraw command line */
48 int redraw_status; /* 1=Redraw status line */
49
50 /*=NP================================================================*/
51 /* Global data for new panel display */
52 /* (Note: all NPD mods are identified by the string =NP= */
53 /*===================================================================*/
54
55 static int NPDup = 0; /* 1 = new panel is up */
56 static int NPDinit = 0; /* 1 = new panel initialized */
57 static int NPhelpup = 0; /* 1 = help panel showing */
58 static int NPhelppaint = 1; /* 1 = help pnl s/b painted */
59 static int NPhelpdown = 0; /* 1 = help pnl coming down */
60 static int NPregdisp = 0; /* which regs are displayed: */
61 /* 0=gpr, 1=cr, 2=ar, 3=fpr */
62 static int NPcmd = 0; /* 1 = NP in command mode */
63 static int NPdataentry = 0; /* 1 = NP in data-entry mode */
64 static int NPdevsel = 0; /* 1 = device being selected */
65 static char NPpending; /* pending data entry cmd */
66 static char NPentered[256]; /* Data which was entered */
67 static char NPprompt1[40]; /* Left bottom screen prompt */
68 static char NPoldprompt1[40]; /* Left bottom screen prompt */
69 static char NPprompt2[40]; /* Right bottom screen prompt*/
70 static char NPoldprompt2[40]; /* Right bottom screen prompt*/
71 static char NPsel2; /* dev sel part 2 cmd letter */
72 static char NPdevice; /* Which device is selected */
73 static int NPasgn; /* Index to dev being init'ed*/
74 static int NPlastdev; /* Number of devices */
75 static int NPcpugraph_ncpu; /* Number of CPUs to display */
76
77 static char *NPregnum[] = {" 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7",
78 " 8"," 9","10","11","12","13","14","15"
79 };
80 static char *NPregnum64[] = {"0", "1", "2", "3", "4", "5", "6", "7",
81 "8", "9", "A", "B", "C", "D", "E", "F"
82 };
83
84 /* Boolean fields; redraw the corresponding data field if false */
85 static int NPcpunum_valid,
86 NPcpupct_valid,
87 NPpsw_valid,
88 NPpswstate_valid,
89 NPregs_valid,
90 NPaddr_valid,
91 NPdata_valid,
92 #ifdef OPTION_MIPS_COUNTING
93 NPmips_valid,
94 NPsios_valid,
95 #endif // OPTION_MIPS_COUNTING
96 NPdevices_valid,
97 NPcpugraph_valid;
98
99 /* Current CPU states */
100 static U16 NPcpunum;
101 static int NPcpupct;
102 static int NPpswmode;
103 static int NPpswzhost;
104 static QWORD NPpsw;
105 static char NPpswstate[16];
106 static int NPregmode;
107 static int NPregzhost;
108 static U64 NPregs64[16];
109 static U32 NPregs[16];
110 static U32 NPaddress;
111 static U32 NPdata;
112 #ifdef OPTION_MIPS_COUNTING
113 static U32 NPmips;
114 static U32 NPsios;
115 #else
116 static U64 NPinstcount;
117 #endif // OPTION_MIPS_COUNTING
118 static int NPcpugraph;
119 static int NPcpugraphpct[MAX_CPU_ENGINES];
120
121 /* Current device states */
122 #define NP_MAX_DEVICES (PANEL_MAX_ROWS - 3)
123 static int NPonline[NP_MAX_DEVICES];
124 static U16 NPdevnum[NP_MAX_DEVICES];
125 static int NPbusy[NP_MAX_DEVICES];
126 static U16 NPdevtype[NP_MAX_DEVICES];
127 static int NPopen[NP_MAX_DEVICES];
128 static char NPdevnam[NP_MAX_DEVICES][128];
129
130 static short NPcurrow, NPcurcol;
131 static int NPcolorSwitch;
132 static short NPcolorFore;
133 static short NPcolorBack;
134 static int NPdatalen;
135
136 static char *NPhelp[] = {
137 "All commands consist of one character keypresses. The various commands are",
138 "highlighted onscreen by bright white versus the gray of other lettering.",
139 " ",
140 "Press the escape key to terminate the control panel and go to command mode.",
141 " ",
142 "Display Controls: G - General purpose regs C - Control regs",
143 " A - Access registers F - Floating Point regs",
144 " I - Display main memory at 'ADDRESS'",
145 "CPU controls: L - IPL S - Start CPU",
146 " E - External interrupt P - Stop CPU",
147 " W - Exit Hercules T - Restart interrupt",
148 "Storage update: R - Enter ADDRESS to be updated",
149 " D - Enter DATA to be updated at ADDRESS",
150 " O - place DATA value at ADDRESS",
151 " ",
152 "Peripherals: N - enter a new name for the device file assignment",
153 " U - send an I/O attention interrupt",
154 " ",
155 "In the display of devices, a green device letter means the device is online,",
156 "a lighted device address means the device is busy, and a green model number",
157 "means the attached file is open to the device",
158 " ",
159 " Press Escape to return to control panel operations",
160 "" };
161
162 ///////////////////////////////////////////////////////////////////////
163
164 #define MSG_SIZE PANEL_MAX_COLS /* Size of one message */
165 #define MAX_MSGS 2048 /* Number of slots in buffer */
166 //#define MAX_MSGS 300 /* (for testing scrolling) */
167 #define MSG_LINES (cons_rows - 2) /* #lines in message area */
168 #define SCROLL_LINES (MSG_LINES - numkept) /* #of scrollable lines */
169 #define CMD_SIZE 256 /* cmdline buffer size */
170
171 ///////////////////////////////////////////////////////////////////////
172
173 static int cons_rows = 0; /* console height in lines */
174 static int cons_cols = 0; /* console width in chars */
175 static short cur_cons_row = 0; /* current console row */
176 static short cur_cons_col = 0; /* current console column */
177 static char *cons_term = NULL; /* TERM env value */
178 static char cmdins = 1; /* 1==insert mode, 0==overlay*/
179
180 static char cmdline[CMD_SIZE+1]; /* Command line buffer */
181 static int cmdlen = 0; /* cmdline data len in bytes */
182 static int cmdoff = 0; /* cmdline buffer cursor pos */
183
184 static int cursor_on_cmdline = 1; /* bool: cursor on cmdline */
185 static char saved_cmdline[CMD_SIZE+1]; /* Saved command */
186 static int saved_cmdlen = 0; /* Saved cmdline data len */
187 static int saved_cmdoff = 0; /* Saved cmdline buffer pos */
188 static short saved_cons_row = 0; /* Saved console row */
189 static short saved_cons_col = 0; /* Saved console column */
190
191 static int cmdcols = 0; /* visible cmdline width cols*/
192 static int cmdcol = 0; /* cols cmdline scrolled righ*/
193 static FILE *confp = NULL; /* Console file pointer */
194
195 ///////////////////////////////////////////////////////////////////////
196
197 #define CMD_PREFIX_STR "Command ==> " /* Keep same len as below! */
198 #ifdef OPTION_CMDTGT
199 #define CMD_PREFIX_STR1 "SCP ======> " /* Keep same len as above! */
200 #define CMD_PREFIX_STR2 "PrioSCP ==> " /* Keep same len as above! */
201 #endif // OPTION_CMDTGT
202
203 #define CMD_PREFIX_LEN (strlen(CMD_PREFIX_STR))
204 #define CMDLINE_ROW ((short)(cons_rows-1))
205 #define CMDLINE_COL ((short)(CMD_PREFIX_LEN+1))
206
207 ///////////////////////////////////////////////////////////////////////
208
209 #define ADJ_SCREEN_SIZE() \
210 do { \
211 int rows, cols; \
212 get_dim (&rows, &cols); \
213 if (rows != cons_rows || cols != cons_cols) { \
214 cons_rows = rows; \
215 cons_cols = cols; \
216 cmdcols = cons_cols - CMDLINE_COL; \
217 redraw_msgs = redraw_cmd = redraw_status = 1; \
218 NPDinit = 0; \
219 clr_screen(); \
220 } \
221 } while (0)
222
223 #define ADJ_CMDCOL() /* (called after modifying cmdoff) */ \
224 do { \
225 if (cmdoff-cmdcol > cmdcols) { /* past right edge of screen */ \
226 cmdcol = cmdoff-cmdcols; \
227 } else if (cmdoff < cmdcol) { /* past left edge of screen */ \
228 cmdcol = cmdoff; \
229 } \
230 } while (0)
231
232 #define PUTC_CMDLINE() \
233 do { \
234 ASSERT(cmdcol <= cmdlen); \
235 for (i=0; cmdcol+i < cmdlen && i < cmdcols; i++) \
236 draw_char (cmdline[cmdcol+i]); \
237 } while (0)
238
239 ///////////////////////////////////////////////////////////////////////
240
241 typedef struct _PANMSG /* Panel message control block structure */
242 {
243 struct _PANMSG* next; /* --> next entry in chain */
244 struct _PANMSG* prev; /* --> prev entry in chain */
245 int msgnum; /* msgbuf 0-relative entry# */
246 char msg[MSG_SIZE]; /* text of panel message */
247 #if defined(OPTION_MSGCLR)
248 short fg; /* text color */
249 short bg; /* screen background color */
250 #if defined(OPTION_MSGHLD)
251 int keep:1; /* sticky flag */
252 struct timeval expiration; /* when to unstick if sticky */
253 #endif // defined(OPTION_MSGHLD)
254 #endif // defined(OPTION_MSGCLR)
255 }
256 PANMSG; /* Panel message control block structure */
257
258 static PANMSG* msgbuf; /* Circular message buffer */
259 static PANMSG* topmsg; /* message at top of screen */
260 static PANMSG* curmsg; /* newest message */
261 static int wrapped = 0; /* wrapped-around flag */
262 static int numkept = 0; /* count of kept messages */
263 static int npquiet = 0; /* screen updating flag */
264
265 ///////////////////////////////////////////////////////////////////////
266
267 static char *lmsbuf = NULL; /* xxx */
268 static int lmsndx = 0; /* xxx */
269 static int lmsnum = -1; /* xxx */
270 static int lmscnt = -1; /* xxx */
271 static int lmsmax = LOG_DEFSIZE/2; /* xxx */
272 static int keybfd = -1; /* Keyboard file descriptor */
273
274 static REGS copyregs, copysieregs; /* Copied regs */
275
276 ///////////////////////////////////////////////////////////////////////
277
278 #if defined(OPTION_MSGCLR) /* -- Message coloring build option -- */
279 #if defined(OPTION_MSGHLD) /* -- Sticky messages build option -- */
280
281 #define KEEP_TIMEOUT_SECS 120 /* #seconds kept msgs expire */
282 static PANMSG* keptmsgs; /* start of keep chain */
283 static PANMSG* lastkept; /* last entry in keep chain */
284
285 /*-------------------------------------------------------------------*/
286 /* Remove and Free a keep chain entry from the keep chain */
287 /*-------------------------------------------------------------------*/
unkeep(PANMSG * pk)288 static void unkeep( PANMSG* pk )
289 {
290 if (pk->prev)
291 pk->prev->next = pk->next;
292 if (pk->next)
293 pk->next->prev = pk->prev;
294 if (pk == keptmsgs)
295 keptmsgs = pk->next;
296 if (pk == lastkept)
297 lastkept = pk->prev;
298 free( pk );
299 numkept--;
300 }
301
302 /*-------------------------------------------------------------------*/
303 /* Allocate and Add a new kept message to the keep chain */
304 /*-------------------------------------------------------------------*/
keep(PANMSG * p)305 static void keep( PANMSG* p )
306 {
307 PANMSG* pk;
308 ASSERT( p->keep );
309 pk = malloc( sizeof(PANMSG) );
310 memcpy( pk, p, sizeof(PANMSG) );
311 if (!keptmsgs)
312 keptmsgs = pk;
313 pk->next = NULL;
314 pk->prev = lastkept;
315 if (lastkept)
316 lastkept->next = pk;
317 lastkept = pk;
318 numkept++;
319 /* Must ensure we always have at least 2 scrollable lines */
320 while (SCROLL_LINES < 2)
321 {
322 /* Permanently unkeep oldest kept message */
323 msgbuf[keptmsgs->msgnum].keep = 0;
324 unkeep( keptmsgs );
325 }
326 }
327
328 /*-------------------------------------------------------------------*/
329 /* Remove a kept message from the kept chain */
330 /*-------------------------------------------------------------------*/
unkeep_by_keepnum(int keepnum,int perm)331 static void unkeep_by_keepnum( int keepnum, int perm )
332 {
333 PANMSG* pk;
334 int i;
335
336 /* Validate call */
337 if (!numkept || keepnum < 0 || keepnum > numkept-1)
338 {
339 ASSERT(FALSE); // bad 'keepnum' passed!
340 return;
341 }
342
343 /* Chase keep chain to find kept message to be unkept */
344 for (i=0, pk=keptmsgs; pk && i != keepnum; pk = pk->next, i++);
345
346 /* If kept message found, unkeep it */
347 if (pk)
348 {
349 if (perm)
350 {
351 msgbuf[pk->msgnum].keep = 0;
352
353 #if defined(_DEBUG) || defined(DEBUG)
354 msgbuf[pk->msgnum].fg = COLOR_YELLOW;
355 #endif // defined(_DEBUG) || defined(DEBUG)
356 }
357 unkeep(pk);
358 }
359 }
360 #endif // defined(OPTION_MSGHLD)
361 #endif // defined(OPTION_MSGCLR)
362
363 #if defined(OPTION_MSGHLD)
364 /*-------------------------------------------------------------------*/
365 /* unkeep messages once expired */
366 /*-------------------------------------------------------------------*/
expire_kept_msgs(int unconditional)367 void expire_kept_msgs(int unconditional)
368 {
369 struct timeval now;
370 PANMSG *pk = keptmsgs;
371 int i;
372
373 gettimeofday(&now, NULL);
374
375 while (pk)
376 {
377 for (i=0, pk=keptmsgs; pk; i++, pk = pk->next)
378 {
379 if (unconditional || now.tv_sec >= pk->expiration.tv_sec)
380 {
381 unkeep_by_keepnum(i,1); // remove message from chain
382 break; // start over again from the beginning
383 }
384 }
385 }
386 }
387 #endif // defined(OPTION_MSGHLD)
388
389 #if defined(OPTION_MSGCLR) /* -- Message coloring build option -- */
390 /*-------------------------------------------------------------------*/
391 /* Get the color name from a string */
392 /*-------------------------------------------------------------------*/
393
394 #define CHECKCOLOR(s, cs, c, cc) if(!strncasecmp(s, cs, sizeof(cs) - 1)) { *c = cc; return(sizeof(cs) - 1); }
395
get_color(char * string,short * color)396 int get_color(char *string, short *color)
397 {
398 CHECKCOLOR(string, "black", color, COLOR_BLACK)
399 else CHECKCOLOR(string, "cyan", color, COLOR_CYAN)
400 else CHECKCOLOR(string, "blue", color, COLOR_BLUE)
401 else CHECKCOLOR(string, "darkgrey", color, COLOR_DARK_GREY)
402 else CHECKCOLOR(string, "green", color, COLOR_GREEN)
403 else CHECKCOLOR(string, "lightblue", color, COLOR_LIGHT_BLUE)
404 else CHECKCOLOR(string, "lightcyan", color, COLOR_LIGHT_CYAN)
405 else CHECKCOLOR(string, "lightgreen", color, COLOR_LIGHT_GREEN)
406 else CHECKCOLOR(string, "lightgrey", color, COLOR_LIGHT_GREY)
407 else CHECKCOLOR(string, "lightmagenta", color, COLOR_LIGHT_MAGENTA)
408 else CHECKCOLOR(string, "lightred", color, COLOR_LIGHT_RED)
409 else CHECKCOLOR(string, "lightyellow", color, COLOR_LIGHT_YELLOW)
410 else CHECKCOLOR(string, "magenta", color, COLOR_MAGENTA)
411 else CHECKCOLOR(string, "red", color, COLOR_RED)
412 else CHECKCOLOR(string, "white", color, COLOR_WHITE)
413 else CHECKCOLOR(string, "yellow", color, COLOR_YELLOW)
414 else return(0);
415 }
416
417 /*-------------------------------------------------------------------*/
418 /* Read, process and remove the "<pnl...>" colorizing message prefix */
419 /* Syntax: */
420 /* <pnl,token,...> */
421 /* Mandatory prefix "<pnl," */
422 /* followed by one or more tokens separated by "," */
423 /* ending with a ">" */
424 /* Valid tokens: */
425 /* color(fg, bg) specifies the message's color */
426 /* keep keeps message on screen until removed */
427 /*-------------------------------------------------------------------*/
colormsg(PANMSG * p)428 void colormsg(PANMSG *p)
429 {
430 int i = 0; // current message text index
431 int len; // length of color-name token
432
433 if(!strncasecmp(p->msg, "<pnl", 4))
434 {
435 // examine "<pnl...>" panel command(s)
436 i += 4;
437 while(p->msg[i] == ',')
438 {
439 i += 1; // skip ,
440 if(!strncasecmp(&p->msg[i], "color(", 6))
441 {
442 // inspect color command
443 i += 6; // skip color(
444 len = get_color(&p->msg[i], &p->fg);
445 if(!len)
446 break; // no valid color found
447 i += len; // skip colorname
448 if(p->msg[i] != ',')
449 break; // no ,
450 i++; // skip ,
451 len = get_color(&p->msg[i], &p->bg);
452 if(!len)
453 break; // no valid color found
454 i += len; // skip colorname
455 if(p->msg[i] != ')')
456 break; // no )
457 i++; // skip )
458 }
459 else if(!strncasecmp(&p->msg[i], "keep", 4))
460 {
461 #if defined(OPTION_MSGHLD)
462 p->keep = 1;
463 gettimeofday(&p->expiration, NULL);
464 p->expiration.tv_sec += sysblk.keep_timeout_secs;
465 #endif // defined(OPTION_MSGHLD)
466 i += 4; // skip keep
467 }
468 else
469 break; // rubbish
470 }
471 if(p->msg[i] == '>')
472 {
473 // Remove "<pnl...>" string from message
474 i += 1;
475 memmove(p->msg, &p->msg[i], MSG_SIZE - i);
476 memset(&p->msg[MSG_SIZE - i], SPACE, i);
477 return;
478 }
479 }
480
481 /* rubbish or no panel command */
482 p->fg = COLOR_DEFAULT_FG;
483 p->bg = COLOR_DEFAULT_BG;
484 #if defined(OPTION_MSGHLD)
485 p->keep = 0;
486 #endif // defined(OPTION_MSGHLD)
487 }
488 #endif // defined(OPTION_MSGCLR)
489
490 /*-------------------------------------------------------------------*/
491 /* Screen manipulation primitives */
492 /*-------------------------------------------------------------------*/
493
beep()494 static void beep()
495 {
496 console_beep( confp );
497 }
498
oldest_msg()499 static PANMSG* oldest_msg()
500 {
501 return (wrapped) ? curmsg->next : msgbuf;
502 }
503
newest_msg()504 static PANMSG* newest_msg()
505 {
506 return curmsg;
507 }
508
lines_scrolled()509 static int lines_scrolled()
510 {
511 /* return # of lines 'up' from current line that we're scrolled. */
512 if (topmsg->msgnum <= curmsg->msgnum)
513 return curmsg->msgnum - topmsg->msgnum;
514 return MAX_MSGS - (topmsg->msgnum - curmsg->msgnum);
515 }
516
visible_lines()517 static int visible_lines()
518 {
519 return (lines_scrolled() + 1);
520 }
521
is_currline_visible()522 static int is_currline_visible()
523 {
524 return (visible_lines() <= SCROLL_LINES);
525 }
526
lines_remaining()527 static int lines_remaining()
528 {
529 return (SCROLL_LINES - visible_lines());
530 }
531
scroll_up_lines(int numlines,int doexpire)532 static void scroll_up_lines( int numlines, int doexpire )
533 {
534 int i;
535
536 #if defined(OPTION_MSGHLD)
537 if (doexpire)
538 expire_kept_msgs(0);
539 #else
540 UNREFERENCED(doexpire);
541 #endif // defined(OPTION_MSGHLD)
542
543 for (i=0; i < numlines && topmsg != oldest_msg(); i++)
544 {
545 topmsg = topmsg->prev;
546
547 #if defined(OPTION_MSGHLD)
548 // If new topmsg is simply the last entry in the keep chain
549 // then we didn't really backup a line (all we did was move
550 // our topmsg ptr), so if that's the case then we need to
551 // continue backing up until we reach a non-kept message.
552 // Only then is the screen actually scrolled up one line.
553
554 while (1
555 && topmsg->keep
556 && lastkept
557 && lastkept->msgnum == topmsg->msgnum
558 )
559 {
560 unkeep( lastkept );
561 if (topmsg == oldest_msg())
562 break;
563 topmsg = topmsg->prev;
564 }
565 #endif // defined(OPTION_MSGHLD)
566 }
567 }
568
scroll_down_lines(int numlines,int doexpire)569 static void scroll_down_lines( int numlines, int doexpire )
570 {
571 int i;
572
573 #if defined(OPTION_MSGHLD)
574 if (doexpire)
575 expire_kept_msgs(0);
576 #else
577 UNREFERENCED(doexpire);
578 #endif // defined(OPTION_MSGHLD)
579
580 for (i=0; i < numlines && topmsg != newest_msg(); i++)
581 {
582 #if defined(OPTION_MSGHLD)
583 // If the topmsg should be kept and is not already in our
584 // keep chain, then adding it to our keep chain before
585 // setting topmsg to the next entry does not really scroll
586 // the screen any (all it does is move the topmsg ptr),
587 // so if that's the case then we need to keep doing that
588 // until we eventually find the next non-kept message.
589 // Only then is the screen really scrolled down one line.
590
591 while (1
592 && topmsg->keep
593 && (!lastkept || topmsg->msgnum != lastkept->msgnum)
594 )
595 {
596 keep( topmsg );
597 topmsg = topmsg->next;
598 if (topmsg == newest_msg())
599 break;
600 }
601 #endif // defined(OPTION_MSGHLD)
602 if (topmsg != newest_msg())
603 topmsg = topmsg->next;
604 }
605 }
606
page_up(int doexpire)607 static void page_up( int doexpire )
608 {
609 #if defined(OPTION_MSGHLD)
610 if (doexpire)
611 expire_kept_msgs(0);
612 #else
613 UNREFERENCED(doexpire);
614 #endif // defined(OPTION_MSGHLD)
615 scroll_up_lines( SCROLL_LINES - 1, 0 );
616 }
page_down(int doexpire)617 static void page_down( int doexpire )
618 {
619 #if defined(OPTION_MSGHLD)
620 if (doexpire)
621 expire_kept_msgs(0);
622 #else
623 UNREFERENCED(doexpire);
624 #endif // defined(OPTION_MSGHLD)
625 scroll_down_lines( SCROLL_LINES - 1, 0 );
626 }
627
scroll_to_top_line(int doexpire)628 static void scroll_to_top_line( int doexpire )
629 {
630 #if defined(OPTION_MSGHLD)
631 if (doexpire)
632 expire_kept_msgs(0);
633 #else
634 UNREFERENCED(doexpire);
635 #endif // defined(OPTION_MSGHLD)
636 topmsg = oldest_msg();
637 #if defined(OPTION_MSGHLD)
638 while (keptmsgs)
639 unkeep( keptmsgs );
640 #endif // defined(OPTION_MSGHLD)
641 }
642
scroll_to_bottom_line(int doexpire)643 static void scroll_to_bottom_line( int doexpire )
644 {
645 #if defined(OPTION_MSGHLD)
646 if (doexpire)
647 expire_kept_msgs(0);
648 #else
649 UNREFERENCED(doexpire);
650 #endif // defined(OPTION_MSGHLD)
651 while (topmsg != newest_msg())
652 scroll_down_lines( 1, 0 );
653 }
654
scroll_to_bottom_screen(int doexpire)655 static void scroll_to_bottom_screen( int doexpire )
656 {
657 #if defined(OPTION_MSGHLD)
658 if (doexpire)
659 expire_kept_msgs(0);
660 #else
661 UNREFERENCED(doexpire);
662 #endif // defined(OPTION_MSGHLD)
663 scroll_to_bottom_line( 0 );
664 page_up( 0 );
665 }
666
do_panel_command(void * cmd)667 static void do_panel_command( void* cmd )
668 {
669 if (!is_currline_visible())
670 scroll_to_bottom_screen( 1 );
671 if (cmd != (void*)cmdline)
672 strlcpy( cmdline, cmd, sizeof(cmdline) );
673 panel_command( cmdline );
674 cmdline[0] = '\0';
675 cmdlen = 0;
676 cmdoff = 0;
677 ADJ_CMDCOL();
678 }
679
do_prev_history()680 static void do_prev_history()
681 {
682 if (history_prev() != -1)
683 {
684 strcpy(cmdline, historyCmdLine);
685 cmdlen = strlen(cmdline);
686 cmdoff = cmdlen < cmdcols ? cmdlen : 0;
687 ADJ_CMDCOL();
688 }
689 }
690
do_next_history()691 static void do_next_history()
692 {
693 if (history_next() != -1)
694 {
695 strcpy(cmdline, historyCmdLine);
696 cmdlen = strlen(cmdline);
697 cmdoff = cmdlen < cmdcols ? cmdlen : 0;
698 ADJ_CMDCOL();
699 }
700 }
701
clr_screen()702 static void clr_screen ()
703 {
704 clear_screen (confp);
705 }
706
get_dim(int * y,int * x)707 static void get_dim (int *y, int *x)
708 {
709 get_console_dim( confp, y, x);
710 if (*y > PANEL_MAX_ROWS)
711 *y = PANEL_MAX_ROWS;
712 if (*x > PANEL_MAX_COLS)
713 *x = PANEL_MAX_COLS;
714 #if defined(WIN32) && !defined( _MSVC_ )
715 /* If running from a cygwin command prompt we do
716 * better with one less row.
717 */
718 if (!cons_term || strcmp(cons_term, "xterm"))
719 (*y)--;
720 #endif // defined(WIN32) && !defined( _MSVC_ )
721 }
722
723 #if defined(OPTION_EXTCURS)
get_keepnum_by_row(int row)724 static int get_keepnum_by_row( int row )
725 {
726 // PROGRAMMING NOTE: right now all of our kept messages are
727 // always placed at the very top of the screen (starting on
728 // line 1), but should we at some point in the future decide
729 // to use the very top line of the screen for something else
730 // (such as a title or status line for example), then all we
731 // need to do is modify the below variable and the code then
732 // adjusts itself automatically. (I try to avoid hard-coded
733 // constants whenever possible). -- Fish
734
735 static int keep_beg_row = 1; // screen 1-relative line# of first kept msg
736
737 if (0
738 || row < keep_beg_row
739 || row > (keep_beg_row + numkept - 1)
740 )
741 return -1;
742
743 return (row - keep_beg_row);
744 }
745 #endif /*defined(OPTION_EXTCURS)*/
746
set_color(short fg,short bg)747 static void set_color (short fg, short bg)
748 {
749 set_screen_color (confp, fg, bg);
750 }
751
set_pos(short y,short x)752 static void set_pos (short y, short x)
753 {
754 cur_cons_row = y;
755 cur_cons_col = x;
756 y = y < 1 ? 1 : y > cons_rows ? cons_rows : y;
757 x = x < 1 ? 1 : x > cons_cols ? cons_cols : x;
758 set_screen_pos (confp, y, x);
759 }
760
is_cursor_on_cmdline()761 static int is_cursor_on_cmdline()
762 {
763 #if defined(OPTION_EXTCURS)
764 get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
765 cursor_on_cmdline =
766 (1
767 && cur_cons_row == CMDLINE_ROW
768 && cur_cons_col >= CMDLINE_COL
769 && cur_cons_col <= CMDLINE_COL + cmdcols
770 );
771 #else // !defined(OPTION_EXTCURS)
772 cursor_on_cmdline = 1;
773 #endif // defined(OPTION_EXTCURS)
774 return cursor_on_cmdline;
775 }
776
cursor_cmdline_home()777 static void cursor_cmdline_home()
778 {
779 cmdoff = 0;
780 ADJ_CMDCOL();
781 set_pos( CMDLINE_ROW, CMDLINE_COL );
782 }
783
cursor_cmdline_end()784 static void cursor_cmdline_end()
785 {
786 cmdoff = cmdlen;
787 ADJ_CMDCOL();
788 set_pos( CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol );
789 }
790
save_command_line()791 static void save_command_line()
792 {
793 memcpy( saved_cmdline, cmdline, sizeof(saved_cmdline) );
794 saved_cmdlen = cmdlen;
795 saved_cmdoff = cmdoff;
796 saved_cons_row = cur_cons_row;
797 saved_cons_col = cur_cons_col;
798 }
799
restore_command_line()800 static void restore_command_line()
801 {
802 memcpy( cmdline, saved_cmdline, sizeof(cmdline) );
803 cmdlen = saved_cmdlen;
804 cmdoff = saved_cmdoff;
805 cur_cons_row = saved_cons_row;
806 cur_cons_col = saved_cons_col;
807 }
808
draw_text(char * text)809 static void draw_text (char *text)
810 {
811 int len;
812 char *short_text;
813
814 if (cur_cons_row < 1 || cur_cons_row > cons_rows
815 || cur_cons_col < 1 || cur_cons_col > cons_cols)
816 return;
817 len = strlen(text);
818 if ((cur_cons_col + len - 1) <= cons_cols)
819 fprintf (confp, "%s", text);
820 else
821 {
822 len = cons_cols - cur_cons_col + 1;
823 if ((short_text = strdup(text)) == NULL)
824 return;
825 short_text[len] = '\0';
826 fprintf (confp, "%s", short_text);
827 free (short_text);
828 }
829 cur_cons_col += len;
830 }
831
write_text(char * text,int size)832 static void write_text (char *text, int size)
833 {
834 if (cur_cons_row < 1 || cur_cons_row > cons_rows
835 || cur_cons_col < 1 || cur_cons_col > cons_cols)
836 return;
837 if (cons_cols - cur_cons_col + 1 < size)
838 size = cons_cols - cur_cons_col + 1;
839 fwrite (text, size, 1, confp);
840 cur_cons_col += size;
841 }
842
draw_char(int c)843 static void draw_char (int c)
844 {
845 if (cur_cons_row < 1 || cur_cons_row > cons_rows
846 || cur_cons_col < 1 || cur_cons_col > cons_cols)
847 return;
848 fputc (c, confp);
849 cur_cons_col++;
850 }
851
draw_fw(U32 fw)852 static void draw_fw (U32 fw)
853 {
854 char buf[9];
855 sprintf (buf, "%8.8X", fw);
856 draw_text (buf);
857 }
858
draw_dw(U64 dw)859 static void draw_dw (U64 dw)
860 {
861 char buf[17];
862 sprintf (buf, "%16.16"I64_FMT"X", dw);
863 draw_text (buf);
864 }
865
fill_text(char c,short x)866 static void fill_text (char c, short x)
867 {
868 char buf[PANEL_MAX_COLS+1];
869 int len;
870
871 if (x > PANEL_MAX_COLS) x = PANEL_MAX_COLS;
872 len = x + 1 - cur_cons_col;
873 if (len <= 0) return;
874 memset (buf, c, len);
875 buf[len] = '\0';
876 draw_text (buf);
877 }
878
draw_button(short bg,short fg,short hfg,char * left,char * mid,char * right)879 static void draw_button (short bg, short fg, short hfg, char *left, char *mid, char *right)
880 {
881 set_color (fg, bg);
882 draw_text (left);
883 set_color (hfg, bg);
884 draw_text (mid);
885 set_color (fg, bg);
886 draw_text (right);
887 }
888
set_console_title()889 static void set_console_title ()
890 {
891 if (!sysblk.pantitle) return;
892
893 #if defined( _MSVC_ )
894 w32_set_console_title(sysblk.pantitle);
895 #else /*!defined(_MSVC_) */
896 /* For Unix systems we set the window title by sending a special
897 escape sequence (depends on terminal type) to the console.
898 See http://www.faqs.org/docs/Linux-mini/Xterm-Title.html */
899 if (!cons_term) return;
900 if (strcmp(cons_term,"xterm")==0
901 || strcmp(cons_term,"rxvt")==0
902 || strcmp(cons_term,"dtterm")==0
903 || strcmp(cons_term,"screen")==0)
904 {
905 fprintf(confp,"%c]0;%s%c",'\033',sysblk.pantitle,'\007');
906 }
907 #endif /*!defined(_MSVC_) */
908 }
909
910 /*=NP================================================================*/
911 /* Initialize the NP data */
912 /*===================================================================*/
913
NP_init()914 static void NP_init()
915 {
916 NPdataentry = 0;
917 strcpy(NPprompt1, "");
918 strcpy(NPprompt2, "");
919 }
920
921 /*=NP================================================================*/
922 /* This draws the initial screen template */
923 /*===================================================================*/
924
NP_screen_redraw(REGS * regs)925 static void NP_screen_redraw (REGS *regs)
926 {
927 int i, line;
928 char buf[1024];
929
930 /* Force all data to be redrawn */
931 NPcpunum_valid = NPcpupct_valid = NPpsw_valid =
932 NPpswstate_valid = NPregs_valid = NPaddr_valid =
933 NPdata_valid =
934 NPdevices_valid = NPcpugraph_valid = 0;
935 #if defined(OPTION_MIPS_COUNTING)
936 NPmips_valid = NPsios_valid = 0;
937 #endif /*defined(OPTION_MIPS_COUNTING)*/
938
939 #if defined(_FEATURE_SIE)
940 if(regs->sie_active)
941 regs = regs->guestregs;
942 #endif /*defined(_FEATURE_SIE)*/
943
944 /*
945 * Draw the static parts of the NP screen
946 */
947 set_color (COLOR_LIGHT_GREY, COLOR_BLACK );
948 clr_screen ();
949
950 /* Line 1 - title line */
951 set_color (COLOR_WHITE, COLOR_BLUE );
952 set_pos (1, 1);
953 draw_text (" Hercules CPU : %");
954 fill_text (' ', 30);
955 draw_text ((char *)get_arch_mode_string(NULL));
956 fill_text (' ', 38);
957 set_color (COLOR_LIGHT_GREY, COLOR_BLUE );
958 draw_text ("| ");
959 set_color (COLOR_WHITE, COLOR_BLUE );
960
961 /* Center "Peripherals" on the right-hand-side */
962 if (cons_cols > 52)
963 fill_text (' ', 40 + (cons_cols - 52) / 2);
964 draw_text ("Peripherals");
965 fill_text (' ', (short)cons_cols);
966
967 /* Line 2 - peripheral headings */
968 set_pos (2, 41);
969 set_color (COLOR_WHITE, COLOR_BLACK);
970 draw_char ('U');
971 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
972 draw_text(" Addr Modl Type Assig");
973 set_color (COLOR_WHITE, COLOR_BLACK);
974 draw_char ('n');
975 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
976 draw_text("ment");
977
978 /* 4th line - PSW */
979 NPpswmode = (regs->arch_mode == ARCH_900);
980 NPpswzhost =
981 #if defined(_FEATURE_SIE)
982 !NPpswmode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900;
983 #else
984 0;
985 #endif /*defined(_FEATURE_SIE)*/
986 set_pos (4, NPpswmode || NPpswzhost ? 19 : 10);
987 draw_text ("PSW");
988
989 /* Lines 6 .. 13 : register area */
990 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
991 NPregmode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1));
992 NPregzhost =
993 #if defined(_FEATURE_SIE)
994 (regs->arch_mode != ARCH_900
995 && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900
996 && (NPregdisp == 0 || NPregdisp == 1));
997 #else
998 0;
999 #endif /*defined(_FEATURE_SIE)*/
1000 if (NPregmode == 1 || NPregzhost)
1001 {
1002 for (i = 0; i < 8; i++)
1003 {
1004 set_pos (i+6, 1);
1005 draw_text (NPregnum64[i*2]);
1006 set_pos (i+6, 20);
1007 draw_text (NPregnum64[i*2+1]);
1008 }
1009 }
1010 else
1011 {
1012 for (i = 0; i < 4; i++)
1013 {
1014 set_pos (i*2+7,9);
1015 draw_text (NPregnum[i*4]);
1016 set_pos (i*2+7,18);
1017 draw_text (NPregnum[i*4+1]);
1018 set_pos (i*2+7,27);
1019 draw_text (NPregnum[i*4+2]);
1020 set_pos (i*2+7,36);
1021 draw_text (NPregnum[i*4+3]);
1022 }
1023 }
1024
1025 /* Line 14 : register selection */
1026 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1027 set_pos (14, 6);
1028 draw_text ("GPR");
1029 set_pos (14, 14);
1030 draw_text ("CR");
1031 set_pos (14, 22);
1032 draw_text ("AR");
1033 set_pos (14, 30);
1034 draw_text ("FPR");
1035
1036 /* Line 16 .. 17 : Address and data */
1037 set_pos (16, 2);
1038 draw_text ("ADD");
1039 set_color (COLOR_WHITE, COLOR_BLACK);
1040 draw_char ('R');
1041 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1042 draw_text ("ESS:");
1043 set_pos (16, 22);
1044 set_color (COLOR_WHITE, COLOR_BLACK);
1045 draw_char ('D');
1046 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1047 draw_text ("ATA:");
1048
1049 /* Line 18 : separator */
1050 set_pos (18, 1);
1051 fill_text ('-', 38);
1052
1053 /* Lines 19 .. 23 : buttons */
1054
1055 set_pos (19, 16);
1056 draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " ST", "O", " " );
1057 set_pos (19, 24);
1058 draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " D", "I", "S " );
1059 set_pos (19, 32);
1060 draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " RS", "T", " " );
1061
1062 #if defined(OPTION_MIPS_COUNTING)
1063 set_pos (20, 3);
1064 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1065 draw_text ("MIPS");
1066 set_pos (20, 9);
1067 draw_text ("SIO/s");
1068 #endif /*defined(OPTION_MIPS_COUNTING)*/
1069
1070 set_pos (22, 2);
1071 draw_button(COLOR_GREEN, COLOR_LIGHT_GREY, COLOR_WHITE, " ", "S", "TR ");
1072 set_pos (22, 9);
1073 draw_button(COLOR_RED, COLOR_LIGHT_GREY, COLOR_WHITE, " ST", "P", " " );
1074 set_pos (22, 16);
1075 draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " ", "E", "XT ");
1076 set_pos (22, 24);
1077 draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " IP", "L", " " );
1078 set_pos (22, 32);
1079 draw_button(COLOR_RED, COLOR_LIGHT_GREY, COLOR_WHITE, " P", "W", "R " );
1080
1081 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1082
1083 /* CPU busy graph */
1084 line = 24;
1085 NPcpugraph_ncpu = MIN(cons_rows - line - 2, HI_CPU);
1086 if (HI_CPU > 0)
1087 {
1088 NPcpugraph = 1;
1089 NPcpugraph_valid = 0;
1090 set_pos (line++, 1);
1091 fill_text ('-', 38);
1092 set_pos (line++, 1);
1093 draw_text ("CPU");
1094 for (i = 0; i < NPcpugraph_ncpu; i++)
1095 {
1096 sprintf (buf, "%02X ", i);
1097 set_pos (line++, 1);
1098 draw_text (buf);
1099 }
1100 }
1101 else
1102 NPcpugraph = 0;
1103
1104 /* Vertical separators */
1105 for (i = 2; i <= cons_rows; i++)
1106 {
1107 set_pos (i , 39);
1108 draw_char ('|');
1109 }
1110
1111 /* Last line : horizontal separator */
1112 if (cons_rows >= 24)
1113 {
1114 set_pos (cons_rows, 1);
1115 fill_text ('-', 38);
1116 draw_char ('|');
1117 fill_text ('-', cons_cols);
1118 }
1119
1120 /* positions the cursor */
1121 set_pos (cons_rows, cons_cols);
1122 }
1123
1124 /*=NP================================================================*/
1125 /* This refreshes the screen with new data every cycle */
1126 /*===================================================================*/
1127
NP_update(REGS * regs)1128 static void NP_update(REGS *regs)
1129 {
1130 int i, n;
1131 int mode, zhost;
1132 QWORD curpsw;
1133 U32 addr, aaddr;
1134 DEVBLK *dev;
1135 int online, busy, open;
1136 char *devclass;
1137 char devnam[128];
1138 char buf[1024];
1139
1140 if (NPhelpup == 1)
1141 {
1142 if (NPhelpdown == 1)
1143 {
1144 NP_init();
1145 NP_screen_redraw(regs);
1146 NPhelpup = 0;
1147 NPhelpdown = 0;
1148 NPhelppaint = 1;
1149 }
1150 else
1151 {
1152 if (NPhelppaint)
1153 {
1154 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1155 clr_screen ();
1156 for (i = 0; strcmp(NPhelp[i], ""); i++)
1157 {
1158 set_pos (i+1, 1);
1159 draw_text (NPhelp[i]);
1160 }
1161 NPhelppaint = 0;
1162 }
1163 return;
1164 }
1165 }
1166
1167 #if defined(_FEATURE_SIE)
1168 if(SIE_MODE(regs))
1169 regs = regs->hostregs;
1170 #endif /*defined(_FEATURE_SIE)*/
1171
1172 /* line 1 : cpu number and percent busy */
1173 if (!NPcpunum_valid || NPcpunum != regs->cpuad)
1174 {
1175 set_color (COLOR_WHITE, COLOR_BLUE);
1176 set_pos (1, 16);
1177 sprintf (buf, "%4.4X:",regs->cpuad);
1178 draw_text (buf);
1179 NPcpunum_valid = 1;
1180 NPcpunum = regs->cpuad;
1181 }
1182
1183 #if defined(OPTION_MIPS_COUNTING)
1184 if (!NPcpupct_valid || NPcpupct != regs->cpupct)
1185 {
1186 set_color (COLOR_WHITE, COLOR_BLUE);
1187 set_pos (1, 22);
1188 sprintf(buf, "%3d", regs->cpupct);
1189 draw_text (buf);
1190 NPcpupct_valid = 1;
1191 NPcpupct = regs->cpupct;
1192 }
1193 #else // !defined(OPTION_MIPS_COUNTING)
1194 if (!NPcpupct_valid)
1195 {
1196 set_color (COLOR_WHITE, COLOR_BLUE);
1197 set_pos (1, 21);
1198 draw_text (" ");
1199 NPcpupct_valid = 1;
1200 }
1201 #endif /*defined(OPTION_MIPS_COUNTING)*/
1202
1203 #if defined(_FEATURE_SIE)
1204 if(regs->sie_active)
1205 regs = regs->guestregs;
1206 #endif /*defined(_FEATURE_SIE)*/
1207
1208 mode = (regs->arch_mode == ARCH_900);
1209 zhost =
1210 #if defined(_FEATURE_SIE)
1211 !mode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900;
1212 #else // !defined(_FEATURE_SIE)
1213 0;
1214 #endif // defined(_FEATURE_SIE)
1215
1216 /* Redraw the psw template if the mode changed */
1217 if (NPpswmode != mode || NPpswzhost != zhost)
1218 {
1219 NPpswmode = mode;
1220 NPpswzhost = zhost;
1221 NPpsw_valid = NPpswstate_valid = 0;
1222 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1223 set_pos (3, 1);
1224 fill_text (' ',38);
1225 set_pos (4, 1);
1226 fill_text (' ', 38);
1227 set_pos (4, NPpswmode || NPpswzhost ? 19 : 10);
1228 draw_text ("PSW");
1229 }
1230
1231 /* Display the psw */
1232 memset (curpsw, 0, sizeof(QWORD));
1233 copy_psw (regs, curpsw);
1234 if (!NPpsw_valid || memcmp(NPpsw, curpsw, sizeof(QWORD)))
1235 {
1236 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1237 set_pos (3, 3);
1238 if (mode)
1239 {
1240 draw_dw (fetch_dw(curpsw));
1241 set_pos (3, 22);
1242 draw_dw (fetch_dw(curpsw+8));
1243 }
1244 else if (zhost)
1245 {
1246 draw_fw (fetch_fw(curpsw));
1247 // draw_fw (0);
1248 draw_fw (fetch_fw(curpsw+4)); /* *JJ */
1249 set_pos (3, 22);
1250 // draw_fw (fetch_fw(curpsw+4) & 0x80000000 ? 0x80000000 : 0);
1251 // draw_fw (fetch_fw(curpsw+4) & 0x7fffffff);
1252 draw_text("----------------"); /* *JJ */
1253 }
1254 else
1255 {
1256 draw_fw (fetch_fw(curpsw));
1257 set_pos (3, 12);
1258 draw_fw (fetch_fw(curpsw+4));
1259 }
1260 NPpsw_valid = 1;
1261 memcpy (NPpsw, curpsw, sizeof(QWORD));
1262 }
1263
1264 /* Display psw state */
1265 sprintf (buf, "%2d%c%c%c%c%c%c%c%c",
1266 regs->psw.amode64 ? 64 :
1267 regs->psw.amode ? 31 : 24,
1268 regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.',
1269 sysblk.inststep ? 'T' : '.',
1270 WAITSTATE (®s->psw) ? 'W' : '.',
1271 regs->loadstate ? 'L' : '.',
1272 regs->checkstop ? 'C' : '.',
1273 PROBSTATE(®s->psw) ? 'P' : '.',
1274 SIE_MODE(regs) ? 'S' : '.',
1275 mode ? 'Z' : '.');
1276 if (!NPpswstate_valid || strcmp(NPpswstate, buf))
1277 {
1278 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK );
1279 set_pos (mode || zhost ? 4 : 3, 28);
1280 draw_text (buf);
1281 NPpswstate_valid = 1;
1282 strcpy (NPpswstate, buf);
1283 }
1284
1285 /* Redraw the register template if the regmode switched */
1286 mode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1));
1287 zhost =
1288 #if defined(_FEATURE_SIE)
1289 (regs->arch_mode != ARCH_900
1290 && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900
1291 && (NPregdisp == 0 || NPregdisp == 1));
1292 #else // !defined(_FEATURE_SIE)
1293 0;
1294 #endif /*defined(_FEATURE_SIE)*/
1295 if (NPregmode != mode || NPregzhost != zhost)
1296 {
1297 NPregmode = mode;
1298 NPregzhost = zhost;
1299 NPregs_valid = 0;
1300 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1301 if (NPregmode || NPregzhost)
1302 {
1303 /* 64 bit registers */
1304 for (i = 0; i < 8; i++)
1305 {
1306 set_pos (i+6, 1);
1307 fill_text (' ', 38);
1308 set_pos (i+6, 1);
1309 draw_text (NPregnum64[i*2]);
1310 set_pos (i+6, 20);
1311 draw_text (NPregnum64[i*2+1]);
1312 }
1313 }
1314 else
1315 {
1316 /* 32 bit registers */
1317 for (i = 0; i < 4; i++)
1318 {
1319 set_pos (i*2+6,1);
1320 fill_text (' ', 38);
1321 set_pos (i*2+7,1);
1322 fill_text (' ', 38);
1323 set_pos (i*2+7,9);
1324 draw_text (NPregnum[i*4]);
1325 set_pos (i*2+7,18);
1326 draw_text (NPregnum[i*4+1]);
1327 set_pos (i*2+7,27);
1328 draw_text (NPregnum[i*4+2]);
1329 set_pos (i*2+7,36);
1330 draw_text (NPregnum[i*4+3]);
1331 }
1332 }
1333 }
1334
1335 /* Display register values */
1336 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK );
1337 if (NPregmode)
1338 {
1339 /* 64 bit registers */
1340 for (i = 0; i < 16; i++)
1341 {
1342 switch (NPregdisp) {
1343 case 0:
1344 if (!NPregs_valid || NPregs64[i] != regs->GR_G(i))
1345 {
1346 set_pos (6 + i/2, 3 + (i%2)*19);
1347 draw_dw (regs->GR_G(i));
1348 NPregs64[i] = regs->GR_G(i);
1349 }
1350 break;
1351 case 1:
1352 if (!NPregs_valid || NPregs64[i] != regs->CR_G(i))
1353 {
1354 set_pos (6 + i/2, 3 + (i%2)*19);
1355 draw_dw (regs->CR_G(i));
1356 NPregs64[i] = regs->CR_G(i);
1357 }
1358 break;
1359 }
1360 }
1361 }
1362 else if (NPregzhost)
1363 {
1364 /* 32 bit registers on 64 bit template */
1365 for (i = 0; i < 16; i++)
1366 {
1367 switch (NPregdisp) {
1368 case 0:
1369 if (!NPregs_valid || NPregs[i] != regs->GR_L(i))
1370 {
1371 set_pos (6 + i/2, 3 + (i%2)*19);
1372 // draw_fw (0);
1373 draw_text("--------");
1374 draw_fw (regs->GR_L(i));
1375 NPregs[i] = regs->GR_L(i);
1376 }
1377 break;
1378 case 1:
1379 if (!NPregs_valid || NPregs[i] != regs->CR_L(i))
1380 {
1381 set_pos (6 + i/2, 3 + (i%2)*19);
1382 // draw_fw (0);
1383 draw_text("--------");
1384 draw_fw (regs->CR_L(i));
1385 NPregs[i] = regs->CR_L(i);
1386 }
1387 break;
1388 }
1389 }
1390 }
1391 else
1392 {
1393 /* 32 bit registers */
1394 addr = NPaddress;
1395 for (i = 0; i < 16; i++)
1396 {
1397 switch (NPregdisp) {
1398 default:
1399 case 0:
1400 if (!NPregs_valid || NPregs[i] != regs->GR_L(i))
1401 {
1402 set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1403 draw_fw (regs->GR_L(i));
1404 NPregs[i] = regs->GR_L(i);
1405 }
1406 break;
1407 case 1:
1408 if (!NPregs_valid || NPregs[i] != regs->CR_L(i))
1409 {
1410 set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1411 draw_fw (regs->CR_L(i));
1412 NPregs[i] = regs->CR_L(i);
1413 }
1414 break;
1415 case 2:
1416 if (!NPregs_valid || NPregs[i] != regs->AR(i))
1417 {
1418 set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1419 draw_fw (regs->AR(i));
1420 NPregs[i] = regs->AR(i);
1421 }
1422 break;
1423 case 3:
1424 if (!NPregs_valid || NPregs[i] != regs->fpr[i])
1425 {
1426 set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1427 draw_fw (regs->fpr[i]);
1428 NPregs[i] = regs->fpr[i];
1429 }
1430 break;
1431 case 4:
1432 aaddr = APPLY_PREFIXING (addr, regs->PX);
1433 addr += 4;
1434 if (aaddr + 3 > regs->mainlim)
1435 break;
1436 if (!NPregs_valid || NPregs[i] != fetch_fw(regs->mainstor + aaddr))
1437 {
1438 set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1439 draw_fw (fetch_fw(regs->mainstor + aaddr));
1440 NPregs[i] = fetch_fw(regs->mainstor + aaddr);
1441 }
1442 break;
1443 }
1444 }
1445 }
1446
1447 /* Update register selection indicator */
1448 if (!NPregs_valid)
1449 {
1450 set_pos (14, 6);
1451 set_color (NPregdisp == 0 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1452 draw_char ('G');
1453
1454 set_pos (14, 14);
1455 set_color (NPregdisp == 1 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1456 draw_char ('C');
1457
1458 set_pos (14, 22);
1459 set_color (NPregdisp == 2 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1460 draw_char ('A');
1461
1462 set_pos (14, 30);
1463 set_color (NPregdisp == 3 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1464 draw_char ('F');
1465 }
1466
1467 NPregs_valid = 1;
1468
1469 /* Address & Data */
1470 if (!NPaddr_valid)
1471 {
1472 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1473 set_pos (16, 12);
1474 draw_fw (NPaddress);
1475 NPaddr_valid = 1;
1476 }
1477 if (!NPdata_valid)
1478 {
1479 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1480 set_pos (16, 30);
1481 draw_fw (NPdata);
1482 NPdata_valid = 1;
1483 }
1484
1485 /* Rates */
1486 #ifdef OPTION_MIPS_COUNTING
1487 if (!NPmips_valid || sysblk.mipsrate != NPmips)
1488 {
1489 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1490 set_pos (19, 1);
1491 sprintf(buf, "%3.1d.%2.2d",
1492 sysblk.mipsrate / 1000000, (sysblk.mipsrate % 1000000) / 10000);
1493 draw_text (buf);
1494 NPmips = sysblk.mipsrate;
1495 NPmips_valid = 1;
1496 }
1497 if (!NPsios_valid || NPsios != sysblk.siosrate)
1498 {
1499 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1500 set_pos (19, 7);
1501 sprintf(buf, "%7d", sysblk.siosrate);
1502 draw_text (buf);
1503 NPsios = sysblk.siosrate;
1504 NPsios_valid = 1;
1505 }
1506 #endif /* OPTION_MIPS_COUNTING */
1507
1508 /* Optional cpu graph */
1509 if (NPcpugraph)
1510 {
1511 for (i = 0; i < NPcpugraph_ncpu; i++)
1512 {
1513 if (!IS_CPU_ONLINE(i))
1514 {
1515 if (!NPcpugraph_valid || NPcpugraphpct[i] != -2.0)
1516 {
1517 set_color (COLOR_RED, COLOR_BLACK);
1518 set_pos (26+i, 4);
1519 draw_text ("OFFLINE");
1520 fill_text (' ', 38);
1521 NPcpugraphpct[i] = -2.0;
1522 }
1523 }
1524 else if (sysblk.regs[i]->cpustate != CPUSTATE_STARTED)
1525 {
1526 if (!NPcpugraph_valid || NPcpugraphpct[i] != -1.0)
1527 {
1528 set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1529 set_pos (26+i, 4);
1530 draw_text ("STOPPED");
1531 fill_text (' ', 38);
1532 NPcpugraphpct[i] = -1.0;
1533 }
1534 }
1535 else if (!NPcpugraph_valid || NPcpugraphpct[i] != sysblk.regs[i]->cpupct)
1536 {
1537 n = (34 * sysblk.regs[i]->cpupct) / 100;
1538 if (n == 0 && sysblk.regs[i]->cpupct > 0)
1539 n = 1;
1540 else if (n > 34)
1541 n = 34;
1542 set_color (n > 17 ? COLOR_WHITE : COLOR_LIGHT_GREY, COLOR_BLACK);
1543 set_pos (26+i, 4);
1544 fill_text ('*', n+3);
1545 fill_text (' ', 38);
1546 NPcpugraphpct[i] = sysblk.regs[i]->cpupct;
1547 }
1548 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1549 }
1550 NPcpugraph_valid = 1;
1551 }
1552
1553 /* Process devices */
1554 for (i = 0, dev = sysblk.firstdev; dev != NULL; i++, dev = dev->nextdev)
1555 {
1556 if (i >= cons_rows - 3) break;
1557 if (!dev->allocated) continue;
1558
1559 online = (dev->console && dev->connected) || strlen(dev->filename) > 0;
1560 busy = dev->busy != 0 || IOPENDING(dev) != 0;
1561 open = dev->fd > 2;
1562
1563 /* device identifier */
1564 if (!NPdevices_valid || online != NPonline[i])
1565 {
1566 set_pos (i+3, 41);
1567 set_color (online ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK);
1568 draw_char (i < 26 ? 'A' + i : '.');
1569 NPonline[i] = online;
1570 }
1571
1572 /* device number */
1573 if (!NPdevices_valid || dev->devnum != NPdevnum[i] || NPbusy[i] != busy)
1574 {
1575 set_pos (i+3, 43);
1576 set_color (busy ? COLOR_LIGHT_YELLOW : COLOR_LIGHT_GREY, COLOR_BLACK);
1577 sprintf (buf, "%4.4X", dev->devnum);
1578 draw_text (buf);
1579 NPdevnum[i] = dev->devnum;
1580 NPbusy[i] = busy;
1581 }
1582
1583 /* device type */
1584 if (!NPdevices_valid || dev->devtype != NPdevtype[i] || open != NPopen[i])
1585 {
1586 set_pos (i+3, 48);
1587 set_color (open ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK);
1588 sprintf (buf, "%4.4X", dev->devtype);
1589 draw_text (buf);
1590 NPdevtype[i] = dev->devtype;
1591 NPopen[i] = open;
1592 }
1593
1594 /* device class and name */
1595 (dev->hnd->query)(dev, &devclass, sizeof(devnam), devnam);
1596 if (!NPdevices_valid || strcmp(NPdevnam[i], devnam))
1597 {
1598 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1599 set_pos (i+3, 53);
1600 sprintf (buf, "%-4.4s", devclass);
1601 draw_text (buf);
1602 /* Draw device name only if they're NOT assigning a new one */
1603 if (0
1604 || NPdataentry != 1
1605 || NPpending != 'n'
1606 || NPasgn != i
1607 )
1608 {
1609 set_pos (i+3, 58);
1610 draw_text (devnam);
1611 fill_text (' ', PANEL_MAX_COLS);
1612 }
1613 }
1614 }
1615
1616 /* Complete the device state table */
1617 if (!NPdevices_valid)
1618 {
1619 NPlastdev = i > 26 ? 26 : i - 1;
1620 for ( ; i < NP_MAX_DEVICES; i++)
1621 {
1622 NPonline[i] = NPdevnum[i] = NPbusy[i] = NPdevtype[i] = NPopen[i] = 0;
1623 strcpy (NPdevnam[i], "");
1624 }
1625 NPdevices_valid = 1;
1626 }
1627
1628 /* Prompt 1 */
1629 if (strcmp(NPprompt1, NPoldprompt1))
1630 {
1631 strcpy(NPoldprompt1, NPprompt1);
1632 if (strlen(NPprompt1) > 0)
1633 {
1634 set_color (COLOR_WHITE, COLOR_BLUE);
1635 set_pos (cons_rows, (40 - strlen(NPprompt1)) / 2);
1636 draw_text (NPprompt1);
1637 }
1638 else if (cons_rows >= 24)
1639 {
1640 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1641 set_pos (cons_rows, 1);
1642 fill_text ('-', 38);
1643 }
1644 }
1645
1646 /* Prompt 2 */
1647 if (strcmp(NPprompt2, NPoldprompt2))
1648 {
1649 strcpy(NPoldprompt2, NPprompt2);
1650 if (strlen(NPprompt2) > 0)
1651 {
1652 set_color (COLOR_WHITE, COLOR_BLUE);
1653 set_pos (cons_rows, 41);
1654 draw_text (NPprompt2);
1655 }
1656 else if (cons_rows >= 24)
1657 {
1658 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1659 set_pos (cons_rows, 41);
1660 fill_text ('-', cons_cols);
1661 }
1662 }
1663
1664 /* Data entry field */
1665 if (NPdataentry && redraw_cmd)
1666 {
1667 set_pos (NPcurrow, NPcurcol);
1668 if (NPcolorSwitch)
1669 set_color (NPcolorFore, NPcolorBack);
1670 fill_text (' ', NPcurcol + NPdatalen - 1);
1671 set_pos (NPcurrow, NPcurcol);
1672 PUTC_CMDLINE();
1673 redraw_cmd = 0;
1674 }
1675 else
1676 /* Position the cursor to the bottom right */
1677 set_pos(cons_rows, cons_cols);
1678 }
1679
1680 /* ============== End of the main NP block of code =============*/
1681
1682 static void panel_cleanup(void *unused); // (forward reference)
1683
1684 #ifdef OPTION_MIPS_COUNTING
1685
1686 ///////////////////////////////////////////////////////////////////////
1687 // "maxrates" command support...
1688
1689 #define DEF_MAXRATES_RPT_INTVL ( 1440 )
1690
1691 DLL_EXPORT U32 curr_high_mips_rate = 0; // (high water mark for current interval)
1692 DLL_EXPORT U32 curr_high_sios_rate = 0; // (high water mark for current interval)
1693
1694 DLL_EXPORT U32 prev_high_mips_rate = 0; // (saved high water mark for previous interval)
1695 DLL_EXPORT U32 prev_high_sios_rate = 0; // (saved high water mark for previous interval)
1696
1697 DLL_EXPORT time_t curr_int_start_time = 0; // (start time of current interval)
1698 DLL_EXPORT time_t prev_int_start_time = 0; // (start time of previous interval)
1699
1700 DLL_EXPORT U32 maxrates_rpt_intvl = DEF_MAXRATES_RPT_INTVL;
1701
update_maxrates_hwm()1702 DLL_EXPORT void update_maxrates_hwm() // (update high-water-mark values)
1703 {
1704 time_t current_time = 0;
1705 U32 elapsed_secs = 0;
1706
1707 if (curr_high_mips_rate < sysblk.mipsrate)
1708 curr_high_mips_rate = sysblk.mipsrate;
1709
1710 if (curr_high_sios_rate < sysblk.siosrate)
1711 curr_high_sios_rate = sysblk.siosrate;
1712
1713 // Save high water marks for current interval...
1714
1715 time( ¤t_time );
1716
1717 elapsed_secs = current_time - curr_int_start_time;
1718
1719 if ( elapsed_secs >= ( maxrates_rpt_intvl * 60 ) )
1720 {
1721 prev_high_mips_rate = curr_high_mips_rate;
1722 prev_high_sios_rate = curr_high_sios_rate;
1723
1724 curr_high_mips_rate = 0;
1725 curr_high_sios_rate = 0;
1726
1727 prev_int_start_time = curr_int_start_time;
1728 curr_int_start_time = current_time;
1729 }
1730 }
1731 #endif // OPTION_MIPS_COUNTING
1732 ///////////////////////////////////////////////////////////////////////
1733
copy_regs(int cpu)1734 REGS *copy_regs(int cpu)
1735 {
1736 REGS *regs;
1737
1738 if (cpu < 0 || cpu >= MAX_CPU_ENGINES)
1739 cpu = 0;
1740
1741 obtain_lock (&sysblk.cpulock[cpu]);
1742
1743 if ((regs = sysblk.regs[cpu]) == NULL)
1744 {
1745 release_lock(&sysblk.cpulock[cpu]);
1746 return &sysblk.dummyregs;
1747 }
1748
1749 memcpy (©regs, regs, sysblk.regs_copy_len);
1750
1751 if (copyregs.hostregs == NULL)
1752 {
1753 release_lock(&sysblk.cpulock[cpu]);
1754 return &sysblk.dummyregs;
1755 }
1756
1757 #if defined(_FEATURE_SIE)
1758 if (regs->sie_active)
1759 {
1760 memcpy (©sieregs, regs->guestregs, sysblk.regs_copy_len);
1761 copyregs.guestregs = ©sieregs;
1762 copysieregs.hostregs = ©regs;
1763 regs = ©sieregs;
1764 }
1765 else
1766 #endif // defined(_FEATURE_SIE)
1767 regs = ©regs;
1768
1769 SET_PSW_IA(regs);
1770
1771 release_lock(&sysblk.cpulock[cpu]);
1772 return regs;
1773 }
1774
format_int(uint64_t ic)1775 static char *format_int(uint64_t ic)
1776 {
1777 static char obfr[32]; /* Enough for displaying 2^64-1 */
1778 char grps[7][4]; /* 7 groups of 3 digits */
1779 int maxg=0;
1780 int i;
1781
1782 strcpy(grps[0],"0");
1783 while(ic>0)
1784 {
1785 int grp;
1786 grp=ic%1000;
1787 ic/=1000;
1788 if(ic==0)
1789 {
1790 sprintf(grps[maxg],"%u",grp);
1791 }
1792 else
1793 {
1794 sprintf(grps[maxg],"%3.3u",grp);
1795 }
1796 maxg++;
1797 }
1798 if(maxg) maxg--;
1799 obfr[0]=0;
1800 for(i=maxg;i>=0;i--)
1801 {
1802 strcat(obfr,grps[i]);
1803 if(i)
1804 {
1805 strcat(obfr,",");
1806 }
1807 }
1808 return obfr;
1809 }
1810
1811
1812 /*-------------------------------------------------------------------*/
1813 /* Panel display thread */
1814 /* */
1815 /* This function runs on the main thread. It receives messages */
1816 /* from the log task and displays them on the screen. It accepts */
1817 /* panel commands from the keyboard and executes them. It samples */
1818 /* the PSW periodically and displays it on the screen status line. */
1819 /*-------------------------------------------------------------------*/
1820
1821 #if defined(OPTION_DYNAMIC_LOAD)
panel_display_r(void)1822 void panel_display_r (void)
1823 #else
1824 void panel_display (void)
1825 #endif // defined(OPTION_DYNAMIC_LOAD)
1826 {
1827 #ifndef _MSVC_
1828 int rc; /* Return code */
1829 int maxfd; /* Highest file descriptor */
1830 fd_set readset; /* Select file descriptors */
1831 struct timeval tv; /* Select timeout structure */
1832 #endif // _MSVC_
1833 int i; /* Array subscripts */
1834 int len; /* Length */
1835 REGS *regs; /* -> CPU register context */
1836 QWORD curpsw; /* Current PSW */
1837 QWORD prvpsw; /* Previous PSW */
1838 BYTE prvstate = 0xFF; /* Previous stopped state */
1839 U64 prvicount = 0; /* Previous instruction count*/
1840 #if defined(OPTION_MIPS_COUNTING)
1841 U64 prvtcount = 0; /* Previous total count */
1842 #endif /*defined(OPTION_MIPS_COUNTING)*/
1843 int prvcpupct = 0; /* Previous cpu percentage */
1844 #if defined(OPTION_SHARED_DEVICES)
1845 U32 prvscount = 0; /* Previous shrdcount */
1846 #endif // defined(OPTION_SHARED_DEVICES)
1847 char readbuf[MSG_SIZE]; /* Message read buffer */
1848 int readoff = 0; /* Number of bytes in readbuf*/
1849 BYTE c; /* Character work area */
1850 size_t kbbufsize = CMD_SIZE; /* Size of keyboard buffer */
1851 char *kbbuf = NULL; /* Keyboard input buffer */
1852 int kblen; /* Number of chars in kbbuf */
1853 U32 aaddr; /* Absolute address for STO */
1854 char buf[1024]; /* Buffer workarea */
1855
1856 SET_THREAD_NAME("panel_display");
1857
1858 /* Display thread started message on control panel */
1859 logmsg (_("HHCPN001I Control panel thread started: "
1860 "tid="TIDPAT", pid=%d\n"),
1861 thread_id(), getpid());
1862
1863 /* Notify logger_thread we're in control */
1864 sysblk.panel_init = 1;
1865
1866 hdl_adsc("panel_cleanup",panel_cleanup, NULL);
1867 history_init();
1868
1869 /* Set up the input file descriptors */
1870 confp = stderr;
1871 keybfd = STDIN_FILENO;
1872
1873 /* Initialize screen dimensions */
1874 cons_term = getenv ("TERM");
1875 get_dim (&cons_rows, &cons_cols);
1876
1877 /* Clear the command-line buffer */
1878 memset (cmdline, 0, sizeof(cmdline));
1879 cmdcols = cons_cols - CMDLINE_COL;
1880
1881 /* Obtain storage for the keyboard buffer */
1882 if (!(kbbuf = malloc (kbbufsize)))
1883 {
1884 logmsg(_("HHCPN002S Cannot obtain keyboard buffer: %s\n"),
1885 strerror(errno));
1886 return;
1887 }
1888
1889 /* Obtain storage for the circular message buffer */
1890 msgbuf = malloc (MAX_MSGS * sizeof(PANMSG));
1891 if (msgbuf == NULL)
1892 {
1893 fprintf (stderr,
1894 _("HHCPN003S Cannot obtain message buffer: %s\n"),
1895 strerror(errno));
1896 return;
1897 }
1898
1899 /* Initialize circular message buffer */
1900 for (curmsg = msgbuf, i=0; i < MAX_MSGS; curmsg++, i++)
1901 {
1902 curmsg->next = curmsg + 1;
1903 curmsg->prev = curmsg - 1;
1904 curmsg->msgnum = i;
1905 memset(curmsg->msg,SPACE,MSG_SIZE);
1906 #if defined(OPTION_MSGCLR)
1907 curmsg->bg = COLOR_DEFAULT_FG;
1908 curmsg->fg = COLOR_DEFAULT_BG;
1909 #if defined(OPTION_MSGHLD)
1910 curmsg->keep = 0;
1911 memset( &curmsg->expiration, 0, sizeof(curmsg->expiration));
1912 #endif // defined(OPTION_MSGHLD)
1913 #endif // defined(OPTION_MSGCLR)
1914 }
1915
1916 /* Complete the circle */
1917 msgbuf->prev = msgbuf + MAX_MSGS - 1;
1918 msgbuf->prev->next = msgbuf;
1919
1920 /* Indicate "first-time" state */
1921 curmsg = topmsg = NULL;
1922 wrapped = 0;
1923 numkept = 0;
1924 #if defined(OPTION_MSGHLD)
1925 keptmsgs = lastkept = NULL;
1926 #endif // defined(OPTION_MSGHLD)
1927
1928 /* Set screen output stream to NON-buffered */
1929 setvbuf (confp, NULL, _IONBF, 0);
1930
1931 /* Put the terminal into cbreak mode */
1932 set_or_reset_console_mode( keybfd, 1 );
1933
1934 /* Set console title */
1935 set_console_title();
1936
1937 /* Clear the screen */
1938 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
1939 clr_screen ();
1940 redraw_msgs = redraw_cmd = redraw_status = 1;
1941
1942 /* Process messages and commands */
1943 while ( 1 )
1944 {
1945 #if defined(OPTION_MIPS_COUNTING)
1946 update_maxrates_hwm(); // (update high-water-mark values)
1947 #endif // defined(OPTION_MIPS_COUNTING)
1948
1949 #if defined( _MSVC_ )
1950 /* Wait for keyboard input */
1951 #define WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS (20)
1952 for (i=sysblk.panrate/WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS; i && !kbhit(); i--)
1953 Sleep(WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS);
1954
1955 ADJ_SCREEN_SIZE();
1956
1957 /* If keyboard input has [finally] arrived, then process it */
1958 if ( kbhit() )
1959 {
1960 /* Read character(s) from the keyboard */
1961 kbbuf[0] = getch();
1962 kbbuf[kblen=1] = '\0';
1963 translate_keystroke( kbbuf, &kblen );
1964
1965 #else // !defined( _MSVC_ )
1966
1967 /* Set the file descriptors for select */
1968 FD_ZERO (&readset);
1969 FD_SET (keybfd, &readset);
1970 maxfd = keybfd;
1971
1972 /* Wait for a message to arrive, a key to be pressed,
1973 or the inactivity interval to expire */
1974 tv.tv_sec = sysblk.panrate / 1000;
1975 tv.tv_usec = (sysblk.panrate * 1000) % 1000000;
1976 rc = select (maxfd + 1, &readset, NULL, NULL, &tv);
1977 if (rc < 0 )
1978 {
1979 if (errno == EINTR) continue;
1980 fprintf (stderr,
1981 _("HHCPN004E select: %s\n"),
1982 strerror(errno));
1983 break;
1984 }
1985
1986 ADJ_SCREEN_SIZE();
1987
1988 /* If keyboard input has arrived then process it */
1989 if (FD_ISSET(keybfd, &readset))
1990 {
1991 /* Read character(s) from the keyboard */
1992 kblen = read (keybfd, kbbuf, kbbufsize-1);
1993
1994 if (kblen < 0)
1995 {
1996 fprintf (stderr,
1997 _("HHCPN005E keyboard read: %s\n"),
1998 strerror(errno));
1999 break;
2000 }
2001
2002 kbbuf[kblen] = '\0';
2003
2004 #endif // defined( _MSVC_ )
2005
2006 /* =NP= : Intercept NP commands & process */
2007 if (NPDup == 1)
2008 {
2009 if (NPdevsel == 1)
2010 {
2011 NPdevsel = 0;
2012 NPdevice = kbbuf[0]; /* save the device selected */
2013 kbbuf[0] = NPsel2; /* setup for 2nd part of rtn */
2014 }
2015 if (NPdataentry == 0 && kblen == 1)
2016 { /* We are in command mode */
2017 if (NPhelpup == 1)
2018 {
2019 if (kbbuf[0] == 0x1b)
2020 NPhelpdown = 1;
2021 kbbuf[0] = '\0';
2022 redraw_status = 1;
2023 }
2024 cmdline[0] = '\0';
2025 cmdlen = 0;
2026 cmdoff = 0;
2027 ADJ_CMDCOL();
2028 switch(kbbuf[0]) {
2029 case 0x1B: /* ESC */
2030 NPDup = 0;
2031 restore_command_line();
2032 ADJ_CMDCOL();
2033 redraw_msgs = redraw_cmd = redraw_status = 1;
2034 npquiet = 0; // (forced for one paint cycle)
2035 break;
2036 case '?':
2037 NPhelpup = 1;
2038 redraw_status = 1;
2039 break;
2040 case 'S': /* START */
2041 case 's':
2042 do_panel_command("herc startall");
2043 break;
2044 case 'P': /* STOP */
2045 case 'p':
2046 do_panel_command("herc stopall");
2047 break;
2048 case 'O': /* Store */
2049 case 'o':
2050 regs = copy_regs(sysblk.pcpu);
2051 aaddr = APPLY_PREFIXING (NPaddress, regs->PX);
2052 if (aaddr > regs->mainlim)
2053 break;
2054 store_fw (regs->mainstor + aaddr, NPdata);
2055 redraw_status = 1;
2056 break;
2057 case 'I': /* Display */
2058 case 'i':
2059 NPregdisp = 4;
2060 NPregs_valid = 0;
2061 redraw_status = 1;
2062 break;
2063 case 'g': /* display GPR */
2064 case 'G':
2065 NPregdisp = 0;
2066 NPregs_valid = 0;
2067 redraw_status = 1;
2068 break;
2069 case 'a': /* Display AR */
2070 case 'A':
2071 NPregdisp = 2;
2072 NPregs_valid = 0;
2073 redraw_status = 1;
2074 break;
2075 case 'c':
2076 case 'C': /* Case CR */
2077 NPregdisp = 1;
2078 NPregs_valid = 0;
2079 redraw_status = 1;
2080 break;
2081 case 'f': /* Case FPR */
2082 case 'F':
2083 NPregdisp = 3;
2084 NPregs_valid = 0;
2085 redraw_status = 1;
2086 break;
2087 case 'r': /* Enter address */
2088 case 'R':
2089 NPdataentry = 1;
2090 redraw_cmd = 1;
2091 NPpending = 'r';
2092 NPcurrow = 16;
2093 NPcurcol = 12;
2094 NPdatalen = 8;
2095 NPcolorSwitch = 1;
2096 NPcolorFore = COLOR_WHITE;
2097 NPcolorBack = COLOR_BLUE;
2098 strcpy(NPentered, "");
2099 strcpy(NPprompt1, "Enter Address");
2100 redraw_status = 1;
2101 break;
2102 case 'd': /* Enter data */
2103 case 'D':
2104 NPdataentry = 1;
2105 redraw_cmd = 1;
2106 NPpending = 'd';
2107 NPcurrow = 16;
2108 NPcurcol = 30;
2109 NPdatalen = 8;
2110 NPcolorSwitch = 1;
2111 NPcolorFore = COLOR_WHITE;
2112 NPcolorBack = COLOR_BLUE;
2113 strcpy(NPentered, "");
2114 strcpy(NPprompt1, "Enter Data Value");
2115 redraw_status = 1;
2116 break;
2117 case 'l': /* IPL */
2118 case 'L':
2119 NPdevsel = 1;
2120 NPsel2 = 1;
2121 strcpy(NPprompt2, "Select Device for IPL");
2122 redraw_status = 1;
2123 break;
2124 case 1: /* IPL - 2nd part */
2125 i = toupper(NPdevice) - 'A';
2126 if (i < 0 || i > NPlastdev) {
2127 strcpy(NPprompt2, "");
2128 redraw_status = 1;
2129 break;
2130 }
2131 sprintf (cmdline, "herc ipl %4.4x", NPdevnum[i]);
2132 do_panel_command(cmdline);
2133 strcpy(NPprompt2, "");
2134 redraw_status = 1;
2135 break;
2136 case 'u': /* Device interrupt */
2137 case 'U':
2138 NPdevsel = 1;
2139 NPsel2 = 2;
2140 strcpy(NPprompt2, "Select Device for Interrupt");
2141 redraw_status = 1;
2142 break;
2143 case 2: /* Device int: part 2 */
2144 i = toupper(NPdevice) - 'A';
2145 if (i < 0 || i > NPlastdev) {
2146 strcpy(NPprompt2, "");
2147 redraw_status = 1;
2148 break;
2149 }
2150 sprintf (cmdline, "herc i %4.4x", NPdevnum[i]);
2151 do_panel_command(cmdline);
2152 strcpy(NPprompt2, "");
2153 redraw_status = 1;
2154 break;
2155 case 'n': /* Device Assignment */
2156 case 'N':
2157 NPdevsel = 1;
2158 NPsel2 = 3;
2159 strcpy(NPprompt2, "Select Device to Reassign");
2160 redraw_status = 1;
2161 break;
2162 case 3: /* Device asgn: part 2 */
2163 i = toupper(NPdevice) - 'A';
2164 if (i < 0 || i > NPlastdev) {
2165 strcpy(NPprompt2, "");
2166 redraw_status = 1;
2167 break;
2168 }
2169 NPdataentry = 1;
2170 redraw_cmd = 1;
2171 NPpending = 'n';
2172 NPasgn = i;
2173 NPcurrow = 3 + i;
2174 NPcurcol = 58;
2175 NPdatalen = cons_cols - 57;
2176 NPcolorSwitch = 1;
2177 NPcolorFore = COLOR_DEFAULT_LIGHT;
2178 NPcolorBack = COLOR_BLUE;
2179 strcpy(NPentered, "");
2180 strcpy(NPprompt2, "New Name, or [enter] to Reload");
2181 redraw_status = 1;
2182 break;
2183 case 'W': /* POWER */
2184 case 'w':
2185 NPdevsel = 1;
2186 NPsel2 = 4;
2187 strcpy(NPprompt1, "Confirm Powerdown Y or N");
2188 redraw_status = 1;
2189 break;
2190 case 4: /* POWER - 2nd part */
2191 if (NPdevice == 'y' || NPdevice == 'Y')
2192 do_panel_command("herc quit");
2193 strcpy(NPprompt1, "");
2194 redraw_status = 1;
2195 break;
2196 case 'T': /* Restart */
2197 case 't':
2198 NPdevsel = 1;
2199 NPsel2 = 5;
2200 strcpy(NPprompt1, "Confirm Restart Y or N");
2201 redraw_status = 1;
2202 break;
2203 case 5: /* Restart - part 2 */
2204 if (NPdevice == 'y' || NPdevice == 'Y')
2205 do_panel_command("herc restart");
2206 strcpy(NPprompt1, "");
2207 redraw_status = 1;
2208 break;
2209 case 'E': /* Ext int */
2210 case 'e':
2211 NPdevsel = 1;
2212 NPsel2 = 6;
2213 strcpy(NPprompt1, "Confirm External Interrupt Y or N");
2214 redraw_status = 1;
2215 break;
2216 case 6: /* External - part 2 */
2217 if (NPdevice == 'y' || NPdevice == 'Y')
2218 do_panel_command("herc ext");
2219 strcpy(NPprompt1, "");
2220 redraw_status = 1;
2221 break;
2222 default:
2223 break;
2224 }
2225 NPcmd = 1;
2226 } else { /* We are in data entry mode */
2227 if (kbbuf[0] == 0x1B) {
2228 /* Switch back to command mode */
2229 NPdataentry = 0;
2230 NPaddr_valid = 0;
2231 NPdata_valid = 0;
2232 strcpy(NPprompt1, "");
2233 strcpy(NPprompt2, "");
2234 NPcmd = 1;
2235 }
2236 else
2237 NPcmd = 0;
2238 }
2239 if (NPcmd == 1)
2240 kblen = 0; /* don't process as command */
2241 }
2242 /* =NP END= */
2243
2244 /* Process characters in the keyboard buffer */
2245 for (i = 0; i < kblen; )
2246 {
2247 /* Test for HOME */
2248 if (strcmp(kbbuf+i, KBD_HOME) == 0) {
2249 if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) {
2250 cursor_cmdline_home();
2251 redraw_cmd = 1;
2252 } else {
2253 scroll_to_top_line( 1 );
2254 redraw_msgs = 1;
2255 }
2256 break;
2257 }
2258
2259 /* Test for END */
2260 if (strcmp(kbbuf+i, KBD_END) == 0) {
2261 if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) {
2262 cursor_cmdline_end();
2263 redraw_cmd = 1;
2264 } else {
2265 scroll_to_bottom_screen( 1 );
2266 redraw_msgs = 1;
2267 }
2268 break;
2269 }
2270
2271 /* Test for CTRL+HOME */
2272 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_HOME) == 0) {
2273 scroll_to_top_line( 1 );
2274 redraw_msgs = 1;
2275 break;
2276 }
2277
2278 /* Test for CTRL+END */
2279 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_END) == 0) {
2280 scroll_to_bottom_line( 1 );
2281 redraw_msgs = 1;
2282 break;
2283 }
2284
2285 /* Process UPARROW */
2286 if (NPDup == 0 && strcmp(kbbuf+i, KBD_UP_ARROW) == 0)
2287 {
2288 do_prev_history();
2289 redraw_cmd = 1;
2290 break;
2291 }
2292
2293 /* Process DOWNARROW */
2294 if (NPDup == 0 && strcmp(kbbuf+i, KBD_DOWN_ARROW) == 0)
2295 {
2296 do_next_history();
2297 redraw_cmd = 1;
2298 break;
2299 }
2300
2301 #if defined(OPTION_EXTCURS)
2302 /* Process ALT+UPARROW */
2303 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_UP_ARROW) == 0) {
2304 get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2305 if (cur_cons_row <= 1)
2306 cur_cons_row = cons_rows + 1;
2307 set_pos( --cur_cons_row, cur_cons_col );
2308 break;
2309 }
2310
2311 /* Process ALT+DOWNARROW */
2312 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_DOWN_ARROW) == 0) {
2313 get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2314 if (cur_cons_row >= cons_rows)
2315 cur_cons_row = 1 - 1;
2316 set_pos( ++cur_cons_row, cur_cons_col );
2317 break;
2318 }
2319 #endif // defined(OPTION_EXTCURS)
2320
2321 /* Test for PAGEUP */
2322 if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_UP) == 0) {
2323 page_up( 1 );
2324 redraw_msgs = 1;
2325 break;
2326 }
2327
2328 /* Test for PAGEDOWN */
2329 if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_DOWN) == 0) {
2330 page_down( 1 );
2331 redraw_msgs = 1;
2332 break;
2333 }
2334
2335 /* Test for CTRL+UPARROW */
2336 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_UP_ARROW) == 0) {
2337 scroll_up_lines(1,1);
2338 redraw_msgs = 1;
2339 break;
2340 }
2341
2342 /* Test for CTRL+DOWNARROW */
2343 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_DOWN_ARROW) == 0) {
2344 scroll_down_lines(1,1);
2345 redraw_msgs = 1;
2346 break;
2347 }
2348
2349 /* Process BACKSPACE */
2350 if (kbbuf[i] == '\b' || kbbuf[i] == '\x7F') {
2351 if (NPDup == 0 && !is_cursor_on_cmdline())
2352 beep();
2353 else {
2354 if (cmdoff > 0) {
2355 int j;
2356 for (j = cmdoff-1; j<cmdlen; j++)
2357 cmdline[j] = cmdline[j+1];
2358 cmdoff--;
2359 cmdlen--;
2360 ADJ_CMDCOL();
2361 }
2362 i++;
2363 redraw_cmd = 1;
2364 }
2365 break;
2366 }
2367
2368 /* Process DELETE */
2369 if (strcmp(kbbuf+i, KBD_DELETE) == 0) {
2370 if (NPDup == 0 && !is_cursor_on_cmdline())
2371 beep();
2372 else {
2373 if (cmdoff < cmdlen) {
2374 int j;
2375 for (j = cmdoff; j<cmdlen; j++)
2376 cmdline[j] = cmdline[j+1];
2377 cmdlen--;
2378 }
2379 i++;
2380 redraw_cmd = 1;
2381 }
2382 break;
2383 }
2384
2385 /* Process LEFTARROW */
2386 if (strcmp(kbbuf+i, KBD_LEFT_ARROW) == 0) {
2387 if (cmdoff > 0) cmdoff--;
2388 ADJ_CMDCOL();
2389 i++;
2390 redraw_cmd = 1;
2391 break;
2392 }
2393
2394 /* Process RIGHTARROW */
2395 if (strcmp(kbbuf+i, KBD_RIGHT_ARROW) == 0) {
2396 if (cmdoff < cmdlen) cmdoff++;
2397 ADJ_CMDCOL();
2398 i++;
2399 redraw_cmd = 1;
2400 break;
2401 }
2402
2403 #if defined(OPTION_EXTCURS)
2404 /* Process ALT+LEFTARROW */
2405 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_LEFT_ARROW) == 0) {
2406 get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2407 if (cur_cons_col <= 1)
2408 {
2409 cur_cons_row--;
2410 cur_cons_col = cons_cols + 1;
2411 }
2412 if (cur_cons_row < 1)
2413 cur_cons_row = cons_rows;
2414 set_pos( cur_cons_row, --cur_cons_col );
2415 break;
2416 }
2417
2418 /* Process ALT+RIGHTARROW */
2419 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_RIGHT_ARROW) == 0) {
2420 get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2421 if (cur_cons_col >= cons_cols)
2422 {
2423 cur_cons_row++;
2424 cur_cons_col = 0;
2425 }
2426 if (cur_cons_row > cons_rows)
2427 cur_cons_row = 1;
2428 set_pos( cur_cons_row, ++cur_cons_col );
2429 break;
2430 }
2431 #endif // defined(OPTION_EXTCURS)
2432
2433 /* Process INSERT */
2434 if (strcmp(kbbuf+i, KBD_INSERT) == 0 ) {
2435 cmdins = !cmdins;
2436 set_console_cursor_shape( confp, cmdins );
2437 i++;
2438 break;
2439 }
2440
2441 /* Process ESCAPE */
2442 if (kbbuf[i] == '\x1B') {
2443 /* If data on cmdline, erase it */
2444 if ((NPDup == 1 || is_cursor_on_cmdline()) && cmdlen) {
2445 cmdline[0] = '\0';
2446 cmdlen = 0;
2447 cmdoff = 0;
2448 ADJ_CMDCOL();
2449 redraw_cmd = 1;
2450 } else {
2451 /* =NP= : Switch to new panel display */
2452 save_command_line();
2453 NP_init();
2454 NPDup = 1;
2455 /* =END= */
2456 }
2457 break;
2458 }
2459
2460 /* Process TAB */
2461 if (kbbuf[i] == '\t' || kbbuf[i] == '\x7F') {
2462 if (NPDup == 1 || !is_cursor_on_cmdline()) {
2463 cursor_cmdline_home();
2464 redraw_cmd = 1;
2465 } else {
2466 tab_pressed(cmdline, &cmdoff);
2467 cmdlen = strlen(cmdline);
2468 ADJ_CMDCOL();
2469 i++;
2470 redraw_cmd = 1;
2471 }
2472 break;
2473 }
2474
2475 #if defined(OPTION_EXTCURS)
2476 /* ENTER key special handling */
2477 if (NPDup == 0 && kbbuf[i] == '\n')
2478 {
2479 /* Get cursor pos and check if on cmdline */
2480 if (!is_cursor_on_cmdline())
2481 {
2482 int keepnum = get_keepnum_by_row( cur_cons_row );
2483 if (keepnum >= 0)
2484 {
2485 #if defined(OPTION_MSGHLD)
2486 /* ENTER pressed on kept msg; remove msg */
2487 unkeep_by_keepnum( keepnum, 1 );
2488 #endif // defined(OPTION_MSGHLD)
2489 redraw_msgs = 1;
2490 break;
2491 }
2492 /* ENTER pressed NOT on cmdline */
2493 beep();
2494 break;
2495 }
2496 /* ENTER pressed on cmdline; fall through
2497 for normal ENTER keypress handling... */
2498 }
2499 #endif // defined(OPTION_EXTCURS)
2500
2501 /* Process the command when the ENTER key is pressed */
2502 if (kbbuf[i] == '\n') {
2503 if (cmdlen == 0 && NPDup == 0 && !sysblk.inststep &&
2504 sysblk.cmdtgt == 0) {
2505 history_show();
2506 } else {
2507 cmdline[cmdlen] = '\0';
2508 /* =NP= create_thread replaced with: */
2509 if (NPDup == 0) {
2510 if ('#' == cmdline[0] || '*' == cmdline[0]) {
2511 if (!is_currline_visible())
2512 scroll_to_bottom_screen( 1 );
2513 history_requested = 0;
2514 do_panel_command(cmdline);
2515 redraw_cmd = 1;
2516 cmdlen = 0;
2517 cmdoff = 0;
2518 ADJ_CMDCOL();
2519 redraw_cmd = 1;
2520 } else {
2521 history_requested = 0;
2522 do_panel_command(cmdline);
2523 redraw_cmd = 1;
2524 if (history_requested == 1) {
2525 strcpy(cmdline, historyCmdLine);
2526 cmdlen = strlen(cmdline);
2527 cmdoff = cmdlen;
2528 ADJ_CMDCOL();
2529 NPDup = 0;
2530 NPDinit = 1;
2531 }
2532 }
2533 } else {
2534 NPdataentry = 0;
2535 NPcurrow = cons_rows;
2536 NPcurcol = cons_cols;
2537 NPcolorSwitch = 0;
2538 switch (NPpending) {
2539 case 'r':
2540 sscanf(cmdline, "%x", &NPaddress);
2541 NPaddr_valid = 0;
2542 strcpy(NPprompt1, "");
2543 break;
2544 case 'd':
2545 sscanf(cmdline, "%x", &NPdata);
2546 NPdata_valid = 0;
2547 strcpy(NPprompt1, "");
2548 break;
2549 case 'n':
2550 if (strlen(cmdline) < 1) {
2551 strcpy(cmdline, NPdevnam[NPasgn]);
2552 }
2553 strcpy(NPdevnam[NPasgn], "");
2554 sprintf (NPentered, "herc devinit %4.4x %s",
2555 NPdevnum[NPasgn], cmdline);
2556 do_panel_command(NPentered);
2557 strcpy(NPprompt2, "");
2558 break;
2559 default:
2560 break;
2561 }
2562 redraw_status = 1;
2563 cmdline[0] = '\0';
2564 cmdlen = 0;
2565 cmdoff = 0;
2566 ADJ_CMDCOL();
2567 }
2568 /* =END= */
2569 redraw_cmd = 1;
2570 }
2571 break;
2572 } /* end if (kbbuf[i] == '\n') */
2573
2574 /* Ignore non-printable characters */
2575 if (!isprint(kbbuf[i])) {
2576 beep();
2577 i++;
2578 continue;
2579 }
2580
2581 /* Ignore all other keystrokes not on cmdline */
2582 if (NPDup == 0 && !is_cursor_on_cmdline()) {
2583 beep();
2584 break;
2585 }
2586
2587 /* Append the character to the command buffer */
2588 ASSERT(cmdlen <= CMD_SIZE-1 && cmdoff <= cmdlen);
2589 if (0
2590 || (cmdoff >= CMD_SIZE-1)
2591 || (cmdins && cmdlen >= CMD_SIZE-1)
2592 )
2593 {
2594 /* (no more room!) */
2595 beep();
2596 }
2597 else /* (there's still room) */
2598 {
2599 ASSERT(cmdlen < CMD_SIZE-1 || (!cmdins && cmdoff < cmdlen));
2600 if (cmdoff >= cmdlen)
2601 {
2602 /* Append to end of buffer */
2603 ASSERT(!(cmdoff > cmdlen)); // (sanity check)
2604 cmdline[cmdoff++] = kbbuf[i];
2605 cmdline[cmdoff] = '\0';
2606 cmdlen++;
2607 }
2608 else
2609 {
2610 ASSERT(cmdoff < cmdlen);
2611 if (cmdins)
2612 {
2613 /* Insert: make room by sliding all
2614 following chars right one position */
2615 int j;
2616 for (j=cmdlen-1; j>=cmdoff; j--)
2617 cmdline[j+1] = cmdline[j];
2618 cmdline[cmdoff++] = kbbuf[i];
2619 cmdlen++;
2620 }
2621 else
2622 {
2623 /* Overlay: replace current position */
2624 cmdline[cmdoff++] = kbbuf[i];
2625 }
2626 }
2627 ADJ_CMDCOL();
2628 redraw_cmd = 1;
2629 }
2630 i++;
2631 } /* end for(i) */
2632 } /* end if keystroke */
2633
2634 FinishShutdown:
2635
2636 // If we finished processing all of the message data
2637 // the last time we were here, then get some more...
2638
2639 if ( lmsndx >= lmscnt ) // (all previous data processed?)
2640 {
2641 lmscnt = log_read( &lmsbuf, &lmsnum, LOG_NOBLOCK );
2642 lmsndx = 0;
2643 }
2644 else if ( lmsndx >= lmsmax )
2645 {
2646 lmsbuf += lmsndx; // pick up where we left off at...
2647 lmscnt -= lmsndx; // pick up where we left off at...
2648 lmsndx = 0;
2649 }
2650
2651 // Process all message data or until limit reached...
2652
2653 // (limiting the amount of data we process a console message flood
2654 // from preventing keyboard from being read since we need to break
2655 // out of the below message data processing loop to loop back up
2656 // to read the keyboard again...)
2657
2658 /* Read message bytes until newline... */
2659 while ( lmsndx < lmscnt && lmsndx < lmsmax )
2660 {
2661 /* Initialize the read buffer */
2662 if (!readoff || readoff >= MSG_SIZE) {
2663 memset (readbuf, SPACE, MSG_SIZE);
2664 readoff = 0;
2665 }
2666
2667 /* Read message bytes and copy into read buffer
2668 until we either encounter a newline character
2669 or our buffer is completely filled with data. */
2670 while ( lmsndx < lmscnt && lmsndx < lmsmax )
2671 {
2672 /* Read a byte from the message pipe */
2673 c = *(lmsbuf + lmsndx); lmsndx++;
2674
2675 /* Break to process received message
2676 whenever a newline is encountered */
2677 if (c == '\n' || c == '\r') {
2678 readoff = 0; /* (for next time) */
2679 break;
2680 }
2681
2682 /* Handle tab character */
2683 if (c == '\t') {
2684 readoff += 8;
2685 readoff &= 0xFFFFFFF8;
2686 /* Messages longer than one screen line will
2687 be continued on the very next screen line */
2688 if (readoff >= MSG_SIZE)
2689 break;
2690 else continue;
2691 }
2692
2693 /* Eliminate non-displayable characters */
2694 if (!isgraph(c)) c = SPACE;
2695
2696 /* Stuff byte into message processing buffer */
2697 readbuf[readoff++] = c;
2698
2699 /* Messages longer than one screen line will
2700 be continued on the very next screen line */
2701 if (readoff >= MSG_SIZE)
2702 break;
2703 } /* end while ( lmsndx < lmscnt && lmsndx < lmsmax ) */
2704
2705 /* If we have a message to be displayed (or a complete
2706 part of one), then copy it to the circular buffer. */
2707 if (!readoff || readoff >= MSG_SIZE) {
2708
2709 /* First-time here? */
2710 if (curmsg == NULL) {
2711 curmsg = topmsg = msgbuf;
2712 } else {
2713 /* Perform autoscroll if needed */
2714 if (is_currline_visible()) {
2715 while (lines_remaining() < 1)
2716 scroll_down_lines(1,1);
2717 /* Set the display update indicator */
2718 redraw_msgs = 1;
2719 }
2720
2721 /* Go on to next available msg buffer */
2722 curmsg = curmsg->next;
2723
2724 /* Updated wrapped indicator */
2725 if (curmsg == msgbuf)
2726 wrapped = 1;
2727 }
2728
2729 /* Copy message into next available PANMSG slot */
2730 memcpy( curmsg->msg, readbuf, MSG_SIZE );
2731
2732 #if defined(OPTION_MSGCLR)
2733 /* Colorize and/or keep new message if needed */
2734 colormsg(curmsg);
2735 #endif // defined(OPTION_MSGCLR)
2736
2737 } /* end if (!readoff || readoff >= MSG_SIZE) */
2738 } /* end Read message bytes until newline... */
2739
2740 /* Don't read or otherwise process any input
2741 once system shutdown has been initiated
2742 */
2743 if ( sysblk.shutdown )
2744 {
2745 if ( sysblk.shutfini ) break;
2746 /* wait for system to finish shutting down */
2747 usleep(10000);
2748 lmsmax = INT_MAX;
2749 goto FinishShutdown;
2750 }
2751
2752 /* =NP= : Reinit traditional panel if NP is down */
2753 if (NPDup == 0 && NPDinit == 1) {
2754 redraw_msgs = redraw_status = redraw_cmd = 1;
2755 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2756 clr_screen ();
2757 }
2758 /* =END= */
2759
2760 /* Obtain the PSW for target CPU */
2761 regs = copy_regs(sysblk.pcpu);
2762 memset (curpsw, 0x00, sizeof(curpsw));
2763 copy_psw (regs, curpsw);
2764
2765 /* Set the display update indicator if the PSW has changed
2766 or if the instruction counter has changed, or if
2767 the CPU stopped state has changed */
2768 if (memcmp(curpsw, prvpsw, sizeof(curpsw)) != 0
2769 || prvicount != INSTCOUNT(regs)
2770 || prvcpupct != regs->cpupct
2771 #if defined(OPTION_SHARED_DEVICES)
2772 || prvscount != sysblk.shrdcount
2773 #endif // defined(OPTION_SHARED_DEVICES)
2774 || prvstate != regs->cpustate
2775 #if defined(OPTION_MIPS_COUNTING)
2776 || (NPDup && NPcpugraph && prvtcount != sysblk.instcount)
2777 #endif /*defined(OPTION_MIPS_COUNTING)*/
2778 )
2779 {
2780 redraw_status = 1;
2781 memcpy (prvpsw, curpsw, sizeof(prvpsw));
2782 prvicount = INSTCOUNT(regs);
2783 prvcpupct = regs->cpupct;
2784 prvstate = regs->cpustate;
2785 #if defined(OPTION_SHARED_DEVICES)
2786 prvscount = sysblk.shrdcount;
2787 #endif // defined(OPTION_SHARED_DEVICES)
2788 #if defined(OPTION_MIPS_COUNTING)
2789 prvtcount = sysblk.instcount;
2790 #endif /*defined(OPTION_MIPS_COUNTING)*/
2791 }
2792
2793 /* =NP= : Display the screen - traditional or NP */
2794 /* Note: this is the only code block modified rather */
2795 /* than inserted. It makes the block of 3 ifs in the */
2796 /* original code dependent on NPDup == 0, and inserts */
2797 /* the NP display as an else after those ifs */
2798
2799 if (NPDup == 0) {
2800 /* Rewrite the screen if display update indicators are set */
2801 if (redraw_msgs && !npquiet)
2802 {
2803 /* Display messages in scrolling area */
2804 PANMSG* p;
2805
2806 /* Save cursor location */
2807 saved_cons_row = cur_cons_row;
2808 saved_cons_col = cur_cons_col;
2809
2810 #if defined(OPTION_MSGHLD)
2811 /* Unkeep kept messages if needed */
2812 expire_kept_msgs(0);
2813 #endif // defined(OPTION_MSGHLD)
2814 i = 0;
2815 #if defined(OPTION_MSGHLD)
2816 /* Draw kept messages first */
2817 for (p=keptmsgs; i < (SCROLL_LINES + numkept) && p; i++, p = p->next)
2818 {
2819 set_pos (i+1, 1);
2820 #if defined(OPTION_MSGCLR)
2821 set_color (p->fg, p->bg);
2822 #else // !defined(OPTION_MSGCLR)
2823 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2824 #endif // defined(OPTION_MSGCLR)
2825 write_text (p->msg, MSG_SIZE);
2826 }
2827 #endif // defined(OPTION_MSGHLD)
2828
2829 /* Then draw current screen */
2830 for (p=topmsg; i < (SCROLL_LINES + numkept) && (p != curmsg->next || p == topmsg); i++, p = p->next)
2831 {
2832 set_pos (i+1, 1);
2833 #if defined(OPTION_MSGCLR)
2834 set_color (p->fg, p->bg);
2835 #else // !defined(OPTION_MSGCLR)
2836 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2837 #endif // defined(OPTION_MSGCLR)
2838 write_text (p->msg, MSG_SIZE);
2839 }
2840
2841 /* Pad remainder of screen with blank lines */
2842 for (; i < (SCROLL_LINES + numkept); i++)
2843 {
2844 set_pos (i+1, 1);
2845 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2846 erase_to_eol( confp );
2847 }
2848
2849 /* Display the scroll indicators */
2850 if (topmsg != oldest_msg())
2851 {
2852 /* More messages precede top line */
2853 set_pos (1, cons_cols);
2854 set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG);
2855 draw_text ("+");
2856 }
2857 if (!is_currline_visible())
2858 {
2859 /* More messages follow bottom line */
2860 set_pos (cons_rows-2, cons_cols);
2861 set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG);
2862 draw_text ("V");
2863 }
2864
2865 /* restore cursor location */
2866 cur_cons_row = saved_cons_row;
2867 cur_cons_col = saved_cons_col;
2868 } /* end if(redraw_msgs) */
2869
2870 if (redraw_cmd)
2871 {
2872 /* Save cursor location */
2873 saved_cons_row = cur_cons_row;
2874 saved_cons_col = cur_cons_col;
2875
2876 /* Display the command line */
2877 set_pos (CMDLINE_ROW, 1);
2878 set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG);
2879
2880 #if defined(OPTION_CMDTGT)
2881 switch(sysblk.cmdtgt)
2882 {
2883 case 0: // cmdtgt herc
2884 {
2885 draw_text(CMD_PREFIX_STR);
2886 break;
2887 }
2888 case 1: // cmdtgt scp
2889 {
2890 draw_text(CMD_PREFIX_STR1);
2891 break;
2892 }
2893 case 2: // cmdtgt pscp
2894 {
2895 draw_text(CMD_PREFIX_STR2);
2896 break;
2897 }
2898 }
2899 #else // !defined(OPTION_CMDTGT)
2900 draw_text (CMD_PREFIX_STR);
2901 #endif // defined(OPTION_CMDTGT)
2902
2903 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2904 PUTC_CMDLINE ();
2905 fill_text (' ',cons_cols);
2906
2907 /* restore cursor location */
2908 cur_cons_row = saved_cons_row;
2909 cur_cons_col = saved_cons_col;
2910 } /* end if(redraw_cmd) */
2911
2912 if (redraw_status && !npquiet)
2913 {
2914 /* Save cursor location */
2915 saved_cons_row = cur_cons_row;
2916 saved_cons_col = cur_cons_col;
2917
2918 memset (buf, ' ', cons_cols);
2919 len = sprintf (buf, "CPU%4.4X ", sysblk.pcpu);
2920 if (IS_CPU_ONLINE(sysblk.pcpu))
2921 {
2922 char ibuf[64];
2923 len += sprintf(buf+len, "PSW=%8.8X%8.8X ",
2924 fetch_fw(curpsw), fetch_fw(curpsw+4));
2925 if (regs->arch_mode == ARCH_900)
2926 len += sprintf (buf+len, "%16.16"I64_FMT"X ",
2927 fetch_dw (curpsw+8));
2928 #if defined(_FEATURE_SIE)
2929 else
2930 if( SIE_MODE(regs) )
2931 {
2932 for(i = 0;i < 16;i++)
2933 buf[len++] = '-';
2934 buf[len++] = ' ';
2935 }
2936 #endif /*defined(_FEATURE_SIE)*/
2937 len += sprintf (buf+len, "%2d%c%c%c%c%c%c%c%c",
2938 regs->psw.amode64 ? 64 :
2939 regs->psw.amode ? 31 : 24,
2940 regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.',
2941 sysblk.inststep ? 'T' : '.',
2942 WAITSTATE(®s->psw) ? 'W' : '.',
2943 regs->loadstate ? 'L' : '.',
2944 regs->checkstop ? 'C' : '.',
2945 PROBSTATE(®s->psw) ? 'P' : '.',
2946 SIE_MODE(regs) ? 'S' : '.',
2947 regs->arch_mode == ARCH_900 ? 'Z' : '.');
2948 buf[len++] = ' ';
2949 sprintf (ibuf, "instcount=%s", format_int(INSTCOUNT(regs)));
2950 if (len + (int)strlen(ibuf) < cons_cols)
2951 len = cons_cols - strlen(ibuf);
2952 strcpy (buf + len, ibuf);
2953 }
2954 else
2955 {
2956 len += sprintf (buf+len,"%s", "Offline");
2957 buf[len++] = ' ';
2958 }
2959 buf[cons_cols] = '\0';
2960 set_pos (cons_rows, 1);
2961 set_color (COLOR_LIGHT_YELLOW, COLOR_RED);
2962 draw_text (buf);
2963
2964 /* restore cursor location */
2965 cur_cons_row = saved_cons_row;
2966 cur_cons_col = saved_cons_col;
2967 } /* end if(redraw_status) */
2968
2969 /* Flush screen buffer and reset display update indicators */
2970 if (redraw_msgs || redraw_cmd || redraw_status)
2971 {
2972 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2973 if (NPDup == 0 && NPDinit == 1)
2974 {
2975 NPDinit = 0;
2976 restore_command_line();
2977 set_pos (cur_cons_row, cur_cons_col);
2978 }
2979 else if (redraw_cmd)
2980 set_pos (CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol);
2981 else
2982 set_pos (cur_cons_row, cur_cons_col);
2983 fflush (confp);
2984 redraw_msgs = redraw_cmd = redraw_status = 0;
2985 }
2986
2987 } else { /* (NPDup == 1) */
2988
2989 if (redraw_status || (NPDinit == 0 && NPDup == 1)
2990 || (redraw_cmd && NPdataentry == 1)) {
2991 if (NPDinit == 0) {
2992 NPDinit = 1;
2993 NP_screen_redraw(regs);
2994 NP_update(regs);
2995 fflush (confp);
2996 }
2997 }
2998 /* Update New Panel every panrate interval */
2999 if (!npquiet) {
3000 NP_update(regs);
3001 fflush (confp);
3002 }
3003 redraw_msgs = redraw_cmd = redraw_status = 0;
3004 }
3005
3006 /* =END= */
3007
3008 /* Force full screen repaint if needed */
3009 if (!sysblk.npquiet && npquiet)
3010 redraw_msgs = redraw_cmd = redraw_status = 1;
3011 npquiet = sysblk.npquiet;
3012
3013 } /* end while */
3014
3015 ASSERT( sysblk.shutdown ); // (why else would we be here?!)
3016
3017 } /* end function panel_display */
3018
3019 static void panel_cleanup(void *unused)
3020 {
3021 int i;
3022 PANMSG* p;
3023
3024 UNREFERENCED(unused);
3025
3026 log_wakeup(NULL);
3027
3028 set_screen_color( stderr, COLOR_DEFAULT_FG, COLOR_DEFAULT_BG );
3029 clear_screen( stderr );
3030
3031 /* Scroll to last full screen's worth of messages */
3032 scroll_to_bottom_screen( 1 );
3033
3034 /* Display messages in scrolling area */
3035 for (i=0, p = topmsg; i < SCROLL_LINES && p != curmsg->next; i++, p = p->next)
3036 {
3037 set_pos (i+1, 1);
3038 #if defined(OPTION_MSGCLR)
3039 set_color (p->fg, p->bg);
3040 #else // !defined(OPTION_MSGCLR)
3041 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
3042 #endif // defined(OPTION_MSGCLR)
3043 write_text (p->msg, MSG_SIZE);
3044 }
3045
3046 /* Restore the terminal mode */
3047 set_or_reset_console_mode( keybfd, 0 );
3048
3049 /* Position to next line */
3050 fwrite("\n",1,1,stderr);
3051
3052 /* Read and display any msgs still remaining in the system log */
3053 while((lmscnt = log_read(&lmsbuf, &lmsnum, LOG_NOBLOCK)))
3054 fwrite(lmsbuf,lmscnt,1,stderr);
3055
3056 fflush(stderr);
3057 }
3058