root/src/dps8/panelScraper.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. update_apu
  2. update_cpts
  3. update_data_1
  4. update_data_2
  5. update_data_3
  6. update_data_4
  7. update_data_5
  8. update_data_6
  9. update_data_7
  10. update_data_scroll
  11. update_data
  12. update_display
  13. lwrite
  14. send_lamp_data
  15. set_message
  16. time_handler
  17. update_port
  18. scraperThreadMain
  19. panelScraperInit
  20. panelScraperStart
  21. panelScraperStop
  22. panelScraperMsg

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: 2395ba22-655a-11ef-85db-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2013-2024 Charles Anthony
   9  * Copyright (c) 2021-2024 The DPS8M Development Team
  10  *
  11  * This software is made available under the terms of the ICU License.
  12  * See the LICENSE.md file at the top-level directory of this distribution.
  13  *
  14  * ---------------------------------------------------------------------------
  15  */
  16 
  17 // XXX APU match enable code not implemented
  18 
  19 // XXX control points not done
  20 
  21 // XXX panel4_red_ready_light_state
  22 // XXX cpu.panel7_enabled_light_state
  23 
  24 // CFLAGS += -DL68
  25 // CFLAGS += -DPANEL
  26 // CFLAGS += -DWAM
  27 // LOCALOBJS += panelScraper.o
  28 // LOCALLIBS += -lpthread
  29 
  30 // socat -d -d pty,raw,echo=0,link=/tmp/com_local pty,raw,echo=0,link=/tmp/com_remote
  31 // socat -d -d pty,raw,echo=0,link=/dev/ttyUSB1 pty,raw,echo=0,link=/tmp/com_remote
  32 
  33 #include <termios.h>
  34 #include <fcntl.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 #include <poll.h>
  39 #include <errno.h>
  40 
  41 #include "panelScraper.h"
  42 
  43 #include "../font8x8/font8x8.h"
  44 
  45 #include "dps8.h"
  46 #include "dps8_sys.h"
  47 #include "dps8_cpu.h"
  48 
  49 #undef cpu
  50 static cpu_state_t * volatile panel_cpup;
  51 #define cpu (* panel_cpup)
  52 
  53 #include <pthread.h>
  54 #include <sys/types.h>
  55 #include <sys/stat.h>
  56 #include <fcntl.h>
  57 #include <unistd.h>
  58 #if defined(__MINGW64__) || defined(__MINGW32__)
  59 # define FD HANDLE
  60 #else
  61 # include <poll.h>
  62 # define FD int
  63 #endif
  64 
  65 #if !defined MIN
  66 # define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
  67 #endif
  68 
  69 static pthread_t scraperThread;
  70 
  71 static int scraperThreadArg;
  72 
  73 #define msgLen 4096
  74 static char message [msgLen];
  75 static int c_offset = 0;
  76 
  77 // Lamp state
  78 
  79 #define nrows 16
  80 #define ncols 40
  81 static bool banks [nrows] [ncols];
  82 #define bank_a banks [ 0]
  83 #define bank_b banks [ 1]
  84 #define bank_c banks [ 2]
  85 #define bank_d banks [ 3]
  86 #define bank_e banks [ 4]
  87 #define bank_f banks [ 5]
  88 #define bank_g banks [ 6]
  89 #define bank_h banks [ 7]
  90 #define bank_i banks [ 8]
  91 #define bank_j banks [ 9]
  92 #define bank_k banks [10]
  93 #define bank_l banks [11]
  94 #define bank_m banks [12]
  95 #define bank_n banks [13]
  96 #define bank_o banks [14]
  97 #define bank_p banks [15]
  98 
  99 #define SETL(lights, light_os, from, n) \
 100   for (uint i = 0; i < (n); i ++) \
 101     lights [(light_os) + i] = !! ((from) & (1llu << ((n) - i - 1)));
 102 
 103 #define SETLA(lights, light_os, from, n) \
 104   for (uint i = 0; i < (n); i ++) \
 105     lights [(light_os) + i] = !! from [i];
 106 
 107 #define SETL1(lights, light_os, from) \
 108   lights [(light_os)] = !! (from);
 109 
 110 static void update_apu (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 111   {
 112     uint n = cpu.APU_panel_scroll_select_n_sw;
 113 
 114     switch (cpu.APU_panel_scroll_wheel_sw)
 115       {
 116         //  1 "PTW ASSOCIATIVE MEMORY MATCH LOGIC REGISTER N (N=0-15)"
 117         case 0:
 118           {
 119             if (cpu.APU_panel_scroll_select_ul_sw)
 120               { // Upper
 121                 // 0:14 SEGMENT POINTER
 122                 // 15:26 PAGE NUMBER
 123                 // 27 FULL
 124                 // 32:35 USAGE CNT
 125                 SETL (bank_a, 0+3, cpu.PTWAM[n].POINTER, 15);
 126                 SETL (bank_a, 15+3, cpu.PTWAM[n].PAGENO, 12);
 127                 SETL1 (bank_a, 27+3, cpu.PTWAM[n].FE);
 128                 SETL (bank_a, 32+3, cpu.PTWAM[n].USE, 4);
 129               }
 130             else
 131               { // Lower
 132                 // Empty
 133               }
 134           }
 135           break;
 136 
 137         //  2 "PTW ASSOCIATIVE MEMORY REGISTER N (N=0-15)"
 138         case 1:
 139           {
 140             if (cpu.APU_panel_scroll_select_ul_sw)
 141               { // Upper
 142                 // 0:17 PAGE ADDRESS
 143                 // 29 MOD
 144                 SETL (bank_a, 0+3, cpu.PTWAM[n].ADDR, 18);
 145                 SETL1 (bank_a, 29+3, cpu.PTWAM[n].M);
 146               }
 147             else
 148               { // Lower
 149                 // Empty
 150               }
 151           }
 152           break;
 153 
 154         //   3 "SDW ASSOCIATIVE MEMORY MATCH LOGIC REGISTER N (N=0-15)"
 155         case 2:
 156           {
 157             if (cpu.APU_panel_scroll_select_ul_sw)
 158               { // Upper
 159                 // 0:14 SEGMENT POINTER
 160                 // 27 FULL
 161                 // 32:35 USAGE CNT
 162                 SETL (bank_a, 0+3, cpu.SDWAM[n].POINTER, 15);
 163                 SETL1 (bank_a, 27+3, cpu.SDWAM[n].FE);
 164                 SETL (bank_a, 32+3, cpu.SDWAM[n].USE, 4);
 165               }
 166             else
 167               { // Lower
 168                 // Empty
 169               }
 170           }
 171           break;
 172 
 173         //   4 "SDW ASSOCIATIVE MEMORY REGISTER N (N=0-15)"
 174         case 3:
 175           {
 176             if (cpu.APU_panel_scroll_select_ul_sw)
 177               { // Upper
 178                 // 0:23 ADDRESS
 179                 // 24:26 R1
 180                 // 27:29 R2
 181                 // 30:32 R3
 182                 SETL (bank_a, 0+3, cpu.SDWAM[n].ADDR, 24);
 183                 SETL (bank_a, 24+3, cpu.SDWAM[n].R1, 3);
 184                 SETL (bank_a, 27+3, cpu.SDWAM[n].R2, 3);
 185                 SETL (bank_a, 30+3, cpu.SDWAM[n].R2, 3);
 186               }
 187             else
 188               { // Lower
 189                 // 1:14 SEGMENT BOUNDARY
 190                 // 15 READ
 191                 // 16 EXEC
 192                 // 17 WRITE
 193                 // 18 PRIV
 194                 // 19 UNPG
 195                 // 20 GATE
 196                 // 22:35 CALL LIMITER
 197                 SETL (bank_a, 1+3, cpu.SDWAM[n].BOUND, 14);
 198                 SETL1 (bank_a, 15+3, cpu.SDWAM[n].R);
 199                 SETL1 (bank_a, 16+3, cpu.SDWAM[n].E);
 200                 SETL1 (bank_a, 17+3, cpu.SDWAM[n].W);
 201                 SETL1 (bank_a, 18+3, cpu.SDWAM[n].P);
 202                 SETL1 (bank_a, 19+3, cpu.SDWAM[n].U);
 203                 SETL1 (bank_a, 20+3, cpu.SDWAM[n].G);
 204                 SETL (bank_a, 22+3, cpu.SDWAM[n].EB, 14);
 205               }
 206           }
 207           break;
 208 
 209         //   5 "DESCRIPTOR REGISTER BANK-ADDRESS 0 -- LAST PTW OR DSPTW FETCHED FROM STORE"
 210         case 4:
 211           {
 212             if (cpu.APU_panel_scroll_select_ul_sw)
 213               { // Upper
 214                 // 0:17 PAGE ADDRESS
 215                 // 26 ACSD // XXX Guessing: on: DSPTW; off: PTW
 216                 SETL (bank_a, 0+3, cpu.lastPTWOffset, 18);
 217                 SETL1 (bank_a, 26+3, cpu.lastPTWIsDS);
 218               }
 219             else
 220               { // Lower
 221                 // 1:14 SEGMENT BOUNDARY
 222                 // 15 READ
 223                 // 16 EXEC
 224                 // 17 WRITE
 225                 // 18 PRIV
 226                 // 19 UNPG
 227                 // 20 GATE
 228                 // 22:35 CALL LIMITER
 229                 SETL (bank_a, 1+3, cpu.SDWAM[n].BOUND, 14);
 230                 SETL1 (bank_a, 15+3, cpu.SDWAM[n].R);
 231                 SETL1 (bank_a, 16+3, cpu.SDWAM[n].E);
 232                 SETL1 (bank_a, 17+3, cpu.SDWAM[n].W);
 233                 SETL1 (bank_a, 18+3, cpu.SDWAM[n].P);
 234                 SETL1 (bank_a, 19+3, cpu.SDWAM[n].U);
 235                 SETL1 (bank_a, 20+3, cpu.SDWAM[n].G);
 236                 SETL (bank_a, 22+3, cpu.SDWAM[n].EB, 14);
 237               }
 238           }
 239           break;
 240 
 241         //   6 "DESCRIPTOR REGISTER BANK-ADDRESS 1 -- DSBR REGISTER"
 242         case 5:
 243           {
 244             if (cpu.APU_panel_scroll_select_ul_sw)
 245               { // Upper
 246                 // 0:23 ADDRESS
 247                 SETL (bank_a, 0+3, cpu.DSBR.ADDR, 24);
 248               }
 249             else
 250               { // Lower
 251                 SETL (bank_a, 1+3, cpu.SDWAM[n].BOUND, 14);
 252                 SETL1 (bank_a, 15+3, cpu.SDWAM[n].R);
 253                 SETL1 (bank_a, 16+3, cpu.SDWAM[n].E);
 254                 SETL1 (bank_a, 17+3, cpu.SDWAM[n].W);
 255                 SETL1 (bank_a, 18+3, cpu.SDWAM[n].P);
 256                 SETL1 (bank_a, 19+3, cpu.SDWAM[n].U);
 257                 SETL1 (bank_a, 20+3, cpu.SDWAM[n].G);
 258                 SETL (bank_a, 22+3, cpu.SDWAM[n].EB, 14);
 259               }
 260           }
 261           break;
 262 
 263         //   7 "DESCRIPTOR REGISTER BANK-ADDRESS 2 -- LAST SDW FETCHED FROM STORE"
 264         case 6:
 265           {
 266             if (cpu.APU_panel_scroll_select_ul_sw)
 267               { // Upper
 268                 // 0:23 ADDRESS
 269                 // 24:26 R1
 270                 // 27:29 R2
 271                 // 30:32 R3
 272                 SETL (bank_a, 0+3, cpu.SDW0.ADDR, 24);
 273                 SETL (bank_a, 24+3, cpu.SDW0.R1, 3);
 274                 SETL (bank_a, 27+3, cpu.SDW0.R2, 3);
 275                 SETL (bank_a, 30+3, cpu.SDW0.R2, 3);
 276               }
 277             else
 278               { // Lower
 279                 // 1:14 SEGMENT BOUNDARY
 280                 // 15 READ
 281                 // 16 EXEC
 282                 // 17 WRITE
 283                 // 18 PRIV
 284                 // 19 UNPG
 285                 // 20 GATE
 286                 // 22:35 CALL LIMITER
 287                 SETL (bank_a, 1+3, cpu.SDW0.BOUND, 14);
 288                 SETL1 (bank_a, 15+3, cpu.SDW0.R);
 289                 SETL1 (bank_a, 16+3, cpu.SDW0.E);
 290                 SETL1 (bank_a, 17+3, cpu.SDW0.W);
 291                 SETL1 (bank_a, 18+3, cpu.SDW0.P);
 292                 SETL1 (bank_a, 19+3, cpu.SDW0.U);
 293                 SETL1 (bank_a, 20+3, cpu.SDW0.G);
 294                 SETL (bank_a, 22+3, cpu.SDW0.EB, 14);
 295               }
 296           }
 297           break;
 298 
 299         //   8 "APU DATA OUT BUS"
 300         // XXX No idea; put address and finalAddress in the display.
 301         case 7:
 302           {
 303             if (cpu.APU_panel_scroll_select_ul_sw)
 304               { // Upper
 305                 // XXX No idea; guess offset
 306                 // XXX 0-17 offset
 307                 SETL (bank_a, 0+3, cpu.APUDataBusOffset, 18);
 308                 // XXX 18-35 no idea
 309               }
 310             else
 311               { // Lower
 312                 // XXX No idea; guess final address
 313                 // XXX 0-35 final address
 314                 SETL (bank_a, 0+3, cpu.APUDataBusAddr, 24);
 315               }
 316           }
 317           break;
 318 
 319         //   9 "ACCESS VIOLATION FAULT REGISTER"
 320         case 8:
 321           {
 322             if (cpu.APU_panel_scroll_select_ul_sw)
 323               { // Upper
 324                 // 0:23 APU MEMORY ADDRESS REGISTER // XXX Guessing with APUMemAdr
 325                 // 33:35 RALR
 326                 SETL (bank_a, 0+3, cpu.APUMemAddr, 24);
 327                 SETL (bank_a, 24+3, cpu.rRALR, 3);
 328               }
 329             else
 330               { // Lower
 331                 // 0:15 IRO -- OOSB
 332                 // 18:28 APU OP CODE REGISTER
 333                 // XXX Guessing that IRO--OOSB  is the fault set generated
 334                 // XXX by the APU; saved in acvFaults
 335                 word16 flts = (word16) cpu.acvFaults;
 336                 SETL (bank_a, 3+3, flts, 16);
 337                 // XXX APUCycleBits is 12 bits, only 11 are on the display.
 338                 // XXX Ignoring the high bit (PI_AP)
 339                 word11 cyc = (cpu.cu.APUCycleBits >> 3) & MASK11;
 340                 SETL (bank_a, 18+3, cyc, 11);
 341               }
 342           }
 343           break;
 344 
 345         //  10 "POINTER REGISTER N (N=0-7)"
 346         case 9:
 347           {
 348             if (cpu.APU_panel_scroll_select_ul_sw)
 349               { // Upper
 350                 // 3:17 SEGMENT NUMBER
 351                 // 18:20 RING
 352                 // 33:35 RING HOLD
 353                 n &= 7;
 354                 SETL (bank_a, 3+3, cpu.PAR[n].SNR, 15);
 355                 SETL (bank_a, 18+3, cpu.PAR[n].RNR, 3);
 356                 SETL (bank_a, 33+3, cpu.RSDWH_R1, 3);
 357               }
 358             else
 359               { // Lower
 360                 // 0 !FLT
 361                 // 1:2 DIR-FLT#
 362                 // 3: ACV
 363 
 364                 // XXX Assuming '!F' refers to the DF bit in the working SDW. It may refer to
 365                 // the DF bit in the match trap.
 366                 SETL1 (bank_a, 0+3, cpu.SDW0.DF);
 367                 SETL (bank_a, 1+3, cpu.SDW0.FC, 2);
 368 
 369                 // XXX Guessing that ACV is the fault set generated by the APU; saved in acvFaults
 370                 word16 flts = (word16) cpu.acvFaults;
 371                 SETL (bank_a, 3+3, flts, 16);
 372                 SETL (bank_a, 30+3, cpu.TPR.TBR, 6);
 373               }
 374           }
 375           break;
 376 
 377         //  11 "STORE CONTROL UNIT-PAIR 1"
 378         case 10:
 379           {
 380             if (cpu.APU_panel_scroll_select_ul_sw)
 381               { // Upper
 382                 // 0:35 CU word 0
 383                 SETL (bank_a, 0+3, cpu.PPR.PRR, 3);
 384                 SETL (bank_a, 3+3, cpu.PPR.PSR, 15);
 385                 SETL1 (bank_a, 18+3, cpu.PPR.P);
 386                 SETL1 (bank_a, 19+3, cpu.cu.XSF);
 387                 SETL1 (bank_a, 20+3, cpu.cu.SDWAMM);
 388                 SETL1 (bank_a, 21+3, cpu.cu.SD_ON);
 389                 SETL1 (bank_a, 22+3, cpu.cu.PTWAMM);
 390                 SETL1 (bank_a, 23+3, cpu.cu.PT_ON);
 391                 SETL (bank_a, 24+3, cpu.cu.APUCycleBits, 12);
 392               }
 393             else
 394               { // Lower
 395                 // 0:35 CU word 1
 396                 SETL1 (bank_a,  0+3, cpu.cu.IRO_ISN);
 397                 SETL1 (bank_a,  1+3, cpu.cu.OEB_IOC);
 398                 SETL1 (bank_a,  2+3, cpu.cu.EOFF_IAIM);
 399                 SETL1 (bank_a,  3+3, cpu.cu.ORB_ISP);
 400                 SETL1 (bank_a,  4+3, cpu.cu.ROFF_IPR);
 401                 SETL1 (bank_a,  5+3, cpu.cu.OWB_NEA);
 402                 SETL1 (bank_a,  6+3, cpu.cu.WOFF_OOB);
 403                 SETL1 (bank_a,  7+3, cpu.cu.NO_GA);
 404                 SETL1 (bank_a,  8+3, cpu.cu.OCB);
 405                 SETL1 (bank_a,  9+3, cpu.cu.OCALL);
 406                 SETL1 (bank_a, 10+3, cpu.cu.BOC);
 407                 SETL1 (bank_a, 11+3, cpu.cu.PTWAM_ER);
 408                 SETL1 (bank_a, 12+3, cpu.cu.CRT);
 409                 SETL1 (bank_a, 13+3, cpu.cu.RALR);
 410                 SETL1 (bank_a, 14+3, cpu.cu.SDWAM_ER);
 411                 SETL1 (bank_a, 15+3, cpu.cu.OOSB);
 412                 SETL1 (bank_a, 16+3, cpu.cu.PARU);
 413                 SETL1 (bank_a, 17+3, cpu.cu.PARL);
 414                 SETL1 (bank_a, 18+3, cpu.cu.ONC1);
 415                 SETL1 (bank_a, 19+3, cpu.cu.ONC2);
 416                 SETL (bank_a, 20+3, cpu.cu.IA, 4);
 417                 SETL (bank_a, 24+3, cpu.cu.IACHN, 3);
 418                 SETL (bank_a, 27+3, cpu.cu.CNCHN, 3);
 419                 SETL (bank_a, 30+3, cpu.cu.FI_ADDR, 5);
 420                 word1 fi = cpu.cycle == INTERRUPT_cycle ? 0 : 1;
 421                 SETL1 (bank_a, 35+3, fi);
 422               }
 423           }
 424           break;
 425 
 426         //  12 "STORE CONTROL UNIT-PAIR 2"
 427         case 11:
 428           {
 429             if (cpu.APU_panel_scroll_select_ul_sw)
 430               { // Upper
 431                 // 0:35 CU word 2
 432                 SETL (bank_a,  0+3,  cpu.TPR.TRR, 3);
 433                 SETL (bank_a,  3+3, cpu.TPR.TSR, 15);
 434                 SETL (bank_a, 27+3, (word3) cpu.switches.cpu_num, 3);
 435                 SETL (bank_a, 30+3, cpu.cu.delta, 6);
 436               }
 437             else
 438               { // Lower
 439                 // 0:35 CU word 3
 440                 //SETL (bank_a, 18+3, cpu.cu.TSN_PRNO [0], 3);
 441                 //SETL (bank_a, 21+3, cpu.cu.TSN_VALID [0], 1);
 442                 //SETL (bank_a, 22+3, cpu.cu.TSN_PRNO [1], 3);
 443                 //SETL (bank_a, 25+3, cpu.cu.TSN_VALID [1], 1);
 444                 //SETL (bank_a, 26+3, cpu.cu.TSN_PRNO [2], 3);
 445                 //SETL (bank_a, 29+3, cpu.cu.TSN_VALID [3], 1);
 446                 SETL (bank_a, 30+3, cpu.TPR.TBR, 6);
 447 
 448               }
 449           }
 450           break;
 451 
 452         //  13 "STORE CONTROL UNIT-PAIR 3 (UPPER DOES NOT DISPLAY)"
 453         case 12:
 454           {
 455             if (cpu.APU_panel_scroll_select_ul_sw)
 456               { // Upper
 457                 // 0:35 CU word 4
 458               }
 459             else
 460               { // Lower
 461                 // 0:35 CU word 5
 462                 SETL (bank_a,  0+3, cpu.TPR.CA, 18);
 463                 SETL1 (bank_a, 18+3, cpu.cu.repeat_first);
 464                 SETL1 (bank_a, 19+3, cpu.cu.rpt);
 465                 SETL1 (bank_a, 20+3, cpu.cu.rd);
 466                 SETL1 (bank_a, 21+3, cpu.cu.rl);
 467                 SETL1 (bank_a, 22+3, cpu.cu.pot);
 468                 // 23, 1 PON Prepare operand no tally // XXX Missing
 469                 SETL1 (bank_a, 24+3, cpu.cu.xde);
 470                 SETL1 (bank_a, 25+3, cpu.cu.xdo);
 471                 // 26, 1 ITP Execute ITP indirect cycle // XXX Missing
 472                 SETL1 (bank_a, 27+3, cpu.cu.rfi);
 473                 // 28, 1 ITS Execute ITS indirect cycle // XXX Missing
 474                 SETL1 (bank_a, 29+3, cpu.cu.FIF);
 475                 SETL (bank_a, 30+3, cpu.cu.CT_HOLD, 6);
 476               }
 477           }
 478           break;
 479 
 480         //  14 "STORE CONTROL UNIT-PAIR 4"
 481 // Jeff 1Feb17 "However, the APU SCROLL does not have a wire on the 14
 482 // position, so 14 is going to show 15 instead of 13."
 483         //case 13:
 484         case 15:
 485           {
 486             if (cpu.APU_panel_scroll_select_ul_sw)
 487               { // Upper
 488                 // 0:35 CU word 6
 489                 SETL (bank_a,  0+3, cpu.cu.IWB, 36);
 490               }
 491             else
 492               { // Lower
 493                 // 0:35 CU word 7
 494                 SETL (bank_a,  0+3, cpu.cu.IRODD, 36);
 495               }
 496           }
 497           break;
 498 
 499         default:
 500           {
 501             time_t t = time (NULL);
 502             SETL (bank_a, 0+3, (word36) t, 36);
 503           }
 504           break;
 505       }
 506   }
 507 
 508 static void update_cpts (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 509   {
 510     // switch ()
 511     // XXX
 512     switch (cpu.CP_panel_wheel_sw)
 513       {
 514         case 0:
 515           SETLA (bank_b, 0+3, cpu.cpt [0], 36);
 516           SETLA (bank_c, 0+3, cpu.cpt [1], 36);
 517           break;
 518         case 1:
 519           SETLA (bank_b, 0+3, cpu.cpt [2], 36);
 520           SETLA (bank_c, 0+3, cpu.cpt [3], 36);
 521           break;
 522         case 2:
 523           SETLA (bank_b, 0+3, cpu.cpt [4], 36);
 524           SETLA (bank_c, 0+3, cpu.cpt [5], 36);
 525           break;
 526         case 3:
 527           SETLA (bank_b, 0+3, cpu.cpt [6], 36);
 528           SETLA (bank_c, 0+3, cpu.cpt [7], 36);
 529           break;
 530         case 4:
 531           SETLA (bank_b, 0+3, cpu.cpt [8], 36);
 532           SETLA (bank_c, 0+3, cpu.cpt [9], 36);
 533           break;
 534         case 5:
 535           SETLA (bank_b, 0+3, cpu.cpt [10], 36);
 536           SETLA (bank_c, 0+3, cpu.cpt [11], 36);
 537           break;
 538         case 6:
 539           SETLA (bank_b, 0+3, cpu.cpt [12], 36);
 540           SETLA (bank_c, 0+3, cpu.cpt [13], 36);
 541           break;
 542         case 7:
 543           SETLA (bank_b, 0+3, cpu.cpt [14], 36);
 544           SETLA (bank_c, 0+3, cpu.cpt [15], 36);
 545           break;
 546         case 8:
 547           SETLA (bank_b, 0+3, cpu.cpt [16], 36);
 548           SETLA (bank_c, 0+3, cpu.cpt [17], 36);
 549           break;
 550         case 9:
 551           SETLA (bank_b, 0+3, cpu.cpt [18], 36);
 552           SETLA (bank_c, 0+3, cpu.cpt [19], 36);
 553           break;
 554         case 10:
 555           SETLA (bank_b, 0+3, cpu.cpt [20], 36);
 556           SETLA (bank_c, 0+3, cpu.cpt [21], 36);
 557           break;
 558         case 11:
 559           SETLA (bank_b, 0+3, cpu.cpt [22], 36);
 560           SETLA (bank_c, 0+3, cpu.cpt [23], 36);
 561           break;
 562         case 12:
 563           SETLA (bank_b, 0+3, cpu.cpt [24], 36);
 564           SETLA (bank_c, 0+3, cpu.cpt [25], 36);
 565           break;
 566         case 13:
 567           SETLA (bank_b, 0+3, cpu.cpt [26], 36);
 568           SETLA (bank_c, 0+3, cpu.cpt [27], 36);
 569           break;
 570       }
 571     //SETL (bank_b, 0, cpu.rA, 36);
 572     SETL1 (bank_b, 36+3, cpu.panel4_red_ready_light_state);
 573     //SETL (bank_c, 0, cpu.rA, 36);
 574     SETL1 (bank_c, 36+3, cpu.panel7_enabled_light_state);
 575   }
 576 
 577 static void update_data_1 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 578   {
 579     // XXX No idea what data is supposed to be displayed; displaying the address and data.
 580     SETL (bank_d, 0+3, cpu.portAddr [cpu.DATA_panel_d1_sw], 24);
 581     SETL (bank_e, 0+3, cpu.portData [cpu.DATA_panel_d1_sw], 36);
 582   }
 583 
 584 static void update_data_2 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 585   {
 586     // BAR/ADR0    ADR1   ADR2   ADR3   ADR4   ADR5   ADR6   ADR7   CACHE
 587     // XXX No idea
 588     // XXX BAR No idea
 589     // CACHE No idea
 590     // XXX PAR registers?
 591     // XXX upper: PR
 592     //   0- 5: BITNO
 593     //   6-17: SNR
 594     //  18-35: WORDNO
 595     // XXX lower:
 596     //   0-17: WORDNO
 597     //  18-19: CHAR
 598     //  20-23: BITNO
 599     //
 600     SETL (bank_d, 0+3, cpu.PAR[cpu.DATA_panel_d2_sw].PR_BITNO, 6);
 601     SETL (bank_d, 6+3, cpu.PAR[cpu.DATA_panel_d2_sw].SNR, 15);
 602     SETL (bank_d, 18+3, cpu.PAR[cpu.DATA_panel_d2_sw].WORDNO, 18);
 603 
 604     SETL (bank_e, 0+3, cpu.PAR[cpu.DATA_panel_d2_sw].WORDNO, 18);
 605     SETL (bank_e, 18+3, cpu.PAR[cpu.DATA_panel_d2_sw].AR_CHAR, 2);
 606     SETL (bank_e, 20+3, cpu.PAR[cpu.DATA_panel_d2_sw].AR_BITNO, 4);
 607   }
 608 
 609 static void update_data_3 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 610   {
 611     // PTR/LEN1    PTR/LEN2   PTR/LEN2   ZX/LEN   ZER/ZGR   EA2   ERR/TIMER   SCR/LVL   IBICT   TALLY
 612     // Decimal unit data.
 613     switch (cpu.DATA_panel_d3_sw)
 614       {
 615         case 0: // PTR_LEN 1
 616           // 1U
 617           // XXX Guessing CU PTR 1
 618           // XXX 0-18 D1_PTR_W
 619           SETL (bank_d, 0+3, cpu.du.D1_PTR_W, 18);
 620           // XXX 18-35 probably D1_PTR_B, not tracked.
 621           // 1L
 622           // XXX No idea, probably LEVEL and D1_RES, which are not tracked
 623           break;
 624         case 1: // PTR_LEN 2
 625           // 2U
 626           // XXX Guessing CU PTR 2
 627           // XXX 0-18 D2_PTR_W
 628           SETL (bank_d, 0+3, cpu.du.D2_PTR_W, 18);
 629           // XXX 18-35 probably D2_PTR_B, not tracked.
 630           // 2L
 631           // XXX No idea, probably LEVEL and D2_RES, which are not tracked
 632           break;
 633         case 2: // PTR_LEN 3
 634           // 3U
 635           // XXX Guessing CU PTR 3
 636           // XXX 0-18 D3_PTR_W
 637           SETL (bank_d, 0+3, cpu.du.D3_PTR_W, 18);
 638           // XXX 18-35 probably D3_PTR_B, not tracked.
 639           // 3L
 640           // XXX No idea, probably LEVEL and D1_RES, which are not tracked
 641           break;
 642         case 3: // ZX/LEN
 643           // XXX No idea
 644           break;
 645         case 4: // ZER/ZGR
 646           // XXX No idea
 647           break;
 648         case 5: // EA2
 649           // XXX No idea
 650           break;
 651         case 6: // ERR/TIMER
 652           // XXX 6U No idea
 653           // XXX 6L Guessing RT
 654           SETL (bank_e, 0+3, cpu.rTR, 27);
 655           break;
 656         case 7: // SCR/LVL
 657           // XXX No idea
 658           break;
 659         case 8: // IBICT
 660           // XXX No idea Ins. Buffer IC Tracker?
 661           // XXX Guess U IBW_IRODD, L IC
 662           SETL (bank_d, 0+3, IWB_IRODD, 36);
 663           SETL (bank_e, 0+3, cpu.PPR.IC, 18);
 664           break;
 665         case 9: // TALLY
 666           // XXX No idea; addrmod TALLY? DU CHTALLY?
 667           SETL (bank_e, 0+3, cpu.AM_tally, 12);
 668           break;
 669       }
 670   }
 671 
 672 static void update_data_4 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 673   {
 674     // XXX No idea
 675   }
 676 
 677 static void update_data_5 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 678   {
 679     switch (cpu.DATA_panel_d3_sw)
 680       {
 681         case 0: // ZUPK
 682           // XXX No idea
 683           break;
 684         case 1: // RALN
 685           // XXX No idea
 686           break;
 687         case 2: // ZALN
 688           // XXX No idea
 689           break;
 690         case 3: // ZBLN
 691           // XXX No idea
 692           break;
 693         case 4: // ZPKS
 694           // XXX No idea
 695           break;
 696         case 5: // R1WRT
 697           // XXX No idea
 698           break;
 699         case 6: // R2WRT
 700           // XXX No idea
 701           break;
 702         case 7: // CH-TALLY
 703           SETL (bank_d, 0+3, cpu.du.CHTALLY, 24);
 704           break;
 705         case 8: // ZAS
 706           // XXX No idea
 707           break;
 708       }
 709   }
 710 
 711 static void update_data_6 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 712   {
 713     // XXX No idea
 714   }
 715 
 716 static void update_data_7 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 717   {
 718     // XXX No idea
 719   }
 720 
 721 static void update_data_scroll (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 722   {
 723     switch (cpu.DATA_panel_wheel_sw)
 724       {
 725         case 0: // 1 AQ
 726           {
 727             SETL (bank_d, 0+3, cpu.rA, 36);
 728             SETL (bank_e, 0+3, cpu.rQ, 36);
 729           }
 730           break;
 731 
 732         case 1: // 2 X0/X1/X2/X3
 733           {
 734             SETL (bank_d, 0+3, cpu.rX[0], 18);
 735             SETL (bank_d, 18+3, cpu.rX[1], 18);
 736             SETL (bank_e, 0+3, cpu.rX[2], 18);
 737             SETL (bank_e, 18+3, cpu.rX[3], 18);
 738           }
 739           break;
 740 
 741         case 2: // 3 X4/X5/X6/X7
 742           {
 743             SETL (bank_d, 0+3, cpu.rX[4], 18);
 744             SETL (bank_d, 18+3, cpu.rX[5], 18);
 745             SETL (bank_e, 0+3, cpu.rX[6], 18);
 746             SETL (bank_e, 18+3, cpu.rX[7], 18);
 747           }
 748           break;
 749 
 750         case 3: // 4 EAQ
 751           {
 752             SETL (bank_d, 0+3, cpu.rE, 8);
 753             SETL (bank_d, 8+3, cpu.rA >> 8, 36 - 8);
 754             SETL (bank_e, 0+3, cpu.rA, 8);
 755             SETL (bank_e, 0+3, cpu.rQ >> 8, 36 - 8);
 756           }
 757           break;
 758 
 759         case 4: // 5 EA
 760           {
 761             // XXX Guessing rE
 762             SETL (bank_d, 0+3, cpu.rE, 8);
 763           }
 764           break;
 765 
 766         case 5: // 6 RACT
 767           {
 768             // XXX No idea
 769           }
 770           break;
 771 
 772         case 6: // 7
 773           {
 774             // The contents of the APU history register
 775 //printf ("%u\n", cpu.DATA_panel_hr_sel_sw);
 776             SETL (bank_d, 0+3, cpu.history[L68_APU_HIST_REG][cpu.DATA_panel_hr_sel_sw][0], 36);
 777             SETL (bank_e, 0+3, cpu.history[L68_APU_HIST_REG][cpu.DATA_panel_hr_sel_sw][1], 36);
 778 
 779 
 780 
 781 
 782 
 783 
 784 
 785 
 786 
 787 
 788 
 789 
 790 
 791 
 792 
 793 
 794 
 795 
 796 
 797 
 798 
 799 
 800 
 801 
 802 
 803 
 804 
 805 
 806 
 807 
 808 
 809 
 810 
 811 
 812 
 813 
 814 
 815 
 816 
 817 
 818 
 819 
 820 
 821           }
 822           break;
 823 
 824         case 7: // 8
 825           {
 826             // 8U Empty
 827             // 8L 0:35 DIRECT BUFFER XXX GUess directOperand
 828             SETL (bank_e, 0+3, cpu.ou.directOperand, 36);
 829 
 830           }
 831           break;
 832 
 833         case 8: // 9
 834           {
 835             // 9U 0:31 High 32 bits of the FAULT REGISTER
 836             SETL (bank_d, 0+3, cpu.faultRegister [0] & 0777777777760LLU, 36);
 837             // 9L Empty
 838           }
 839           break;
 840 
 841         case 9: // 10
 842           {
 843             // XXX The upper and lower are the same thing?
 844             SETL (bank_d, 0+3, cpu.MR.r, 36);
 845             memcpy (bank_e, bank_d, sizeof (bank_e));
 846           }
 847           break;
 848 
 849         case 10: // 11
 850           {
 851             // The contents of the CU history register
 852             SETL (bank_d, 0+3, cpu.history[CU_HIST_REG][cpu.DATA_panel_hr_sel_sw][0], 36);
 853             SETL (bank_e, 0+3, cpu.history[CU_HIST_REG][cpu.DATA_panel_hr_sel_sw][1], 36);
 854           }
 855           break;
 856 
 857         case 11: // 12
 858           {
 859             // The contents of the OU history register
 860             SETL (bank_d, 0+3, cpu.history[L68_OU_HIST_REG][cpu.DATA_panel_hr_sel_sw][0], 36);
 861             SETL (bank_e, 0+3, cpu.history[L68_OU_HIST_REG][cpu.DATA_panel_hr_sel_sw][1], 36);
 862           }
 863           break;
 864 
 865         case 12: // 13
 866           {
 867             // The contents of the DU history register
 868             SETL (bank_d, 0+3, cpu.history[L68_DU_HIST_REG][cpu.DATA_panel_hr_sel_sw][0], 36);
 869             SETL (bank_e, 0+3, cpu.history[L68_DU_HIST_REG][cpu.DATA_panel_hr_sel_sw][1], 36);
 870           }
 871           break;
 872 
 873         case 13: // 14
 874           {
 875 
 876             SETL (bank_d, 0+3, cpu.cu.IWB, 36);
 877             SETL (bank_e, 0+3, cpu.cu.IRODD, 36);
 878           }
 879           break;
 880       }
 881   }
 882 
 883 static void update_data (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 884   {
 885     switch (cpu.DATA_panel_ds_sw)
 886       {
 887         case 0: // #1
 888           update_data_1 ();
 889           break;
 890         case 1: // #2
 891           update_data_2 ();
 892           break;
 893         case 2: // #3
 894           update_data_3 ();
 895           break;
 896         case 3: // SCROLL
 897           update_data_scroll ();
 898           break;
 899         case 4: // #4
 900           update_data_4 ();
 901           break;
 902         case 5: // #5
 903           update_data_5 ();
 904           break;
 905         case 6: // #6
 906           update_data_6 ();
 907           break;
 908         case 7: // #7
 909           update_data_7 ();
 910           break;
 911         default:
 912           break;
 913       }
 914   }
 915 
 916 static void update_display (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 917   {
 918     SETL (bank_f, 0, cpu.cu.IR, 18);
 919     SETL (bank_f, 18, cpu.history_cyclic [0], 4);
 920     SETL (bank_f, 22, cpu.history_cyclic [1], 4);
 921     SETL (bank_f, 26, cpu.history_cyclic [2], 4);
 922     SETL (bank_f, 30, cpu.history_cyclic [3], 4);
 923     SETL (bank_g,  0, cpu.PPR.IC, 18);
 924 
 925     // XXX Simplifying assumption: 4 * 4MW SCUS, ports DEFG idle.
 926     SETL (bank_g, 18, cpu.portSelect == 0 ? 1 : 0, 1);
 927     SETL (bank_g, 19, cpu.portSelect == 1 ? 1 : 0, 1);
 928     SETL (bank_g, 20, cpu.portSelect == 2 ? 1 : 0, 1);
 929     SETL (bank_g, 21, cpu.portSelect == 3 ? 1 : 0, 1);
 930 
 931     // XXX OU/DU/CU/APU ST/LD no idea
 932 
 933     // XXX EXC INT Guess execute interrupt
 934     bool exc_int = cpu.cycle == INTERRUPT_cycle ||
 935                    cpu.cycle == INTERRUPT_EXEC_cycle /*||
 936                    cpu.cycle == INTERRUPT_EXEC2_cycle*/;
 937     SETL (bank_g, 34, exc_int ? 1 : 0, 1);
 938 
 939     // XXX INS FCH Guess instruction fetch
 940     bool ins_fch = cpu.cycle == INTERRUPT_cycle ||
 941                    cpu.cycle == FAULT_cycle ||
 942                    cpu.cycle == FETCH_cycle;
 943     SETL (bank_g, 35, ins_fch ? 1 : 0, 1);
 944 
 945     // XXX DIR BUF no idea. DIRECT OPERAND?
 946 
 947     // XXX RSW 1/2 no idea. y from the last RSW instruction?
 948 
 949     // XXX MP CYL no idea.
 950 
 951     SETL (bank_h, 3, cpu.cu.IWB, 36);
 952 
 953     // XXX Guess: showing EIS descriptor #1
 954     SETL (bank_i, 3, cpu.IWRAddr, 36);
 955 
 956     // XXX Guess: IWR ADDR is CA
 957     SETL (bank_j, 3, cpu.PPR.IC, 18);
 958 
 959 // prepare_state is PIA POA         RIW SIW POT PON RAW SAW
 960 // display is       PIA POA POL POP RIW SIW POT PON RAW SAW
 961     word2 pia_poa = cpu.prepare_state >> 6;
 962     SETL (bank_j, 21, pia_poa, 2);
 963     SETL (bank_j, 23, cpu.du.POL, 2);
 964     SETL (bank_j, 24, cpu.du.POP, 1);
 965     SETL (bank_j, 25, cpu.prepare_state, 6);
 966 
 967     SETL (bank_j, 31, cpu.wasXfer, 1);
 968     SETL (bank_j, 32, cpu.cu.xde, 1);
 969     SETL (bank_j, 33, cpu.cu.xdo, 1);
 970     SETL1 (bank_j, 34, USE_IRODD);
 971     SETL (bank_j, 35, cpu.cu.rpt, 1);
 972     SETL (bank_j, 36, cpu.cu.rl, 1);
 973     SETL (bank_j, 37, cpu.cu.rd, 1);
 974     // XXX M/S Master/Slave (BAR)?
 975     SETL (bank_j, 38, TSTF (cpu.cu.IR, I_NBAR), 1);
 976 
 977     // XXX Looks like EIS state data
 978     // XXX D1 Descriptor #1, SEL DMA DMB FRS A/1 RD1 no idea
 979     // XXX D1 Descriptor #2, SEL DMA DMB FRS A/1 RD1 no idea
 980     // XXX D1 Descriptor #3, SEL DMA DMB FRS A/1 RD1 no idea
 981     SETL (bank_k, 21, cpu.dataMode, 7);
 982     // XXX CTA CTB CT1 CTL no idea
 983     // XXX L<W pg 60 '-DLVL>WD-SZ load with count less than word size'
 984     // XXX EXH Exhaust tally/count
 985     // XXX EXR IDR RD END
 986 
 987     // 0:17 CA
 988     // ZONE XXX no idea
 989     // COMMAND XXX no idea
 990     // ZAC/PAR XXX no idea
 991     SETL (bank_l,  3, cpu.TPR.CA, 18);
 992 
 993     SETL (bank_m, 3, cpu.ou.RS, 9);
 994     SETL (bank_m, 12, cpu.ou.characterOperandSize ? 1 : 0, 1);
 995     SETL (bank_m, 13, cpu.ou.characterOperandOffset & MASK3, 3);
 996     SETL (bank_m, 16, cpu.ou.crflag, 1);
 997     SETL (bank_m, 17, cpu.ou.directOperandFlag ? 1 : 0, 1);
 998     SETL (bank_m, 18, cpu.ou.RS, 9);
 999     SETL (bank_m, 27, cpu.ou.cycle, 9);
1000     SETL (bank_m, 36, cpu.ou.RB1_FULL, 1);
1001     SETL (bank_m, 37, cpu.ou.RP_FULL, 1);
1002     SETL (bank_m, 38, cpu.ou.RS_FULL, 1);
1003 
1004     //    Label OU Hist
1005     //  0 FDUD  FDUD     Decimal Unit Idle
1006     SETL1 (bank_n, 3, cpu.du.cycle2 & du2_DUD);
1007     //  1 GDLD
1008     //  2 GLP1
1009     //  3 GLP2
1010     //  4 GEA1  FA/Il Descriptor l active
1011     SETL1 (bank_n, 7, cpu.du.cycle1 & du1_FA_I1);
1012     //  5 GEM1
1013     //  6 GED1
1014     //  7 GDB   DGDB Decimal to binary execution gate
1015     SETL1 (bank_n, 10, cpu.du.cycle2 & du2_DGDB);
1016     //  8 GBD   DGBD Binary to decimal execution gate
1017     SETL1 (bank_n, 11, cpu.du.cycle2 & du2_DGBD);
1018     //  9 GSP
1019     // 10 GED2
1020     // 11 GEA2  FA/I2 Descriptor 2 active
1021     SETL1 (bank_n, 14, cpu.du.cycle1 & du1_FA_I2);
1022     // 12 GADD
1023     // 13 GCMP
1024     // 14 GMSY
1025     // 15 GMA
1026     // 16 GMS
1027     // 17 GQDF
1028     // 18 GQPA
1029     // 19 GQR1
1030     // 20 GQR2
1031     // 21 GRC
1032     // 22 GRND
1033     // 23 GCLZ
1034     // 24 GEDJ
1035     // 25 GEA3  FA/I3 Descriptor 3 active
1036     SETL1 (bank_n, 28, cpu.du.cycle1 & du1_FA_I3);
1037     // 26 GEAM
1038     // 27 GEDC
1039     // 28 GSTR  GSTR Numeric store gate
1040     SETL1 (bank_n, 31, cpu.du.cycle2 & du2_GSTR);
1041     // 29 GSDR
1042     // 30 NSTR  ANSTR Alphanumeric store gate
1043     SETL1 (bank_n, 32, cpu.du.cycle2 & du2_ANSTR);
1044     // 31 SDUD
1045     // 32 ?
1046     // 33 ?
1047     // 34 ?
1048     // 35 FLTG
1049     // 36 FRND  FRND Rounding flag
1050     SETL1 (bank_n, 39, cpu.du.cycle2 & du2_FRND);
1051 
1052     //  0 ALD1  ANLD1 Alphanumeric operand one load gate
1053     SETL1 (bank_o, 3, cpu.du.cycle2 & du2_ANLD1);
1054     //  1 ALD2  ANLD2 Alphanumeric operand one load gate
1055     SETL1 (bank_o, 4, cpu.du.cycle2 & du2_ANLD2);
1056     //  2 NLD1  GLDP1 Numeric operand one load gate
1057     SETL1 (bank_o, 5, cpu.du.cycle2 & du2_NLD1);
1058     //  3 NLD2  GLDP2 Numeric operand one load gate
1059     SETL1 (bank_o, 6, cpu.du.cycle2 & du2_NLD2);
1060     //  4 LWT1  LDWRT1 Load rewrite register one gate
1061     SETL1 (bank_o, 7, cpu.du.cycle2 & du2_LDWRT1);
1062     //  5 LWT2  LDWRT2 Load rewrite register two gate
1063     SETL1 (bank_o, 8, cpu.du.cycle2 & du2_LDWRT2);
1064     //  6 ASTR
1065     //  7 ANPK
1066     //  8 FGCH
1067     //  9 XMOP  FEXMOP Execute MOP gate
1068     SETL1 (bank_o, 12, cpu.du.cycle2 & du2_FEXOP);
1069     // 10 BLNK  FBLNK Blanking gate
1070     SETL1 (bank_o, 13, cpu.du.cycle2 & du2_FBLNK);
1071     // 11 ?
1072     // 12 ?
1073     // 13 CS=0
1074     // 14 CU=0
1075     // 15 FI=0
1076     // 16 CU=V
1077     // 17 UM<V
1078     // 18 ?
1079     // 19 ?
1080     // 20 ?
1081     // 21 ?
1082     // 22 ?
1083     // 23 ?
1084     // 24 ?
1085     // 25 ?
1086     // 26 ?
1087     // 27 ?
1088     // 28 L<128  -FLEN<128 Length less than 128
1089     SETL1 (bank_o, 31, !(cpu.du.cycle2 & du2_nFLEN_128));
1090     // 29 END SEQ  -FEND-SEQ End sequence flag
1091     SETL1 (bank_o, 32, !(cpu.du.cycle2 & du2_nFEND_SEQ));
1092     // 30 ?
1093     // 31 ?
1094     // 32 ?
1095     // 33 ?
1096     // 34 ?
1097     // 35 ?
1098     // 36 ?
1099 
1100     SETL (bank_p, 3, cpu.apu.state, 34);
1101 
1102     // XXX No idea
1103   }
1104 
1105 #define Z(z) memset (z, 0, sizeof (z))
1106 #define O(z) memset (z, 1, sizeof (z))
1107 
1108 #define nibble(bank, n) \
1109   '@' + \
1110   (bank [n + 0] ? 020 : 0) + \
1111   (bank [n + 1] ? 010 : 0) + \
1112   (bank [n + 2] ? 004 : 0) + \
1113   (bank [n + 3] ? 002 : 0) + \
1114   (bank [n + 4] ? 001 : 0)
1115 
1116 #define nibbles(bank) nibble (bank,  0), nibble (bank,  5), \
1117                       nibble (bank, 10), nibble (bank, 15), \
1118                       nibble (bank, 20), nibble (bank, 25), \
1119                       nibble (bank, 30), nibble (bank, 35)
1120 
1121 static void lwrite (FD fd, const void * buf, size_t count)
     /* [previous][next][first][last][top][bottom][index][help] */
1122   {
1123 #if defined(__MINGW64__) || defined(__MINGW32__)
1124     DWORD bytes_written;
1125     if(!WriteFile(fd, buf, count, &bytes_written, NULL))
1126     {
1127         fprintf(stderr, "Error\n");
1128         CloseHandle(fd);
1129         exit (1);
1130     }
1131 #else
1132     write (fd, buf, count);
1133 #endif
1134   }
1135 
1136 static void send_lamp_data (FD fd)
     /* [previous][next][first][last][top][bottom][index][help] */
1137   {
1138     char buf [129];
1139     sprintf (buf, "0%c%c%c%c%c%c%c%c\n", nibbles (bank_a));
1140     lwrite (fd, buf, 10);
1141     sprintf (buf, "1%c%c%c%c%c%c%c%c\n", nibbles (bank_b));
1142     lwrite (fd, buf, 10);
1143     sprintf (buf, "2%c%c%c%c%c%c%c%c\n", nibbles (bank_c));
1144     lwrite (fd, buf, 10);
1145     sprintf (buf, "3%c%c%c%c%c%c%c%c\n", nibbles (bank_d));
1146     lwrite (fd, buf, 10);
1147     sprintf (buf, "4%c%c%c%c%c%c%c%c\n", nibbles (bank_e));
1148     lwrite (fd, buf, 10);
1149     sprintf (buf, "5%c%c%c%c%c%c%c%c\n", nibbles (bank_f));
1150     lwrite (fd, buf, 10);
1151     sprintf (buf, "6%c%c%c%c%c%c%c%c\n", nibbles (bank_g));
1152     lwrite (fd, buf, 10);
1153     sprintf (buf, "7%c%c%c%c%c%c%c%c\n", nibbles (bank_h));
1154     lwrite (fd, buf, 10);
1155     sprintf (buf, "8%c%c%c%c%c%c%c%c\n", nibbles (bank_i));
1156     lwrite (fd, buf, 10);
1157     sprintf (buf, "9%c%c%c%c%c%c%c%c\n", nibbles (bank_j));
1158     lwrite (fd, buf, 10);
1159     sprintf (buf, ":%c%c%c%c%c%c%c%c\n", nibbles (bank_k));
1160     lwrite (fd, buf, 10);
1161     sprintf (buf, ";%c%c%c%c%c%c%c%c\n", nibbles (bank_l));
1162     lwrite (fd, buf, 10);
1163     sprintf (buf, "<%c%c%c%c%c%c%c%c\n", nibbles (bank_m));
1164     lwrite (fd, buf, 10);
1165     sprintf (buf, "=%c%c%c%c%c%c%c%c\n", nibbles (bank_n));
1166     lwrite (fd, buf, 10);
1167     sprintf (buf, ">%c%c%c%c%c%c%c%c\n", nibbles (bank_o));
1168     lwrite (fd, buf, 10);
1169     sprintf (buf, "?%c%c%c%c%c%c%c%c\n", nibbles (bank_p));
1170     lwrite (fd, buf, 10);
1171 #if defined(__MINGW64__) || defined(__MINGW32__)
1172 #else
1173     syncfs (fd);
1174 #endif
1175   }
1176 
1177 static void set_message (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1178   {
1179     int nchars = (int) strlen (message);
1180     int nbits = nchars * 8;
1181     int r, c;
1182 
1183 #define start_row 7
1184     for (r = 0; r < 0 + 8; r ++)
1185       {
1186         for (c = 0; c < ncols; c ++)
1187           {
1188             int c2 = (c + c_offset) % nbits;
1189             int char2 = c2 / 8;
1190             unsigned char fontbits = font8x8_basic [(unsigned int) message [(unsigned int) char2]] [r];
1191             int whichbit = c2 % 8;
1192             unsigned char bit1 = fontbits & (1 << (/*7 -*/ whichbit));
1193             banks [r + start_row] [c] = !!bit1;
1194 //printw ("r %d c %d c2 %d char2 %d fontbits %02x whichbit %d bit1 %02x\n", r, c, c2, char2, fontbits, whichbit, bit1);
1195           }
1196       }
1197     c_offset = (c_offset + 1) % nbits;
1198   }
1199 
1200 static int time_handler (FD fd)
     /* [previous][next][first][last][top][bottom][index][help] */
1201   {
1202     //if (cpu.DATA_panel_trackers_sw == 0) // A
1203 if (0)
1204       {
1205         int sec1 = (int) (clock () / CLOCKS_PER_SEC) & 1;
1206         if (sec1)
1207           {
1208             Z (bank_a);
1209             Z (bank_b);
1210             Z (bank_c);
1211             Z (bank_d);
1212             Z (bank_e);
1213             Z (bank_f);
1214             Z (bank_g);
1215             Z (bank_h);
1216             Z (bank_i);
1217             Z (bank_j);
1218             Z (bank_k);
1219             Z (bank_l);
1220             Z (bank_m);
1221             Z (bank_n);
1222             Z (bank_o);
1223             Z (bank_p);
1224           }
1225         else
1226           {
1227             O (bank_a);
1228             O (bank_b);
1229             O (bank_c);
1230             O (bank_d);
1231             O (bank_e);
1232             O (bank_f);
1233             O (bank_g);
1234             O (bank_h);
1235             O (bank_i);
1236             O (bank_j);
1237             O (bank_k);
1238             O (bank_l);
1239             O (bank_m);
1240             O (bank_n);
1241             O (bank_o);
1242             O (bank_p);
1243           }
1244         send_lamp_data (fd);
1245         return TRUE;
1246       }
1247 
1248     Z (bank_a);
1249     Z (bank_b);
1250     Z (bank_c);
1251     Z (bank_d);
1252     Z (bank_e);
1253     Z (bank_f);
1254     Z (bank_g);
1255     Z (bank_h);
1256     Z (bank_i);
1257     Z (bank_j);
1258     Z (bank_k);
1259     Z (bank_l);
1260     Z (bank_m);
1261     Z (bank_n);
1262     Z (bank_o);
1263     Z (bank_p);
1264 
1265     update_apu ();
1266     update_cpts ();
1267     update_data ();
1268     update_display ();
1269     if (message [0])
1270       set_message ();
1271     send_lamp_data (fd);
1272     return TRUE;
1273   }
1274 
1275 static unsigned char port_buf [9];
1276 static bool port_data [40];
1277 static int port_state = 0;
1278 
1279 static void update_port (FD port_fd)
     /* [previous][next][first][last][top][bottom][index][help] */
1280   {
1281 more:;
1282 #if !defined(__MINGW64__)
1283 # if !defined(__MINGW32__)
1284     if (poll (& (struct pollfd) { .fd = port_fd, .events = POLLIN }, 1, 0) == 1)
1285 # endif
1286 #endif
1287       {
1288         unsigned char ch;
1289 #if defined(__MINGW64__) || defined(__MINGW32__)
1290         DWORD bytes_read;
1291         ReadFile(port_fd, &ch, 1, &bytes_read, NULL);
1292         ssize_t nr = bytes_read;
1293 #else
1294         ssize_t nr = read (port_fd, & ch, 1);
1295 #endif
1296         if (nr != 1)
1297           {
1298             static int first = 1;
1299             if (first)
1300               {
1301                 perror ("read");
1302                 first = 0;
1303               }
1304             port_state = 0;
1305             return;
1306             //exit (1);
1307           }
1308 //printf ("%c", ch);
1309         if (ch & 040)
1310           {
1311             port_state = 0;
1312           }
1313         if (port_state < 0 || port_state > 8)
1314           {
1315             //exit (1);
1316             port_state = 0;
1317             return;
1318           }
1319         port_buf [port_state ++] = ch;
1320         if (port_state < 9)
1321           goto more;
1322 //printf ("\n");
1323 //printf ("got one\n");
1324 
1325         //for (int i = 0; i < 9; i ++)
1326           //printf ("%c", port_buf [i]);
1327         //printf ("\n");
1328 
1329         port_data [ 0] = !! (port_buf [1] & 020);
1330         port_data [ 1] = !! (port_buf [1] & 010);
1331         port_data [ 2] = !! (port_buf [1] & 004);
1332         port_data [ 3] = !! (port_buf [1] & 002);
1333         port_data [ 4] = !! (port_buf [1] & 001);
1334 
1335         port_data [ 5] = !! (port_buf [2] & 020);
1336         port_data [ 6] = !! (port_buf [2] & 010);
1337         port_data [ 7] = !! (port_buf [2] & 004);
1338         port_data [ 8] = !! (port_buf [2] & 002);
1339         port_data [ 9] = !! (port_buf [2] & 001);
1340 
1341         port_data [10] = !! (port_buf [3] & 020);
1342         port_data [11] = !! (port_buf [3] & 010);
1343         port_data [12] = !! (port_buf [3] & 004);
1344         port_data [13] = !! (port_buf [3] & 002);
1345         port_data [14] = !! (port_buf [3] & 001);
1346 
1347         port_data [15] = !! (port_buf [4] & 020);
1348         port_data [16] = !! (port_buf [4] & 010);
1349         port_data [17] = !! (port_buf [4] & 004);
1350         port_data [18] = !! (port_buf [4] & 002);
1351         port_data [19] = !! (port_buf [4] & 001);
1352 
1353         port_data [20] = !! (port_buf [5] & 020);
1354         port_data [21] = !! (port_buf [5] & 010);
1355         port_data [22] = !! (port_buf [5] & 004);
1356         port_data [23] = !! (port_buf [5] & 002);
1357         port_data [24] = !! (port_buf [5] & 001);
1358 
1359         port_data [25] = !! (port_buf [6] & 020);
1360         port_data [26] = !! (port_buf [6] & 010);
1361         port_data [27] = !! (port_buf [6] & 004);
1362         port_data [28] = !! (port_buf [6] & 002);
1363         port_data [29] = !! (port_buf [6] & 001);
1364 
1365         port_data [30] = !! (port_buf [7] & 020);
1366         port_data [31] = !! (port_buf [7] & 010);
1367         port_data [32] = !! (port_buf [7] & 004);
1368         port_data [33] = !! (port_buf [7] & 002);
1369         port_data [34] = !! (port_buf [7] & 001);
1370 
1371         port_data [35] = !! (port_buf [8] & 020);
1372         port_data [36] = !! (port_buf [8] & 010);
1373         port_data [37] = !! (port_buf [8] & 004);
1374         port_data [38] = !! (port_buf [8] & 002);
1375         port_data [39] = !! (port_buf [8] & 001);
1376 
1377         //for (int i = 0; i < 40; i ++)
1378           //printf ("%d", port_data [i] ? 1 : 0);
1379         //printf ("\n");
1380 
1381         port_state = 0;
1382 
1383 #define SETS(word, data, from, n) \
1384   for (uint i = 0; i < (n); i ++) \
1385     if (data [from + i]) \
1386       (word) |= 1llu << ((n) - 1 - i); \
1387     else \
1388       (word) &= ~ (1llu << ((n) - 1 - i))
1389 
1390         switch (port_buf [0])
1391           {
1392             case '0': // A
1393               SETS (cpu.APU_panel_segno_sw, port_data, 0, 15);
1394               SETS (cpu.APU_panel_enable_match_ptw_sw, port_data, 15, 1);
1395               SETS (cpu.APU_panel_enable_match_sdw_sw, port_data, 16, 1);
1396               SETS (cpu.APU_panel_scroll_select_ul_sw, port_data, 17, 1);
1397               SETS (cpu.APU_panel_scroll_select_n_sw, port_data, 18, 4);
1398               SETS (cpu.APU_panel_scroll_wheel_sw, port_data, 22, 4);
1399               break;
1400 
1401             case '1': // B
1402               SETS (cpu.switches.data_switches, port_data, 0, 36);
1403               break;
1404 
1405             case '2': // C
1406               SETS (cpu.switches.addr_switches, port_data, 0, 18);
1407               SETS (cpu.APU_panel_enter_sw, port_data, 18, 1);
1408               SETS (cpu.APU_panel_display_sw, port_data, 19, 1);
1409               SETS (cpu.panelInitialize, port_data, 20, 1);
1410               SETS (cpu.CP_panel_wheel_sw, port_data, 21, 4);
1411               break;
1412 
1413             case '3': // D
1414               SETS (cpu.DATA_panel_ds_sw, port_data, 0, 4);
1415         //for (int i = 0; i < 40; i ++)
1416           //printf ("%d", port_data [i] ? 1 : 0);
1417         //printf ("\n");
1418 //printf ("set to %d\n", cpu.DATA_panel_ds_sw);
1419               switch (cpu.DATA_panel_ds_sw)
1420                 {
1421                   case 0:
1422                     SETS (cpu.DATA_panel_d1_sw, port_data, 4, 4);
1423                     break;
1424                   case 1:
1425                     SETS (cpu.DATA_panel_d2_sw, port_data, 4, 4);
1426                     break;
1427                   case 2:
1428                     SETS (cpu.DATA_panel_d3_sw, port_data, 4, 4);
1429                     break;
1430                   case 3:
1431                     SETS (cpu.DATA_panel_wheel_sw, port_data, 4, 4);
1432                     break;
1433                   case 4:
1434                     SETS (cpu.DATA_panel_d4_sw, port_data, 4, 4);
1435                     break;
1436                   case 5:
1437                     SETS (cpu.DATA_panel_d5_sw, port_data, 4, 4);
1438                     break;
1439                   case 6:
1440                     SETS (cpu.DATA_panel_d6_sw, port_data, 4, 4);
1441                     break;
1442                   case 7:
1443                     SETS (cpu.DATA_panel_d7_sw, port_data, 4, 4);
1444                     break;
1445                 }
1446               SETS (cpu.DATA_panel_addr_stop_sw, port_data, 8, 4);
1447               SETS (cpu.DATA_panel_enable_sw, port_data, 12, 1);
1448               SETS (cpu.DATA_panel_validate_sw, port_data, 13, 1);
1449               SETS (cpu.DATA_panel_auto_fast_sw, port_data, 14, 1);
1450               SETS (cpu.DATA_panel_auto_slow_sw, port_data, 15, 1);
1451               SETS (cpu.DATA_panel_cycle_sw, port_data, 16, 3);
1452               SETS (cpu.DATA_panel_step_sw, port_data, 19, 1);
1453               SETS (cpu.DATA_panel_s_trig_sw, port_data, 20, 1);
1454               SETS (cpu.DATA_panel_execute_sw, port_data, 21, 1);
1455               SETS (cpu.DATA_panel_scope_sw, port_data, 22, 1);
1456               SETS (cpu.DATA_panel_init_sw, port_data, 23, 1);
1457               SETS (cpu.DATA_panel_exec_sw, port_data, 24, 1);
1458               SETS (cpu.DATA_panel_hr_sel_sw, port_data, 25, 4);
1459               SETS (cpu.DATA_panel_trackers_sw, port_data, 29, 4);
1460               break;
1461           }
1462         goto more;
1463       }
1464   }
1465 
1466 static volatile bool scraperRunning = false;
1467 static volatile bool scraperCancel = false;
1468 
1469 static void * scraperThreadMain (void * arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1470   {
1471     sim_printf ("panel scraper\n");
1472     uint cpuNum = (uint) * (int *) arg;
1473     panel_cpup = cpus + cpuNum;
1474 
1475     const char *device = "/dev/ttyUSB1";
1476 
1477     struct termios  config;
1478     int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
1479     if(fd == -1)
1480       {
1481         printf( "failed to open port\n" );
1482         goto die;
1483       }
1484     if(tcgetattr(fd, &config) < 0)
1485       {
1486         printf ("can't get\n");
1487         close (fd);
1488         goto die;
1489       }
1490 
1491     // Input flags - Turn off input processing
1492     //
1493     // convert break to null byte, no CR to NL translation,
1494     // no NL to CR translation, don't mark parity errors or breaks
1495     // no input parity check, don't strip high bit off,
1496     // no XON/XOFF software flow control
1497     //
1498     config.c_iflag &= ~(unsigned int) (IGNBRK | BRKINT | ICRNL |
1499                         INLCR | PARMRK | INPCK | ISTRIP | IXON);
1500 
1501     //
1502     // Output flags - Turn off output processing
1503     //
1504     // no CR to NL translation, no NL to CR-NL translation,
1505     // no NL to CR translation, no column 0 CR suppression,
1506     // no Ctrl-D suppression, no fill characters, no case mapping,
1507     // no local output processing
1508     //
1509     // config.c_oflag &= ~(OCRNL | ONLCR | ONLRET |
1510     //                     ONOCR | ONOEOT| OFILL | OLCUC | OPOST);
1511     config.c_oflag = 0;
1512 
1513     //
1514     // No line processing
1515     //
1516     // echo off, echo newline off, canonical mode off,
1517     // extended input processing off, signal chars off
1518     //
1519     config.c_lflag &= ~(unsigned int) (ECHO | ECHONL | ICANON | IEXTEN | ISIG);
1520 
1521     //
1522     // Turn off character processing
1523     //
1524     // clear current char size mask, no parity checking,
1525     // no output processing, force 8 bit input
1526     //
1527     config.c_cflag &= ~(unsigned int) (CSIZE | PARENB);
1528     config.c_cflag |= CS8;
1529 
1530     //
1531     // One input byte is enough to return from read()
1532     // Inter-character timer off
1533     //
1534     config.c_cc[VMIN]  = 1;
1535     config.c_cc[VTIME] = 0;
1536 
1537     //
1538     // Communication speed (simple version, using the predefined
1539     // constants)
1540     //
1541     if(cfsetispeed(&config, B38400) < 0 || cfsetospeed(&config, B38400) < 0)
1542       {
1543         printf ("can't set speed\n");
1544         close (fd);
1545         goto die;
1546       }
1547 
1548      //
1549      // Finally, apply the configuration
1550      //
1551      if(tcsetattr(fd, TCSAFLUSH, &config) < 0)
1552        {
1553          printf ("can't set %d\n", errno);
1554          close (fd);
1555          goto die;
1556        }
1557 
1558     while (1)
1559       {
1560         if (scraperCancel)
1561           goto die;
1562         time_handler (fd);
1563         update_port (fd);
1564         //sim_sleep (1);
1565         //sim_usleep (42000);  // 114 bytes, 11 bit serial data 38400 baud
1566         sim_usleep (80000);
1567       }
1568 
1569 die:;
1570     if (fd != -1)
1571       close (fd);
1572     fd = -1;
1573     scraperRunning = false;
1574     return NULL;
1575   }
1576 
1577 void panelScraperInit (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1578   {
1579     scraperRunning = false;
1580     scraperCancel = false;
1581   }
1582 
1583 int panelScraperStart (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1584   {
1585     if (scraperRunning)
1586       {
1587         sim_printf ("scraper already running\n");
1588         return SCPE_ARG;
1589       }
1590 
1591     scraperCancel = false;
1592 
1593     // Assume cpu 0 for now
1594     scraperThreadArg = 0;
1595 
1596     int rc = pthread_create (& scraperThread, NULL, scraperThreadMain,
1597                              & scraperThreadArg);
1598     if (rc == 0)
1599       scraperRunning = true;
1600     else
1601       {
1602         sim_printf ("pthread_create returned %d\n", rc);
1603         return SCPE_ARG;
1604       }
1605     return SCPE_OK;
1606   }
1607 
1608 int panelScraperStop (void)
     /* [previous][next][first][last][top][bottom][index][help] */
1609   {
1610     if (! scraperRunning)
1611       {
1612         sim_printf ("scraper not running\n");
1613         return SCPE_ARG;
1614       }
1615 
1616     scraperCancel = true;
1617 
1618     sim_printf ("scraper signaled\n");
1619     return SCPE_OK;
1620   }
1621 
1622 int panelScraperMsg (const char * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1623   {
1624     c_offset = 0;  // Ignore race condition; at worst it might briefly display
1625                    // wrong characters
1626     if (msg)
1627       {
1628         strncpy (message, msg, sizeof (message));
1629         message [msgLen - 1] = 0;
1630       }
1631     else
1632       message [0] = 0;
1633     return SCPE_OK;
1634   }
1635 

/* [previous][next][first][last][top][bottom][index][help] */