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

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