PiDP-8/I Software

Check-in Differences
Log In

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Difference From e6215cb721c88b57 To 7ce3553bf5f4bccd

2017-09-12
12:24
Small fix to allow tools/version to be run by Makefile when building out of tree. Also cleaned up the code a bit. check-in: c94cb7be8f user: tangent tags: trunk
2017-09-08
05:02
Added cover scan of the green-yellow 1968 edition of DEC's "Small Computer Handbook" for the PDP-8/I. check-in: e6215cb721 user: tangent tags: trunk
2017-09-05
06:30
Added a sensible-default cd $prefix/share/media to etc/pidp8i-init.in just before the "start simulator under screen" call, so that SIMH's CWD will be somewhere useful, not taking the default used by the OS's init system, which may well be something entirely unhelpful like /. check-in: 46366581f0 user: tangent tags: trunk
2016-11-21
09:33
Upstream version 20151215, containing everything from the tarball except for backups and *.o. Also, all CRLF text files converted to LF. check-in: ec36ee3dab user: tangent tags: trunk, v20151215
09:11
initial empty check-in check-in: 7ce3553bf5 user: tangent tags: trunk

Deleted .fossil-settings/binary-glob.
1
2
3
4
5
6
7
8
9
10
11
12
doc/*.jpg
doc/*.png
examples/*.pt
labels/*.pdf
media/*/*.bin
media/*/*.dsk
media/*/*.pt
media/*/*.rk05
media/*/*.tu56
pics/*/*.jpg
pics/*/*.png
schematics/*.pdf
<
<
<
<
<
<
<
<
<
<
<
<
























Deleted .fossil-settings/crlf-glob.
1
2
3
4
5
src/scp.*
src/sim_*.[ch]
src/sim_*.in
src/PDP8/pdp8_*.[ch]
src/PDP8/pidp8i.c.in
<
<
<
<
<










Deleted .fossil-settings/ignore-glob.
1
doc/simh/*.pdf
<


Deleted AUTHORS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# Creators and Major Contributors to the PiDP-8/I Project

*   **Oscar Vermeulen <oscar.vermeulen@hotmail.com>**:

    -   Creator of the project (both hardware and software)
    
    -   Author of the initial modifications to the SIMH PDP-8 simulator
        necessary to make it use the PiDP-8/I front panel hardware

    -   Curator of the default set of binary demo media

    -   Author of the simulator setup scripts

    -   Initiator of much else in the project

    -   Author of the bulk of the documentation

    -   Host and major contributor to the PiDP-8/I support forum on
        Google Groups

    -   Hardware kit assembler and distributor

*   **Robert M Supnik** Primary author of the SIMH PDP-8 simulator upon
    which this project is based.

*   **Mike Barnes** Ported Oscar Vermeulen's SIMH 3.9 based PiDP-8/I
    simulator to the new SIMH 4.0 code base.  (September 2015.)

*   **Dylan McNamee** Ported the software to Buildroot for the official
    2015.12.15 binary OS images, and helped to merge the James L-W
    "alt-serial" mode in.

*   **Mark G. Thomas** Creator of the installation scripts for the
    2015.12.15 release, which were folded into the `make install`
    handler within `Makefile.in`. Also wrote the version of the SysV
    init script that came with that release as `rc.pidp8`, shipped here
    as `pidp8i-init`.

*   **Ian Schofield <isysxp@gmail.com>** Modified the LED lamp driving
    code in the simulator to better simulate the incandescent lamps in
    the original PDP-8/I hardware.  (The bulk of his original code has
    since been rewritten, but the core idea remains, and it is doubtful
    whether the current method would exist without his instigation.)

*   **Henk Gooijen <henk.gooijen@boschrexroth.nl>** Pushed the PDP-8
    simulator's internal EAE step counter value down into the PiDP-8/I's
    LED manipulation code, without which the step counter LEDs remain
    dark even when using the EAE.

*   **Paul R. Bernard <prb@downspout.ca>** wrote `src/test.c` and the
    core of what now appears as `doc/pidp8i-test.md`. (The program builds
    and installs as `pidp8i-test`.)  He also provided a one-line fix
    that completes the work of Henk Gooijen's step counter patch.

*   **Rick Murphy <k1mu.nospam@gmail.com>** optimized the `pep001.pal`
    example so that it fits into a single page of PDP-8 core, and
    provided several useful files in his OS/8 disk images that have
    managed to land in this software distribution's OS/8 disk image.

*   **Tony Hill <hill.anthony@gmail.com>** Merged all the upstream SIMH
    changes produced between late September 2015 and late December 2016
    into the PiDP-8/I simulator.

*   **Bill Cattey <bill.cattey@gmail.com>** aka poetnerd. Currently
    working on system pack images. Making myself useful where I can.

*   **Warren Young <tangentsoft@gmail.com>** Did everything listed in
    `ChangeLog.md` that is not attributed to anyone else.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































Deleted COPYING.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# Licenses

The PiDP-8/I software distribution is an agglomeration of software from
multiple sources.  Several different licenses apply to its parts.  This
file guides you to those individual licenses.


## SIMH License

Most of the files in this software distribution are released under the
terms of the SIMH license, a copy of which typically appears at the top
of each file it applies to. This includes not only SIMH proper but also
several files written by PiDP-8/I software project contributors who
chose to license their contributions under the same license.

For a few files, textual inclusion of the license inside the file itself
was impractical, so this license is applied by reference to [a file
included with the distribution][sl].

[sl]: https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md


## PiDP-8/I Design Files

The PiDP-8/I design files in [`hardware/pidp8i`][hwp] were released
under the Creative Commons [Attribution-NonCommercial-ShareAlike 4.0
International][ccl] license [on the mailing list][pdp8il] by their
author, Oscar Vermeulen.

[ccl]: https://creativecommons.org/licenses/by-nc-sa/4.0/
[hwp]: https://tangentsoft.com/pidp8i/dir?name=hardware/pdp8i&ci=trunk
[pdp8il]: https://groups.google.com/d/msg/pidp-8/bcIH9uEB_kU/zg9uho7NDAAJ


## autosetup License

The `configure` script and the contents of the `autosetup` directory are
released under the FreeBSD license given in [`autosetup/LICENSE`][as].

[as]: https://tangentsoft.com/pidp8i/doc/trunk/autosetup/LICENSE


## palbart License

The `palbart` program and its manual page are released under the terms
of the license given in [`palbart/LICENSE.md`][pl].

[pl]: https://tangentsoft.com/pidp8i/doc/trunk/palbart/LICENSE.md


## OS/8 License

The OS/8 media images included with this software distribution are
released under the Digital License Agreement presented in
[`media/os8/LICENSE.md`][dla].

[dla]: https://tangentsoft.com/pidp8i/doc/trunk/media/os8/LICENSE.md


## Other DEC Software

The other files in the [`media`][md] and [`examples`][ed] directories
that originate from Digital Equipment Corporation are believed to fall
under the [public domain license][pdp8pd] DEC released all their PDP-8
software under after it stopped being ecomonmically viable. Documented
releases for specific software (e.g. TSS/8) may be difficult to come by,
however.

[md]: https://tangentsoft.com/pidp8i/dir?ci=trunk&name=media
[ed]: https://tangentsoft.com/pidp8i/dir?ci=trunk&name=examples


## ETOS License

ETOS was a commercial product produced outside of DEC. No public
documented declaration of license is known to be available for it, but
we have [a third-hand report][el] that its creators are fine with ETOS
being redistributed.

[el]: http://mailman.trailing-edge.com/pipermail/simh/2017-January/016169.html
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































Deleted ChangeLog.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
# PiDP-8/I Changes

## Version 2017.04.04

*   Removed the PDP-8 CPU idle detection feature.  Oscar Vermeulen
    reports that it also interfered with NLS LED driving mode in his
    last version, and we have no reason to believe our NLS code is
    sufficiently different to avoid the problem.

    This does not affect ILS users, since enabling ILS mode disables
    this change.

    NLS system upgrades wouldn't normally be affected because the
    changed files are not normally overwritten on installation.  If
    you're affected, you know it, and how to fix it.

*   Replaced the earlier attempts at finding an ideal IPS rate for the
    simulator when run on single-core hosts with usage of SIMH's
    percentage style throttle rates.  We now explicitly set the throttle
    rate to "50%" which not only achieves an even higher throttle rate
    than in earlier releases, it's reliable in the face of varying
    background CPU usage.  See the single-core section of
    `README-throttle.md` for details.


## Version 2017.04.01 The "I May Be a Fool, but I am *Your* Fool" Release

*   Added the `configure --alt-serial-mod` option to change the GPIO
    code to work with [James L-W's alternative serial mod][sm2].

*   Increased the stock CPU throttle from 0.67 MIPS to 0.85 MIPS on most
    Pi 1 class devices, except for the Pi Zero which is a bit faster and
    so is able to run at 1.25 MIPS.

    (Testing shows that increasing it further causes SIMH to complain
    that it doesn't have enough CPU power to run that fast, despite the
    fact that top(1) shows it taking only about half the available CPU
    power.  It's just as well: we don't want to hog all the CPU power on
    a single-core Pi, anyway.)

*   When built in NLS mode, most of the PDP-8 simulator configuration
    files we generate now have CPU idle detection enabled, allowing host
    CPU usage to drop when the simulated CPU is basically idle, such as
    when waiting for keyboard input.

*   Replaced a simplistic 2-second delay in the startup sequence of the
    simulator, `pidp8i-test`, and "[Incandescent Thought][it]" with a
    smarter interlocked startup sequencing mechanism that largely
    eliminates the delay.

*   Fixed a problem introduced in v20170204 which causes the `LOAD_ADD`
    and `DEPOSIT` switch handlers to generate incorrect core addresses
    when the SIMH PDP-8 CPU core sets bits beyond the lower 12 in the PC
    register.  We were assuming this register is always 12-bit clean,
    but it isn't.

*   Merged in upstream SIMH improvements.  Changes relevant to the
    PiDP-8/I include:

    *   The PDP-8 CPU reset mechanism now does more of what our
        preexisting `START` switch handler did, so we now delegate to
        that upstream mechanism, reducing behavior differences between
        the cases.

    *   Improved keyboard polling behavior in terminal handler.

    *   Fixed many bugs identified by Coverity Scan in many different
        subsystems of the simulator.  Normally I wouldn't note such a
        low-level change in this user-centric document, but it is
        possible that some of these improvements fix user-visible bugs.

*   SIMH's default PDP-8 configuration enables the DF32 disk device with
    the short name "DF", but since the SIMH `DEPOSIT` command works on
    both devices and registers, a command like `d df 0` is ambiguous,
    causing the default configuration of SIMH to give a "Too few
    arguments" error for this command, even though it's obvious that you
    mean the CPU DF register here.  (Surely you didn't mean to overwrite
    the first word of your disk image instead?)  Since upstream refuses
    to fix it, I have disabled the DF32 device in all of the default
    `boot/*.script` files.

    Since these scripts aren't overwritten on installation, this will
    only affect new installs unless you say `make mediainstall`, in
    which case your binary OS media is also overwritten.  Do this at
    your own risk!

*   Many improvements to the `SING_STEP` + `DF` USB auto-mounting and
    SIMH attaching feature:

    *   Prior versions apparently could only mount paper tape images
        correctly.  This release includes a fix that allows RX type
        floppy images and TU type DECtape images to autoattach.

    *   Changed the meaning of `SING_STEP` + `DF=7` from attaching an RL
        type removable hard disk cartridge image to the first RL01 drive
        to attaching an older and more period-correct RK type image to
        the *second* RK05 drive.  The second half of the change lets you
        use this feature along with the stock OS/8 image to attach a
        second hard disk at runtime.

    *   The file name matching code used by this feature was only using
        the first character of the file name extension, and it wasn't
        pinning the match to the end of the file name string.  Thus, if
        you'd set `DF=0`, it would look for the first file with `.p`
        anywhere in the file name, not `.pt` at the end, as expected.

    *   Improved error messages given when this feature doesn't work.

*   The `pidp8i-test` program now accepts a `-v` flag to make it give
    the version and configuration string and exit.

*   `pidp8i-test` now exits more cleanly, shutting down ncurses, turning
    off the front panel LEDs, and writing a diagnostic message on signal
    exits.

*   The version number part of the configuration string written by
    `pidp8i-test -v` and as the first line of output from the simulator
    now uses the same 10-digit Fossil checkin ID format as the Fossil
    timeline, making it easier to match that version to a particular
    Fossil checkin.

*   The Raspberry Pi model detection code behind the Pi model tag in the
    configuration string was only doing the right thing for the more
    common Pi models.  It now reports the correct Pi model for the
    various flavors of Compute Module and the Pi Zero.

*   Improved error handling in the process that inserts the version info
    into the configuration string emitted when the simulator and test
    programs start up.

*   We now build and link in the upstream `sim_video` module, which
    allows access to a video display via SDL.  We do not currently
    use this in the project core, but I recall hearing about a
    third-party project that uses this for a local graphical X-Y
    vector display implementation for playing Spacewar!  When built
    on a system without SDL or even a local bitmap display, this
    code becomes nearly a no-op, affecting build time very little.

*   SIMH changes to a different delay mechanism at CPU throttle rates
    below 1000 IPS, which prevents our incandescent lamp simulator from
    running correctly.  Therefore, when you give a `./configure
    --throttle` flag value that would use this throttle mode, we disable
    the ILS even when building on multi-core Raspberry Pis.

    (This fix doesn't disable the ILS at run time if you manually set a
    throttle value under 1000 IPS via a SIMH command.  We'll try to help
    you avoid accidentally shooting yourself in the foot, but if you're
    going to *aim*, you're on your own.)

*   Several internal refactorings to improve code style, reduce the
    [upstream SIMH patch footprint][foot], and fix corner case bugs.

[foot]: http://pastebin.com/5Jnx15QX
[it]:   https://tangentsoft.com/pidp8i/wiki?name=Incandescent+Thought
[sm2]:  https://groups.google.com/d/msg/pidp-8/-leCRMKqI1Q/Dy5RiELIFAAJ


## Version 2017.02.04

*   Largely rewrote the incandescent lamp simulator (ILS) feature.
    The core of Ian Schofield's original contribution is still hiding
    in there if you go spelunking, but everything surrounding it
    is different.

    The changes and design decisions surrounding this are [complicated
    and subtle][ilsstory], but the end result is that the ILS is now
    free of judders, blips, shudders, and chugs.  (Those are nuanced
    technical terms for "badness.")  The ILS is now buttery smooth from
    1 kIPS to the many-MIPS rate you get running un-throttled on a Pi 3.

*   Although most of the ILS work does not directly apply to the "no
    lamp simulator" (NLS) case, the sample rate dithering reduces
    display update artifacts seen in this case as well.

*   Slowed the ILS brightness rates down a bit: more lampy, less
    snappy.  Whether this is accurate or not is something we'll have
    to determine through research separately in progress.

*   The ILS display is a bit brighter: the delay values used in prior
    versions put a cap on max brightness that was well under the full
    LED brightness achievable.

*   For the first time, it is possible to build Deeper Thought (any
    version) against the ILS, with minor adjustments.  Prior versions of
    the ILS had too different an external interface to allow this.  Full
    details are in a [new wiki article][ithought].

*   In normal free-running mode, the simulator lights the Fetch and
    Execute LEDs at 50%, whereas before there was an imbalance that
    purely had to do with the much lower complexity of fetching an
    instruction inside the simulator vs executing it.
    
    (In real hardware, the complexities were different: fetch involved a
    core memory retrieval, very much non-instantaneous, whereas the
    execution of the fetched instruction kind of happened all at once in
    complicated electron flows, rather than the sequential C code of the
    SIMH PDP-8 simulator.  Thus, it was reasonable for DEC to talk about
    PDP-8/I fetch-and-execute cycles as if the two steps were of equal
    time complexity.)

    I haven't compared the resulting LED appearance to a real PDP-8/I.

*   Several other tweaks to LED state handling to better match real
    hardware.

*   Redesigned the `pidp8i-test` program to allow manual stepping
    forwards and backwards in addition to the previous auto-advancing
    behavior.
    
    As soon as you press one of the arrow keys, the test program moves
    to the next or previous action in the sequence and stops
    auto-advancing.  This mode is useful when testing the hardware with
    a multimeter or similar, and you need a certain row or column to
    stay lit up indefinitely.

    You can also press <kbd>R</kbd> to resume auto-advancing behavior,
    or either <kbd>Ctrl-C</kbd> or <kbd>X</kbd> to exit the program
    gracefully.

    This requires that you have `libncurses-dev` installed on your Pi.

*   The SIMH PDP-8 simulator's internal SR register now matches the
    hardware switches when you say Ctrl-E then `ex sr`.  Prior versions
    only loaded the hardware switch register values into the internal
    register when it executed an `OSR` instruction.

*   Copied the KiCad design files into the source tree since they are
    now formally released by Oscar Vermeulen under a Creative
    Commons license.  Also included the PDF version of the schematic
    produced by Tony Hill.  (This is all in the `hardware/` directory.)

*   Lowered the default simulator throttle value for single-core Pi
    boards from 1332 kIPS to 666 kIPS after doing some testing with
    the current code on a Raspberry Pi 1 Model B+.  This value was
    chosen since it is approximately twice the speed of a PDP-8/I.
    This leaves a fair bit of CPU left over for background tasks,
    including interactive shell use.

    This value may be a bit low for Pi Zero users, but it is easily
    [adjustable][rmth].

*   Merged in the relevant SIMH updates.  This is all internal stuff
    that doesn't affect current PiDP-8/I behavior.

*   Many build system and documentation improvements.

[ilsstory]: https://tangentsoft.com/pidp8i/wiki?name=Incandescent+Lamp+Simulator
[ithought]: https://tangentsoft.com/pidp8i/wiki?name=Incandescent+Thought


## Version 2017.01.23

*   When any program that talks to the PiDP-8/I front panel starts up,
    it now prints out a banner modeled on the [Erlang configuration
    line][ecl].  For example, when I run the software in the development
    tree on my PiDP-8/I, I get the following:

        PiDP-8/I trunk:i49cd065c [pi3b] [ils] [serpcb] [gpio]

    It tells me that:
    
    *   I'm running code built from Fossil checkin ID 49cd065c on the
        trunk branch, as opposed to a release version, which would be
        marked `release:v20170123` or similar.  (The `i` here is a tag
        standing for "ID", as in Fossil checkin ID.  Contrast `v` used
        to tag release version numbers.)

    *   I'm running it on a Raspberry Pi 3 Model B with Ian Schofield's
        incandescent lamp simulator (ILS) feature enabled.

    *   The software is built to expect that the PiDP-8/I PCB and the Pi
        board attached to it have had the serial mods made to them.

    *   The GPIO module found the GPIO hardware and was able to attach
        to it.

*   I get a very different result when running it on my desktop machine:

        PiDP-8/I trunk:id8536d91 [cake] [nls] [nopcb] [rt]

    This tells me:

    *   I'm running a different version of the development branch (i.e.
        the "trunk") of the code than what's running on the Pi.

    *   It's not running on a Pi at all.  (Cake ≠ pi.)

    *   I've disabled the ILS feature, so it's running with the "no lamp
        simulator" (NLS) GPIO module.
    
    *   Which is all to the good, because there's no point burning CPU
        power running the ILS code on a host machine that doesn't have a
        PiDP-8/I PCB attached.

    *   The GPIO thread is running with real-time privileges.

*   The ILS feature can now be disabled at `configure` time via the new
    `--no-lamp-simulator` flag.  This option is automatically set when
    building on a single-core Raspberry Pi.  (The flag is there only to
    allow someone building the software on a multi-core host machine to
    disable the ILS.)

*   Tweaked the ILS decay constants to be asymmetric, better mimicking
    the way real incandescent lamps work: they heat up to full
    brightness faster than they fade to perceptively "off."

*   The LED values used by the GPIO thread were being recalculated way
    too often.

    In the ILS case, it was updating the values approximately at the
    same rate as the ILS's PWM core frequency, roughly 7,500 times per
    second, which is far higher than the human persistence of vision
    limit.  While the PWM rate does need to be that fast to do its job,
    the underlying LED state values do not need to change nearly that
    often to fool the human into seeing instantaneous updates.

    The NLS case was actually worse, recalculating the LED values on
    every instruction executed by the PDP-8 CPU simulator, which even on
    a Pi 1 is likely to be a few MHz.

    In both the ILS and NLS cases, we now update the LED values about
    100 times a second, maintaining that rate dynamically based on the
    current execution speed of the simulator.

*   In prior versions, the ILS was only updating at its intended rate
    when the PDP-8 simulator was running flat-out on a current
    multi-core Raspberry Pi.  If you throttled the SIMH simulator to a
    slower execution rate, the display quality would start to degrade
    noticeably below about 1 MIPS.

*   With the prior fix, we now ship 5.script (i.e. the handler for
    starting the simulator with IF=5, or restarting it with IF=5 +
    `SING_STEP`) set to a throttle value of 30 kIPS, which allows the
    human to see each AC/MQ modification.  The built-in delay loops are
    still there, else we'd have to drop this to well under 1 kIPS.

*   The `SING_INST` switch now immediately puts the processor into
    single instruction mode, not requiring a separate press of the
    `STOP` key, as in prior versions.  This is the correct behavior
    according to the 1967-1968 edition of DEC's Small Computer Handbook
    for the PDP-8/I.

*   Greatly simplified the way single-instruction mode, processor
    stoppage, and the `CONT` key work.  The prior implementation was
    error-prone and difficult to understand.  This fixes a particularly
    bad interaction between the way `HLT` instructions and `CONT` key
    presses were handled, causing the processor to not resume correctly
    from `HLT` state.

*   Consolidated and cleaned up the bulk of the PiDP-8/I switch handling
    code so that it is not so intimately tied into the guts of the PDP-8
    CPU emulator.  This will greatly increase the chance that future
    updates to the upstream SIMH code will apply cleanly to our version.

*   Fixed a bug in `examples/bit-rotate.pal` which caused it to skip the
    actual bit rotation step.  We were trying to microcode two
    instructions into one that the PDP-8 won't accept together, and we
    didn't catch it until now because the HLT bug masked it, and the
    `palbart` assembler we ship isn't smart enough to notice the bug.

*   Fully generalized the mechanism for generating `obj/*.lst`,
    `bin/*.pt`, and `boot/*.script` from `examples/*.pal`.  You can now
    drop any PAL assembly language program into the `examples` directory
    and type `make` to build these various output forms automatically
    using the shipped version of `palbart`.  This effectively turns this
    PiDP-8/I software distribution into a PDP-8 assembly language
    development environment: rapidly build, test, and debug your PAL
    programs on your PC before you deploy them to real hardware.  Or,
    write PAL programs to debug the hardware or simulator, as we did
    with `examples/bit-rotate.pal`.

*   Fixed a sorting bug in the tool that generates `boot/*.script` from
    `obj/*.lst`, resulting in `dep` instructions that weren't sorted by
    core address.  This didn't cause any real problem, but it made
    tracing the execution of a PAL assembly program difficult if you
    were trying to refer to the `boot/*.script` file to check that the
    PiDP-8/I's front panel is showing the correct register values.

*   Updated SIMH to the latest upstream version and shipping a subset of
    the SIMH docs as unversioned files from tangentsoft.com.

*   The `configure` script now aborts the build if it sees that you're
    trying to build the software as root, since that means it generates
    the init script and the pidp8i script expecting to run the installed
    software as root, not as your normal user.  The most common way this
    happens is that you have a configured source tree, then change one
    of the `*.in` files and say `sudo make install`, thinking to build
    and install the change in one step.  This fixes that.

*   Several improvements to the build system.

[ecl]: http://stackoverflow.com/q/1182025/142454


## Version 2017.01.16

*   Prior releases did not include proper licensing for many of the
    included files.  This project was, therefore, not a proper Open
    Source Software project.  This problem has been fixed.

    In this release, many files that were previously technically only
    under standard copyright due to having no grant of license now have
    an explicit license, typically the same as SIMH itself.  (Thank you
    to all of the authors who allowed me to apply this license to their
    contributions!)

    For several other files, I was able to trace down some prior license
    and include its text here for the first time.

    There remain a few "gray" items: the TSS/8 and ETOS disk images.
    See the [`COPYING.md` file][copying] for more on the current status
    of these OS images.  If the legal status of these files clarifies in
    the future, this software distribution will react accordingly, even
    if that means removing these files from the distribution if we learn
    that these files are not freely-redistributable, as we currently
    believe them to be today.

*   The Step Counter LEDs on the front panel weren't being lit properly
    when EAE instructions were being used.  Thanks for this patch go to
    Henk Gooijen and Paul R. Bernard.

*   The prior `boot/1.script` and `boot/5.script` files are no longer
    simply opaque lists of octal addresses and machine code.  They are
    generated from PAL assembly files provided in the `examples`
    directory, so that you can now modify the assembly code and type
    `make` to rebuild these boot scripts.

*   The mechanism behind the prior item is fully general-purpose, not
    something that only works with `1.script` and `5.script`.  Any
    `examples/*.pal` file found at `make` time is transformed into a
    SIMH boot script named after the PAL file and placed in the `boot`
    directory.  This gives you an easier way to run PDP-8 assembly code
    inside the simulator.  After saying `make` to transform `*.pal` into
    `*.script` files, you can run the program with `bin/pidp8i-sim
    boot/my-program.script` to poke your program's octal values into
    core and run it.  This round-trip edit-and-run process is far faster
    than any of the options given in the [examples' `README.md`
    file][ex].

*   Disassembled both versions of the RIM loader to commented, labeled
    PAL assembly language files.  If you ever wanted to know what those
    16 mysterious instructions printed on the front panel of your
    PiDP-8/I did, you can now read my pidgin interpretation of these
    programs in `examples/*-rim.loader.pal` and become just as confused
    as I am now. :)

*   The two RIM loader implementations now start with a nonstandard
    `HLT` instruction so that when you fire up the simulator with IF=1 to
    start the high-speed RIM loader, it automatically halts for you, so
    you don't have to remember to STOP the processor manually.

    There is currently [a bug][hltbug] in the way the simulator handles
    `HLT` instructions which prevents you from simply pressing START or
    CONT to enter the RIM loader after you've attached your paper tape,
    so you still have to manually toggle in the 7756 starting address
    and press START to load the tape into core.  (I hope to fix this
    before the next release, but no promises.)

*   Added the `configure --throttle` feature for making the simulator
    run at a different speed than it normally does.  See
    [`README-throttle.md`][rmth] for details.

*   The build system now reacts differently when building the PiDP-8/I
    software on a single-core Raspberry Pi:

    *   If you're building the trunk or release branch, you'll get a
        configure error because it knows you can't run the current
        implementation of the incandescent lamp simulator on a
        single-core Pi.  (Not enough spare CPU power, even with heavy
        amounts of throttling.)

    *   If you're building the no-lamp-simulator branch, it inserts a
        throttle value into the generated `boot/*.script` files that do
        not already contain a throttle value so that the simulator
        doesn't hog 100% of the lone core, leaving some spare cycles for
        background tasks.  The above `--throttle` feature overrides
        this.

    These features effectively replace the manual instructions in the
    old `README-single-core.md` file, which is no longer included with
    this software distribution, starting with this release.

*   Lowered the real-time priority of the GPIO thread from 98 to 4.
    This should not result in a user-visible change in behavior, but it
    is called out here in case it does.  (In our testing, such high
    values simply aren't necessary to get the necessary performance,
    even on the trunk branch with the incandescent lamp simulator.)

*   Since v20161128, when you `make install` on a system with an
    existing PiDP-8/I software installation, the binary OS media images
    were not being overwritten, on purpose, since you may have modified
    them locally, so the installer chose not to overwrite your versions.

    With this release, the same principle applies to the SIMH boot
    scripts (e.g. `$prefix/share/boot/0.script`) since those are also
    things the user might want to modify.

    This release and prior ones do have important changes to some of
    these files, so if you do not wish to overwrite your local changes
    with a `make mediainstall` command, you might want to diff the two
    versions and decide which changes to copy over or merge into your
    local files.

[hltbug]:  https://tangentsoft.com/pidp8i/info/f961906a5c24f5de
[copying]: https://tangentsoft.com/pidp8i/doc/trunk/COPYING.md
[rmth]:    https://tangentsoft.com/pidp8i/doc/trunk/README-throttle.md


## Version 2017.01.05

*   Automated the process for merging in new SIMH updates.  From within
    the PiDP-8/I software build directory, simply say `make simh-update`
    and it will do its best to merge in the latest upstream changes.

    This process is more for the PiDP-8/I software maintainers than for
    the end users of that software, but if you wish to update your SIMH
    software without waiting for a new release of *this* software, you
    now have a nice automated system for doing that.

*   Updated SIMH using that new process.  The changes relevant to the
    PiDP-8/I since the prior update in release v20161226 are:

    *   Many more improvements to the simulator's internal timer system.
        This should make deliberate underclocking more accurate.

    *   It is now possible to get hex debug logs for the simulator console
        port by cranking up the simulator's debug level.

*   The simulator now reports the upstream Git commit ID it is based on
    in its version string, so that if you report bugs upstream to the
    SIMH project, you can give them a version number that will be
    meaningful to them.  (They don't care about our vYYYYMMDD release
    numbers or our Fossil checkin IDs.)


## Version 2016.12.26 (The Boxing Day release)

*   Tony Hill updated SIMH to the latest upstream version.

    This change represents about 15 months worth of work in the
    [upstream project][simh] — plus a fair bit of work by Tony to merge
    it all — so I will only summarize the improvements affecting the
    PDP-8 simulator here:

    *   Many improvements to the internal handling of timers.
    
        The most user-visible improvement is that you can now clock your
        emulated PDP-8 down to well below the performance of a real
        PDP-8 via `SET THROTTLE`, which can be useful for making
        blinkenlights demos run at human speeds without adding huge
        delay loops to the PDP-8 code implementing that demo.

    *   Increased the number of supported terminals from four to either
        twelve or sixteen, depending on how you look at it.  Eight of
        the additional supported terminal devices are conflict-free,
        while the final four variously conflict with one or more of the
        other features of the simulated PDP-8.  If you want to use all
        16, you will be unable to use the FPP, CT, MT and TSC features
        of the system.

        This limitation reflects the way the PDP-8 worked.  It is not an
        arbitrary limitation of SIMH.

    *   Added support for the LS8E printer interface option used by the
        WPS8 word processing system.

    *   The simulator's command console now shows the FPP register
        descriptions when using it as a PDP-8 debugger.

    *   Added the `SHOW TTIX/TTOX DEVNO` SIMH command to display the
        device numbers used for TTIX and TTOX.

    *   The `SHOW TTIX SUMMARY` SIMH command is now case-insensitive.

    *   Upstream improvements to host OS/compiler compatibility.  This
        increases the chances that this software will build out of the
        box on random non-Raspbian systems such as your development
        laptop running some uncommon operating system.

*   When you `make install`, we now disable Deeper Thought 2 and the
    legacy `pidp8` service if we find them, since they conflict with our
    `pidp8i` service.

*   Added the install user to the `gpio` group if you `make install` if
    that group is present at install time.  This is useful when building
    and installing the software on an existing Raspbian SD card while
    logged in as a user other than `pi` or `pidp8i`.

[simh]: https://github.com/simh/simh/


## Version 2016.12.18

*   The entire software stack now runs without explicit root privileges.
    It now runs under the user and group of the one who built the
    software.

    For the few instances where it does need elevated privileges, a
    limited-scope set of sudo rules are installed that permit the
    simulator to run the necessary helper programs.

*   The power down and reboot front panel switch combinations are no
    longer sensitive to the order you flip the switches.

*   Changed the powerdown front panel switch combination to the more
    mnemonically sensible `Sing_Step` + `Sing_Inst` + `Stop`.

    Its prior switch combo — `Sing_Step` + `Sing_Inst` + `Start` — is
    now the reboot sequence, with the mnemomic "restart."

*   Removed the USB stick mount/unmount front panel switch combos.  The
    automount feature precludes a need for a manual mount command, and
    unmount isn't necessary for paper tape images on FAT sticks.

*   The simulator now runs correctly on systems where the GPIO setup
    process fails.  (Basically, anything that isn't a Raspberry Pi.)
    Prior to this, this failure was just blithely ignored, causing
    subsequent code to behave as though all switches were being pressed
    at the same time, causing utter havoc.

    The practical benefit of this is that you can now work with the
    software on your non-Pi desktop machine, losing out only on the
    front panel LEDs and switches.  Everything else works just as on the
    Pi.  You no longer need a separate vanilla SimH setup.

*   Added a locking mechanism that prevents `pidpi8-test` and
    `pidp8i-sim` from fighting over the front panel LEDs.  While
    one of the two is running, the other refuses to run.

*   Added `examples/ac-mq-blinker.pal`, the PAL8 assembly code for the
    `boot/5.script` demo.

*   Fixed two unrelated problems with OS/8's FORTRAN IV implementation
    which prevented it from a) building new software; and b) running
    already-built binaries.  Thanks go to Rick Murphy for providing the
    working OS/8 images from which the files needed to fix these two
    problems were extracted.

*   Added the VT100-patched `VTEDIT` TECO macro from Rick Murphy's OS/8
    images, and made it automatically run when you run TECO from the
    OS/8 disk pack.  Also added documentation for it in `VTEDIT.DC` on
    the disk pack as well as [in the wiki][vteditdoc].

*   The default user name on the binary OS images is now `pidp8i`
    instead of `pi`, its password has changed to `edsonDeCastro1968`,
    and it demands a password change on first login.  I realize it's a
    hassle, but I decided I didn't want to contribute to the plague of
    open-to-the-world IoT boxes.

*   Many build system and documentation improvements.

[vteditdoc]: https://tangentsoft.com/pidp8i/wiki?name=Using+VTEDIT


## Version 2016.12.06

*   The `pidp8i-test` program's LED test routines did not work correctly
    when built against the incandescent lamp simulator version of the
    GPIO module.  Reworked the build so that this test program builds
    against the no-lamp-simulator version instead so that you don't have
    to choose between having the lamp simulator or having a working
    `pidp8i-test` program.

*   More improvements to `examples/pep001.pal`.

*   Extracted improved `PRINTS` routine from that example as
    `examples/routines/prints.pal`.


## Version 2016.12.05

*   This release marks the first binary SD card image released under my
    maintainership of the software.  As such, the major user-visible
    features in this release of the Fossil tree simply support that:

    *   The `pidp8i-init` script now understands that the OS's SSH host
        keys may be missing, and re-generates them.  Without this
        security measure, anyone who downloads that binary OS image
        could impersonate the SSH server on *your* PiDP-8/I.

    *   Added a `RELEASE-PROCESS.md` document.  This is primarily for my
        own benefit, to ensure that I don't miss a step, particularly
        given the complexity of producing the binary OS image.  However,
        you may care to look into it to see what goes on over here on
        the other side of the Internet. :)

*   Added an OS/8 BASIC solution to Project Euler Problem #1, so you can
    see how much simpler it is compared to the PAL8 assembly language
    version added in the prior release.

*   Updated the PAL8 assembly version with several clever optimizations
    by Rick Murphy, the primary effect of which is that it now fits into
    a single page of PDP-8 core memory.


## Version 2016.12.03

*   Debounced the switches.  See [the mailing list post][cdb] announcing
    this fix for details.

*   Merged the [`pidp8i-test` program][testpg] from the mailing list.
    The LED testing portion of this program [currently][gpiols] only works
    correctly without the incandescent lamp simulation patch applied.

*   Added a solution to [Project Euler Problem #1][pep001] in PAL8
    assembly language and wrote the [saga of my battle][p1saga] with
    this problem into the wiki.  This also adds a couple of useful PAL8
    routines in `examples/routines`.

*   Integrated David Gesswein's latest `palbart` program (v2.13) into
    the source distribution so that we don't have to:
    
    1.  ship pre-built RIM format paper tapes for the examples; and

    2.  put up with the old versions that OS package repos tend to have
        (Ubuntu is still shipping v2.4, from 6 years ago!)

*   Fixed a bug in the `make install` script that caused it to skip
    installing `screen` and `usbmount` from the OS's package repo when
    they are found to be missing.

*   Fixed a related bug that prevented it from disabling the serial
    console if you configure the software without `--serial-mod` and
    then install it, causing the serial console and the GPIO code in the
    PiDP-8/I simulator to fight over GPIO pins 14 and 15.

*   Removed the last of the duplicate binary media entries.  This makes
    the zip files for this version well under half the size of those for
    the 2015.12.15 upstream release despite having more features.

[cdb]:    https://groups.google.com/d/msg/pidp-8/Fg9I8OFTXHU/VjamSoFxDAAJ
[testpg]: https://groups.google.com/d/msg/pidp-8/UmIaBv2L9Ts/wB1CVeGDAwAJ
[gpiols]: https://tangentsoft.com/pidp8i/tktview?name=9843cab968
[pep001]: https://projecteuler.net/problem=1
[p1saga]: https://tangentsoft.com/pidp8i/wiki?name=PEP001.PA


## Version 2016.11.28

*   Added an intelligent, powerful build system, replacing the
    bare-bones `Makefile` based build system in the upstream version.
    See [`README.md`][readme] for more info on this.

*   The installation is now completely relocatable via `./configure
    --prefix=/some/other/place`. The upstream version would not work if
    installed somewhere other than `/opt/pidp8` due to many hard-coded
    absolute paths.  (This is enabled by the new build system, but
    fixing it was not simply a matter of swapping out the build system.)

*   Changed all of the various "PDP," "PDP-8", and "PiDP-8" strings to
    variants on "PiDP-8/I", partly for consistency and partly because it
    seems unlikely that this software will ever be used with anything
    other than the PiDP-8/I project.

    Part of this renaming means that the default installation location
    is now `/opt/pidp8i`, which has the nice side benefit that
    installing this version of the software will not overwrite an
    existing installation of the upstream version in `/opt/pidp8`.

    Another user-visible aspect of this change is that the upstream
    version's `pdp.sh` script to [re]enter the simulator is now called
    `pidp8i`.

*   Merged Ian Schofield's [Display update for the PiDP8][dupatch]
    patch.  Currently it is not optional, but there is [a plan][dudis] to
    allow this feature to be disabled via a `configure` script option.

*   The scripts that control the startup sequence of the PiDP-8/I
    simulator now include helpful header comments and emit useful
    status messages to the console.  Stare no more at opaque lists
    of SimH commands, wondering what each script does!

*   Merged `scanswitch` into the top-level `src` directory, since the
    only thing keeping it in a separate directory was the redundant
    `gpio.h` file. There were minor differences between the two `gpio.h`
    files, but their differences do not matter.

*   Installing multiple times no longer overwrites the binary OS/program
    media, since the disk images in particular may contain local
    changes.  If you want your media images overwritten, you can insist
    on it via `make mediainstall`.

*   The installation tree follows the Linux Filesystem Hierarchy
    Standard, so that files are in locations an experienced Linux user
    would expect to find them.  The biggest changes are that the content
    of the upstream `bootscripts` tree is now installed into
    `$prefix/share/boot`, and the OS/program media images which used to
    be in `imagefiles` are now in `$prefix/share/media`.

*   Added a bunch of ancillary material: [wiki articles][wiki],
    [USB stick label artwork][art], a PAL8 assembly [example program][ex]
    for you to toggle in, etc. Also filed a bunch of [tickets][tix]
    detailing feature proposals, known bugs and weaknesses, etc. If you
    were looking for ways to contribute to the development effort, these
    new resources provide a bunch of ideas.

*   Made some efforts toward portability.

    While this project will always center around Raspbian and the
    PiDP-8/I add-on board, the intent is that you should be able to
    unpack the project on any other Unix type system and at least get
    the simulator up and running with the normal SimH manual control
    over execution instead of the nice front panel controls provided by
    the PiDP-8/I board.

    In particular, the software now builds under Mac OS X, though it
    does not yet run properly.  (The modified SimH PDP-8 simulator
    currently misbehaves if the PiDP-8/I panel is not present.  Fixing
    this is on the radar.)

*   Fixed a bunch of bugs!

[readme]:  https://tangentsoft.com/pidp8i/doc/trunk/README.md
[dupatch]: https://groups.google.com/forum/#!topic/pidp-8/fmjt7AD1gIA
[dudis]:   https://tangentsoft.com/pidp8i/tktview?name=e06f8ae936
[wiki]:    https://tangentsoft.com/pidp8i/wcontent
[ex]:      https://tangentsoft.com/pidp8i/doc/trunk/examples/README.md
[art]:     https://tangentsoft.com/pidp8i/dir?c=trunk&name=labels
[tix]:     https://tangentsoft.com/pidp8i/tickets


## Version 2015.12.15

*   The last release of the software made by Oscar Vermeulen, the
    creator of the PiDP-8/I project. This version of the software
    derives from it, but differs in many ways. (See above.)

    Since May of 2017, this version of the software is now considered
    the current stable version.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted HACKERS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
Hacking on the PiDP-8/I Software
====

If you are going to make any changes to the PiDP-8/I software, here are
some rules and hints to keep in mind while you work.


Getting Started with Fossil
----

The PiDP-8/I software project is hosted using the [Fossil][fossil]
[distributed version control system][dvcs].  Fossil provides most of the
features of GitHub under a simpler operating model than Subversion
without tying you to a proprietary web service.

This guide will introduce you to some of the basics, but you should also
at least read the [Fossil Quick Start Guide][fqsg]. For a more thorough
introduction, I recommend [the Schimpf book][fbook]. If you have
questions, it is best to ask them on [its low-volume mailing list][fml],
though you may also ask me, either on [the PiDP-8/I mailing list][ggml]
or via private email.

You must use Fossil version 2.1 or higher with our repository, or you
will get an error.

If you started with one of our PiDP-8/I binary OS images made in or
after April 2017, Fossil 2.x is already installed.

If you're starting from some other OS, you either won't have Fossil
installed at all, or you'll most likley be using an older version, since
the Debian project is still shipping version 1.37 and likely will
continue to do so until 2020 or so.  You'll have to build Fossil from
source:

    $ sudo apt install libssl-dev
    $ wget -O fossil-release.tar.gz \
      https://fossil-scm.org/index.html/tarball/fossil-release?uuid=release
    $ tar xvf fossil-release.tar.gz
    $ cd fossil-release
    $ ./configure
    $ make
    $ sudo make install

Fossil is also available for all common desktop platforms.  One of [the
official binaries][fbin] may work on your system.  If you're getting
binaries from a third party, be sure it is Fossil 2.1 or higher.


[fbin]:   http://fossil-scm.org/index.html/uv/download.html
[dvcs]:   http://en.wikipedia.org/wiki/Distributed_revision_control
[fbook]:  http://www.fossil-scm.org/schimpf-book/home
[fml]:    http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/fossil-users
[fossil]: http://fossil-scm.org/
[fqsg]:   http://fossil-scm.org/index.html/doc/trunk/www/quickstart.wiki
[ggml]:   https://groups.google.com/forum/#!forum/pidp-8


Fossil Anonymous Access
----

To clone the code repository anonymously, say:

    $ mkdir -p ~/museum ~/src/pidp8i/trunk
    $ sudo apt install fossil
    $ fossil clone https://tangentsoft.com/pidp8i ~/museum/pidp8i.fossil
    $ cd ~/src/pidp8i/trunk
    $ fossil open ~/museum/pidp8i.fossil

The `clone` command gets you a file called `pidp8i.fossil` containing
the full history of PiDP-8/I from the upstream 2015.12.15 release
onward.  You can call that clone file anything you like and put it in
any directory you like.  Even the `.fossil` extension is largely a
convention, not a requirement.


Working With Existing Tags and Branches
----

The directory structure shown in the commands above is more complicated
than strictly necessary, but it has a number of nice properties.

First, it collects other software projects under a common top-level
directory, which I'm calling `~/src`, but you are free to use any scheme
you like.

Second, the top-level project directory stores multiple separate
checkouts, one for each branch or tag I'm actively working with at the
moment.  So, to add a few other checkouts, you could say:

    $ cd ~/src/pidp8i
    $ mkdir -p release          # another branch
    $ mkdir -p v20151215        # a tag this time, not a branch
      ...etc...
    $ cd release
    $ fossil open ~/museum/pidp8i.fossil release
    $ cd ../v20151215
    $ fossil open ~/museum/pidp8i.fossil v20151215
      ...etc...

This gives you multiple independent checkouts.  The branch checkouts
remain pinned to the tip of that branch, so that if someone else checks
changes in on that branch and you say `fossil update`, those changes
appear in your checkout of that branch.  The tag checkouts simply give
you the latest checkin with that tag; saying `fossil update` in a
checkout made from a tag will fast-forward you to the tip of the branch
that tag was made on.

(In Fossil, tags and branches are related, but the details are beyond
our scope here.  See the [Fossil Quick Start Guide][fqsg] and the
documents it links to for more details.)

This directory scheme shows an important difference between Fossil and
Git: with Git, the checkout and the clone are intermingled in the same
directory tree, but in Fossil, they are strictly separate.  Git can
emulate Fossil's normal working style through its [worktree][gitwt]
feature, but it's a kind of lash-up using symlinks and such, whereas
with Fossil, there is no confusion: the repository clone is a single
SQLite database file — here, `pidp8i.fossil` — and the checkouts are
made from the contents of that database.

Another important difference relative to Git is that with Fossil, local
checkins attempt to automatically sync checked-in changes back to the
repository you cloned from.  (This only works if you have a login on the
remote repository, the subject of the next section.)  This solves a
number of problems with Git, all stemming from the fact that Git almost
actively tries to make sure every clone differs from every other in some
important way.

While Fossil does allow offline operation and local independent clones,
its default mode of operation is to try and keep the clones in sync as
much as possible.  Git works the way it does because it was designed to
meet the needs of the Linux kernel development project, which is
inherently federated, so Git tries to operate in a federated model as
well.  Fossil is better for smaller, more coherent teams, where there is
a single, clear goal for the project and a single source for its
official code.  Fossil helps remote developers cooperate, whereas Git
helps remote developers go off on their own tangents for extended
periods of time and optionally sync back up with each other
occasionally.

Fossil is a better match for the way the PiDP-8/I software project
works: we want you to cooperate closely with us, not go off on wild
tangents.

[gitwt]:  https://git-scm.com/docs/git-worktree


Fossil Developer Access
----

If you have a developer account on tangentsoft.com's Fossil instance, just
add your username to the URL like so:

    $ fossil clone http://username@tangentsoft.com/pidp8i pidp8i.fossil

Fossil will ask you for the password for `username` on the remote Fossil
instance, and it will offer to remember it for you.  If you let it
remember the password, operation from then on is scarcely different from
working with an anonymous clone, except that on checkin, your changes
will be sync'd back to the repository on tangentsoft.com if you're
online at the time.

If you're working offline, Fossil will still do the checkin, but you'll
be able to sync with the central repoisitory once you get back online.
It is best to work on a branch when unable to use Fossil's autosync
feature, as you are less likely to have a sync conflict when attempting
to send a new branch to the central server than in attempting to merge
your changes to the tip of trunk into the current upstream trunk, which
may well have changed since you went offline.

You can purposely work offline by disabling autosync mode:

    $ fossil set autosync 0

Until you re-enable it (`autosync 1`) Fossil will stop trying to sync
your local changes back to the central repo.  In this mode, Fossil works
more like Git's default mode, buying you many of the same problems that
go along with that working style.  I recommend disabling autosync mode
only when you are truly going to be offline, and don't want Fossil
attempting to sync when you know it will fail.


Getting Developer Access
----

The administrator of this repository is Warren Young, whose email you
can find on the [official PiDP-8/I project mailing list][ggml].  I
generally give developer access to anyone who makes a reasonable
request.


Creating Branches
----

Creating a branch in Fossil is scary-simple, to the point that those
coming from other version control systems may ask, "Is that really all
there is to it?"  Yes, really, this is it:

    $ fossil ci --branch new-branch-name

That is to say, you make your changes as you normally would; then when
you go to check them in, you give the `--branch` option to the
`ci/checkin` command to put the changes on a new branch, rather than add
them to the same branch the changes were made against.

While developers with login rights to the PiDP-8/I Fossil instance are
allowed to check in on the trunk at any time, we recommend using
branches whenever you're working on something experimental, or where you
can't make the necessary changes in a single coherent checkin.
Basically, `trunk` should always build without error, and it should
always function correctly.  Branches are for isolating work until it is
ready to merge into the trunk.

Here again we have a difference with Git: because Fossil normally syncs
your work back to the central repository, this means we get to see the
branches you are still working on.  This is a *good thing*.  Do not fear
committing broken or otherwise bad code to a branch.  [You are not your
code.][daff]  We are software developers, too: we understand that
software development is an iterative process, and that not all ideas
spring forth perfect and production-ready from the fingers of its
developers.  These public branches let your collaborators see what
you're up to, and maybe lend advice or a hand in the work, but mostly
public branches let your collaborators see what you're up to, so they're
not surprised when the change finally lands in trunk.

This is part of what I mean about Fossil fostering close cooperation
rather than fostering wild tangents.

Jim McCarthy (author of [Dynamics of Software Development][dosd]) has a
presentation on YouTube that touches on this topic at a couple of
points:

* [Don't go dark](https://www.youtube.com/watch?v=9OJ9hplU8XA)
* [Beware of a guy in a room](https://www.youtube.com/watch?v=oY6BCHqEbyc)

Fossil's sync-by-default behavior fights these negative tendencies.

PiDP-8/I project developers are welcome to create branches at will. The
main rule is to follow the branch naming scheme: all lowercase with
hyphens separating words. See the [available branch list][brlist] for
examples to emulate.

[brlist]: https://tangentsoft.com/pidp8i/brlist
[daff]:   http://www.hanselman.com/blog/YouAreNotYourCode.aspx
[dosd]:   http://amzn.to/2iEVoBL


Debug Builds
----

By default, the build system creates a release build, but you can force
it to produce a binary without as much optimization and with debug
symbols included:

     $ ./configure --debug-mode


Manipulating the Build System Source Files
----

The [autosetup build system][asbs] is composed of these files and
directories:

     auto.def
     autosetup/
     configure
     Makefile.in

Unlike with GNU Autoconf, which you may be familiar with, the
`configure` script is not output from some other tool.  It is just a
driver for the Tcl and C code under the `autosetup` directory.  If you
have to modify any of these files to get some needed effect, you should
try to get that change into the upstream project, then merge that change
down into the local copy when it lands upstream.

The bulk of the customization to the build system is in `auto.def`,
which is a Tcl script run by `autosetup` via the `configure` script.
Some knowledge of [Tcl syntax][tcldoc] will therefore be helpful in
modifying it.

If you do not have Tcl installed on your system, `configure` builds a
minimal Tcl interpreter called `jimsh0`, based on the [Jim Tcl][jim]
project.  Developers working on the build system are encoruaged to use
this stripped-down version of Tcl rather than "real" Tcl because Jim Tcl
is more or less a strict subset of Tcl, so any changes you make that
work with the `jimsh0` interpreter should also work with "real" Tcl, but
not vice versa.  If you have Tcl installed and don't really need it,
consider uninstalling it to force `autosetup` to build and use `jimsh0`.

The `Makefile.in` file is largely a standard [GNU `make`][gmake] file
excepting only that it has variables substituted into it by
[`autosetup`][asbs] using its `@VARIABLE@` syntax.  At this time, we do
not attempt to achieve compatibility with other `make` programs, though
in the future we may need it to work with [BSD `make`][bmake] as well,
so if you are adding features, you might want to stick to the common
subset of features implemented by both the GNU and BSD flavors of
`make`.  We do not anticpate any need to support any other `make`
flavors.

(This, by the way, is why we're not using some heavy-weight build system
such as the GNU Autotools, CMake, etc.  The primary advantage of GNU
Autotools is that you can generate source packages that will configure
and build on weird and ancient flavors of Unix; we don't need that.
Cross-platform build systems such as CMake ease building the same
software on multiple disparate platforms straightforward, but the
PiDP-8/I software is built primarily on and for a single operating
system, Rasbpian Linux.  It also happens to build and run on other
modern Unix and Linux systems, for which we also do not need the full
power of something like CMake.  `autosetup` and GNU `make` suffice for
our purposes here.)

[asbs]:   http://msteveb.github.io/autosetup/
[bmake]:  https://www.freebsd.org/doc/en/books/developers-handbook/tools-make.html
[gmake]:  https://www.gnu.org/software/make/
[jim]:    http://jim.tcl.tk/
[tcldoc]: http://wiki.tcl.tk/11485


Submitting Patches
----

If you do not have a developer login on the PiDP-8/I software
repository, you can still send changes to the project.

The simplest way is to say this after developing your change against the
trunk of PiDP-8/I:

    $ fossil diff > my-changes.patch

Then attach that file to a new [PiDP-8/I mailing list][ggml] message
along with a declaration of the license you wish to contribute your
changes under.  We suggest using the [SIMH license][simhl], but any
[non-viral][viral] [OSI-approved license][osil] should suffice.

If your change is more than a small patch, `fossil diff` might not
incorporate all of the changes you have made.  The old unified `diff`
format can't encode branch names, file renamings, file deletions, tags,
checkin comments, and other Fossil-specific information.  For such
changes, it is better to send a Fossil bundle:

    $ fossil set autosync 0                # disable autosync
    $ fossil checkin --branch my-changes
      ...followed by more checkins on that branch...
    $ fossil bundle export --branch my-changes my-changes.bundle

After that first `fossil checkin --branch ...` command, any subsequent
changes will also be made on that branch without needing a `--branch`
option until you explicitly switch to some other branch.  This lets you
build up a larger change on a private branch until you're ready to
submit the whole thing as a bundle.

Because you are working on a branch on your private copy of the
PiDP-8/I Fossil repository, you are free to make as many checkins as
you like on the new branch before giving the `bundle export` command.

Once you are done with the bundle, send it to the mailing list just as
with the patch.

If you provide a quality patch, we are likely to offer you a developer
login on [the repository][repo] so you don't have to continue with the
patch or bundle methods.

Please make your patches or experimental branch bundles against the tip
of the current trunk.  PiDP-8/I often drifts enough during development
that a patch against a stable release may not apply to the trunk cleanly
otherwise.

[osil]:  https://opensource.org/licenses
[repo]:  http://tangentsoft.com/pidp8i/
[simhl]: https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md
[viral]: https://en.wikipedia.org/wiki/Viral_license


The PiDP-8/I Software Project Code Style Rules
----

Every code base should have a common code style.  Love it or
hate it, here are PiDP-8/I's current code style rules:

**C Source Code**

File types: `c`, `h`, `c.in`

We follow the SIMH project's pre-existing code style when modifying one
of its source files:

*   Spaces for indents, size 4

*   DOS line endings.  (Yes, even though this is a Linux-based project!
    All decent Linux text editors can cope with this.)

*   Function, structure, type, and variable names are all lowercase,
    with underscores separating words

*   Macro names are in `ALL_UPPERCASE_WITH_UNDERSCORES`

*   Whitespace in the SIMH C files is of a style I have never seen
    anywhere else in my decades of software development.  This example
    shows the important features:

        int some_function (char some_parameter)
        {
        int some_variable = 0;

        if (some_parameter != '\0') {
            int nbytes = sizeof (some_parameter);
            char *buffer = malloc (4 * nbytes);

            switch (some_parameter) {
                case 'a':
                    do_something_with_buffer ((char *)buffer); 
                default:
                    do_something_else ();
                }
            }
        else {
            some_other_function (with_a_large, "number of parameters",
                wraps_with_a_single, "indent level");
            printf (stderr, "Failed to allocate buffer.\n");
            }
        }
    
    It is vaguely like K&R C style except that:

    -   The top level of statements in a function are not indented

    -   The closing curly brace is indented to the same level as the
        statement(s) it contains

    -   There is a space before all opening parentheses, not just those
        used in `if`, `while`, and similar flow control statements.

        Nested open parentheses do not have extra spaces, however.  Only
        the outer opening parenthesis has a space separating it from
        what went before.

    -   Multiple variables declared together don't have their types and
        variable names aligned in columns.

I find that this style is mostly sensible, but with two serious problems:
I find the indented closing curly braces confusing, and I find that the
loss of the first indent level for the statements inside a function makes
functions all visually run together in a screenful of code.  Therefore,
when we have the luxury to be working on a file separate from SIMH,
we use a variant of its style with these two changes, which you can
produce with the `tools/restyle` command.  See its internal comments for
details.

That gives the following, when applied to the above example:

        int some_function (char some_parameter)
        {
            int some_variable = 0;

            if (some_parameter != '\0') {
                int nbytes = sizeof (some_parameter);
                char *buffer = malloc (4 * nbytes);

                switch (some_parameter) {
                    case 'a':
                        do_something_with_buffer ((char *)buffer); 
                    default:
                        do_something_else ();
                }
            }
            else {
                some_other_function (with_a_large, "number of parameters",
                    wraps_with_a_single, "indent level");
                printf (stderr, "Failed to allocate buffer.\n");
            }
        }
    
If that looks greatly different, realize that it is just two indenting
level differences: add one indent at function level, except for the
closing braces, which we leave at their previous position.

SIMH occasionally exceeds 100-column lines.  I recommend breaking
long lines at 72 columns.  Call me an 80-column traditionalist.

When in doubt, mimic what you see in the current code.  When still in
doubt, ask on the mailing list.

[indent]: http://linux.die.net/man/1/indent


**Plain Text Files**

File types: `md`, `txt`

*   Spaces for indents, size 4.

*   Unix line endings.  The only common text editor I'm aware of that
    has a problem with this is Notepad, and people looking at these
    files anywhere other than unpacked on a Raspberry Pi box are
    probably looking at them through the Fossil web interface on
    tangentsoft.com.

*   Markdown files must follow the syntax flavor understood by
    [Fossil's Markdown interpreter][fmd].

[fmd]: https://tangentsoft.com/pidp8i/md_rules
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
########################################################################
# Makefile.in - Processed by autosetup's configure script to generate
#    the GNU make(1) file for building the PiDP-8/I software.
#
# If you are seeing this at the top of a file called Makefile and you
# intend to make edits, do that in Makefile.in.  Saying "make" will then
# re-build Makefile from that modified Makefile.in before proceeding to
# do the "make" operation.
#
# Copyright © 2015-2017 Oscar Vermeulen, Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

# Git commit ID of the latest version of the SIMH 4 project on GitHub 
# that has been merged into this source base.
SGCID=17903827bdb294f7e60d4c7f172bd6a1a71dfbd5

CFLAGS = @CFLAGS@ -Wno-unused-result -Wno-parentheses @BUILDMODE@ \
	-DUSE_READER_THREAD -DHAVE_DLOPEN=so -DPIDP8I -DSIM_ASYNCH_IO \
	-DHAVE_REGEX_H -DHAVE_GLOB -DSIM_GIT_COMMIT_ID=$(SGCID) \
	-D_GNU_SOURCE -U__STRICT_ANSI__ \
	-I @srcdir@/src -I @srcdir@/src/PDP8 -I src

SIM = bin/pidp8i-sim
BINS = bin/palbart $(SIM) bin/pidp8i-test libexec/scanswitch

BUILDDIRS = bin libexec obj/PDP8

INSTDIRS = bin etc libexec share/boot share/media share/man/man1

OBJS = \
	obj/gpio-common.o \
	obj/PDP8/pdp8_df.o \
	obj/PDP8/pdp8_cpu.o \
	obj/PDP8/pdp8_clk.o \
	obj/PDP8/pdp8_ct.o \
	obj/PDP8/pdp8_dt.o \
	obj/PDP8/pdp8_fpp.o \
	obj/PDP8/pdp8_lp.o \
	obj/PDP8/pdp8_mt.o \
	obj/PDP8/pdp8_pt.o \
	obj/PDP8/pdp8_rf.o \
	obj/PDP8/pdp8_rk.o \
	obj/PDP8/pdp8_rl.o \
	obj/PDP8/pdp8_rx.o \
	obj/PDP8/pdp8_sys.o \
	obj/PDP8/pdp8_td.o \
	obj/PDP8/pdp8_tsc.o \
	obj/PDP8/pdp8_tt.o \
	obj/PDP8/pdp8_ttx.o \
	obj/PDP8/pidp8i.o \
	obj/scp.o \
	obj/sim_console.o \
	obj/sim_disk.o \
	obj/sim_ether.o \
	obj/sim_fio.o \
	obj/sim_serial.o \
	obj/sim_sock.o \
	obj/sim_tape.o \
	obj/sim_timer.o \
	obj/sim_tmxr.o \
	obj/sim_video.o

ifeq (@BUILD_DEEPER_THOUGHT@, 1)
BINS += bin/deeper
endif

LIBS = -lm -ldl -lpthread

ASM_PTS     := $(wildcard @srcdir@/asm/*.pal)
ASM_PTS     := $(subst @srcdir@/asm,bin,$(ASM_PTS))
ASM_PTS     := $(ASM_PTS:.pal=.pt)
EX_PTS      := $(wildcard @srcdir@/examples/*.pal)
EX_PTS      := $(subst @srcdir@/examples,bin,$(EX_PTS))
EX_PTS      := $(EX_PTS:.pal=.pt)
LISTINGS    := $(ASM_PTS:.pt=.lst) $(EX_PTS:.pt=.lst)
LISTINGS    := $(subst bin/,obj/,$(LISTINGS))
BOOTSCRIPTS := $(LISTINGS:.lst=.script)
BOOTSCRIPTS := $(subst obj/,boot/,$(BOOTSCRIPTS)) \
	boot/1.script \
	boot/5.script

# List of *.in files from auto.def file, except for this present file
# (Makefile.in) which is handled separately.  This list should only
# change when the list of "make-template" calls in auto.def changes.
#
# If the first file listed below changes, change the AUTOREBUILD rule
# near the end of this file to match!
INFILES = \
	@srcdir@/bin/pidp8i.in \
	@srcdir@/boot/0.script.in \
	@srcdir@/boot/2.script.in \
	@srcdir@/boot/3.script.in \
	@srcdir@/boot/4.script.in \
	@srcdir@/boot/6.script.in \
	@srcdir@/boot/7.script.in \
	@srcdir@/etc/pidp8i-init.in \
	@srcdir@/etc/sudoers.in \
	@srcdir@/src/gpio-common.c.in \
	@srcdir@/src/PDP8/pidp8i.c.in \
	@srcdir@/tools/simh-update.in
PRECIOUS_INFILES = \
	@srcdir@/Makefile.in \
	@srcdir@/examples/Makefile.in \
	@srcdir@/src/Makefile.in \
	@srcdir@/src/PDP8/Makefile.in
OUTFILES := $(subst @srcdir@/,,$(INFILES))
OUTFILES := $(subst .in,,$(OUTFILES))
PRECIOUS_OUTFILES := $(subst @srcdir@/,,$(PRECIOUS_INFILES))
PRECIOUS_OUTFILES := $(subst .in,,$(PRECIOUS_OUTFILES))

CLTXT = /boot/cmdline.txt

.PHONY: tags
.PRECIOUS: $(PRECIOUS_OUTFILES)

all: $(OUTFILES) $(PRECIOUS_OUTFILES) $(BUILDDIRS) $(BINS) $(BOOTSCRIPTS) $(LISTINGS) $(ASM_PTS) $(EX_PTS)
	@chmod 755 bin/pidp8i

clean:
	@rm -f $(BINS) $(BOOTSCRIPTS) $(ASM_PTS) $(EX_PTS) $(LISTINGS) $(OBJS) $(OUTFILES) \
		tags \
		obj/*.d \
		obj/*.o \
		obj/PDP8/*.d \
		@srcdir@/examples/*.err
	@-rmdir -p $(BUILDDIRS) 2> /dev/null || true

distclean: clean
	@rm -f $(PRECIOUS_OUTFILES) \
		config.log \
		autosetup/jimsh0 \
		src/config.h

ctags tags:
	@ctags -R @srcdir@
ifeq (@HAVE_PROG_CSCOPE@, 1)
	@cscope -bR -s@srcdir@
endif

install: all
	@echo Installing to @prefix@...

	@# Create any missing install tree directories
	for d in $(INSTDIRS) ; do @INSTALL@ -m 755 -d @prefix@/$$d ; done

	@# Install files into those dirs and set their perms
	for f in $(BINS) ; do @INSTALL@ -m 755 -D -s $$f @prefix@/$$f ; done
	@INSTALL@ -m 755 @srcdir@/bin/pidp8i @prefix@/bin
	-for f in @prefix@/bin/pidp8i-* ; do setcap 'cap_sys_nice=eip' $$f ; done || true
	test -e @MEDIADIR@/os8/os8.rk05 || $(MAKE) mediainstall

	@# If this is a Debian-type system, install needed helper programs
	@test -x /usr/bin/apt-get -a ! -h /media/usb && apt-get -y install usbmount || true
	@test -x /usr/bin/apt-get -a ! -x /usr/bin/screen && apt-get -y install screen || true

	@# Disable competing services if this is a Raspberry Pi
	@(test -x /bin/systemctl && /bin/systemctl disable deeper || true)
	@(test -x /bin/systemctl && /bin/systemctl disable pidp8  || true)

	@# Install the init script if this system is systemd based.
	@INSTALL@ -m 755 @srcdir@/etc/pidp8i-init @prefix@/etc
	@(  test -w /etc/init.d -a -x /bin/systemctl && \
		ln -sf @ABSPREFIX@/etc/pidp8i-init /etc/init.d/pidp8i && \
		/bin/systemctl enable pidp8i \
	) || true

	@# Give the install user permission to use GPIO if done on a Pi
	@grep -q '^gpio:' /etc/group && usermod -a -G gpio @INSTUSR@ || true

	@# Give the install user permission to shut down and reboot the Pi
	@# if this is a systemd/sudo based system.
	@(	test -d /etc/sudoers.d -a -w /etc/sudoers.d -a -x /bin/systemctl && \
		@INSTALL@ -m 440 -o root -g root @srcdir@/etc/sudoers \
		    /etc/sudoers.d/099_pidp8i \
	) || true

	@# Add installation bin dir to the non-root user's PATH unless it's
	@# already in there or we aren't running under sudo.
	@(for p in .profile .bash_profile ; do \
		test -n "$$SUDO_USER" -a -w "/home/$$SUDO_USER/$$p" && \
			! grep -qF "@ABSPREFIX@/bin" "/home/$$SUDO_USER/$$p" && \
			echo "export PATH=\$$PATH:@ABSPREFIX@/bin" >> "/home/$$SUDO_USER/$$p" ; \
	done) || true

	@# Ditto for MANPATH
	@(for p in .profile .bash_profile ; do \
		test -n "$$SUDO_USER" -a -w "/home/$$SUDO_USER/$$p" && \
			! grep -qF "@ABSPREFIX@/share/man" "/home/$$SUDO_USER/$$p" && \
			echo "export MANPATH=\$$MANPATH:@ABSPREFIX@/share/man" >> "/home/$$SUDO_USER/$$p" ; \
	done) || true

	@# If serial mod is disabled, turn off serial console and kgdb stuff
	@# in case they were enabled previously, else they will fight with
	@# our use of GPIO.
	@(  test -z "@PCB_SERIAL_MOD_ANY@" -a -r $(CLTXT) && ! -w $(CLTXT) && \
		cp -p $(CLTXT) "$(CLTXT)"_orig && \
		sed -e 's/console\=[a-zA-Z0-9]+,[0-9]+ //' \
		    -e  's/kgdboc\=[a-zA-Z0-9]+,[0-9]+ //' -i $(CLTXT) \
	) || true

	@# Install palbart stuff
	@INSTALL@ -m 755 bin/palbart @prefix@/bin
	@INSTALL@ -m 644 @srcdir@/palbart/palbart.1 @prefix@/share/man/man1

mediainstall:
	@echo "[Re]installing OS and program media..."
	@cd @srcdir@ ; \
	find media \( \
		-name \*.bin  -o \
		-name \*.dsk  -o \
		-name \*.rk05 -o \
		-name \*.tu56 \
	\) -exec @INSTALL@ -D -m 664 -g @INSTGRP@ {} @ABSPREFIX@/share/{} \;
	@INSTALL@ -m 664 -g @INSTGRP@ boot/*.script @BOOTDIR@

reconfig:
	@AUTOREMAKE@

release: all
	@srcdir@/tools/mkrel

run:
	$(SIM) @srcdir@/boot/0.script

simh-update simh-update-f:
	@@srcdir@/tools/simh-update $(subst simh-update,,$@)


# Rule for compiling *.c to *.o and autogenerating dependency info.
# Explained at http://scottmcpeak.com/autodepend/autodepend.html
#
# Reflect any changes here into near-duplicate below!
obj/%.o: @srcdir@/src/%.c
	$(CC)  -c $(CFLAGS) @srcdir@/src/$*.c -o obj/$*.o
	$(CC) -MM $(CFLAGS) @srcdir@/src/$*.c > obj/$*.d
	@mv -f obj/$*.d obj/$*.d.tmp
	@sed -e 's|.*:|obj/$*.o:|' < obj/$*.d.tmp > obj/$*.d
	@sed -e 's/.*://' -e 's/\\$$//' < obj/$*.d.tmp | fmt -1 | \
		sed -e 's/^ *//' -e 's/$$/:/' >> obj/$*.d
	@rm -f obj/$*.d.tmp

# Near-duplicate of above rule for those *.c files generated from *.c.in
# files in the srcdir.  Needed when building out-of-tree.
obj/%.o: src/%.c
	$(CC)  -c $(CFLAGS) src/$*.c -o obj/$*.o
	$(CC) -MM $(CFLAGS) src/$*.c > obj/$*.d
	@mv -f obj/$*.d obj/$*.d.tmp
	@sed -e 's|.*:|obj/$*.o:|' < obj/$*.d.tmp > obj/$*.d
	@sed -e 's/.*://' -e 's/\\$$//' < obj/$*.d.tmp | fmt -1 | \
		sed -e 's/^ *//' -e 's/$$/:/' >> obj/$*.d
	@rm -f obj/$*.d.tmp

# Rule for building PAL assembly language programs in asm/*.pal.
obj/%.lst bin/%.pt: @srcdir@/asm/%.pal bin/palbart
	bin/palbart -lr $< || cat obj/$*.err
	mv @srcdir@/asm/$*.lst obj
	mv @srcdir@/asm/$*.rim bin/$*.pt

# Ditto for those in examples/*.pal.
obj/%.lst bin/%.pt: @srcdir@/examples/%.pal bin/palbart
	bin/palbart -lr $< || cat obj/$*.err
	mv @srcdir@/examples/$*.lst obj
	mv @srcdir@/examples/$*.rim bin/$*.pt

# Rule for translating PAL assembly language program listings to SIMH
# boot scripts.
boot/%.script: obj/%.lst
	@srcdir@/tools/mkbootscript $<

# Rules for making aliases of named example programs translated to boot
# scripts as special numbered boot scripts
boot/1.script: boot/hs-rim-loader.script
	ln -f $< $@
boot/5.script: boot/ac-mq-blinker.script
	ln -f $< $@

bin/palbart: @srcdir@/palbart/palbart.c
	$(CC) -Wall -Wno-strict-prototypes @BUILDMODE@ $< -o $@
	$(CC) -MM $< -o obj/palbart.d

$(BUILDDIRS):
	mkdir -p $@

$(SIM): $(OBJS) obj/gpio-@LED_DRIVER_MODULE@ls.o
	$(CC) -o $@ $^ $(LIBS)

bin/pidp8i-test: obj/test.o obj/gpio-nls.o obj/gpio-common.o
	$(CC) -o $@ $^ $(LIBS) -lncurses

bin/deeper: obj/deeper.o obj/gpio-@LED_DRIVER_MODULE@ls.o obj/gpio-common.o
	$(CC) -o $@ $^ $(LIBS)

libexec/scanswitch: obj/scanswitch.o obj/gpio-nls.o obj/gpio-common.o
	$(CC) -o $@ $^ $(LIBS)

ifeq ($(findstring clean,$(MAKECMDGOALS)),)
Makefile: @srcdir@/Makefile.in @srcdir@/auto.def $(INFILES) $(PRECIOUS_INFILES) @AUTODEPS@
	@AUTOREMAKE@ && $(MAKE)

# Rebuild simulator whenever one of its *.in files change.
#
# This is trickier than it appears.  If you simply make $(OUTFILES)
# depend on $(INFILES), make(1) thinks it can build all of $(OUTFILES)
# in parallel if given -jN, which causes ./configure --args to run N
# times in parallel, which blows the build system up right good and
# proper; bits everywhere.  We purposely list only the first file in
# $(INFILES) here to prevent that.  The other files in $(INFILES) will
# also be built, which confuses make(1) somewhat, but it figures things
# out on the subsequent $(MAKE) call.
#
# We also list files like tools/version which, when they change, trigger
# a rebuild of $(OUTFILES) because their change may affect what gets
# generated.  This happened when we moved from 8 to 10 character Fossil
# artifact IDs in the version string to match Fossil timeline's default.
bin/pidp8i: @srcdir@/bin/pidp8i.in @srcdir@/tools/version
	@AUTOREMAKE@ && $(MAKE)
endif

# Rebuild simulator if the version string tool changes, since its output
# may have changed.
src/gpio-common.c: @srcdir@/tools/version

-include $(OBJS:.o=.d) obj/scanswitch.d

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































































































































































































































































































































































































































































Deleted README-throttle.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# Throttling the Simulator

When you do not give the `--throttle` option to the `configure` script,
the simulator's speed is set based on the number of CPU cores detected
by the `tools/corecount` script.


## Multi-Core Default

If `corecount` detects a multi-core system, the default behavior is to
not throttle the simulator at all, since there are only 2 threads in the
software that take substantial amounts of CPU power.

The most hungry thread is the PDP-8 simulator proper, which runs flat-out,
taking an entire core's available power by default.

The other hungry thread is the one that drives the front panel LEDs,
which takes about 35% of a single core's power on a Raspberry Pi 3 when
you build the software with the incandescent lamp simulator enabled.

This leaves over 2 cores worth of CPU power untapped on multi-core
Raspberry Pis, so the system performance remains snappy even with the
simulator running.

You can force this behavior with `--throttle=none`.


## Single-Core Default

If the `configure` script decides that you're building this on a
single-core system, it purposely throttles the PDP-8 simulator so that
it takes about 50% of a single core's worth of power on your system.

Since different single-core Raspberry Pi boards run at different default
clock rates — overclocking aside — we cannot just set a single IPS value
and know that it's correct.

Besides that, SIMH's reaction to not having enough host CPU power to run
at the requested IPS rate is to *turn off throttling entirely*, thus
hogging the whole host CPU, exactly the opposite of what you want by
turning on throttling! Since host CPU power is briefly impacted when
starting the simulator up for the first time, SIMH's guesses about
whether you've asked it to run at too fast a rate undershoot the actual
capability of the hardware badly.

Worse, when you set the PiDP-8/I software to start on boot via
`systemd`, it's running in parallel with other startup tasks, further
reducing the amount of host CPU power available to the simulator at the
instant of startup, requiring an even lower IPS rate if you want to
prevent SIMH from going into no-throttle mode.

The solution to all of these problems is `set throttle 50%`, which tells
SIMH to dynamically adjust the IPS rate according to available host CPU
power. This does mean you don't get a steady IPS rate, but it does
enforce our wish to leave some CPU power left over for background tasks.

You might wish to adjust that default host/simulator CPU usage split.
The `--throttle` option accepts percentages:

     ./configure --throttle='75%'

Note the single-quoted value: you must do that to avoid problems with
the shell, since the percent character is special to it.

Incidentally, you cannot use this throttling feature to leave enough CPU
power on a single-core Pi to run the [incandescent lamp simulator][ils].
We've tried, and you have to clock the simulator down to less than the
speed of a PDP-8/S!  We're working on ways to improve the speed of that
lamp simulator to let it run on single-core raspberry Pis, but we may
not succeed. For this reason, the build system disables the incandescent
lamp simulator feature on a single-core Pi.

You can force the build system to select this throttle value even on a
multi-core Pi with `--throttle=single-core`.

You will erroneously get this single-core behavior if you run the
`configure` script on a system where `tools/corecount` has no built-in
way to count the CPU cores in your system correctly, so it returns 1,
forcing a single-core build.  That script currently only returns the
correct value on Linux, BSD, and macOS systems.  To fix it, you can
either say `--throttle=none` or you can patch `tools/corecount` to
properly report the number of cores on your system.  If you choose the
latter path, please send the patch to the mailing list so it can be
integrated into the next release of the software.


## Underclocking

There are many reasons to make the software run slower than it normally
would.  You may achieve such ends by giving the `--throttle` option to
the `configure` script:

*   `--throttle=CPUTYPE`: if you give a value referencing one of the
    many PDP-8 family members, it selects a value based on the execution
    time of a `TAD` instruction in direct access mode on that processor:

    | Value            | Alias For | Memory Cycle Time
    ---------------------------------------------------
    | `pdp8e`          | 416k      | 1.2 µs
    | `pdp8i`, `pdp8a` | 333k      | 1.5 µs
    | `pdp8l`, `pdp8`  | 313k      | 1.6 µs
    | `ha6120`         | 182k      | 2.7 µs
    | `im6100a`        | 200k      | 2.5 µs
    | `im6100`         | 100k      | 5 µs
    | `im6100c`        | 83k       | 6 µs
    | `pdp8s`          | 63k       | 8 µs

    I chose `TAD` because it's a typical instruction for the processor,
    and its execution speed is based on the memory cycle time for the
    processor, an easy specification to find.  Other instructions (e.g.
    most OPR instructions) execute faster than this, while others (e.g.
    IOT) execute far slower.  (See the processor's manual for details.)

    SIMH, on the other hand, does not discriminate.  When you say
    `--throttle=pdp8i`, causing the build system to insert `SET THROTTLE
    333k` commands into the SIMH boot scripts, the SIMH PDP-8 simulator
    does its best to execute exactly 333,000 instructions per second,
    regardless of the instruction type.  Consequently, if you were to
    benchmark this simulator configured with one of the options above,
    there would doubtless be some difference in execution speed when
    compared to the original hardware, depending on the mix of
    instructions executed.

    (See the I/O Matters section below for a further complication.)

    The values for the Intersil and Harris CMOS microprocessors are for
    the fastest clock speed supported for that particular chip.  Use the
    `STRING` form of this option (documented below) if you wish to
    emulate an underclocked microprocessor.

*   `--throttle=human`: Causes the computer to throttle the human.

    "I'm sorry, Dave, but you are not worthy to run this software."

    "Aaackkthhhpptt..."

    No, wait, that can't be right.
    
    Let's see here...ah, yes, what it *actually* does is slows the
    processor down to 10 instructions per second, about the fastest that
    allows the human eye to easily discern LED state changes as
    separate.  If you increase it very much above this, the eye starts
    seeing the LED state changes as a blur.

    This mode is useful for running otherwise-useful software as a
    "blinkenlights" demo.

    This mode disables the incandescent lamp simulator (ILS); see below.

*   `--throttle=trace`: Runs one instruction per second.  The effect is
    as if you were running a PDP-8/I in single-instruction mode and were
    pressing the `CONT` button once a second to step through a program.

    This mode also disables the ILS.

*   `--throttle=STRING`: any value not otherwise understood is passed
    directly to SIMH in `SET THROTTLE` commands inserted into the
    generated `boot/*.script` files.  You can use any string here that
    SIMH itself supports; [read the fine manual][tfm].

    If you use the ratio form here (e.g. `--throttle=123/456`) the
    configuration script disables the ILS feature because of the way
    SIMH handles this type of timing.  The ratio form of CPU throttling
    tells SIMH to run some number of instructions and then sleep for
    some number of milliseconds.  (The above 123/456 example means "run
    123 instructions, then sleep for 456 ms.")  This batched instruction
    execution scheme interferes with the high-speed LED panel update
    rate, so we must disable the ILS when running with such a throttle
    value set.

    Therefore, you should only use the ratio form of throttle value when
    you need to get under 1000 instructions per second.  For any value
    over that, give `--throttle=1k` or higher, which allows the ILS
    feature to properly maintain its LED brightness values.


## I/O Matters

The throttle mechanism discussed above only affects the speed of the
PDP-8 CPU simulator. It does not affect the speed of I/O operations.

The only I/O channel you can throttle in the same way is a serial
terminal by purposely choosing a slower bit rate for it than the maximum
value.  If you set it to 110 bps, it runs at the speed of a Teletype
Model 33 ASR, the most common terminal type used for the PDP-8/I, and
most other early PDP-8 flavors.  Later PDP-8s were often paired with (or
integrated into!) glass TTYs such as the VT05, which flew along at 2400
bps.  Then things got really fancy with the VT52, which screamed along
at 9600 bps. Wowee!

I'm not aware of a way to make SIMH slow the other I/O operations, such
as disk access speeds, in order to emulate the speed of the actual
hardware.


## License

Copyright © 2017 by Warren Young. This document is licensed under
the terms of [the SIMH license][sl].

[sl]:  https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md
[ils]: https://tangentsoft.com/pidp8i/wiki?name=Incandescent+Lamp+Simulator
[tfm]: https://tangentsoft.com/pidp8i/uv/doc/simh/main.pdf
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































































































































































Deleted README.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# Getting Started with the PiDP-8/I Software

## Prerequisites

*   A Raspberry Pi with the 40-pin GPIO connector.  That rules out the
    first-generation Raspberry Pi model A and B boards which had a
    26-pin GPIO connector.

*   An SD card containing Raspbian or something sufficiently close.
    This software is currently tested with the Jessie Lite distribution.

    Ideally, you will install a fresh OS image onto an unused SD card
    rather than use this software to modify an existing OS installation,
    but there is currently no known hard incompatibilty that prevents
    you from integrating this software into an existing OS.

*   This software distribution, unpacked somewhere convenient within the
    Raspberry Pi filesystem.

    Unlike with the [upstream 2015.12.15 release][upst], this present
    release of the software should *not* be unpacked into `/opt/pidp8`.
    I recommend that you unpack it into `$HOME/src`, `/usr/local/src` or
    similar, but it really doesn't matter where you put it, as long as
    your user has full write access to that directory.

*   A working C compiler and other standard Linux build tools, such as
    `make(1)`.  On Debian type systems — including Raspbian — you can
    install such tools with `sudo apt install build-essential`


## Configuring, Building and Installing

This software distribution builds and installs in the same way as most
other Linux/Unix software these days.  The short-and-sweet is:

    $ ./configure && make && sudo make install

If you've checked out a new version of the source code and the `make`
step fails, try redoing the `configure` step. Sometimes changes made to
the source code invalidate prior `make` dependencies, which are
implicitly repaired by the `configure` script.


### Configure Script Options

You can change a few things about the way the software is built and
installed by giving options to the `configure` script:


#### --prefix

Perhaps the most widely useful `configure` script option is `--prefix`,
which lets you override the default installation directory,
`/opt/pidp8i`.  You could make it install the software under your home
directory on the Pi with this command:

    $ ./configure --prefix=$HOME/pidp8i && sudo make install

Although this is installing to a directory your user has write access
to, you still need to install via `sudo` because the installation
process does other things that do require `root` access.


#### --no-lamp-simulator

If you build the software on a multi-core host, the PDP-8/I simulator is
normally built with the [incandescent lamp simulator][ils] feature,
which drives the LEDs in a way that mimics the incandescent lamps used
in the original PDP-8/I. (We call this the ILS for short.) This feature
currently takes too much CPU power to run on anything but a multi-core
Raspberry Pi, currently limited to the Pi 2 and Pi 3 series.

If you configure the software on a single-core Pi — models A+, B+, and
Zero — the simulator uses the original low-CPU-usage LED driving method
instead. (a.k.a. NLS for short, named after this configuration option.)

Those on a multi-core host who want this low-CPU-usage LED driving
method can give the `--no-lamp-simulator` option to `configure`.  This
method not only uses less CPU, which may be helpful if you're trying to
run a lot of background tasks on your Pi 2 or Pi 3, it can also be
helpful when the CPU is [heavily throttled][thro].


#### --serial-mod

If you have done [Oscar's serial mod][sm1] to your PiDP-8/I PCB and the
Raspberry Pi you have connected to it, add `--serial-mod` to the
`configure` command above.

If you do not give this flag at `configure` time with these hardware
modifications in place, the front panel will not work correctly, and
trying to run the software may even crash the Pi.

If you give this flag and your PCBs are *not* modified, most of the
hardware will work correctly, but several lights and switches will not
work correctly.


#### --alt-serial-mod

This flag is for an [alternative serial mod by James L-W][sm2]. It
doesn't require mods to the Pi, and the mods to the PiDP-8/I board are
different from Oscar's.  This flag changes the GPIO code to work with
these modifications to the PiDP-8/I circuit design.

See the linked mailing list thread for details.

As with `--serial-mod`, you should only enable this flag if you have
actually done the mods as specified by James L-W.


#### --throttle

See [`README-throttle.md`][thro] for the values this option takes.  If
you don't give this option, the simulator runs as fast as possible, more
or less.


#### --help

Run `./configure --help` for more information on your options here.


## Overwriting the Local Simulator Setup

When you run `sudo make install` step on a system that already has an
existing installation, it purposely does not overwrite two classes of
files:

1.  **The binary PDP-8 media files**, such as the RK05 disk image that
    holds the OS/8 image the simulator boots from by default. These media
    image files are considered "precious" because you may have modified
    the OS configuration or saved personal files to the disk the OS
    boots from, which in turn modifies this media image file out in the
    host operating environment.

2.  **The PDP-8 simulator configuration files**, installed as
    `$prefix/share/boot/*.script`, which may similarly have local
    changes, and thus be precious to you.

Sometimes this "protect the precious" behavior isn't what you want.
(Gollum!) One common reason this may be the case is that you've damaged
your local configuration and want to start over. Another common case is
that the newer software you're installing contains changes that you want
to reflect into your local configuration.

You have several options here:

1.  If you just want to reflect upstream PDP-8 simulator configuration
    file changes into your local versions, you can hand-edit the
    installed simulator configuration scripts to match the changes in
    the newly-generated `boot/*.script` files under the build directory.

2.  If the upstream change is to the binary PDP-8 media image files and
    you're unwilling to overwrite them wholesale, you'll have to mount
    both versions of the media image files under the PDP-8 simulator and
    copy the changes over by hand.

3.  If your previously installed binary OS media images — e.g. the OS/8
    RK05 disk image that the simulator boots from by default — are
    precious but the simulator configuration scripts aren't precious,
    you can just copy the generated `boot/*.script` files from the build
    directory into the installation directory, `$prefix/share/boot`.
    (See the `--prefix` option above for the meaning of `$prefix`.)

4.  If neither your previously installed simulator configuration files
    nor the binary media images are precious, you can force the
    installation script to overwrite them both with a `sudo make
    mediainstall` command after `sudo make install`.

    Beware that this is potentially destructive! If you've made changes
    to your PDP-8 operating systems or have saved files to your OS
    system disks, this option will overwrite those changes!


## Testing

You can test your PiDP-8/I LED and switch functions with these commands:

    $ sudo systemctl stop pidp8i
    $ pidp8i-test

You may have to log out and back in before the second command will work,
since the installation script modifies your normal user's `PATH` the
first time you install onto a given system.

It is important to stop the PiDP-8/I simulator before running the test
program, since both programs need exclusive access to the LEDs and
switches on the front panel.  After you are done testing, you can start
the PiDP-8/I simulator back up with:

    $ sudo systemctl start pidp8i

See [its documentation][test] for more details.


## Using the Software

For the most part, this software distribution works like the upstream
[2015.12.15 distribution][usd].  Its [documentation][prj] therefore
describes this software too, for the most part.

The largest user-visible difference between the two software
distributions is that all of the shell commands affecting the software
were renamed to include `pidp8i` in their name:

1.  To start the simulator:

        $ sudo systemctl start pidp8i

    This will happen automatically on reboot unless you disable the
    service, such as in order to run one of the various [forks of Deeper
    Thought][dt2].

2.  To attach the terminal you're working on to the simulator:

        $ pidp8i

3.  To detach from the simulator's terminal interface while leaving the
    PiDP-8/I simulator running, type <kbd>Ctrl-A d</kbd>.  You can
    re-attach to it later with a `pidp8i` command.

4.  To shut the simulator down while attached to its terminal interface,
    type <kbd>Ctrl-E</kbd> to pause the simulator, then at the `simh>`
    prompt type `quit`.  Type `help` at that prompt to get some idea of
    what else you can do with the simulator command language, or read
    the [SIMH Users' Guide][sdoc].

5.  To shut the simulator down from the Raspbian command line:

        $ sudo systemctl stop pidp8i

There are [other major differences][mdif] between the upstream
distribution and this one.  See that linked wiki article for details.


## License

Copyright © 2016-2017 by Warren Young. This document is licensed under
the terms of [the SIMH license][sl].


[prj]:  https://tangentsoft.com/pidp8i/
[upst]: http://obsolescence.wixsite.com/obsolescence/pidp-8
[sm1]:  http://obsolescence.wixsite.com/obsolescence/2016-pidp-8-building-instructions
[sm2]:  https://groups.google.com/d/msg/pidp-8/-leCRMKqI1Q/Dy5RiELIFAAJ
[usd]:  http://obsolescence.wixsite.com/obsolescence/pidp-8-details
[dt2]:  https://github.com/VentureKing/Deeper-Thought-2
[sdoc]: https://tangentsoft.com/pidp8i/uv/doc/simh/main.pdf
[prj]:  http://obsolescence.wixsite.com/obsolescence/pidp-8
[test]: https://tangentsoft.com/pidp8i/doc/trunk/doc/pidp8i-test.md
[thro]: https://tangentsoft.com/pidp8i/doc/trunk/README-throttle.md
[mdif]: https://tangentsoft.com/pidp8i/wiki?name=Major+Differences
[sl]:   https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md
[ils]:  https://tangentsoft.com/pidp8i/wiki?name=Incandescent+Lamp+Simulator
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































































































































































































































































































































































































































Deleted RELEASE-PROCESS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# PiDP-8/I Software Release Process

This documents the process for producing release versions of the
software.


## Update ChangeLog.md

Trawl the Fossil timeline for user-visible changes since the last
release, and write them up in user-focused form into the `ChangeLog.md`
file.  If a regular user of the software cannot see a given change, it
shouldn't go in the `ChangeLog.md`; let it be documented via the
timeline only.


## Update the Release Branch

Run `make release` to check the `ChangeLog.md` file changes in, tagging
that checkin with a release version tag of the form vYYYYMMDD and merge
those changes into the `release` branch.

It runs entirely automatically unless an error occurs, in which case it
stops immediately, so check its output for errors before continuing.


## Update the Home Page Links

The zip and tarball links on the front page produce files named after
the date of the release. Those dates need to be updated immediately
after tagging the release, since they point at the "release" tag applied
by the previous step, so they begin shipping the new release immediately
after tagging it.


## Produce the Normal Binary OS Image

Start with the latest version of [Raspbian Lite][os] on a multi-core
Raspberry Pi.

1.  If the version of the base OS has changed since the last binary OS
    image was created, download the new one.

    While the OS is downloading, zero the SD card you're going to use
    for this, so the prior contents don't affect this process.
    
    Blast the base OS image onto the cleaned SD card.

2.  Boot it up on a multi-core Pi.

    Log in, then retreive and initialize BOSI:

        $ wget https://tangentsoft.com/bosi
        $ chmod +x bosi
        $ exec sudo ./bosi init

    The `exec` bit is required so that the `bosi` invocation is run as
    root without any processes running as `pi` in case the `init` step
    sees that user `pi` hasn't been changed to `pidp8i` here: the
    `usermod` command we give to make that change will refuse to do what
    we ask if there are any running processes owned by user `pi`.

    It will either reboot the system after completing its tasks
    successfully or exit early, giving the reason it failed.

3.  Clone the software repo and build the softare:

        $ ./bosi build

    On reboot, say `top -H` to make sure the software is running and
    that the CPU percentages are reasonable for the platform.

    You may also want to check that it is running properly with a
    `pidp8i` command.  Is the configuration line printed by the
    simulator correct?  Does OS/8 run?  Are there any complaints from
    SIMH, such as about insufficient CPU power?

4.  Do final inside-the-image steps:

        $ ./bosi prepare

5.  Move the SD card to a USB reader plugged into the Pi, boot the Pi
    from its prior SD card, and shrink the OS image:

        $ wget https://tangentsoft.com/bosi
        $ chmod +x bosi
        $ ./bosi shrink

6.  Move the USB reader to the Mac,¹ then say:

        $ bosi image [nls]

    For the ILS images, you can give "ils" as a parameter or leave it
    blank.

7.  The prior step rewrote the SD card with the image file it created.
    Boot it up and make sure it still works.  If you're happy with it,
    give this command *on the desktop PC*.

        $ bosi finish [nls]

    As above, the parameter can be "ils" or left off for the ILS images.

[os]: https://www.raspberrypi.org/downloads/raspbian/


## Produce the "No Lamp Simulator" Binary OS Image

Do the same series of steps above on a single-core Raspberry Pi, except
that you give "nls" parameters to the `image` and `finish` steps.


## Publicizing

While the NLS image uploads — the ILS image was already sent in step 7
in the first pass through the list above — compose the announcement
message, and modify the front page to point to the new images.  You
might also need to update the approximate image sizes reported on that
page.  Post the announcement message and new front page once that second
upload completes.


----------------------

### Footnotes

1.  The image production steps could just as well be done on a Linux box
    or on a Windows box via Cygwin or WSL, but the commands in that
    final stage change due to OS differences.  Since this document
    exists primarily for use by the one who uses it, there is little
    point in having alternatives for other desktop OSes above.  Should
    someone else take over maintainership, they can translate the above
    commands for their own desktop PC.


### License

Copyright © 2016-2017 by Warren Young. This document is licensed under
the terms of [the SIMH license][sl].

[sl]: https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































Deleted SIMH-LICENSE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Copyright © 2015-2017 by various authors

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the names of the authors above shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization from
those authors.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































Deleted asm/asr33-rim-loader.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/ asr33-rim-loader.pal
/
/ Load paper tapes in RIM format from a Teletype Model 33 ASR's paper
/ tape reader.  By contrast with the loader in hs-rim-loader.pal, this
/ is the low-speed paper tape RIM loader.
/
/ This is the RIM loader printed on the front panel of the PDP-8/I.  The
/ RIM loader in hs-rim-loader.pal (which is translated to boot/1.script
/ at build time) is similar to this one, but it works on the DEC high-
/ speed paper tape reader peripheral, which is where the PiDP-8/I's
/ automatic paper tape mounting feature attaches any tape images it
/ finds via USB.
/
/ Therefore, you cannot use this RIM loader if you want to use the
/ PiDP-8/I's automatic media attachment mechanism.  It is included
/ here mainly for documentation at the moment, but also in case
/ someone works out a way to build the simulator so that it can
/ conditionally load tapes from an emulated ASR-33.
/
/ Raw disassembly done from the octal values by Bernhard Baehr's PDP-8/E
/ Simulator.  Comments and labels by Warren Young.  Original copyright
/ by Digital Equipment Corporation: this program appeared in DEC manuals
/ and was printed on the front panel of every PDP-8/I.
/
/ SIMH: echo Installing the RIM loader for the ASR 33 paper tape reader...
/ SIMH: set df disabled

	*7755
	HLT		/ nonstandard: auto-halt on SIMH startup

	/ normal RIM loader entry point, 7756
NEXT,	KCC		/ clear PTR flag
RBYTE1,	KSF		/ loop until PTR is ready
	JMP RBYTE1
	KRB		/ read first byte in
	CLL RTL		/ shift it left by 2, clearing link as well
	RTL		/ and 2 more again
	SPA		/ if top bit of AC is set...
	JMP RBYTE1	/ ...AC contains the addr's value
	RTL		/ ...else rotate it another 2 positions
RBYTE2,	KSF		/ wait for next character
	JMP RBYTE2
	KRS		/ read second byte in
	SNL		/ if link is set...
	DCA I BYTE	/ ...it's the value's address
GOTVAL,	DCA BYTE	/ ...else it's the value at that addr
	JMP NEXT	/ go round again, getting next value from PTR
BYTE,	0
$
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































Deleted asm/hs-rim-loader.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/ hs-rim-loader.pal
/
/ Load paper tapes in RIM format from the DEC high-speed PTR.
/
/ This routine differs from that printed in DEC's manuals in that it
/ starts with a HLT instruction so that when you [re]start SIMH with
/ IF=1, running this program, the processor auto-halts, giving the user
/ the opportunity to attach a paper tape via DF or ATTACH, then start
/ the processor at 7756 as normal.
/
/ The RIM loader code printed on the front panel of the PDP-8/I differs
/ because it is for the the paper tape reader built into a Teletype
/ Model 33 ASR.  See asr33-rim-loader.pal for that other implementation,
/ including more information about it.
/
/ Raw disassembly done from the octal values by Bernhard Baehr's PDP-8/E
/ Simulator.  Comments and labels by Warren Young.  Original copyright
/ by Digital Equipment Corporation: this program appeared in many DEC
/ manuals printed throughout the PDP-8 era variants of which were made
/ (and thus documented) from 1965 to 1979.
/
/ SIMH: echo Installing the RIM loader for the DEC high-speed tape reader...
/ SIMH: set df disabled
/ SIMH: set cpu noidle

	*7755
	HLT		/ nonstandard: auto-halt on SIMH startup

	/ normal RIM loader entry point, 7756
	RFC		/ clear PTR flag
RBYTE1,	RSF		/ loop until PTR is ready
	JMP RBYTE1
	RCC		/ read first byte in
	CLL RTL		/ shift it left by 2, clearing link as well
	RTL		/ and 2 more again
	SPA		/ if top bit of AC is set...
	JMP GOTVAL	/ ...AC contains the addr's value
	RTL		/ ...else rotate it another 2 positions
RBYTE2,	RSF		/ wait for next character
	JMP RBYTE2
	RCC		/ read second byte in
	SNL		/ if link is set...
	DCA I BYTE	/ ...it's the value's address
GOTVAL,	DCA BYTE	/ ...else it's the value at that addr
	JMP RBYTE1	/ go round again, getting next value from PTR
BYTE,	0
$
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































Deleted auto.def.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
########################################################################
# auto.def - Configure file for the PiDP-8/I software build system,
#            based on autosetup.
#
# Copyright © 2016-2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

define defaultprefix /opt/pidp8i

use cc
use cc-lib

options {
	debug-mode        => "create a debug build (default is release)"
	no-lamp-simulator => "use simple LED driver instead of incandescent lamp simulator"
	serial-mod        => "use GPIO drive scheme suitable for Oscar Vermeulen's serial mod method"
	alt-serial-mod    => "use GPIO drive scheme suitable for James L-W's serial mod method"
	throttle:         => "override the throttle values in the boot scripts"
}

if {[opt-bool alt-serial-mod]} {
	msg-result "GPIO drive adjusted for James L-W's serial mods to the PiDP-8/I PCB."
	define PCB_SERIAL_MOD_JLW
	define PCB_SERIAL_MOD_ANY
}

if {[opt-bool serial-mod]} {
	msg-result "GPIO drive adjusted for O. Vermeulen's serial mods to the Pi & PiDP-8/I PCBs."
	define PCB_SERIAL_MOD_OV
	define PCB_SERIAL_MOD_ANY
}

if {[opt-bool debug-mode]} {
	msg-result "Creating a debuggable build."
	define BUILDMODE {-O0 -g}
} else {
	msg-result "Creating a release build."
	define BUILDMODE {-O2}
}

# High-level definitions
set builddir [get-define builddir]
set srcdir [get-define srcdir]
set cores [exec $srcdir/tools/corecount]

# Translate --throttle value to a SIMH command
set tv [opt-val throttle]
set tvsl [string length $tv]
if {($tvsl == 0 && $cores > 1) || $tv == "none"} {
	define SET_THROTTLE {set nothrottle}
	set tv "unlimited"
} else {
	# Rewrite symbolic values with values SIMH can understand.  See
	# README-throttle.md for the justification of these values.
	if {$tv == "single-core" || $tvsl == 0} {
		# It's a single-core Pi board, so just tell SIMH to take half
        # the host CPU power, leaving the rest left for background
        # tasks.  We can't use an IPS value here for several reasons.
        # See README-throttle.md for details.
        set tv "50%"
	} elseif {$tv == "pdp8e"} {
		set tv "416k"
	} elseif {$tv == "pdp8i" || $tv == "pdp8a"} {
		set tv "333k"
	} elseif {$tv == "pdp8l" || $tv == "pdp8"} {
		set tv "313k"
	} elseif {$tv == "ha6120"} {
		set tv "182k"
	} elseif {$tv == "im6100a"} {
		set tv "200k"
	} elseif {$tv == "im6100"} {
		set tv "100k"
	} elseif {$tv == "im6100c"} {
		set tv "83k"
	} elseif {$tv == "pdp8s"} {
		set tv "63k"
	} elseif {$tv == "human"} {
		set tv "1/100"
	} elseif {$tv == "trace"} {
		set tv "1/1000"
	}
	# else, assume --throttle was given a legal SIMH throttle value
    
    if {[string first "/" $tv] > -1} {
        # Assume the ratio given will push us below 1 kIPS, where ILS
        # fails badly because of the simulator's sleeping behavior, so
        # disable the ILS feature if we were going to build it.
        set cores 1
    }

	define SET_THROTTLE "set throttle $tv"
}
msg-result "Simulator CPU throttle set to $tv"

# Swap the incandescent lamp simulator feature out for the original LED
# driving method on single-core hosts.  The user can force this on
# multi-core hosts via --no-lamp-simulator.
if {($cores < 2) || [opt-bool no-lamp-simulator]} {
	msg-result "Driving PiDP-8/I front panel LEDs using low-CPU-usage method."
	define LED_DRIVER_MODULE n
	define ILS_MODE 0
} else {
	msg-result "Driving PiDP-8/I front panel LEDs using incandescent lamp simulator."
	define LED_DRIVER_MODULE i
	define ILS_MODE 1
}

# Check for headers, functions, etc. whose absence we can work around
cc-check-includes time.h
cc-check-function-in-lib clock_gettime rt
cc-check-functions clock_nanosleep nanosleep usleep
cc-check-functions sched_yield

# Ensure we have the libncurses development files installed here, else
# pidp8i-test won't build.
if {![cc-check-includes curses.h]} {
	user-error "Could not find curses.h.  Try installing libncurses-dev."
} elseif {![cc-check-function-in-lib initscr ncurses]} {
	user-error "Could not find initscr() in libncurses."
}

# We need to find an install(1) type program that supports -D.  The
# Raspberry Pi OSes typically used with the PiDB-8/I board do have this,
# but this package also runs on non-Linux OSes (e.g. for testing on a
# desktop Mac) so make sure we've got a suitable implementation.  The
# ginstall name is typical on non-Linux systems where GNU Coreutils was
# installed alongside the core OS utilities.
if {[cc-check-progs ginstall]} {
	define INSTALL ginstall
} elseif {[cc-check-progs install]} {
	if {[catch {exec install -D -d . >& /dev/null} result] == 0} {
		define INSTALL install
	} else {
		user-error "install(1) does not support -D; install GNU Coreutils."
	}
} else {
	user-error "No install(1) type program found; install GNU Coreutils."
}
msg-result "Found GNU install(1) program as [get-define INSTALL]."

# Also find GNU readlink in the same way
if {[cc-check-progs greadlink]} {
	set rlprg greadlink
} elseif {[cc-check-progs readlink]} {
	if {[catch {exec readlink -f . >& /dev/null} result] == 0} {
		set rlprg readlink
	} else {
		user-error "readlink(1) does not support -D; install GNU Coreutils."
	}
} else {
	user-error "No readlink(1) type program found; install GNU Coreutils."
}
msg-result "Found GNU readlink(1) as $rlprg."

# If we have cscope here, we'll use it in the "tags" target
define HAVE_PROG_CSCOPE [cc-check-progs cscope]

# Canonicalize some paths which may be relative and generate others from them
define ABSPREFIX [exec $rlprg -f [get-define prefix]]
define BOOTDIR  "[get-define ABSPREFIX]/share/boot"
define MEDIADIR "[get-define ABSPREFIX]/share/media"

# Remember the name and primary group of the user who installed this, since
# we want to give that group write privileges to some files when they're
# installed, and we want them to own the screen(1) session.
set instgrp [exec id -grn]
set instusr [exec id -urn]
if {$instusr == "root"} {
	msg-result "Error: This software will not install and run as root."
	user-error "Reconfigure without sudo!"
}
define INSTGRP $instgrp
define INSTUSR $instusr
msg-result "Install group for user-writeable files will be $instgrp."
msg-result "Owner of screen(1) session will be $instusr."

# Can we use any nonstandard flags here?  We don't bother including
# flags that both GCC and Clang support.  The ones inside the "if"
# block are those that Clang will accept in an autosetup test but
# then will yell about if you try to use them.  The test checks for
# an -f sub-option that Clang doesn't currently support even enough
# to fool autosetup.
cc-check-standards c99
if {![opt-bool debug-mode]} {
	cc-check-flags -fipa-cp-clone
	cc-check-flags -fno-strict-overflow
	cc-check-flags -fpredictive-commoning
	if ([get-define HAVE_CFLAG_FIPA_CP_CLONE]) {
		cc-check-flags -fgcse-after-reload
		cc-check-flags -finline-functions
		cc-check-flags -fno-unsafe-loop-optimizations
	}
}

# Embed this software's Fossil-based version string into gpio-common.c.
# Fail hard if we can't get this version string because all supported
# configurations require Fossil and work from a Fossil checkout.  Don't
# fall back on some lame "UNKNOWN" version string because that would
# mask a real problem that needs to be diagnosed.
set tool "tools/version"
set cmd "$srcdir/$tool"
set status [catch {exec $cmd} version]
if {$status != 0} {
    # The most likely cause for tools/version to fail is that the repo
    # file has become disassociated from the local checkout directory.
    set sql "select value from vvar where name=\"repository\""
    set cmd "fossil sql --no-repository $srcdir/.fslckout '$sql'"
    set status [catch {exec /bin/sh -c $cmd} path]
    if {$status != 0} {
        user-error "Fossil doesn't seem to work here.  Is it installed?\nCMD: $cmd"
    } elseif {[file exists $path]} {
        user-error "$tool failed to get checkout version from $path"
    } else {
        user-error "$tool failed: $path does not exist."
    }
}
define VERSION $version

# Build Deeper Thought if we find it here
if {[file exists "[get-define srcdir]/src/deeper.c"]} {
    set ls [string toupper "[get-define LED_DRIVER_MODULE]ls"]
	msg-result "Found Deeper Thought; building it against $ls GPIO module"
    define BUILD_DEEPER_THOUGHT 1
}

# Write outputs.
#
# NOTE: If you change the list of files here, change INFILES in
# Makefile.in, too.
make-config-header src/config.h \
	-auto {ENABLE_* HAVE_* PACKAGE_* SIZEOF_*} \
	-bare {ILS_MODE PCB_*}
make-template Makefile.in
make-template bin/pidp8i.in
make-template boot/0.script.in
make-template boot/2.script.in
make-template boot/3.script.in
make-template boot/4.script.in
make-template boot/6.script.in
make-template boot/7.script.in
make-template etc/pidp8i-init.in
make-template etc/sudoers.in
make-template examples/Makefile.in
make-template src/Makefile.in
make-template src/gpio-common.c.in
make-template src/PDP8/Makefile.in
make-template src/PDP8/pidp8i.c.in
make-template tools/simh-update.in
exec chmod +x "$builddir/tools/simh-update"
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































Deleted autosetup/LICENSE.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Unless explicitly stated, all files which form part of autosetup
are released under the following license:

---------------------------------------------------------------------
autosetup - A build environment "autoconfigurator"

Copyright (c) 2010-2011, WorkWare Systems <http://workware.net.au/>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions and the following
   disclaimer in the documentation and/or other materials
   provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE WORKWARE SYSTEMS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WORKWARE
SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
official policies, either expressed or implied, of WorkWare Systems.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































Deleted autosetup/README.autosetup.
1
This is autosetup v0.6.6. See http://msteveb.github.com/autosetup/
<


Deleted autosetup/autosetup.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
#!/bin/sh
# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved
# vim:se syntax=tcl:
# \
dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"

set autosetup(version) 0.6.6

# Can be set to 1 to debug early-init problems
set autosetup(debug) 0

##################################################################
#
# Main flow of control, option handling
#
proc main {argv} {
	global autosetup define

	# There are 3 potential directories involved:
	# 1. The directory containing autosetup (this script)
	# 2. The directory containing auto.def
	# 3. The current directory

	# From this we need to determine:
	# a. The path to this script (and related support files)
	# b. The path to auto.def
	# c. The build directory, where output files are created

	# This is also complicated by the fact that autosetup may
	# have been run via the configure wrapper ([getenv WRAPPER] is set)

	# Here are the rules.
	# a. This script is $::argv0
	#    => dir, prog, exe, libdir
	# b. auto.def is in the directory containing the configure wrapper,
	#    otherwise it is in the current directory.
	#    => srcdir, autodef
	# c. The build directory is the current directory
	#    => builddir, [pwd]

	# 'misc' is needed before we can do anything, so set a temporary libdir
	# in case this is the development version
	set autosetup(libdir) [file dirname $::argv0]/lib
	use misc

	# (a)
	set autosetup(dir) [realdir [file dirname [realpath $::argv0]]]
	set autosetup(prog) [file join $autosetup(dir) [file tail $::argv0]]
	set autosetup(exe) [getenv WRAPPER $autosetup(prog)]
	if {$autosetup(installed)} {
		set autosetup(libdir) $autosetup(dir)
	} else {
		set autosetup(libdir) [file join $autosetup(dir) lib]
	}
	autosetup_add_dep $autosetup(prog)

	# (b)
	if {[getenv WRAPPER ""] eq ""} {
		# Invoked directly
		set autosetup(srcdir) [pwd]
	} else {
		# Invoked via the configure wrapper
		set autosetup(srcdir) [file-normalize [file dirname $autosetup(exe)]]
	}
	set autosetup(autodef) [relative-path $autosetup(srcdir)/auto.def]

	# (c)
	set autosetup(builddir) [pwd]

	set autosetup(argv) $argv
	set autosetup(cmdline) {}
	# options is a list of known options
	set autosetup(options) {}
	# optset is a dictionary of option values set by the user based on getopt
	set autosetup(optset) {}
	# optdefault is a dictionary of default values for options
	set autosetup(optdefault) {}
	set autosetup(optionhelp) {}
	set autosetup(showhelp) 0

	# Parse options
	use getopt

	# At the is point we don't know what is a valid option
	# We simply parse anything that looks like an option
	set autosetup(getopt) [getopt argv]

	#"=Core Options:"
	options-add {
		help:=local  => "display help and options. Optionally specify a module name, such as --help=system"
		version      => "display the version of autosetup"
		ref:=text manual:=text
		reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
		debug        => "display debugging output as autosetup runs"
		install:=.   => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
		force init:=help   => "create initial auto.def, etc.  Use --init=help for known types"
		# Undocumented options
		option-checking=1
		nopager
		quiet
		timing
		conf:
	}

	if {[opt-bool version]} {
		puts $autosetup(version)
		exit 0
	}

	# autosetup --conf=alternate-auto.def
	if {[opt-val conf] ne ""} {
		set autosetup(autodef) [opt-val conf]
	}

	# Debugging output (set this early)
	incr autosetup(debug) [opt-bool debug]
	incr autosetup(force) [opt-bool force]
	incr autosetup(msg-quiet) [opt-bool quiet]
	incr autosetup(msg-timing) [opt-bool timing]

	# If the local module exists, source it now to allow for
	# project-local customisations
	if {[file exists $autosetup(libdir)/local.tcl]} {
		use local
	}

	# Now any auto-load modules
	foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
		automf_load source $file
	}

	if {[opt-val help] ne ""} {
		incr autosetup(showhelp)
		use help
		autosetup_help [opt-val help]
	}

	if {[opt-val {manual ref reference}] ne ""} {
		use help
		autosetup_reference [opt-val {manual ref reference}]
	}

	# Allow combining --install and --init
	set earlyexit 0
	if {[opt-val install] ne ""} {
		use install
		autosetup_install [opt-val install]
		incr earlyexit
	}

	if {[opt-val init] ne ""} {
		use init
		autosetup_init [opt-val init]
		incr earlyexit
	}

	if {$earlyexit} {
		exit 0
	}

	if {![file exists $autosetup(autodef)]} {
		# Check for invalid option first
		options {}
		user-error "No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
	}

	# Parse extra arguments into autosetup(cmdline)
	foreach arg $argv {
		if {[regexp {([^=]*)=(.*)} $arg -> n v]} {
			dict set autosetup(cmdline) $n $v
			define $n $v
		} else {
			user-error "Unexpected parameter: $arg"
		}
	}

	autosetup_add_dep $autosetup(autodef)

	define CONFIGURE_OPTS ""
	foreach arg $autosetup(argv) {
		define-append CONFIGURE_OPTS [quote-if-needed $arg]
	}
	define AUTOREMAKE [file-normalize $autosetup(exe)]
	define-append AUTOREMAKE [get-define CONFIGURE_OPTS]


	# Log how we were invoked
	configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"

	# Note that auto.def is *not* loaded in the global scope
	source $autosetup(autodef)

	# Could warn here if options {} was not specified

	show-notices

	if {$autosetup(debug)} {
		msg-result "Writing all defines to config.log"
		configlog "================ defines ======================"
		foreach n [lsort [array names define]] {
			configlog "define $n $define($n)"
		}
	}

	exit 0
}

# @opt-bool ?-nodefault? option ...
#
# Check each of the named, boolean options and if any have been explicitly enabled
# or disabled by the user, return 1 or 0 accordingly.
#
# If the option was specified more than once, the last value wins.
# e.g. With --enable-foo --disable-foo, [opt-bool foo] will return 0
#
# If no value was specified by the user, returns the default value for the
# first option. If -nodefault is given, this behaviour changes and
# -1 is returned instead.
#
proc opt-bool {args} {
	set nodefault 0
	if {[lindex $args 0] eq "-nodefault"} {
		set nodefault 1
		set args [lrange $args 1 end]
	}
	option-check-names {*}$args

	foreach opt $args {
		if {[dict exists $::autosetup(optset) $opt]} {
			return [dict get $::autosetup(optset) $opt]
		}
	}

	if {$nodefault} {
		return -1
	}
	# Default value is the default for the first option
	return [dict get $::autosetup(optdefault) [lindex $args 0]]
}

# @opt-val option-list ?default=""?
#
# Returns a list containing all the values given for the non-boolean options in 'option-list'.
# There will be one entry in the list for each option given by the user, including if the
# same option was used multiple times.
# If only a single value is required, use something like:
#
## lindex [opt-val $names] end
#
# If no options were set, $default is returned (exactly, not as a list).
#
proc opt-val {names {default ""}} {
	option-check-names {*}$names

	foreach opt $names {
		if {[dict exists $::autosetup(optset) $opt]} {
			lappend result {*}[dict get $::autosetup(optset) $opt]
		}
	}
	if {[info exists result]} {
		return $result
	}
	return $default
}

proc option-check-names {args} {
	foreach o $args {
		if {$o ni $::autosetup(options)} {
			autosetup-error "Request for undeclared option --$o"
		}
	}
}

# Parse the option definition in $opts and update
# ::autosetup(setoptions) and ::autosetup(optionhelp) appropriately
#
proc options-add {opts {header ""}} {
	global autosetup

	# First weed out comment lines
	set realopts {}
	foreach line [split $opts \n] {
		if {![string match "#*" [string trimleft $line]]} {
			append realopts $line \n
		}
	}
	set opts $realopts

	for {set i 0} {$i < [llength $opts]} {incr i} {
		set opt [lindex $opts $i]
		if {[string match =* $opt]} {
			# This is a special heading
			lappend autosetup(optionhelp) $opt ""
			set header {}
			continue
		}

		#puts "i=$i, opt=$opt"
		regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
		if {$name in $autosetup(options)} {
			autosetup-error "Option $name already specified"
		}

		#puts "$opt => $name $colon $equal $value"

		# Find the corresponding value in the user options
		# and set the default if necessary
		if {[string match "-*" $opt]} {
			# This is a documentation-only option, like "-C <dir>"
			set opthelp $opt
		} elseif {$colon eq ""} {
			# Boolean option
			lappend autosetup(options) $name

			if {$value eq "1"} {
				set opthelp "--disable-$name"
			} else {
				set opthelp "--$name"
			}

			# Set the default
			if {$value eq ""} {
				set value 0
			}
			dict set autosetup(optdefault) $name $value

			if {[dict exists $autosetup(getopt) $name]} {
				# The option was specified by the user. Look at the last value.
				lassign [lindex [dict get $autosetup(getopt) $name] end] type setvalue
				if {$type eq "str"} {
					# Can we convert the value to a boolean?
					if {$setvalue in {1 enabled yes}} {
						set setvalue 1
					} elseif {$setvalue in {0 disabled no}} {
						set setvalue 0
					} else {
						user-error "Boolean option $name given as --$name=$setvalue"
					}
				}
				dict set autosetup(optset) $name $setvalue
				#puts "Found boolean option --$name=$setvalue"
			}
		} else {
			# String option.
			lappend autosetup(options) $name

			if {$equal eq "="} {
				# String option with optional value
				set opthelp "--$name?=$value?"
			} else {
				# String option with required value
				set opthelp "--$name=$value"
			}
			dict set autosetup(optdefault) $name $value

			# Get the values specified by the user
			if {[dict exists $autosetup(getopt) $name]} {
				set listvalue {}

				foreach pair [dict get $autosetup(getopt) $name] {
					lassign $pair type setvalue
					if {$type eq "bool" && $setvalue} {
						if {$equal ne "="} {
							user-error "Option --$name requires a value"
						}
						# If given as a boolean, use the default value
						set setvalue $value
					}
					lappend listvalue $setvalue
				}

				#puts "Found string option --$name=$listvalue"
				dict set autosetup(optset) $name $listvalue
			}
		}

		# Now create the help for this option if appropriate
		if {[lindex $opts $i+1] eq "=>"} {
			set desc [lindex $opts $i+2]
			#string match \n* $desc
			if {$header ne ""} {
				lappend autosetup(optionhelp) $header ""
				set header ""
			}
			# A multi-line description
			lappend autosetup(optionhelp) $opthelp $desc
			incr i 2
		}
	}
}

# @module-options optionlist
#
# Like 'options', but used within a module.
proc module-options {opts} {
	set header ""
	if {$::autosetup(showhelp) > 1 && [llength $opts]} {
		set header "Module Options:"
	}
	options-add $opts $header

	if {$::autosetup(showhelp)} {
		# Ensure that the module isn't executed on --help
		# We are running under eval or source, so use break
		# to prevent further execution
		#return -code break -level 2
		return -code break
	}
}

proc max {a b} {
	expr {$a > $b ? $a : $b}
}

proc options-wrap-desc {text length firstprefix nextprefix initial} {
	set len $initial
	set space $firstprefix
	foreach word [split $text] {
		set word [string trim $word]
		if {$word == ""} {
			continue
		}
		if {$len && [string length $space$word] + $len >= $length} {
			puts ""
			set len 0
			set space $nextprefix
		}
		incr len [string length $space$word]
		puts -nonewline $space$word
		set space " "
	}
	if {$len} {
		puts ""
	}
}

proc options-show {} {
	# Determine the max option width
	set max 0
	foreach {opt desc} $::autosetup(optionhelp) {
		if {[string match =* $opt] || [string match \n* $desc]} {
			continue
		}
		set max [max $max [string length $opt]]
	}
	set indent [string repeat " " [expr $max+4]]
	set cols [getenv COLUMNS 80]
	catch {
		lassign [exec stty size] rows cols
	}
	incr cols -1
	# Now output
	foreach {opt desc} $::autosetup(optionhelp) {
		if {[string match =* $opt]} {
			puts [string range $opt 1 end]
			continue
		}
		puts -nonewline "  [format %-${max}s $opt]"
		if {[string match \n* $desc]} {
			puts $desc
		} else {
			options-wrap-desc [string trim $desc] $cols "  " $indent [expr $max + 2]
		}
	}
}

# @options options-spec
#
# Specifies configuration-time options which may be selected by the user
# and checked with opt-val and opt-bool. The format of options-spec follows.
#
# A boolean option is of the form:
#
## name[=0|1]  => "Description of this boolean option"
#
# The default is name=0, meaning that the option is disabled by default.
# If name=1 is used to make the option enabled by default, the description should reflect
# that with text like "Disable support for ...".
#
# An argument option (one which takes a parameter) is of the form:
#
## name:[=]value  => "Description of this option"
#
# If the name:value form is used, the value must be provided with the option (as --name=myvalue).
# If the name:=value form is used, the value is optional and the given value is used as the default
# if it is not provided.
#
# Undocumented options are also supported by omitting the "=> description.
# These options are not displayed with --help and can be useful for internal options or as aliases.
#
# For example, --disable-lfs is an alias for --disable=largefile:
#
## lfs=1 largefile=1 => "Disable large file support"
#
proc options {optlist} {
	# Allow options as a list or args
	options-add $optlist "Local Options:"

	if {$::autosetup(showhelp)} {
		options-show
		exit 0
	}

	# Check for invalid options
	if {[opt-bool option-checking]} {
		foreach o [dict keys $::autosetup(getopt)] {
			if {$o ni $::autosetup(options)} {
				user-error "Unknown option --$o"
			}
		}
	}
}

proc config_guess {} {
	if {[file-isexec $::autosetup(dir)/config.guess]} {
		exec-with-stderr sh $::autosetup(dir)/config.guess
		if {[catch {exec-with-stderr sh $::autosetup(dir)/config.guess} alias]} {
			user-error $alias
		}
		return $alias
	} else {
		configlog "No config.guess, so using uname"
		string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
	}
}

proc config_sub {alias} {
	if {[file-isexec $::autosetup(dir)/config.sub]} {
		if {[catch {exec-with-stderr sh $::autosetup(dir)/config.sub $alias} alias]} {
			user-error $alias
		}
	}
	return $alias
}

# @define name ?value=1?
#
# Defines the named variable to the given value.
# These (name, value) pairs represent the results of the configuration check
# and are available to be checked, modified and substituted.
#
proc define {name {value 1}} {
	set ::define($name) $value
	#dputs "$name <= $value"
}

# @undefine name
#
# Undefine the named variable
#
proc undefine {name} {
	unset -nocomplain ::define($name)
	#dputs "$name <= <undef>"
}

# @define-append name value ...
#
# Appends the given value(s) to the given 'defined' variable.
# If the variable is not defined or empty, it is set to $value.
# Otherwise the value is appended, separated by a space.
# Any extra values are similarly appended.
# If any value is already contained in the variable (as a substring) it is omitted.
#
proc define-append {name args} {
	if {[get-define $name ""] ne ""} {
		# Make a token attempt to avoid duplicates
		foreach arg $args {
			if {[string first $arg $::define($name)] == -1} {
				append ::define($name) " " $arg
			}
		}
	} else {
		set ::define($name) [join $args]
	}
	#dputs "$name += [join $args] => $::define($name)"
}

# @get-define name ?default=0?
#
# Returns the current value of the 'defined' variable, or $default
# if not set.
#
proc get-define {name {default 0}} {
	if {[info exists ::define($name)]} {
		#dputs "$name => $::define($name)"
		return $::define($name)
	}
	#dputs "$name => $default"
	return $default
}

# @is-defined name
#
# Returns 1 if the given variable is defined.
#
proc is-defined {name} {
	info exists ::define($name)
}

# @all-defines
#
# Returns a dictionary (name value list) of all defined variables.
#
# This is suitable for use with 'dict', 'array set' or 'foreach'
# and allows for arbitrary processing of the defined variables.
#
proc all-defines {} {
	array get ::define
}


# @get-env name default
#
# If $name was specified on the command line, return it.
# If $name was set in the environment, return it.
# Otherwise return $default.
#
proc get-env {name default} {
	if {[dict exists $::autosetup(cmdline) $name]} {
		return [dict get $::autosetup(cmdline) $name]
	}
	getenv $name $default
}

# @env-is-set name
#
# Returns 1 if the $name was specified on the command line or in the environment.
# Note that an empty environment variable is not considered to be set.
#
proc env-is-set {name} {
	if {[dict exists $::autosetup(cmdline) $name]} {
		return 1
	}
	if {[getenv $name ""] ne ""} {
		return 1
	}
	return 0
}

# @readfile filename ?default=""?
#
# Return the contents of the file, without the trailing newline.
# If the file doesn't exist or can't be read, returns $default.
#
proc readfile {filename {default_value ""}} {
	set result $default_value
	catch {
		set f [open $filename]
		set result [read -nonewline $f]
		close $f
	}
	return $result
}

# @writefile filename value
#
# Creates the given file containing $value.
# Does not add an extra newline.
#
proc writefile {filename value} {
	set f [open $filename w]
	puts -nonewline $f $value
	close $f
}

proc quote-if-needed {str} {
	if {[string match {*[\" ]*} $str]} {
		return \"[string map [list \" \\" \\ \\\\] $str]\"
	}
	return $str
}

proc quote-argv {argv} {
	set args {}
	foreach arg $argv {
		lappend args [quote-if-needed $arg]
	}
	join $args
}

# @suffix suf list
#
# Takes a list and returns a new list with $suf appended
# to each element
#
## suffix .c {a b c} => {a.c b.c c.c}
#
proc suffix {suf list} {
	set result {}
	foreach p $list {
		lappend result $p$suf
	}
	return $result
}

# @prefix pre list
#
# Takes a list and returns a new list with $pre prepended
# to each element
#
## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
#
proc prefix {pre list} {
	set result {}
	foreach p $list {
		lappend result $pre$p
	}
	return $result
}

# @find-executable name
#
# Searches the path for an executable with the given name.
# Note that the name may include some parameters, e.g. "cc -mbig-endian",
# in which case the parameters are ignored.
# Returns 1 if found, or 0 if not.
#
proc find-executable {name} {
	# Ignore any parameters
	set name [lindex $name 0]
	if {$name eq ""} {
		# The empty string is never a valid executable
		return 0
	}
	foreach p [split-path] {
		dputs "Looking for $name in $p"
		set exec [file join $p $name]
		if {[file-isexec $exec]} {
			dputs "Found $name -> $exec"
			return 1
		}
	}
	return 0
}

# @find-an-executable ?-required? name ...
#
# Given a list of possible executable names,
# searches for one of these on the path.
#
# Returns the name found, or "" if none found.
# If the first parameter is '-required', an error is generated
# if no executable is found.
#
proc find-an-executable {args} {
	set required 0
	if {[lindex $args 0] eq "-required"} {
		set args [lrange $args 1 end]
		incr required
	}
	foreach name $args {
		if {[find-executable $name]} {
			return $name
		}
	}
	if {$required} {
		if {[llength $args] == 1} {
			user-error "failed to find: [join $args]"
		} else {
			user-error "failed to find one of: [join $args]"
		}
	}
	return ""
}

# @configlog msg
#
# Writes the given message to the configuration log, config.log
#
proc configlog {msg} {
	if {![info exists ::autosetup(logfh)]} {
		set ::autosetup(logfh) [open config.log w]
	}
	puts $::autosetup(logfh) $msg
}

# @msg-checking msg
#
# Writes the message with no newline to stdout.
#
proc msg-checking {msg} {
	if {$::autosetup(msg-quiet) == 0} {
		maybe-show-timestamp
		puts -nonewline $msg
		set ::autosetup(msg-checking) 1
	}
}

# @msg-result msg
#
# Writes the message to stdout.
#
proc msg-result {msg} {
	if {$::autosetup(msg-quiet) == 0} {
		maybe-show-timestamp
		puts $msg
		set ::autosetup(msg-checking) 0
		show-notices
	}
}

# @msg-quiet command ...
#
# msg-quiet evaluates it's arguments as a command with output
# from msg-checking and msg-result suppressed.
#
# This is useful if a check needs to run a subcheck which isn't
# of interest to the user.
proc msg-quiet {args} {
	incr ::autosetup(msg-quiet)
	set rc [uplevel 1 $args]
	incr ::autosetup(msg-quiet) -1
	return $rc
}

# Will be overridden by 'use misc'
proc error-stacktrace {msg} {
	return $msg
}

proc error-location {msg} {
	return $msg
}

##################################################################
#
# Debugging output
#
proc dputs {msg} {
	if {$::autosetup(debug)} {
		puts $msg
	}
}

##################################################################
#
# User and system warnings and errors
#
# Usage errors such as wrong command line options

# @user-error msg
#
# Indicate incorrect usage to the user, including if required components
# or features are not found.
# autosetup exits with a non-zero return code.
#
proc user-error {msg} {
	show-notices
	puts stderr "Error: $msg"
	puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
	exit 1
}

# @user-notice msg
#
# Output the given message to stderr.
#
proc user-notice {msg} {
	lappend ::autosetup(notices) $msg
}

# Incorrect usage in the auto.def file. Identify the location.
proc autosetup-error {msg} {
	autosetup-full-error [error-location $msg]
}

# Like autosetup-error, except $msg is the full error message.
proc autosetup-full-error {msg} {
	show-notices
	puts stderr $msg
	exit 1
}

proc show-notices {} {
	if {$::autosetup(msg-checking)} {
		puts ""
		set ::autosetup(msg-checking) 0
	}
	flush stdout
	if {[info exists ::autosetup(notices)]} {
		puts stderr [join $::autosetup(notices) \n]
		unset ::autosetup(notices)
	}
}

proc maybe-show-timestamp {} {
	if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
		puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
	}
}

proc autosetup_version {} {
	return "autosetup v$::autosetup(version)"
}

##################################################################
#
# Directory/path handling
#

proc realdir {dir} {
	set oldpwd [pwd]
	cd $dir
	set pwd [pwd]
	cd $oldpwd
	return $pwd
}

# Follow symlinks until we get to something which is not a symlink
proc realpath {path} {
	while {1} {
		if {[catch {
			set path [file readlink $path]
		}]} {
			# Not a link
			break
		}
	}
	return $path
}

# Convert absolute path, $path into a path relative
# to the given directory (or the current dir, if not given).
#
proc relative-path {path {pwd {}}} {
	set diff 0
	set same 0
	set newf {}
	set prefix {}
	set path [file-normalize $path]
	if {$pwd eq ""} {
		set pwd [pwd]
	} else {
		set pwd [file-normalize $pwd]
	}

	if {$path eq $pwd} {
		return .
	}

	# Try to make the filename relative to the current dir
	foreach p [split $pwd /] f [split $path /] {
		if {$p ne $f} {
			incr diff
		} elseif {!$diff} {
			incr same
		}
		if {$diff} {
			if {$p ne ""} {
				# Add .. for sibling or parent dir
				lappend prefix ..
			}
			if {$f ne ""} {
				lappend newf $f
			}
		}
	}
	if {$same == 1 || [llength $prefix] > 3} {
		return $path
	}

	file join [join $prefix /] [join $newf /]
}

# Add filename as a dependency to rerun autosetup
# The name will be normalised (converted to a full path)
#
proc autosetup_add_dep {filename} {
	lappend ::autosetup(deps) [file-normalize $filename]
}

##################################################################
#
# Library module support
#

# @use module ...
#
# Load the given library modules.
# e.g. 'use cc cc-shared'
#
# Note that module 'X' is implemented in either 'autosetup/X.tcl'
# or 'autosetup/X/init.tcl'
#
# The latter form is useful for a complex module which requires additional
# support file. In this form, '$::usedir' is set to the module directory
# when it is loaded.
#
proc use {args} {
	foreach m $args {
		if {[info exists ::libmodule($m)]} {
			continue
		}
		set ::libmodule($m) 1
		if {[info exists ::modsource($m)]} {
			automf_load eval $::modsource($m)
		} else {
			set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl]
			set found 0
			foreach source $sources {
				if {[file exists $source]} {
					incr found
					break
				}
			}
			if {$found} {
				# For the convenience of the "use" source, point to the directory
				# it is being loaded from
				set ::usedir [file dirname $source]
				automf_load source $source
				autosetup_add_dep $source
			} else {
				autosetup-error "use: No such module: $m"
			}
		}
	}
}

# Load module source in the global scope by executing the given command
proc automf_load {args} {
	if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
		autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
	}
}

# Initial settings
set autosetup(exe) $::argv0
set autosetup(istcl) 1
set autosetup(start) [clock millis]
set autosetup(installed) 0
set autosetup(msg-checking) 0
set autosetup(msg-quiet) 0

# Embedded modules are inserted below here
set autosetup(installed) 1
# ----- module asciidoc-formatting -----

set modsource(asciidoc-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting
# asciidoc format

use formatting

proc para {text} {
    regsub -all "\[ \t\n\]+" [string trim $text] " "
}
proc title {text} {
    underline [para $text] =
    nl
}
proc p {text} {
    puts [para $text]
    nl
}
proc code {text} {
    foreach line [parse_code_block $text] {
        puts "    $line"
    }
    nl
}
proc codelines {lines} {
    foreach line $lines {
        puts "    $line"
    }
    nl
}
proc nl {} {
    puts ""
}
proc underline {text char} {
    regexp "^(\[ \t\]*)(.*)" $text -> indent words
    puts $text
    puts $indent[string repeat $char [string length $words]]
}
proc section {text} {
    underline "[para $text]" -
    nl
}
proc subsection {text} {
    underline "$text" ~
    nl
}
proc bullet {text} {
    puts "* [para $text]"
}
proc indent {text} {
    puts " :: "
    puts [para $text]
}
proc defn {first args} {
    set sep ""
    if {$first ne ""} {
        puts "${first}::"
    } else {
        puts " :: "
    }
    set defn [string trim [join $args \n]]
    regsub -all "\n\n" $defn "\n ::\n" defn
    puts $defn
}
}

# ----- module formatting -----

set modsource(formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides common text formatting

# This is designed for documenation which looks like:
# code {...}
# or
# code {
#    ...
#    ...
# }
# In the second case, we need to work out the indenting
# and strip it from all lines but preserve the remaining indenting.
# Note that all lines need to be indented with the same initial
# spaces/tabs.
#
# Returns a list of lines with the indenting removed.
#
proc parse_code_block {text} {
    # If the text begins with newline, take the following text,
    # otherwise just return the original
    if {![regexp "^\n(.*)" $text -> text]} {
        return [list [string trim $text]]
    }

    # And trip spaces off the end
    set text [string trimright $text]

    set min 100
    # Examine each line to determine the minimum indent
    foreach line [split $text \n] {
        if {$line eq ""} {
            # Ignore empty lines for the indent calculation
            continue
        }
        regexp "^(\[ \t\]*)" $line -> indent
        set len [string length $indent]
        if {$len < $min} {
            set min $len
        }
    }

    # Now make a list of lines with this indent removed
    set lines {}
    foreach line [split $text \n] {
        lappend lines [string range $line $min end]
    }

    # Return the result
    return $lines
}
}

# ----- module getopt -----

set modsource(getopt) {
# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Simple getopt module

# Parse everything out of the argv list which looks like an option
# Everything which doesn't look like an option, or is after --, is left unchanged
# Understands --enable-xxx and --with-xxx as synonyms for --xxx to enable the boolean option xxx.
# Understands --disable-xxx and --without-xxx to disable the boolean option xxx.
#
# The returned value is a dictionary keyed by option name
# Each value is a list of {type value} ... where type is "bool" or "str".
# The value for a boolean option is 0 or 1. The value of a string option is the value given.
proc getopt {argvname} {
	upvar $argvname argv
	set nargv {}

	set opts {}

	for {set i 0} {$i < [llength $argv]} {incr i} {
		set arg [lindex $argv $i]

		#dputs arg=$arg

		if {$arg eq "--"} {
			# End of options
			incr i
			lappend nargv {*}[lrange $argv $i end]
			break
		}

		if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
			# --name=value
			dict lappend opts $name [list str $value]
		} elseif {[regexp {^--(enable-|disable-|with-|without-)?([^=]*)$} $arg -> prefix name]} {
			if {$prefix in {enable- with- ""}} {
				set value 1
			} else {
				set value 0
			}
			dict lappend opts $name [list bool $value]
		} else {
			lappend nargv $arg
		}
	}

	#puts "getopt: argv=[join $argv] => [join $nargv]"
	#array set getopt $opts
	#parray getopt

	set argv $nargv

	return $opts
}
}

# ----- module help -----

set modsource(help) {
# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
# All rights reserved

# Module which provides usage, help and the command reference

proc autosetup_help {what} {
    use_pager

    puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
    puts "This is [autosetup_version], a build environment \"autoconfigurator\""
    puts "See the documentation online at http://msteveb.github.com/autosetup/\n"

    if {$what eq "local"} {
        if {[file exists $::autosetup(autodef)]} {
            # This relies on auto.def having a call to 'options'
            # which will display options and quit
            source $::autosetup(autodef)
        } else {
            options-show
        }
    } else {
        incr ::autosetup(showhelp)
        if {[catch {use $what}]} {
            user-error "Unknown module: $what"
        } else {
            options-show
        }
    }
    exit 0
}

# If not already paged and stdout is a tty, pipe the output through the pager
# This is done by reinvoking autosetup with --nopager added
proc use_pager {} {
    if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
        if {[catch {
            exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
        } msg opts] == 1} {
            if {[dict get $opts -errorcode] eq "NONE"} {
                # an internal/exec error
                puts stderr $msg
                exit 1
            }
        }
        exit 0
    }
}

# Outputs the autosetup references in one of several formats
proc autosetup_reference {{type text}} {

    use_pager

    switch -glob -- $type {
        wiki {use wiki-formatting}
        ascii* {use asciidoc-formatting}
        md - markdown {use markdown-formatting}
        default {use text-formatting}
    }

    title "[autosetup_version] -- Command Reference"

    section {Introduction}

    p {
        See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
    }

    p {
        'autosetup' provides a number of built-in commands which
        are documented below. These may be used from 'auto.def' to test
        for features, define variables, create files from templates and
        other similar actions.
    }

    automf_command_reference

    exit 0
}

proc autosetup_output_block {type lines} {
    if {[llength $lines]} {
        switch $type {
            code {
                codelines $lines
            }
            p {
                p [join $lines]
            }
            list {
                foreach line $lines {
                    bullet $line
                }
                nl
            }
        }
    }
}

# Generate a command reference from inline documentation
proc automf_command_reference {} {
    lappend files $::autosetup(prog)
    lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]

    section "Core Commands"
    set type p
    set lines {}
    set cmd {}

    foreach file $files {
        set f [open $file]
        while {![eof $f]} {
            set line [gets $f]

            # Find lines starting with "# @*" and continuing through the remaining comment lines
            if {![regexp {^# @(.*)} $line -> cmd]} {
                continue
            }

            # Synopsis or command?
            if {$cmd eq "synopsis:"} {
                section "Module: [file rootname [file tail $file]]"
            } else {
                subsection $cmd
            }

            set lines {}
            set type p

            # Now the description
            while {![eof $f]} {
                set line [gets $f]

                if {![regexp {^#(#)? ?(.*)} $line -> hash cmd]} {
                    break
                }
                if {$hash eq "#"} {
                    set t code
                } elseif {[regexp {^- (.*)} $cmd -> cmd]} {
                    set t list
                } else {
                    set t p
                }

                #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"

                if {$t ne $type || $cmd eq ""} {
                    # Finish the current block
                    autosetup_output_block $type $lines
                    set lines {}
                    set type $t
                }
                if {$cmd ne ""} {
                    lappend lines $cmd
                }
            }

            autosetup_output_block $type $lines
        }
        close $f
    }
}
}

# ----- module init -----

set modsource(init) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module to help create auto.def and configure

proc autosetup_init {type} {
	set help 0
	if {$type in {? help}} {
		incr help
	} elseif {![dict exists $::autosetup(inittypes) $type]} {
		puts "Unknown type, --init=$type"
		incr help
	}
	if {$help} {
		puts "Use one of the following types (e.g. --init=make)\n"
		foreach type [lsort [dict keys $::autosetup(inittypes)]] {
			lassign [dict get $::autosetup(inittypes) $type] desc
			# XXX: Use the options-show code to wrap the description
			puts [format "%-10s %s" $type $desc]
		}
		return
	}
	lassign [dict get $::autosetup(inittypes) $type] desc script

	puts "Initialising $type: $desc\n"

	# All initialisations happens in the top level srcdir
	cd $::autosetup(srcdir)

	uplevel #0 $script
}

proc autosetup_add_init_type {type desc script} {
	dict set ::autosetup(inittypes) $type [list $desc $script]
}

# This is for in creating build-system init scripts
#
# If the file doesn't exist, create it containing $contents
# If the file does exist, only overwrite if --force is specified.
#
proc autosetup_check_create {filename contents} {
	if {[file exists $filename]} {
		if {!$::autosetup(force)} {
			puts "I see $filename already exists."
			return
		} else {
			puts "I will overwrite the existing $filename because you used --force."
		}
	} else {
		puts "I don't see $filename, so I will create it."
	}
	writefile $filename $contents
}
}

# ----- module install -----

set modsource(install) {
# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which can install autosetup

proc autosetup_install {dir} {
	if {[catch {
		cd $dir
		file mkdir autosetup

		set f [open autosetup/autosetup w]

		set publicmodules [glob $::autosetup(libdir)/*.auto]

		# First the main script, but only up until "CUT HERE"
		set in [open $::autosetup(dir)/autosetup]
		while {[gets $in buf] >= 0} {
			if {$buf ne "##-- CUT HERE --##"} {
				puts $f $buf
				continue
			}

			# Insert the static modules here
			# i.e. those which don't contain @synopsis:
			puts $f "set autosetup(installed) 1"
			foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] {
				set buf [readfile $file]
				if {[string match "*\n# @synopsis:*" $buf]} {
					lappend publicmodules $file
					continue
				}
				set modname [file rootname [file tail $file]]
				puts $f "# ----- module $modname -----"
				puts $f "\nset modsource($modname) \{"
				puts $f $buf
				puts $f "\}\n"
			}
		}
		close $in
		close $f
		exec chmod 755 autosetup/autosetup

		# Install public modules
		foreach file $publicmodules {
			autosetup_install_file $file autosetup
		}

		# Install support files
		foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} {
			autosetup_install_file $::autosetup(dir)/$file autosetup
		}
		exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh

		writefile autosetup/README.autosetup \
			"This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"

	} error]} {
		user-error "Failed to install autosetup: $error"
	}
	puts "Installed [autosetup_version] to autosetup/"

	# Now create 'configure' if necessary
	autosetup_create_configure
}

proc autosetup_create_configure {} {
	if {[file exists configure]} {
		if {!$::autosetup(force)} {
			# Could this be an autosetup configure?
			if {![string match "*\nWRAPPER=*" [readfile configure]]} {
				puts "I see configure, but not created by autosetup, so I won't overwrite it."
				puts "Remove it or use --force to overwrite."
				return
			}
		} else {
			puts "I will overwrite the existing configure because you used --force."
		}
	} else {
		puts "I don't see configure, so I will create it."
	}
	writefile configure \
{#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
}
	catch {exec chmod 755 configure}
}

# Append the contents of $file to filehandle $f
proc autosetup_install_append {f file} {
	set in [open $file]
	puts $f [read $in]
	close $in
}

proc autosetup_install_file {file dir} {
	if {![file exists $file]} {
		error "Missing installation file '$file'"
	}
	writefile [file join $dir [file tail $file]] [readfile $file]\n
}

if {$::autosetup(installed)} {
	user-error "autosetup can only be installed from development source, not from installed copy"
}
}

# ----- module markdown-formatting -----

set modsource(markdown-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting
# markdown format (kramdown syntax)

use formatting

proc para {text} {
    regsub -all "\[ \t\n\]+" [string trim $text] " " text
    regsub -all {([^a-zA-Z])'([^']*)'} $text {\1**`\2`**} text
    regsub -all {^'([^']*)'} $text {**`\1`**} text
    regsub -all {(http[^ \t\n]*)} $text {[\1](\1)} text
    return $text
}
proc title {text} {
    underline [para $text] =
    nl
}
proc p {text} {
    puts [para $text]
    nl
}
proc codelines {lines} {
    puts "~~~~~~~~~~~~"
    foreach line $lines {
        puts $line
    }
    puts "~~~~~~~~~~~~"
    nl
}
proc code {text} {
    puts "~~~~~~~~~~~~"
    foreach line [parse_code_block $text] {
        puts $line
    }
    puts "~~~~~~~~~~~~"
    nl
}
proc nl {} {
    puts ""
}
proc underline {text char} {
    regexp "^(\[ \t\]*)(.*)" $text -> indent words
    puts $text
    puts $indent[string repeat $char [string length $words]]
}
proc section {text} {
    underline "[para $text]" -
    nl
}
proc subsection {text} {
    puts "### `$text`"
    nl
}
proc bullet {text} {
    puts "* [para $text]"
}
proc defn {first args} {
    puts "^"
    set defn [string trim [join $args \n]]
    if {$first ne ""} {
        puts "**${first}**"
        puts -nonewline ": "
        regsub -all "\n\n" $defn "\n: " defn
    }
    puts "$defn"
}
}

# ----- module misc -----

set modsource(misc) {
# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module containing misc procs useful to modules
# Largely for platform compatibility

set autosetup(istcl) [info exists ::tcl_library]
set autosetup(iswin) [string equal windows $tcl_platform(platform)]

if {$autosetup(iswin)} {
	# mingw/windows separates $PATH with semicolons
	# and doesn't have an executable bit
	proc split-path {} {
		split [getenv PATH .] {;}
	}
	proc file-isexec {exec} {
		# Basic test for windows. We ignore .bat
		if {[file isfile $exec] || [file isfile $exec.exe]} {
			return 1
		}
		return 0
	}
} else {
	# unix separates $PATH with colons and has and executable bit
	proc split-path {} {
		split [getenv PATH .] :
	}
	proc file-isexec {exec} {
		file executable $exec
	}
}

# Assume that exec can return stdout and stderr
proc exec-with-stderr {args} {
	exec {*}$args 2>@1
}

if {$autosetup(istcl)} {
	# Tcl doesn't have the env command
	proc getenv {name args} {
		if {[info exists ::env($name)]} {
			return $::env($name)
		}
		if {[llength $args]} {
			return [lindex $args 0]
		}
		return -code error "environment variable \"$name\" does not exist"
	}
	proc isatty? {channel} {
		dict exists [fconfigure $channel] -xchar
	}
} else {
	if {$autosetup(iswin)} {
		# On Windows, backslash convert all environment variables
		# (Assume that Tcl does this for us)
		proc getenv {name args} {
			string map {\\ /} [env $name {*}$args]
		}
	} else {
		# Jim on unix is simple
		alias getenv env
	}
	proc isatty? {channel} {
		set tty 0
		catch {
			# isatty is a recent addition to Jim Tcl
			set tty [$channel isatty]
		}
		return $tty
	}
}

# In case 'file normalize' doesn't exist
#
proc file-normalize {path} {
	if {[catch {file normalize $path} result]} {
		if {$path eq ""} {
			return ""
		}
		set oldpwd [pwd]
		if {[file isdir $path]} {
			cd $path
			set result [pwd]
		} else {
			cd [file dirname $path]
			set result [file join [pwd] [file tail $path]]
		}
		cd $oldpwd
	}
	return $result
}

# If everything is working properly, the only errors which occur
# should be generated in user code (e.g. auto.def).
# By default, we only want to show the error location in user code.
# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
#
# This is designed to be called for incorrect usage in auto.def, via autosetup-error
#
proc error-location {msg} {
	if {$::autosetup(debug)} {
		return -code error $msg
	}
	# Search back through the stack trace for the first error in a .def file
	for {set i 1} {$i < [info level]} {incr i} {
		if {$::autosetup(istcl)} {
			array set info [info frame -$i]
		} else {
			lassign [info frame -$i] info(caller) info(file) info(line)
		}
		if {[string match *.def $info(file)]} {
			return "[relative-path $info(file)]:$info(line): Error: $msg"
		}
		#puts "Skipping $info(file):$info(line)"
	}
	return $msg
}

# If everything is working properly, the only errors which occur
# should be generated in user code (e.g. auto.def).
# By default, we only want to show the error location in user code.
# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
#
# This is designed to be called for incorrect usage in auto.def, via autosetup-error
#
proc error-stacktrace {msg} {
	if {$::autosetup(debug)} {
		return -code error $msg
	}
	# Search back through the stack trace for the first error in a .def file
	for {set i 1} {$i < [info level]} {incr i} {
		if {$::autosetup(istcl)} {
			array set info [info frame -$i]
		} else {
			lassign [info frame -$i] info(caller) info(file) info(line)
		}
		if {[string match *.def $info(file)]} {
			return "[relative-path $info(file)]:$info(line): Error: $msg"
		}
		#puts "Skipping $info(file):$info(line)"
	}
	return $msg
}

# Given the return from [catch {...} msg opts], returns an appropriate
# error message. A nice one for Jim and a less-nice one for Tcl.
# If 'fulltrace' is set, a full stack trace is provided.
# Otherwise a simple message is provided.
#
# This is designed for developer errors, e.g. in module code or auto.def code
#
#
proc error-dump {msg opts fulltrace} {
	if {$::autosetup(istcl)} {
		if {$fulltrace} {
			return "Error: [dict get $opts -errorinfo]"
		} else {
			return "Error: $msg"
		}
	} else {
		lassign $opts(-errorinfo) p f l
		if {$f ne ""} {
			set result "$f:$l: Error: "
		}
		append result "$msg\n"
		if {$fulltrace} {
			append result [stackdump $opts(-errorinfo)]
		}

		# Remove the trailing newline
		string trim $result
	}
}
}

# ----- module text-formatting -----

set modsource(text-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting

use formatting

proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
    set len 0
    set space $firstprefix
    foreach word [split $text] {
        set word [string trim $word]
        if {$word == ""} {
            continue
        }
        if {$len && [string length $space$word] + $len >= $length} {
            puts ""
            set len 0
            set space $nextprefix
        }
        incr len [string length $space$word]

        # Use man-page conventions for highlighting 'quoted' and *quoted*
        # single words.
        # Use x^Hx for *bold* and _^Hx for 'underline'.
        #
        # less and more will both understand this.
        # Pipe through 'col -b' to remove them.
        if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
            regsub -all . $bareword "_\b&" word
            append word $dot
        } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
            regsub -all . $bareword "&\b&" word
            append word $dot
        }
        puts -nonewline $space$word
        set space " "
    }
    if {$len} {
        puts ""
    }
}
proc title {text} {
    underline [string trim $text] =
    nl
}
proc p {text} {
    wordwrap $text 80
    nl
}
proc codelines {lines} {
    foreach line $lines {
        puts "    $line"
    }
    nl
}
proc nl {} {
    puts ""
}
proc underline {text char} {
    regexp "^(\[ \t\]*)(.*)" $text -> indent words
    puts $text
    puts $indent[string repeat $char [string length $words]]
}
proc section {text} {
    underline "[string trim $text]" -
    nl
}
proc subsection {text} {
    underline "$text" ~
    nl
}
proc bullet {text} {
    wordwrap $text 76 "  * " "    "
}
proc indent {text} {
    wordwrap $text 76 "    " "    "
}
proc defn {first args} {
    if {$first ne ""} {
        underline "    $first" ~
    }
    foreach p $args {
        if {$p ne ""} {
            indent $p
        }
    }
}
}

# ----- module wiki-formatting -----

set modsource(wiki-formatting) {
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Module which provides text formatting
# wiki.tcl.tk format output

use formatting

proc joinlines {text} {
    set lines {}
    foreach l [split [string trim $text] \n] {
        lappend lines [string trim $l]
    }
    join $lines
}
proc p {text} {
    puts [joinlines $text]
    puts ""
}
proc title {text} {
    puts "*** [joinlines $text] ***"
    puts ""
}
proc codelines {lines} {
    puts "======"
    foreach line $lines {
        puts "    $line"
    }
    puts "======"
}
proc code {text} {
    puts "======"
    foreach line [parse_code_block $text] {
        puts "    $line"
    }
    puts "======"
}
proc nl {} {
}
proc section {text} {
    puts "'''$text'''"
    puts ""
}
proc subsection {text} {
    puts "''$text''"
    puts ""
}
proc bullet {text} {
    puts "   * [joinlines $text]"
}
proc indent {text} {
    puts "    :    [joinlines $text]"
}
proc defn {first args} {
    if {$first ne ""} {
        indent '''$first'''
    }

    foreach p $args {
        p $p
    }
}
}


##################################################################
#
# Entry/Exit
#
if {$autosetup(debug)} {
	main $argv
}
if {[catch {main $argv} msg opts] == 1} {
	show-notices
	autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
	if {!$autosetup(debug)} {
		puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
	}
	exit 1
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted autosetup/cc-db.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'cc-db' module provides a knowledge based of system idiosyncrasies
# In general, this module can always be included

use cc

module-options {}

# openbsd needs sys/types.h to detect some system headers
cc-include-needs sys/socket.h sys/types.h
cc-include-needs netinet/in.h sys/types.h
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























Deleted autosetup/cc-lib.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# Provides a library of common tests on top of the 'cc' module.

use cc

module-options {}

# @cc-check-lfs
#
# The equivalent of the AC_SYS_LARGEFILE macro
# 
# defines 'HAVE_LFS' if LFS is available,
# and defines '_FILE_OFFSET_BITS=64' if necessary
#
# Returns 1 if 'LFS' is available or 0 otherwise
#
proc cc-check-lfs {} {
	cc-check-includes sys/types.h
	msg-checking "Checking if -D_FILE_OFFSET_BITS=64 is needed..."
	set lfs 1
	if {[msg-quiet cc-with {-includes sys/types.h} {cc-check-sizeof off_t}] == 8} {
		msg-result no
	} elseif {[msg-quiet cc-with {-includes sys/types.h -cflags -D_FILE_OFFSET_BITS=64} {cc-check-sizeof off_t}] == 8} {
		define _FILE_OFFSET_BITS 64
		msg-result yes
	} else {
		set lfs 0
		msg-result none
	}
	define-feature lfs $lfs
	return $lfs
}

# @cc-check-endian
#
# The equivalent of the AC_C_BIGENDIAN macro
# 
# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
#
# Returns 1 if determined, or 0 if not.
#
proc cc-check-endian {} {
	cc-check-includes sys/types.h sys/param.h
	set rc 0
	msg-checking "Checking endian..."
	cc-with {-includes {sys/types.h sys/param.h}} {
		if {[cctest -code {
			#if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
				#error unknown
			#elif BYTE_ORDER != BIG_ENDIAN
				#error little
			#endif
		}]} {
			define-feature big-endian
			msg-result "big"
			set rc 1
		} elseif {[cctest -code {
			#if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER)
				#error unknown
			#elif BYTE_ORDER != LITTLE_ENDIAN
				#error big
			#endif
		}]} {
			define-feature little-endian
			msg-result "little"
			set rc 1
		} else {
			msg-result "unknown"
		}
	}
	return $rc
}

# @cc-check-flags flag ?...?
#
# Checks whether the given C/C++ compiler flags can be used. Defines feature
# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
# appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'.
proc cc-check-flags {args} {
    set result 1
    array set opts [cc-get-settings]
    switch -exact -- $opts(-lang) {
        c++ {
            set lang C++
            set prefix CXXFLAG
        }
        c {
            set lang C
            set prefix CFLAG
        }
        default {
            autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
        }
    }
    foreach flag $args {
        msg-checking "Checking whether the $lang compiler accepts $flag..."
        if {[cctest -cflags $flag]} {
            msg-result yes
            define-feature $prefix$flag
            cc-with [list -cflags [list $flag]]
            define-append ${prefix}S $flag
        } else {
            msg-result no
            set result 0
        }
    }
    return $result
}

# @cc-check-standards ver ?...?
#
# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
# options, and appends the first working one to '-cflags' and 'CFLAGS' or
# 'CXXFLAGS'.
proc cc-check-standards {args} {
    array set opts [cc-get-settings]
    foreach std $args {
        if {[cc-check-flags -std=$std]} {
            return $std
        }
    }
    return ""
}

# Checks whether $keyword is usable as alignof
proc cctest_alignof {keyword} {
    msg-checking "Checking for $keyword..."
    if {[cctest -code [subst -nobackslashes {
        printf("minimum alignment is %d == %d\n", ${keyword}(char), ${keyword}('x'));
    }]]} then {
        msg-result ok
        define-feature $keyword
    } else {
        msg-result "not found"
    }
}

# @cc-check-c11
#
# Checks for several C11/C++11 extensions and their alternatives. Currently
# checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
proc cc-check-c11 {} {
    msg-checking "Checking for _Static_assert..."
    if {[cctest -code {
        _Static_assert(1, "static assertions are available");
    }]} then {
        msg-result ok
        define-feature _Static_assert
    } else {
        msg-result "not found"
    }

    cctest_alignof _Alignof
    cctest_alignof __alignof__
    cctest_alignof __alignof
}

# @cc-check-alloca
#
# The equivalent of the AC_FUNC_ALLOCA macro
#
# Checks for the existence of alloca
# defines HAVE_ALLOCA and returns 1 if it exists
proc cc-check-alloca {} {
    cc-check-some-feature alloca {
        cctest -includes alloca.h -code { alloca (2 * sizeof (int)); }
    }
}

# @cc-signal-return-type
#
# The equivalent of the AC_TYPE_SIGNAL macro
#
# defines RETSIGTYPE to int or void
proc cc-signal-return-type {} {
    msg-checking "Checking return type of signal handlers..."
    cc-with {-includes {sys/types.h signal.h}} {
        if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} {
                set type int
        } else {
                set type void
        }
        define RETSIGTYPE $type
        msg-result $type
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































































































































































































































































































Deleted autosetup/cc-shared.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'cc-shared' module provides support for shared libraries and shared objects.
# It defines the following variables:
#
## SH_CFLAGS         Flags to use compiling sources destined for a shared library
## SH_LDFLAGS        Flags to use linking (creating) a shared library
## SH_SOPREFIX       Prefix to use to set the soname when creating a shared library
## SH_SOEXT          Extension for shared libs
## SH_SOEXTVER       Format for versioned shared libs - %s = version
## SHOBJ_CFLAGS      Flags to use compiling sources destined for a shared object
## SHOBJ_LDFLAGS     Flags to use linking a shared object, undefined symbols allowed
## SHOBJ_LDFLAGS_R   - as above, but all symbols must be resolved
## SH_LINKFLAGS      Flags to use linking an executable which will load shared objects
## LD_LIBRARY_PATH   Environment variable which specifies path to shared libraries
## STRIPLIBFLAGS     Arguments to strip a dynamic library

module-options {}

# Defaults: gcc on unix
define SHOBJ_CFLAGS -fpic
define SHOBJ_LDFLAGS -shared
define SH_CFLAGS -fpic
define SH_LDFLAGS -shared
define SH_LINKFLAGS -rdynamic
define SH_SOEXT .so
define SH_SOEXTVER .so.%s
define SH_SOPREFIX -Wl,-soname,
define LD_LIBRARY_PATH LD_LIBRARY_PATH
define STRIPLIBFLAGS --strip-unneeded

# Note: This is a helpful reference for identifying the toolchain
#       http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers

switch -glob -- [get-define host] {
	*-*-darwin* {
		define SHOBJ_CFLAGS "-dynamic -fno-common"
		define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
		define SHOBJ_LDFLAGS_R -bundle
		define SH_CFLAGS -dynamic
		define SH_LDFLAGS -dynamiclib
		define SH_LINKFLAGS ""
		define SH_SOEXT .dylib
		define SH_SOEXTVER .%s.dylib
		define SH_SOPREFIX -Wl,-install_name,
		define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
		define STRIPLIBFLAGS -x
	}
	*-*-ming* - *-*-cygwin - *-*-msys {
		define SHOBJ_CFLAGS ""
		define SHOBJ_LDFLAGS -shared
		define SH_CFLAGS ""
		define SH_LDFLAGS -shared
		define SH_LINKFLAGS ""
		define SH_SOEXT .dll
		define SH_SOEXTVER .dll
		define SH_SOPREFIX ""
		define LD_LIBRARY_PATH PATH
	}
	sparc* {
		if {[msg-quiet cc-check-decls __SUNPRO_C]} {
			msg-result "Found sun stdio compiler"
			# sun stdio compiler
			# XXX: These haven't been fully tested. 
			define SHOBJ_CFLAGS -KPIC
			define SHOBJ_LDFLAGS "-G"
			define SH_CFLAGS -KPIC
			define SH_LINKFLAGS -Wl,-export-dynamic
			define SH_SOPREFIX -Wl,-h,
		} else {
			# sparc has a very small GOT table limit, so use -fPIC
			define SH_CFLAGS -fPIC
			define SHOBJ_CFLAGS -fPIC
		}
	}
	*-*-solaris* {
		if {[msg-quiet cc-check-decls __SUNPRO_C]} {
			msg-result "Found sun stdio compiler"
			# sun stdio compiler
			# XXX: These haven't been fully tested. 
			define SHOBJ_CFLAGS -KPIC
			define SHOBJ_LDFLAGS "-G"
			define SH_CFLAGS -KPIC
			define SH_LINKFLAGS -Wl,-export-dynamic
			define SH_SOPREFIX -Wl,-h,
		}
	}
	*-*-hpux {
		# XXX: These haven't been tested
		define SHOBJ_CFLAGS "+O3 +z"
		define SHOBJ_LDFLAGS -b
		define SH_CFLAGS +z
		define SH_LINKFLAGS -Wl,+s
		define LD_LIBRARY_PATH SHLIB_PATH
	}
	*-*-haiku {
		define SHOBJ_CFLAGS ""
		define SHOBJ_LDFLAGS -shared
		define SH_CFLAGS ""
		define SH_LDFLAGS -shared
		define SH_LINKFLAGS ""
		define SH_SOPREFIX ""
		define LD_LIBRARY_PATH LIBRARY_PATH
	}
	microblaze* {
		# Microblaze generally needs -fPIC rather than -fpic
		define SHOBJ_CFLAGS -fPIC
		define SH_CFLAGS -fPIC
	}
}

if {![is-defined SHOBJ_LDFLAGS_R]} {
	define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































Deleted autosetup/cc.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'cc' module supports checking various 'features' of the C or C++
# compiler/linker environment. Common commands are cc-check-includes,
# cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
#
# The following environment variables are used if set:
#
## CC       - C compiler
## CXX      - C++ compiler
## CCACHE   - Set to "none" to disable automatic use of ccache
## CFLAGS   - Additional C compiler flags
## CXXFLAGS - Additional C++ compiler flags
## LDFLAGS  - Additional compiler flags during linking
## LIBS     - Additional libraries to use (for all tests)
## CROSS    - Tool prefix for cross compilation
#
# The following variables are defined from the corresponding
# environment variables if set.
#
## CPPFLAGS
## LINKFLAGS
## CC_FOR_BUILD
## LD

use system

module-options {}

# Note that the return code is not meaningful
proc cc-check-something {name code} {
	uplevel 1 $code
}

# Checks for the existence of the given function by linking
#
proc cctest_function {function} {
	cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
}

# Checks for the existence of the given type by compiling
proc cctest_type {type} {
	cctest -code "$type _x;"
}

# Checks for the existence of the given type/structure member.
# e.g. "struct stat.st_mtime"
proc cctest_member {struct_member} {
	# split at the first dot
	regexp {^([^.]+)[.](.*)$} $struct_member -> struct member
	cctest -code "static $struct _s; return sizeof(_s.$member);"
}

# Checks for the existence of the given define by compiling
#
proc cctest_define {name} {
	cctest -code "#ifndef $name\n#error not defined\n#endif"
}

# Checks for the existence of the given name either as
# a macro (#define) or an rvalue (such as an enum)
#
proc cctest_decl {name} {
	cctest -code "#ifndef $name\n(void)$name;\n#endif"
}

# @cc-check-sizeof type ...
#
# Checks the size of the given types (between 1 and 32, inclusive).
# Defines a variable with the size determined, or "unknown" otherwise.
# e.g. for type 'long long', defines SIZEOF_LONG_LONG.
# Returns the size of the last type.
#
proc cc-check-sizeof {args} {
	foreach type $args {
		msg-checking "Checking for sizeof $type..."
		set size unknown
		# Try the most common sizes first
		foreach i {4 8 1 2 16 32} {
			if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
				set size $i
				break
			}
		}
		msg-result $size
		set define [feature-define-name $type SIZEOF_]
		define $define $size
	}
	# Return the last result
	get-define $define
}

# Checks for each feature in $list by using the given script.
#
# When the script is evaluated, $each is set to the feature
# being checked, and $extra is set to any additional cctest args.
#
# Returns 1 if all features were found, or 0 otherwise.
proc cc-check-some-feature {list script} {
	set ret 1
	foreach each $list {
		if {![check-feature $each $script]} {
			set ret 0
		}
	}
	return $ret
}

# @cc-check-includes includes ...
#
# Checks that the given include files can be used
proc cc-check-includes {args} {
	cc-check-some-feature $args {
		set with {}
		if {[dict exists $::autosetup(cc-include-deps) $each]} {
			set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
			msg-quiet cc-check-includes {*}$deps
			foreach i $deps {
				if {[have-feature $i]} {
					lappend with $i
				}
			}
		}
		if {[llength $with]} {
			cc-with [list -includes $with] {
				cctest -includes $each
			}
		} else {
			cctest -includes $each
		}
	}
}

# @cc-include-needs include required ...
#
# Ensures that when checking for 'include', a check is first
# made for each 'required' file, and if found, it is #included
proc cc-include-needs {file args} {
	foreach depfile $args {
		dict set ::autosetup(cc-include-deps) $file $depfile 1
	}
}

# @cc-check-types type ...
#
# Checks that the types exist.
proc cc-check-types {args} {
	cc-check-some-feature $args {
		cctest_type $each
	}
}

# @cc-check-defines define ...
#
# Checks that the given preprocessor symbol is defined
proc cc-check-defines {args} {
	cc-check-some-feature $args {
		cctest_define $each
	}
}

# @cc-check-decls name ...
#
# Checks that each given name is either a preprocessor symbol or rvalue
# such as an enum. Note that the define used is HAVE_DECL_xxx
# rather than HAVE_xxx
proc cc-check-decls {args} {
	set ret 1
	foreach name $args {
		msg-checking "Checking for $name..."
		set r [cctest_decl $name]
		define-feature "decl $name" $r
		if {$r} {
			msg-result "ok"
		} else {
			msg-result "not found"
			set ret 0
		}
	}
	return $ret
}

# @cc-check-functions function ...
#
# Checks that the given functions exist (can be linked)
proc cc-check-functions {args} {
	cc-check-some-feature $args {
		cctest_function $each
	}
}

# @cc-check-members type.member ...
#
# Checks that the given type/structure members exist.
# A structure member is of the form "struct stat.st_mtime"
proc cc-check-members {args} {
	cc-check-some-feature $args {
		cctest_member $each
	}
}

# @cc-check-function-in-lib function libs ?otherlibs?
#
# Checks that the given function can be found in one of the libs.
#
# First checks for no library required, then checks each of the libraries
# in turn.
#
# If the function is found, the feature is defined and lib_$function is defined
# to -l$lib where the function was found, or "" if no library required.
# In addition, -l$lib is prepended to the LIBS define.
#
# If additional libraries may be needed for linking, they should be specified
# as $extralibs as "-lotherlib1 -lotherlib2".
# These libraries are not automatically added to LIBS.
#
# Returns 1 if found or 0 if not.
# 
proc cc-check-function-in-lib {function libs {otherlibs {}}} {
	msg-checking "Checking libs for $function..."
	set found 0
	cc-with [list -libs $otherlibs] {
		if {[cctest_function $function]} {
			msg-result "none needed"
			define lib_$function ""
			incr found
		} else {
			foreach lib $libs {
				cc-with [list -libs -l$lib] {
					if {[cctest_function $function]} {
						msg-result -l$lib
						define lib_$function -l$lib
						# prepend to LIBS
						define LIBS "-l$lib [get-define LIBS]"
						incr found
						break
					}
				}
			}
		}
	}
	if {$found} {
		define [feature-define-name $function]
	} else {
		msg-result "no"
	}
	return $found
}

# @cc-check-tools tool ...
#
# Checks for existence of the given compiler tools, taking
# into account any cross compilation prefix.
#
# For example, when checking for "ar", first AR is checked on the command
# line and then in the environment. If not found, "${host}-ar" or
# simply "ar" is assumed depending upon whether cross compiling.
# The path is searched for this executable, and if found AR is defined
# to the executable name.
# Note that even when cross compiling, the simple "ar" is used as a fallback,
# but a warning is generated. This is necessary for some toolchains.
#
# It is an error if the executable is not found.
#
proc cc-check-tools {args} {
	foreach tool $args {
		set TOOL [string toupper $tool]
		set exe [get-env $TOOL [get-define cross]$tool]
		if {[find-executable {*}$exe]} {
			define $TOOL $exe
			continue
		}
		if {[find-executable {*}$tool]} {
			msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
			define $TOOL $tool
			continue
		}
		user-error "Failed to find $exe"
	}
}

# @cc-check-progs prog ...
#
# Checks for existence of the given executables on the path.
#
# For example, when checking for "grep", the path is searched for
# the executable, 'grep', and if found GREP is defined as "grep".
#
# If the executable is not found, the variable is defined as false.
# Returns 1 if all programs were found, or 0 otherwise.
#
proc cc-check-progs {args} {
	set failed 0
	foreach prog $args {
		set PROG [string toupper $prog]
		msg-checking "Checking for $prog..."
		if {![find-executable $prog]} {
			msg-result no
			define $PROG false
			incr failed
		} else {
			msg-result ok
			define $PROG $prog
		}
	}
	expr {!$failed}
}

# Adds the given settings to $::autosetup(ccsettings) and
# returns the old settings.
#
proc cc-add-settings {settings} {
	if {[llength $settings] % 2} {
		autosetup-error "settings list is missing a value: $settings"
	}

	set prev [cc-get-settings]
	# workaround a bug in some versions of jimsh by forcing
	# conversion of $prev to a list
	llength $prev

	array set new $prev

	foreach {name value} $settings {
		switch -exact -- $name {
			-cflags - -includes {
				# These are given as lists
				lappend new($name) {*}$value
			}
			-declare {
				lappend new($name) $value
			}
			-libs {
				# Note that new libraries are added before previous libraries
				set new($name) [list {*}$value {*}$new($name)]
			}
			-link - -lang - -nooutput {
				set new($name) $value
			}
			-source - -sourcefile - -code {
				# XXX: These probably are only valid directly from cctest
				set new($name) $value
			}
			default {
				autosetup-error "unknown cctest setting: $name"
			}
		}
	}

	cc-store-settings [array get new]

	return $prev
}

proc cc-store-settings {new} {
	set ::autosetup(ccsettings) $new
}

proc cc-get-settings {} {
	return $::autosetup(ccsettings)
}

# Similar to cc-add-settings, but each given setting
# simply replaces the existing value.
#
# Returns the previous settings
proc cc-update-settings {args} {
	set prev [cc-get-settings]
	cc-store-settings [dict merge $prev $args]
	return $prev
}

# @cc-with settings ?{ script }?
#
# Sets the given 'cctest' settings and then runs the tests in 'script'.
# Note that settings such as -lang replace the current setting, while
# those such as -includes are appended to the existing setting.
#
# If no script is given, the settings become the default for the remainder
# of the auto.def file.
#
## cc-with {-lang c++} {
##   # This will check with the C++ compiler
##   cc-check-types bool
##   cc-with {-includes signal.h} {
##     # This will check with the C++ compiler, signal.h and any existing includes.
##     ...
##   }
##   # back to just the C++ compiler
## }
#
# The -libs setting is special in that newer values are added *before* earlier ones.
#
## cc-with {-libs {-lc -lm}} {
##   cc-with {-libs -ldl} {
##     cctest -libs -lsocket ...
##     # libs will be in this order: -lsocket -ldl -lc -lm
##   }
## }
proc cc-with {settings args} {
	if {[llength $args] == 0} {
		cc-add-settings $settings
	} elseif {[llength $args] > 1} {
		autosetup-error "usage: cc-with settings ?script?"
	} else {
		set save [cc-add-settings $settings]
		set rc [catch {uplevel 1 [lindex $args 0]} result info]
		cc-store-settings $save
		if {$rc != 0} {
			return -code [dict get $info -code] $result
		}
		return $result
	}
}

# @cctest ?settings?
# 
# Low level C compiler checker. Compiles and or links a small C program
# according to the arguments and returns 1 if OK, or 0 if not.
#
# Supported settings are:
#
## -cflags cflags      A list of flags to pass to the compiler
## -includes list      A list of includes, e.g. {stdlib.h stdio.h}
## -declare code       Code to declare before main()
## -link 1             Don't just compile, link too
## -lang c|c++         Use the C (default) or C++ compiler
## -libs liblist       List of libraries to link, e.g. {-ldl -lm}
## -code code          Code to compile in the body of main()
## -source code        Compile a complete program. Ignore -includes, -declare and -code
## -sourcefile file    Shorthand for -source [readfile [get-define srcdir]/$file]
## -nooutput 1         Treat any compiler output (e.g. a warning) as an error
#
# Unless -source or -sourcefile is specified, the C program looks like:
#
## #include <firstinclude>   /* same for remaining includes in the list */
##
## declare-code              /* any code in -declare, verbatim */
##
## int main(void) {
##   code                    /* any code in -code, verbatim */
##   return 0;
## }
#
# Any failures are recorded in 'config.log'
#
proc cctest {args} {
	set src conftest__.c
	set tmp conftest__

	# Easiest way to merge in the settings
	cc-with $args {
		array set opts [cc-get-settings]
	}

	if {[info exists opts(-sourcefile)]} {
		set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
	}
	if {[info exists opts(-source)]} {
		set lines $opts(-source)
	} else {
		foreach i $opts(-includes) {
			if {$opts(-code) ne "" && ![feature-checked $i]} {
				# Compiling real code with an unchecked header file
				# Quickly (and silently) check for it now

				# Remove all -includes from settings before checking
				set saveopts [cc-update-settings -includes {}]
				msg-quiet cc-check-includes $i
				cc-store-settings $saveopts
			}
			if {$opts(-code) eq "" || [have-feature $i]} {
				lappend source "#include <$i>"
			}
		}
		lappend source {*}$opts(-declare)
		lappend source "int main(void) {"
		lappend source $opts(-code)
		lappend source "return 0;"
		lappend source "}"

		set lines [join $source \n]
	}

	# Build the command line
	set cmdline {}
	lappend cmdline {*}[get-define CCACHE]
	switch -exact -- $opts(-lang) {
		c++ {
			lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
		}
		c {
			lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
		}
		default {
			autosetup-error "cctest called with unknown language: $opts(-lang)"
		}
	}

	if {$opts(-link)} {
		lappend cmdline {*}[get-define LDFLAGS]
	} else {
		set tmp conftest__.o
		lappend cmdline -c
	}
	lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""]
	lappend cmdline $src -o $tmp {*}$opts(-libs)
	if {$opts(-link)} {
		lappend cmdline {*}[get-define LIBS]
	}

	# At this point we have the complete command line and the
	# complete source to be compiled. Get the result from cache if
	# we can
	if {[info exists ::cc_cache($cmdline,$lines)]} {
		msg-checking "(cached) "
		set ok $::cc_cache($cmdline,$lines)
		if {$::autosetup(debug)} {
			configlog "From cache (ok=$ok): [join $cmdline]"
			configlog "============"
			configlog $lines
			configlog "============"
		}
		return $ok
	}

	writefile $src $lines\n

	set ok 1
	set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
	if {$err || ($opts(-nooutput) && [string length $result])} {
		configlog "Failed: [join $cmdline]"
		configlog $result
		configlog "============"
		configlog "The failed code was:"
		configlog $lines
		configlog "============"
		set ok 0
	} elseif {$::autosetup(debug)} {
		configlog "Compiled OK: [join $cmdline]"
		configlog "============"
		configlog $lines
		configlog "============"
	}
	file delete $src
	file delete $tmp

	# cache it
	set ::cc_cache($cmdline,$lines) $ok

	return $ok
}

# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
#
# Deprecated - see make-config-header
proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
	user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
	make-config-header $file -auto $autopatterns -bare $barepatterns
}

# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
#
# Examines all defined variables which match the given patterns
# and writes an include file, $file, which defines each of these.
# Variables which match '-auto' are output as follows:
# - defines which have the value "0" are ignored.
# - defines which have integer values are defined as the integer value.
# - any other value is defined as a string, e.g. "value"
# Variables which match '-bare' are defined as-is.
# Variables which match '-str' are defined as a string, e.g. "value"
# Variables which match '-none' are omitted.
#
# Note that order is important. The first pattern which matches is selected
# Default behaviour is:
#
#  -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
#
# If the file would be unchanged, it is not written.
proc make-config-header {file args} {
	set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
	file mkdir [file dirname $file]
	set lines {}
	lappend lines "#ifndef $guard"
	lappend lines "#define $guard"

	# Add some defaults
	lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*

	foreach n [lsort [dict keys [all-defines]]] {
		set value [get-define $n]
		set type [calc-define-output-type $n $args]
		switch -exact -- $type {
			-bare {
				# Just output the value unchanged
			}
			-none {
				continue
			}
			-str {
				set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
			}
			-auto {
				# Automatically determine the type
				if {$value eq "0"} {
					lappend lines "/* #undef $n */"
					continue
				}
				if {![string is integer -strict $value]} {
					set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
				}
			}
			"" {
				continue
			}
			default {
				autosetup-error "Unknown type in make-config-header: $type"
			}
		}
		lappend lines "#define $n $value"
	}
	lappend lines "#endif"
	set buf [join $lines \n]
	write-if-changed $file $buf {
		msg-result "Created $file"
	}
}

proc calc-define-output-type {name spec} {
	foreach {type patterns} $spec {
		foreach pattern $patterns {
			if {[string match $pattern $name]} {
				return $type
			}
		}
	}
	return ""
}

# Initialise some values from the environment or commandline or default settings
foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
	lassign $i var default
	define $var [get-env $var $default]
}

if {[env-is-set CC]} {
	# Set by the user, so don't try anything else
	set try [list [get-env CC ""]]
} else {
	# Try some reasonable options
	set try [list [get-define cross]cc [get-define cross]gcc]
}
define CC [find-an-executable {*}$try]
if {[get-define CC] eq ""} {
	user-error "Could not find a C compiler. Tried: [join $try ", "]"
}

define CPP [get-env CPP "[get-define CC] -E"]

# XXX: Could avoid looking for a C++ compiler until requested
# Note that if CXX isn't found, we just set it to "false". It might not be needed.
if {[env-is-set CXX]} {
	define CXX [find-an-executable -required [get-env CXX ""]]
} else {
	define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
}

# CXXFLAGS default to CFLAGS if not specified
define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]

# May need a CC_FOR_BUILD, so look for one
define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]

if {[get-define CC] eq ""} {
	user-error "Could not find a C compiler. Tried: [join $try ", "]"
}

define CCACHE [find-an-executable [get-env CCACHE ccache]]

# Initial cctest settings
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
set autosetup(cc-include-deps) {}

msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
if {[get-define CXX] ne "false"} {
	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
}
msg-result "Build C compiler...[get-define CC_FOR_BUILD]"

# On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
# but some compilers may not support it, so test here.
switch -glob -- [get-define host] {
	*-*-darwin* {
		if {[cctest -cflags {-g0}]} {
			define cc-default-debug -g0
		}
	}
}

if {![cc-check-includes stdlib.h]} {
	user-error "Compiler does not work. See config.log"
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted autosetup/config.guess.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
#! /bin/sh
# Attempt to guess a canonical system name.
#   Copyright 1992-2014 Free Software Foundation, Inc.

timestamp='2014-11-04'

# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program.  This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
# Please send patches to <config-patches@gnu.org>.


me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION]

Output the configuration name of the system \`$me' is run on.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to <config-patches@gnu.org>."

version="\
GNU config.guess ($timestamp)

Originally written by Per Bothner.
Copyright 1992-2014 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help" >&2
       exit 1 ;;
    * )
       break ;;
  esac
done

if test $# != 0; then
  echo "$me: too many arguments$help" >&2
  exit 1
fi

trap 'exit 1' 1 2 15

# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.

# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
# use `HOST_CC' if defined, but it is deprecated.

# Portable tmp directory creation inspired by the Autoconf team.

set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
 { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
 { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
 { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
dummy=$tmp/dummy ;
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
case $CC_FOR_BUILD,$HOST_CC,$CC in
 ,,)    echo "int x;" > $dummy.c ;
	for c in cc gcc c89 c99 ; do
	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
	     CC_FOR_BUILD="$c"; break ;
	  fi ;
	done ;
	if test x"$CC_FOR_BUILD" = x ; then
	  CC_FOR_BUILD=no_compiler_found ;
	fi
	;;
 ,,*)   CC_FOR_BUILD=$CC ;;
 ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
esac ; set_cc_for_build= ;'

# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
	PATH=$PATH:/.attbin ; export PATH
fi

UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown

case "${UNAME_SYSTEM}" in
Linux|GNU|GNU/*)
	# If the system lacks a compiler, then just pick glibc.
	# We could probably try harder.
	LIBC=gnu

	eval $set_cc_for_build
	cat <<-EOF > $dummy.c
	#include <features.h>
	#if defined(__UCLIBC__)
	LIBC=uclibc
	#elif defined(__dietlibc__)
	LIBC=dietlibc
	#else
	LIBC=gnu
	#endif
	EOF
	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
	;;
esac

# Note: order is significant - the case branches are not exclusive.

case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
    *:NetBSD:*:*)
	# NetBSD (nbsd) targets should (where applicable) match one or
	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
	# switched to ELF, *-*-netbsd* would select the old
	# object file format.  This provides both forward
	# compatibility and a consistent mechanism for selecting the
	# object file format.
	#
	# Note: NetBSD doesn't particularly care about the vendor
	# portion of the name.  We always set it to "unknown".
	sysctl="sysctl -n hw.machine_arch"
	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
	case "${UNAME_MACHINE_ARCH}" in
	    armeb) machine=armeb-unknown ;;
	    arm*) machine=arm-unknown ;;
	    sh3el) machine=shl-unknown ;;
	    sh3eb) machine=sh-unknown ;;
	    sh5el) machine=sh5le-unknown ;;
	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
	esac
	# The Operating System including object format, if it has switched
	# to ELF recently, or will in the future.
	case "${UNAME_MACHINE_ARCH}" in
	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
		eval $set_cc_for_build
		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
			| grep -q __ELF__
		then
		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
		    # Return netbsd for either.  FIX?
		    os=netbsd
		else
		    os=netbsdelf
		fi
		;;
	    *)
		os=netbsd
		;;
	esac
	# The OS release
	# Debian GNU/NetBSD machines have a different userland, and
	# thus, need a distinct triplet. However, they do not need
	# kernel version information, so it can be replaced with a
	# suitable tag, in the style of linux-gnu.
	case "${UNAME_VERSION}" in
	    Debian*)
		release='-gnu'
		;;
	    *)
		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
		;;
	esac
	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
	# contains redundant information, the shorter form:
	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
	echo "${machine}-${os}${release}"
	exit ;;
    *:Bitrig:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
	exit ;;
    *:OpenBSD:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
	exit ;;
    *:ekkoBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
	exit ;;
    *:SolidBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
	exit ;;
    macppc:MirBSD:*:*)
	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    *:MirBSD:*:*)
	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
	exit ;;
    alpha:OSF1:*:*)
	case $UNAME_RELEASE in
	*4.0)
		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
		;;
	*5.*)
		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
		;;
	esac
	# According to Compaq, /usr/sbin/psrinfo has been available on
	# OSF/1 and Tru64 systems produced since 1995.  I hope that
	# covers most systems running today.  This code pipes the CPU
	# types through head -n 1, so we only detect the type of CPU 0.
	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
	case "$ALPHA_CPU_TYPE" in
	    "EV4 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "EV4.5 (21064)")
		UNAME_MACHINE="alpha" ;;
	    "LCA4 (21066/21068)")
		UNAME_MACHINE="alpha" ;;
	    "EV5 (21164)")
		UNAME_MACHINE="alphaev5" ;;
	    "EV5.6 (21164A)")
		UNAME_MACHINE="alphaev56" ;;
	    "EV5.6 (21164PC)")
		UNAME_MACHINE="alphapca56" ;;
	    "EV5.7 (21164PC)")
		UNAME_MACHINE="alphapca57" ;;
	    "EV6 (21264)")
		UNAME_MACHINE="alphaev6" ;;
	    "EV6.7 (21264A)")
		UNAME_MACHINE="alphaev67" ;;
	    "EV6.8CB (21264C)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8AL (21264B)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.8CX (21264D)")
		UNAME_MACHINE="alphaev68" ;;
	    "EV6.9A (21264/EV69A)")
		UNAME_MACHINE="alphaev69" ;;
	    "EV7 (21364)")
		UNAME_MACHINE="alphaev7" ;;
	    "EV7.9 (21364A)")
		UNAME_MACHINE="alphaev79" ;;
	esac
	# A Pn.n version is a patched version.
	# A Vn.n version is a released version.
	# A Tn.n version is a released field test version.
	# A Xn.n version is an unreleased experimental baselevel.
	# 1.2 uses "1.2" for uname -r.
	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
	exitcode=$?
	trap '' 0
	exit $exitcode ;;
    Alpha\ *:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# Should we change UNAME_MACHINE based on the output of uname instead
	# of the specific Alpha model?
	echo alpha-pc-interix
	exit ;;
    21064:Windows_NT:50:3)
	echo alpha-dec-winnt3.5
	exit ;;
    Amiga*:UNIX_System_V:4.0:*)
	echo m68k-unknown-sysv4
	exit ;;
    *:[Aa]miga[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-amigaos
	exit ;;
    *:[Mm]orph[Oo][Ss]:*:*)
	echo ${UNAME_MACHINE}-unknown-morphos
	exit ;;
    *:OS/390:*:*)
	echo i370-ibm-openedition
	exit ;;
    *:z/VM:*:*)
	echo s390-ibm-zvmoe
	exit ;;
    *:OS400:*:*)
	echo powerpc-ibm-os400
	exit ;;
    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
	echo arm-acorn-riscix${UNAME_RELEASE}
	exit ;;
    arm*:riscos:*:*|arm*:RISCOS:*:*)
	echo arm-unknown-riscos
	exit ;;
    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
	echo hppa1.1-hitachi-hiuxmpp
	exit ;;
    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
	if test "`(/bin/universe) 2>/dev/null`" = att ; then
		echo pyramid-pyramid-sysv3
	else
		echo pyramid-pyramid-bsd
	fi
	exit ;;
    NILE*:*:*:dcosx)
	echo pyramid-pyramid-svr4
	exit ;;
    DRS?6000:unix:4.0:6*)
	echo sparc-icl-nx6
	exit ;;
    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
	case `/usr/bin/uname -p` in
	    sparc) echo sparc-icl-nx7; exit ;;
	esac ;;
    s390x:SunOS:*:*)
	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4H:SunOS:5.*:*)
	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
	echo i386-pc-auroraux${UNAME_RELEASE}
	exit ;;
    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
	eval $set_cc_for_build
	SUN_ARCH="i386"
	# If there is a compiler, see if it is configured for 64-bit objects.
	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
	# This test works for both compilers.
	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
		grep IS_64BIT_ARCH >/dev/null
	    then
		SUN_ARCH="x86_64"
	    fi
	fi
	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:6*:*)
	# According to config.sub, this is the proper way to canonicalize
	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
	# it's likely to be more like Solaris than SunOS4.
	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    sun4*:SunOS:*:*)
	case "`/usr/bin/arch -k`" in
	    Series*|S4*)
		UNAME_RELEASE=`uname -v`
		;;
	esac
	# Japanese Language versions have a version number like `4.1.3-JL'.
	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
	exit ;;
    sun3*:SunOS:*:*)
	echo m68k-sun-sunos${UNAME_RELEASE}
	exit ;;
    sun*:*:4.2BSD:*)
	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
	case "`/bin/arch`" in
	    sun3)
		echo m68k-sun-sunos${UNAME_RELEASE}
		;;
	    sun4)
		echo sparc-sun-sunos${UNAME_RELEASE}
		;;
	esac
	exit ;;
    aushp:SunOS:*:*)
	echo sparc-auspex-sunos${UNAME_RELEASE}
	exit ;;
    # The situation for MiNT is a little confusing.  The machine name
    # can be virtually everything (everything which is not
    # "atarist" or "atariste" at least should have a processor
    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
    # to the lowercase version "mint" (or "freemint").  Finally
    # the system name "TOS" denotes a system which is actually not
    # MiNT.  But MiNT is downward compatible to TOS, so this should
    # be no problem.
    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
	echo m68k-atari-mint${UNAME_RELEASE}
	exit ;;
    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
	echo m68k-milan-mint${UNAME_RELEASE}
	exit ;;
    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
	echo m68k-hades-mint${UNAME_RELEASE}
	exit ;;
    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
	echo m68k-unknown-mint${UNAME_RELEASE}
	exit ;;
    m68k:machten:*:*)
	echo m68k-apple-machten${UNAME_RELEASE}
	exit ;;
    powerpc:machten:*:*)
	echo powerpc-apple-machten${UNAME_RELEASE}
	exit ;;
    RISC*:Mach:*:*)
	echo mips-dec-mach_bsd4.3
	exit ;;
    RISC*:ULTRIX:*:*)
	echo mips-dec-ultrix${UNAME_RELEASE}
	exit ;;
    VAX*:ULTRIX*:*:*)
	echo vax-dec-ultrix${UNAME_RELEASE}
	exit ;;
    2020:CLIX:*:* | 2430:CLIX:*:*)
	echo clipper-intergraph-clix${UNAME_RELEASE}
	exit ;;
    mips:*:*:UMIPS | mips:*:*:RISCos)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
#ifdef __cplusplus
#include <stdio.h>  /* for printf() prototype */
	int main (int argc, char *argv[]) {
#else
	int main (argc, argv) int argc; char *argv[]; {
#endif
	#if defined (host_mips) && defined (MIPSEB)
	#if defined (SYSTYPE_SYSV)
	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_SVR4)
	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
	#endif
	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
	#endif
	#endif
	  exit (-1);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c &&
	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
	  SYSTEM_NAME=`$dummy $dummyarg` &&
	    { echo "$SYSTEM_NAME"; exit; }
	echo mips-mips-riscos${UNAME_RELEASE}
	exit ;;
    Motorola:PowerMAX_OS:*:*)
	echo powerpc-motorola-powermax
	exit ;;
    Motorola:*:4.3:PL8-*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
	echo powerpc-harris-powermax
	exit ;;
    Night_Hawk:Power_UNIX:*:*)
	echo powerpc-harris-powerunix
	exit ;;
    m88k:CX/UX:7*:*)
	echo m88k-harris-cxux7
	exit ;;
    m88k:*:4*:R4*)
	echo m88k-motorola-sysv4
	exit ;;
    m88k:*:3*:R3*)
	echo m88k-motorola-sysv3
	exit ;;
    AViiON:dgux:*:*)
	# DG/UX returns AViiON for all architectures
	UNAME_PROCESSOR=`/usr/bin/uname -p`
	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
	then
	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
	       [ ${TARGET_BINARY_INTERFACE}x = x ]
	    then
		echo m88k-dg-dgux${UNAME_RELEASE}
	    else
		echo m88k-dg-dguxbcs${UNAME_RELEASE}
	    fi
	else
	    echo i586-dg-dgux${UNAME_RELEASE}
	fi
	exit ;;
    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
	echo m88k-dolphin-sysv3
	exit ;;
    M88*:*:R3*:*)
	# Delta 88k system running SVR3
	echo m88k-motorola-sysv3
	exit ;;
    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
	echo m88k-tektronix-sysv3
	exit ;;
    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
	echo m68k-tektronix-bsd
	exit ;;
    *:IRIX*:*:*)
	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
	exit ;;
    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
    i*86:AIX:*:*)
	echo i386-ibm-aix
	exit ;;
    ia64:AIX:*:*)
	if [ -x /usr/bin/oslevel ] ; then
		IBM_REV=`/usr/bin/oslevel`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:2:3)
	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
		eval $set_cc_for_build
		sed 's/^		//' << EOF >$dummy.c
		#include <sys/systemcfg.h>

		main()
			{
			if (!__power_pc())
				exit(1);
			puts("powerpc-ibm-aix3.2.5");
			exit(0);
			}
EOF
		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
		then
			echo "$SYSTEM_NAME"
		else
			echo rs6000-ibm-aix3.2.5
		fi
	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
		echo rs6000-ibm-aix3.2.4
	else
		echo rs6000-ibm-aix3.2
	fi
	exit ;;
    *:AIX:*:[4567])
	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
		IBM_ARCH=rs6000
	else
		IBM_ARCH=powerpc
	fi
	if [ -x /usr/bin/lslpp ] ; then
		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
	else
		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
	fi
	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
	exit ;;
    *:AIX:*:*)
	echo rs6000-ibm-aix
	exit ;;
    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
	echo romp-ibm-bsd4.4
	exit ;;
    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
	exit ;;                             # report: romp-ibm BSD 4.3
    *:BOSX:*:*)
	echo rs6000-bull-bosx
	exit ;;
    DPX/2?00:B.O.S.:*:*)
	echo m68k-bull-sysv3
	exit ;;
    9000/[34]??:4.3bsd:1.*:*)
	echo m68k-hp-bsd
	exit ;;
    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
	echo m68k-hp-bsd4.4
	exit ;;
    9000/[34678]??:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	case "${UNAME_MACHINE}" in
	    9000/31? )            HP_ARCH=m68000 ;;
	    9000/[34]?? )         HP_ARCH=m68k ;;
	    9000/[678][0-9][0-9])
		if [ -x /usr/bin/getconf ]; then
		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
		    case "${sc_cpu_version}" in
		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
		      532)                      # CPU_PA_RISC2_0
			case "${sc_kernel_bits}" in
			  32) HP_ARCH="hppa2.0n" ;;
			  64) HP_ARCH="hppa2.0w" ;;
			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
			esac ;;
		    esac
		fi
		if [ "${HP_ARCH}" = "" ]; then
		    eval $set_cc_for_build
		    sed 's/^		//' << EOF >$dummy.c

		#define _HPUX_SOURCE
		#include <stdlib.h>
		#include <unistd.h>

		int main ()
		{
		#if defined(_SC_KERNEL_BITS)
		    long bits = sysconf(_SC_KERNEL_BITS);
		#endif
		    long cpu  = sysconf (_SC_CPU_VERSION);

		    switch (cpu)
			{
			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
			case CPU_PA_RISC2_0:
		#if defined(_SC_KERNEL_BITS)
			    switch (bits)
				{
				case 64: puts ("hppa2.0w"); break;
				case 32: puts ("hppa2.0n"); break;
				default: puts ("hppa2.0"); break;
				} break;
		#else  /* !defined(_SC_KERNEL_BITS) */
			    puts ("hppa2.0"); break;
		#endif
			default: puts ("hppa1.0"); break;
			}
		    exit (0);
		}
EOF
		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
		    test -z "$HP_ARCH" && HP_ARCH=hppa
		fi ;;
	esac
	if [ ${HP_ARCH} = "hppa2.0w" ]
	then
	    eval $set_cc_for_build

	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
	    # generating 64-bit code.  GNU and HP use different nomenclature:
	    #
	    # $ CC_FOR_BUILD=cc ./config.guess
	    # => hppa2.0w-hp-hpux11.23
	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
	    # => hppa64-hp-hpux11.23

	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
		grep -q __LP64__
	    then
		HP_ARCH="hppa2.0w"
	    else
		HP_ARCH="hppa64"
	    fi
	fi
	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
	exit ;;
    ia64:HP-UX:*:*)
	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
	echo ia64-hp-hpux${HPUX_REV}
	exit ;;
    3050*:HI-UX:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#include <unistd.h>
	int
	main ()
	{
	  long cpu = sysconf (_SC_CPU_VERSION);
	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
	     results, however.  */
	  if (CPU_IS_PA_RISC (cpu))
	    {
	      switch (cpu)
		{
		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
		  default: puts ("hppa-hitachi-hiuxwe2"); break;
		}
	    }
	  else if (CPU_IS_HP_MC68K (cpu))
	    puts ("m68k-hitachi-hiuxwe2");
	  else puts ("unknown-hitachi-hiuxwe2");
	  exit (0);
	}
EOF
	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
		{ echo "$SYSTEM_NAME"; exit; }
	echo unknown-hitachi-hiuxwe2
	exit ;;
    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
	echo hppa1.1-hp-bsd
	exit ;;
    9000/8??:4.3bsd:*:*)
	echo hppa1.0-hp-bsd
	exit ;;
    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
	echo hppa1.0-hp-mpeix
	exit ;;
    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
	echo hppa1.1-hp-osf
	exit ;;
    hp8??:OSF1:*:*)
	echo hppa1.0-hp-osf
	exit ;;
    i*86:OSF1:*:*)
	if [ -x /usr/sbin/sysversion ] ; then
	    echo ${UNAME_MACHINE}-unknown-osf1mk
	else
	    echo ${UNAME_MACHINE}-unknown-osf1
	fi
	exit ;;
    parisc*:Lites*:*:*)
	echo hppa1.1-hp-lites
	exit ;;
    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
	echo c1-convex-bsd
	exit ;;
    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
	else echo c2-convex-bsd
	fi
	exit ;;
    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
	echo c34-convex-bsd
	exit ;;
    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
	echo c38-convex-bsd
	exit ;;
    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
	echo c4-convex-bsd
	exit ;;
    CRAY*Y-MP:*:*:*)
	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*[A-Z]90:*:*:*)
	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
	      -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*TS:*:*:*)
	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*T3E:*:*:*)
	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*SV1:*:*:*)
	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    *:UNICOS/mp:*:*)
	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
	exit ;;
    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
	exit ;;
    5000:UNIX_System_V:4.*:*)
	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
	exit ;;
    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
	exit ;;
    sparc*:BSD/OS:*:*)
	echo sparc-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:BSD/OS:*:*)
	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
	exit ;;
    *:FreeBSD:*:*)
	UNAME_PROCESSOR=`/usr/bin/uname -p`
	case ${UNAME_PROCESSOR} in
	    amd64)
		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	    *)
		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
	esac
	exit ;;
    i*:CYGWIN*:*)
	echo ${UNAME_MACHINE}-pc-cygwin
	exit ;;
    *:MINGW64*:*)
	echo ${UNAME_MACHINE}-pc-mingw64
	exit ;;
    *:MINGW*:*)
	echo ${UNAME_MACHINE}-pc-mingw32
	exit ;;
    *:MSYS*:*)
	echo ${UNAME_MACHINE}-pc-msys
	exit ;;
    i*:windows32*:*)
	# uname -m includes "-pc" on this system.
	echo ${UNAME_MACHINE}-mingw32
	exit ;;
    i*:PW*:*)
	echo ${UNAME_MACHINE}-pc-pw32
	exit ;;
    *:Interix*:*)
	case ${UNAME_MACHINE} in
	    x86)
		echo i586-pc-interix${UNAME_RELEASE}
		exit ;;
	    authenticamd | genuineintel | EM64T)
		echo x86_64-unknown-interix${UNAME_RELEASE}
		exit ;;
	    IA64)
		echo ia64-unknown-interix${UNAME_RELEASE}
		exit ;;
	esac ;;
    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
	echo i${UNAME_MACHINE}-pc-mks
	exit ;;
    8664:Windows_NT:*)
	echo x86_64-pc-mks
	exit ;;
    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
	# How do we know it's Interix rather than the generic POSIX subsystem?
	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
	# UNAME_MACHINE based on the output of uname instead of i386?
	echo i586-pc-interix
	exit ;;
    i*:UWIN*:*)
	echo ${UNAME_MACHINE}-pc-uwin
	exit ;;
    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
	echo x86_64-unknown-cygwin
	exit ;;
    p*:CYGWIN*:*)
	echo powerpcle-unknown-cygwin
	exit ;;
    prep*:SunOS:5.*:*)
	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
	exit ;;
    *:GNU:*:*)
	# the GNU system
	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
	exit ;;
    *:GNU/*:*:*)
	# other systems with GNU libc and userland
	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
	exit ;;
    i*86:Minix:*:*)
	echo ${UNAME_MACHINE}-pc-minix
	exit ;;
    aarch64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    aarch64_be:Linux:*:*)
	UNAME_MACHINE=aarch64_be
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    alpha:Linux:*:*)
	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
	  EV5)   UNAME_MACHINE=alphaev5 ;;
	  EV56)  UNAME_MACHINE=alphaev56 ;;
	  PCA56) UNAME_MACHINE=alphapca56 ;;
	  PCA57) UNAME_MACHINE=alphapca56 ;;
	  EV6)   UNAME_MACHINE=alphaev6 ;;
	  EV67)  UNAME_MACHINE=alphaev67 ;;
	  EV68*) UNAME_MACHINE=alphaev68 ;;
	esac
	objdump --private-headers /bin/sh | grep -q ld.so.1
	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    arc:Linux:*:* | arceb:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    arm*:Linux:*:*)
	eval $set_cc_for_build
	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
	    | grep -q __ARM_EABI__
	then
	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	else
	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
		| grep -q __ARM_PCS_VFP
	    then
		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
	    else
		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
	    fi
	fi
	exit ;;
    avr32*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    cris:Linux:*:*)
	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
	exit ;;
    crisv32:Linux:*:*)
	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
	exit ;;
    frv:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    hexagon:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    i*86:Linux:*:*)
	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
	exit ;;
    ia64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    m32r*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    m68*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    mips:Linux:*:* | mips64:Linux:*:*)
	eval $set_cc_for_build
	sed 's/^	//' << EOF >$dummy.c
	#undef CPU
	#undef ${UNAME_MACHINE}
	#undef ${UNAME_MACHINE}el
	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
	CPU=${UNAME_MACHINE}el
	#else
	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
	CPU=${UNAME_MACHINE}
	#else
	CPU=
	#endif
	#endif
EOF
	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
	;;
    openrisc*:Linux:*:*)
	echo or1k-unknown-linux-${LIBC}
	exit ;;
    or32:Linux:*:* | or1k*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    padre:Linux:*:*)
	echo sparc-unknown-linux-${LIBC}
	exit ;;
    parisc64:Linux:*:* | hppa64:Linux:*:*)
	echo hppa64-unknown-linux-${LIBC}
	exit ;;
    parisc:Linux:*:* | hppa:Linux:*:*)
	# Look for CPU level
	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
	  *)    echo hppa-unknown-linux-${LIBC} ;;
	esac
	exit ;;
    ppc64:Linux:*:*)
	echo powerpc64-unknown-linux-${LIBC}
	exit ;;
    ppc:Linux:*:*)
	echo powerpc-unknown-linux-${LIBC}
	exit ;;
    ppc64le:Linux:*:*)
	echo powerpc64le-unknown-linux-${LIBC}
	exit ;;
    ppcle:Linux:*:*)
	echo powerpcle-unknown-linux-${LIBC}
	exit ;;
    s390:Linux:*:* | s390x:Linux:*:*)
	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
	exit ;;
    sh64*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    sh*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    sparc:Linux:*:* | sparc64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    tile*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    vax:Linux:*:*)
	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
	exit ;;
    x86_64:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    xtensa*:Linux:*:*)
	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
	exit ;;
    i*86:DYNIX/ptx:4*:*)
	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
	# earlier versions are messed up and put the nodename in both
	# sysname and nodename.
	echo i386-sequent-sysv4
	exit ;;
    i*86:UNIX_SV:4.2MP:2.*)
	# Unixware is an offshoot of SVR4, but it has its own version
	# number series starting with 2...
	# I am not positive that other SVR4 systems won't match this,
	# I just have to hope.  -- rms.
	# Use sysv4.2uw... so that sysv4* matches it.
	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
	exit ;;
    i*86:OS/2:*:*)
	# If we were able to find `uname', then EMX Unix compatibility
	# is probably installed.
	echo ${UNAME_MACHINE}-pc-os2-emx
	exit ;;
    i*86:XTS-300:*:STOP)
	echo ${UNAME_MACHINE}-unknown-stop
	exit ;;
    i*86:atheos:*:*)
	echo ${UNAME_MACHINE}-unknown-atheos
	exit ;;
    i*86:syllable:*:*)
	echo ${UNAME_MACHINE}-pc-syllable
	exit ;;
    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
	echo i386-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    i*86:*DOS:*:*)
	echo ${UNAME_MACHINE}-pc-msdosdjgpp
	exit ;;
    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
	else
		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
	fi
	exit ;;
    i*86:*:5:[678]*)
	# UnixWare 7.x, OpenUNIX and OpenServer 6.
	case `/bin/uname -X | grep "^Machine"` in
	    *486*)	     UNAME_MACHINE=i486 ;;
	    *Pentium)	     UNAME_MACHINE=i586 ;;
	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
	esac
	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
	exit ;;
    i*86:*:3.2:*)
	if test -f /usr/options/cb.name; then
		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
	elif /bin/uname -X 2>/dev/null >/dev/null ; then
		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
			&& UNAME_MACHINE=i586
		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
			&& UNAME_MACHINE=i686
		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
			&& UNAME_MACHINE=i686
		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
	else
		echo ${UNAME_MACHINE}-pc-sysv32
	fi
	exit ;;
    pc:*:*:*)
	# Left here for compatibility:
	# uname -m prints for DJGPP always 'pc', but it prints nothing about
	# the processor, so we play safe by assuming i586.
	# Note: whatever this is, it MUST be the same as what config.sub
	# prints for the "djgpp" host, or else GDB configury will decide that
	# this is a cross-build.
	echo i586-pc-msdosdjgpp
	exit ;;
    Intel:Mach:3*:*)
	echo i386-pc-mach3
	exit ;;
    paragon:*:*:*)
	echo i860-intel-osf1
	exit ;;
    i860:*:4.*:*) # i860-SVR4
	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
	else # Add other i860-SVR4 vendors below as they are discovered.
	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
	fi
	exit ;;
    mini*:CTIX:SYS*5:*)
	# "miniframe"
	echo m68010-convergent-sysv
	exit ;;
    mc68k:UNIX:SYSTEM5:3.51m)
	echo m68k-convergent-sysv
	exit ;;
    M680?0:D-NIX:5.3:*)
	echo m68k-diab-dnix
	exit ;;
    M68*:*:R3V[5678]*:*)
	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
	OS_REL=''
	test -r /etc/.relid \
	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	  && { echo i486-ncr-sysv4; exit; } ;;
    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
	OS_REL='.3'
	test -r /etc/.relid \
	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
	echo m68k-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    mc68030:UNIX_System_V:4.*:*)
	echo m68k-atari-sysv4
	exit ;;
    TSUNAMI:LynxOS:2.*:*)
	echo sparc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    rs6000:LynxOS:2.*:*)
	echo rs6000-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
	echo powerpc-unknown-lynxos${UNAME_RELEASE}
	exit ;;
    SM[BE]S:UNIX_SV:*:*)
	echo mips-dde-sysv${UNAME_RELEASE}
	exit ;;
    RM*:ReliantUNIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    RM*:SINIX-*:*:*)
	echo mips-sni-sysv4
	exit ;;
    *:SINIX-*:*:*)
	if uname -p 2>/dev/null >/dev/null ; then
		UNAME_MACHINE=`(uname -p) 2>/dev/null`
		echo ${UNAME_MACHINE}-sni-sysv4
	else
		echo ns32k-sni-sysv
	fi
	exit ;;
    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
			# says <Richard.M.Bartel@ccMail.Census.GOV>
	echo i586-unisys-sysv4
	exit ;;
    *:UNIX_System_V:4*:FTX*)
	# From Gerald Hewes <hewes@openmarket.com>.
	# How about differentiating between stratus architectures? -djm
	echo hppa1.1-stratus-sysv4
	exit ;;
    *:*:*:FTX*)
	# From seanf@swdc.stratus.com.
	echo i860-stratus-sysv4
	exit ;;
    i*86:VOS:*:*)
	# From Paul.Green@stratus.com.
	echo ${UNAME_MACHINE}-stratus-vos
	exit ;;
    *:VOS:*:*)
	# From Paul.Green@stratus.com.
	echo hppa1.1-stratus-vos
	exit ;;
    mc68*:A/UX:*:*)
	echo m68k-apple-aux${UNAME_RELEASE}
	exit ;;
    news*:NEWS-OS:6*:*)
	echo mips-sony-newsos6
	exit ;;
    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
	if [ -d /usr/nec ]; then
		echo mips-nec-sysv${UNAME_RELEASE}
	else
		echo mips-unknown-sysv${UNAME_RELEASE}
	fi
	exit ;;
    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
	echo powerpc-be-beos
	exit ;;
    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
	echo powerpc-apple-beos
	exit ;;
    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
	echo i586-pc-beos
	exit ;;
    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
	echo i586-pc-haiku
	exit ;;
    x86_64:Haiku:*:*)
	echo x86_64-unknown-haiku
	exit ;;
    SX-4:SUPER-UX:*:*)
	echo sx4-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-5:SUPER-UX:*:*)
	echo sx5-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-6:SUPER-UX:*:*)
	echo sx6-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-7:SUPER-UX:*:*)
	echo sx7-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8:SUPER-UX:*:*)
	echo sx8-nec-superux${UNAME_RELEASE}
	exit ;;
    SX-8R:SUPER-UX:*:*)
	echo sx8r-nec-superux${UNAME_RELEASE}
	exit ;;
    Power*:Rhapsody:*:*)
	echo powerpc-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Rhapsody:*:*)
	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
	exit ;;
    *:Darwin:*:*)
	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
	eval $set_cc_for_build
	if test "$UNAME_PROCESSOR" = unknown ; then
	    UNAME_PROCESSOR=powerpc
	fi
	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
	    if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
		    (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
		    grep IS_64BIT_ARCH >/dev/null
		then
		    case $UNAME_PROCESSOR in
			i386) UNAME_PROCESSOR=x86_64 ;;
			powerpc) UNAME_PROCESSOR=powerpc64 ;;
		    esac
		fi
	    fi
	elif test "$UNAME_PROCESSOR" = i386 ; then
	    # Avoid executing cc on OS X 10.9, as it ships with a stub
	    # that puts up a graphical alert prompting to install
	    # developer tools.  Any system running Mac OS X 10.7 or
	    # later (Darwin 11 and later) is required to have a 64-bit
	    # processor. This is not true of the ARM version of Darwin
	    # that Apple uses in portable devices.
	    UNAME_PROCESSOR=x86_64
	fi
	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
	exit ;;
    *:procnto*:*:* | *:QNX:[0123456789]*:*)
	UNAME_PROCESSOR=`uname -p`
	if test "$UNAME_PROCESSOR" = "x86"; then
		UNAME_PROCESSOR=i386
		UNAME_MACHINE=pc
	fi
	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
	exit ;;
    *:QNX:*:4*)
	echo i386-pc-qnx
	exit ;;
    NEO-?:NONSTOP_KERNEL:*:*)
	echo neo-tandem-nsk${UNAME_RELEASE}
	exit ;;
    NSE-*:NONSTOP_KERNEL:*:*)
	echo nse-tandem-nsk${UNAME_RELEASE}
	exit ;;
    NSR-?:NONSTOP_KERNEL:*:*)
	echo nsr-tandem-nsk${UNAME_RELEASE}
	exit ;;
    *:NonStop-UX:*:*)
	echo mips-compaq-nonstopux
	exit ;;
    BS2000:POSIX*:*:*)
	echo bs2000-siemens-sysv
	exit ;;
    DS/*:UNIX_System_V:*:*)
	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
	exit ;;
    *:Plan9:*:*)
	# "uname -m" is not consistent, so use $cputype instead. 386
	# is converted to i386 for consistency with other x86
	# operating systems.
	if test "$cputype" = "386"; then
	    UNAME_MACHINE=i386
	else
	    UNAME_MACHINE="$cputype"
	fi
	echo ${UNAME_MACHINE}-unknown-plan9
	exit ;;
    *:TOPS-10:*:*)
	echo pdp10-unknown-tops10
	exit ;;
    *:TENEX:*:*)
	echo pdp10-unknown-tenex
	exit ;;
    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
	echo pdp10-dec-tops20
	exit ;;
    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
	echo pdp10-xkl-tops20
	exit ;;
    *:TOPS-20:*:*)
	echo pdp10-unknown-tops20
	exit ;;
    *:ITS:*:*)
	echo pdp10-unknown-its
	exit ;;
    SEI:*:*:SEIUX)
	echo mips-sei-seiux${UNAME_RELEASE}
	exit ;;
    *:DragonFly:*:*)
	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
	exit ;;
    *:*VMS:*:*)
	UNAME_MACHINE=`(uname -p) 2>/dev/null`
	case "${UNAME_MACHINE}" in
	    A*) echo alpha-dec-vms ; exit ;;
	    I*) echo ia64-dec-vms ; exit ;;
	    V*) echo vax-dec-vms ; exit ;;
	esac ;;
    *:XENIX:*:SysV)
	echo i386-pc-xenix
	exit ;;
    i*86:skyos:*:*)
	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
	exit ;;
    i*86:rdos:*:*)
	echo ${UNAME_MACHINE}-pc-rdos
	exit ;;
    i*86:AROS:*:*)
	echo ${UNAME_MACHINE}-pc-aros
	exit ;;
    x86_64:VMkernel:*:*)
	echo ${UNAME_MACHINE}-unknown-esx
	exit ;;
esac

cat >&2 <<EOF
$0: unable to guess system type

This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from

  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD

If the version you run ($0) is already up to date, please
send the following data and any information you think might be
pertinent to <config-patches@gnu.org> in order to provide the needed
information to handle your system.

config.guess timestamp = $timestamp

uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`

/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`

hostinfo               = `(hostinfo) 2>/dev/null`
/bin/universe          = `(/bin/universe) 2>/dev/null`
/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
/bin/arch              = `(/bin/arch) 2>/dev/null`
/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`

UNAME_MACHINE = ${UNAME_MACHINE}
UNAME_RELEASE = ${UNAME_RELEASE}
UNAME_SYSTEM  = ${UNAME_SYSTEM}
UNAME_VERSION = ${UNAME_VERSION}
EOF

exit 1

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted autosetup/config.sub.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
#! /bin/sh
# Configuration validation subroutine script.
#   Copyright 1992-2014 Free Software Foundation, Inc.

timestamp='2014-12-03'

# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program.  This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").


# Please send patches to <config-patches@gnu.org>.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.

# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD

# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
# Each package is responsible for reporting which valid configurations
# it does not support.  The user should be able to distinguish
# a failure to support a valid configuration from a meaningless
# configuration.

# The goal of this file is to map all the various variations of a given
# machine specification into a single specification in the form:
#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or in some cases, the newer four-part form:
#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
       $0 [OPTION] ALIAS

Canonicalize a configuration name.

Operation modes:
  -h, --help         print this help, then exit
  -t, --time-stamp   print date of last modification, then exit
  -v, --version      print version number, then exit

Report bugs and patches to <config-patches@gnu.org>."

version="\
GNU config.sub ($timestamp)

Copyright 1992-2014 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

help="
Try \`$me --help' for more information."

# Parse command line
while test $# -gt 0 ; do
  case $1 in
    --time-stamp | --time* | -t )
       echo "$timestamp" ; exit ;;
    --version | -v )
       echo "$version" ; exit ;;
    --help | --h* | -h )
       echo "$usage"; exit ;;
    -- )     # Stop option processing
       shift; break ;;
    - )	# Use stdin as input.
       break ;;
    -* )
       echo "$me: invalid option $1$help"
       exit 1 ;;

    *local*)
       # First pass through any local machine types.
       echo $1
       exit ;;

    * )
       break ;;
  esac
done

case $# in
 0) echo "$me: missing argument$help" >&2
    exit 1;;
 1) ;;
 *) echo "$me: too many arguments$help" >&2
    exit 1;;
esac

# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
  knetbsd*-gnu* | netbsd*-gnu* | \
  kopensolaris*-gnu* | \
  storm-chaos* | os2-emx* | rtmk-nova*)
    os=-$maybe_os
    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
    ;;
  android-linux)
    os=-linux-android
    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
    ;;
  *)
    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
    if [ $basic_machine != $1 ]
    then os=`echo $1 | sed 's/.*-/-/'`
    else os=; fi
    ;;
esac

### Let's recognize common machines as not being operating systems so
### that things like config.sub decstation-3100 work.  We also
### recognize some manufacturers as not being operating systems, so we
### can provide default operating systems below.
case $os in
	-sun*os*)
		# Prevent following clause from handling this invalid input.
		;;
	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
	-apple | -axis | -knuth | -cray | -microblaze*)
		os=
		basic_machine=$1
		;;
	-bluegene*)
		os=-cnk
		;;
	-sim | -cisco | -oki | -wec | -winbond)
		os=
		basic_machine=$1
		;;
	-scout)
		;;
	-wrs)
		os=-vxworks
		basic_machine=$1
		;;
	-chorusos*)
		os=-chorusos
		basic_machine=$1
		;;
	-chorusrdb)
		os=-chorusrdb
		basic_machine=$1
		;;
	-hiux*)
		os=-hiuxwe2
		;;
	-sco6)
		os=-sco5v6
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5)
		os=-sco3.2v5
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco4)
		os=-sco3.2v4
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2.[4-9]*)
		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco3.2v[4-9]*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco5v6*)
		# Don't forget version if it is 3.2v4 or newer.
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-sco*)
		os=-sco3.2v2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-udk*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-isc)
		os=-isc2.2
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-clix*)
		basic_machine=clipper-intergraph
		;;
	-isc*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
		;;
	-lynx*178)
		os=-lynxos178
		;;
	-lynx*5)
		os=-lynxos5
		;;
	-lynx*)
		os=-lynxos
		;;
	-ptx*)
		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
		;;
	-windowsnt*)
		os=`echo $os | sed -e 's/windowsnt/winnt/'`
		;;
	-psos*)
		os=-psos
		;;
	-mint | -mint[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
esac

# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
	# Recognize the basic CPU types without company name.
	# Some are omitted here because they have special meanings below.
	1750a | 580 \
	| a29k \
	| aarch64 | aarch64_be \
	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
	| am33_2.0 \
	| arc | arceb \
	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
	| avr | avr32 \
	| be32 | be64 \
	| bfin \
	| c4x | c8051 | clipper \
	| d10v | d30v | dlx | dsp16xx \
	| epiphany \
	| fido | fr30 | frv \
	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
	| hexagon \
	| i370 | i860 | i960 | ia64 \
	| ip2k | iq2000 \
	| k1om \
	| le32 | le64 \
	| lm32 \
	| m32c | m32r | m32rle | m68000 | m68k | m88k \
	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
	| mips | mipsbe | mipseb | mipsel | mipsle \
	| mips16 \
	| mips64 | mips64el \
	| mips64octeon | mips64octeonel \
	| mips64orion | mips64orionel \
	| mips64r5900 | mips64r5900el \
	| mips64vr | mips64vrel \
	| mips64vr4100 | mips64vr4100el \
	| mips64vr4300 | mips64vr4300el \
	| mips64vr5000 | mips64vr5000el \
	| mips64vr5900 | mips64vr5900el \
	| mipsisa32 | mipsisa32el \
	| mipsisa32r2 | mipsisa32r2el \
	| mipsisa32r6 | mipsisa32r6el \
	| mipsisa64 | mipsisa64el \
	| mipsisa64r2 | mipsisa64r2el \
	| mipsisa64r6 | mipsisa64r6el \
	| mipsisa64sb1 | mipsisa64sb1el \
	| mipsisa64sr71k | mipsisa64sr71kel \
	| mipsr5900 | mipsr5900el \
	| mipstx39 | mipstx39el \
	| mn10200 | mn10300 \
	| moxie \
	| mt \
	| msp430 \
	| nds32 | nds32le | nds32be \
	| nios | nios2 | nios2eb | nios2el \
	| ns16k | ns32k \
	| open8 | or1k | or1knd | or32 \
	| pdp10 | pdp11 | pj | pjl \
	| powerpc | powerpc64 | powerpc64le | powerpcle \
	| pyramid \
	| riscv32 | riscv64 \
	| rl78 | rx \
	| score \
	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
	| sh64 | sh64le \
	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
	| spu \
	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
	| ubicom32 \
	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
	| visium \
	| we32k \
	| x86 | xc16x | xstormy16 | xtensa \
	| z8k | z80)
		basic_machine=$basic_machine-unknown
		;;
	c54x)
		basic_machine=tic54x-unknown
		;;
	c55x)
		basic_machine=tic55x-unknown
		;;
	c6x)
		basic_machine=tic6x-unknown
		;;
	leon|leon[3-9])
		basic_machine=sparc-$basic_machine
		;;
	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
		basic_machine=$basic_machine-unknown
		os=-none
		;;
	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
		;;
	ms1)
		basic_machine=mt-unknown
		;;

	strongarm | thumb | xscale)
		basic_machine=arm-unknown
		;;
	xgate)
		basic_machine=$basic_machine-unknown
		os=-none
		;;
	xscaleeb)
		basic_machine=armeb-unknown
		;;

	xscaleel)
		basic_machine=armel-unknown
		;;

	# We use `pc' rather than `unknown'
	# because (1) that's what they normally are, and
	# (2) the word "unknown" tends to confuse beginning users.
	i*86 | x86_64)
	  basic_machine=$basic_machine-pc
	  ;;
	# Object if more than one company name word.
	*-*-*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
	# Recognize the basic CPU types with company name.
	580-* \
	| a29k-* \
	| aarch64-* | aarch64_be-* \
	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
	| avr-* | avr32-* \
	| be32-* | be64-* \
	| bfin-* | bs2000-* \
	| c[123]* | c30-* | [cjt]90-* | c4x-* \
	| c8051-* | clipper-* | craynv-* | cydra-* \
	| d10v-* | d30v-* | dlx-* \
	| elxsi-* \
	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
	| h8300-* | h8500-* \
	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
	| hexagon-* \
	| i*86-* | i860-* | i960-* | ia64-* \
	| ip2k-* | iq2000-* \
	| k1om-* \
	| le32-* | le64-* \
	| lm32-* \
	| m32c-* | m32r-* | m32rle-* \
	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
	| microblaze-* | microblazeel-* \
	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
	| mips16-* \
	| mips64-* | mips64el-* \
	| mips64octeon-* | mips64octeonel-* \
	| mips64orion-* | mips64orionel-* \
	| mips64r5900-* | mips64r5900el-* \
	| mips64vr-* | mips64vrel-* \
	| mips64vr4100-* | mips64vr4100el-* \
	| mips64vr4300-* | mips64vr4300el-* \
	| mips64vr5000-* | mips64vr5000el-* \
	| mips64vr5900-* | mips64vr5900el-* \
	| mipsisa32-* | mipsisa32el-* \
	| mipsisa32r2-* | mipsisa32r2el-* \
	| mipsisa32r6-* | mipsisa32r6el-* \
	| mipsisa64-* | mipsisa64el-* \
	| mipsisa64r2-* | mipsisa64r2el-* \
	| mipsisa64r6-* | mipsisa64r6el-* \
	| mipsisa64sb1-* | mipsisa64sb1el-* \
	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
	| mipsr5900-* | mipsr5900el-* \
	| mipstx39-* | mipstx39el-* \
	| mmix-* \
	| mt-* \
	| msp430-* \
	| nds32-* | nds32le-* | nds32be-* \
	| nios-* | nios2-* | nios2eb-* | nios2el-* \
	| none-* | np1-* | ns16k-* | ns32k-* \
	| open8-* \
	| or1k*-* \
	| orion-* \
	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
	| pyramid-* \
	| rl78-* | romp-* | rs6000-* | rx-* \
	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
	| sparclite-* \
	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
	| tahoe-* \
	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
	| tile*-* \
	| tron-* \
	| ubicom32-* \
	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
	| vax-* \
	| visium-* \
	| we32k-* \
	| x86-* | x86_64-* | xc16x-* | xps100-* \
	| xstormy16-* | xtensa*-* \
	| ymp-* \
	| z8k-* | z80-*)
		;;
	# Recognize the basic CPU types without company name, with glob match.
	xtensa*)
		basic_machine=$basic_machine-unknown
		;;
	# Recognize the various machine names and aliases which stand
	# for a CPU type and a company and sometimes even an OS.
	386bsd)
		basic_machine=i386-unknown
		os=-bsd
		;;
	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
		basic_machine=m68000-att
		;;
	3b*)
		basic_machine=we32k-att
		;;
	a29khif)
		basic_machine=a29k-amd
		os=-udi
		;;
	abacus)
		basic_machine=abacus-unknown
		;;
	adobe68k)
		basic_machine=m68010-adobe
		os=-scout
		;;
	alliant | fx80)
		basic_machine=fx80-alliant
		;;
	altos | altos3068)
		basic_machine=m68k-altos
		;;
	am29k)
		basic_machine=a29k-none
		os=-bsd
		;;
	amd64)
		basic_machine=x86_64-pc
		;;
	amd64-*)
		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	amdahl)
		basic_machine=580-amdahl
		os=-sysv
		;;
	amiga | amiga-*)
		basic_machine=m68k-unknown
		;;
	amigaos | amigados)
		basic_machine=m68k-unknown
		os=-amigaos
		;;
	amigaunix | amix)
		basic_machine=m68k-unknown
		os=-sysv4
		;;
	apollo68)
		basic_machine=m68k-apollo
		os=-sysv
		;;
	apollo68bsd)
		basic_machine=m68k-apollo
		os=-bsd
		;;
	aros)
		basic_machine=i386-pc
		os=-aros
		;;
	aux)
		basic_machine=m68k-apple
		os=-aux
		;;
	balance)
		basic_machine=ns32k-sequent
		os=-dynix
		;;
	blackfin)
		basic_machine=bfin-unknown
		os=-linux
		;;
	blackfin-*)
		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	bluegene*)
		basic_machine=powerpc-ibm
		os=-cnk
		;;
	c54x-*)
		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c55x-*)
		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c6x-*)
		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	c90)
		basic_machine=c90-cray
		os=-unicos
		;;
	cegcc)
		basic_machine=arm-unknown
		os=-cegcc
		;;
	convex-c1)
		basic_machine=c1-convex
		os=-bsd
		;;
	convex-c2)
		basic_machine=c2-convex
		os=-bsd
		;;
	convex-c32)
		basic_machine=c32-convex
		os=-bsd
		;;
	convex-c34)
		basic_machine=c34-convex
		os=-bsd
		;;
	convex-c38)
		basic_machine=c38-convex
		os=-bsd
		;;
	cray | j90)
		basic_machine=j90-cray
		os=-unicos
		;;
	craynv)
		basic_machine=craynv-cray
		os=-unicosmp
		;;
	cr16 | cr16-*)
		basic_machine=cr16-unknown
		os=-elf
		;;
	crds | unos)
		basic_machine=m68k-crds
		;;
	crisv32 | crisv32-* | etraxfs*)
		basic_machine=crisv32-axis
		;;
	cris | cris-* | etrax*)
		basic_machine=cris-axis
		;;
	crx)
		basic_machine=crx-unknown
		os=-elf
		;;
	da30 | da30-*)
		basic_machine=m68k-da30
		;;
	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
		basic_machine=mips-dec
		;;
	decsystem10* | dec10*)
		basic_machine=pdp10-dec
		os=-tops10
		;;
	decsystem20* | dec20*)
		basic_machine=pdp10-dec
		os=-tops20
		;;
	delta | 3300 | motorola-3300 | motorola-delta \
	      | 3300-motorola | delta-motorola)
		basic_machine=m68k-motorola
		;;
	delta88)
		basic_machine=m88k-motorola
		os=-sysv3
		;;
	dicos)
		basic_machine=i686-pc
		os=-dicos
		;;
	djgpp)
		basic_machine=i586-pc
		os=-msdosdjgpp
		;;
	dpx20 | dpx20-*)
		basic_machine=rs6000-bull
		os=-bosx
		;;
	dpx2* | dpx2*-bull)
		basic_machine=m68k-bull
		os=-sysv3
		;;
	ebmon29k)
		basic_machine=a29k-amd
		os=-ebmon
		;;
	elxsi)
		basic_machine=elxsi-elxsi
		os=-bsd
		;;
	encore | umax | mmax)
		basic_machine=ns32k-encore
		;;
	es1800 | OSE68k | ose68k | ose | OSE)
		basic_machine=m68k-ericsson
		os=-ose
		;;
	fx2800)
		basic_machine=i860-alliant
		;;
	genix)
		basic_machine=ns32k-ns
		;;
	gmicro)
		basic_machine=tron-gmicro
		os=-sysv
		;;
	go32)
		basic_machine=i386-pc
		os=-go32
		;;
	h3050r* | hiux*)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	h8300hms)
		basic_machine=h8300-hitachi
		os=-hms
		;;
	h8300xray)
		basic_machine=h8300-hitachi
		os=-xray
		;;
	h8500hms)
		basic_machine=h8500-hitachi
		os=-hms
		;;
	harris)
		basic_machine=m88k-harris
		os=-sysv3
		;;
	hp300-*)
		basic_machine=m68k-hp
		;;
	hp300bsd)
		basic_machine=m68k-hp
		os=-bsd
		;;
	hp300hpux)
		basic_machine=m68k-hp
		os=-hpux
		;;
	hp3k9[0-9][0-9] | hp9[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k2[0-9][0-9] | hp9k31[0-9])
		basic_machine=m68000-hp
		;;
	hp9k3[2-9][0-9])
		basic_machine=m68k-hp
		;;
	hp9k6[0-9][0-9] | hp6[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hp9k7[0-79][0-9] | hp7[0-79][0-9])
		basic_machine=hppa1.1-hp
		;;
	hp9k78[0-9] | hp78[0-9])
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
		# FIXME: really hppa2.0-hp
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][13679] | hp8[0-9][13679])
		basic_machine=hppa1.1-hp
		;;
	hp9k8[0-9][0-9] | hp8[0-9][0-9])
		basic_machine=hppa1.0-hp
		;;
	hppa-next)
		os=-nextstep3
		;;
	hppaosf)
		basic_machine=hppa1.1-hp
		os=-osf
		;;
	hppro)
		basic_machine=hppa1.1-hp
		os=-proelf
		;;
	i370-ibm* | ibm*)
		basic_machine=i370-ibm
		;;
	i*86v32)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv32
		;;
	i*86v4*)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv4
		;;
	i*86v)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-sysv
		;;
	i*86sol2)
		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
		os=-solaris2
		;;
	i386mach)
		basic_machine=i386-mach
		os=-mach
		;;
	i386-vsta | vsta)
		basic_machine=i386-unknown
		os=-vsta
		;;
	iris | iris4d)
		basic_machine=mips-sgi
		case $os in
		    -irix*)
			;;
		    *)
			os=-irix4
			;;
		esac
		;;
	isi68 | isi)
		basic_machine=m68k-isi
		os=-sysv
		;;
	leon-*|leon[3-9]-*)
		basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
		;;
	m68knommu)
		basic_machine=m68k-unknown
		os=-linux
		;;
	m68knommu-*)
		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	m88k-omron*)
		basic_machine=m88k-omron
		;;
	magnum | m3230)
		basic_machine=mips-mips
		os=-sysv
		;;
	merlin)
		basic_machine=ns32k-utek
		os=-sysv
		;;
	microblaze*)
		basic_machine=microblaze-xilinx
		;;
	mingw64)
		basic_machine=x86_64-pc
		os=-mingw64
		;;
	mingw32)
		basic_machine=i686-pc
		os=-mingw32
		;;
	mingw32ce)
		basic_machine=arm-unknown
		os=-mingw32ce
		;;
	miniframe)
		basic_machine=m68000-convergent
		;;
	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
		basic_machine=m68k-atari
		os=-mint
		;;
	mips3*-*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
		;;
	mips3*)
		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
		;;
	monitor)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	morphos)
		basic_machine=powerpc-unknown
		os=-morphos
		;;
	moxiebox)
		basic_machine=moxie-unknown
		os=-moxiebox
		;;
	msdos)
		basic_machine=i386-pc
		os=-msdos
		;;
	ms1-*)
		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
		;;
	msys)
		basic_machine=i686-pc
		os=-msys
		;;
	mvs)
		basic_machine=i370-ibm
		os=-mvs
		;;
	nacl)
		basic_machine=le32-unknown
		os=-nacl
		;;
	ncr3000)
		basic_machine=i486-ncr
		os=-sysv4
		;;
	netbsd386)
		basic_machine=i386-unknown
		os=-netbsd
		;;
	netwinder)
		basic_machine=armv4l-rebel
		os=-linux
		;;
	news | news700 | news800 | news900)
		basic_machine=m68k-sony
		os=-newsos
		;;
	news1000)
		basic_machine=m68030-sony
		os=-newsos
		;;
	news-3600 | risc-news)
		basic_machine=mips-sony
		os=-newsos
		;;
	necv70)
		basic_machine=v70-nec
		os=-sysv
		;;
	next | m*-next )
		basic_machine=m68k-next
		case $os in
		    -nextstep* )
			;;
		    -ns2*)
		      os=-nextstep2
			;;
		    *)
		      os=-nextstep3
			;;
		esac
		;;
	nh3000)
		basic_machine=m68k-harris
		os=-cxux
		;;
	nh[45]000)
		basic_machine=m88k-harris
		os=-cxux
		;;
	nindy960)
		basic_machine=i960-intel
		os=-nindy
		;;
	mon960)
		basic_machine=i960-intel
		os=-mon960
		;;
	nonstopux)
		basic_machine=mips-compaq
		os=-nonstopux
		;;
	np1)
		basic_machine=np1-gould
		;;
	neo-tandem)
		basic_machine=neo-tandem
		;;
	nse-tandem)
		basic_machine=nse-tandem
		;;
	nsr-tandem)
		basic_machine=nsr-tandem
		;;
	op50n-* | op60c-*)
		basic_machine=hppa1.1-oki
		os=-proelf
		;;
	openrisc | openrisc-*)
		basic_machine=or32-unknown
		;;
	os400)
		basic_machine=powerpc-ibm
		os=-os400
		;;
	OSE68000 | ose68000)
		basic_machine=m68000-ericsson
		os=-ose
		;;
	os68k)
		basic_machine=m68k-none
		os=-os68k
		;;
	pa-hitachi)
		basic_machine=hppa1.1-hitachi
		os=-hiuxwe2
		;;
	paragon)
		basic_machine=i860-intel
		os=-osf
		;;
	parisc)
		basic_machine=hppa-unknown
		os=-linux
		;;
	parisc-*)
		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
		os=-linux
		;;
	pbd)
		basic_machine=sparc-tti
		;;
	pbb)
		basic_machine=m68k-tti
		;;
	pc532 | pc532-*)
		basic_machine=ns32k-pc532
		;;
	pc98)
		basic_machine=i386-pc
		;;
	pc98-*)
		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium | p5 | k5 | k6 | nexgen | viac3)
		basic_machine=i586-pc
		;;
	pentiumpro | p6 | 6x86 | athlon | athlon_*)
		basic_machine=i686-pc
		;;
	pentiumii | pentium2 | pentiumiii | pentium3)
		basic_machine=i686-pc
		;;
	pentium4)
		basic_machine=i786-pc
		;;
	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumpro-* | p6-* | 6x86-* | athlon-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pentium4-*)
		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	pn)
		basic_machine=pn-gould
		;;
	power)	basic_machine=power-ibm
		;;
	ppc | ppcbe)	basic_machine=powerpc-unknown
		;;
	ppc-* | ppcbe-*)
		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppcle | powerpclittle | ppc-le | powerpc-little)
		basic_machine=powerpcle-unknown
		;;
	ppcle-* | powerpclittle-*)
		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64)	basic_machine=powerpc64-unknown
		;;
	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
		basic_machine=powerpc64le-unknown
		;;
	ppc64le-* | powerpc64little-*)
		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	ps2)
		basic_machine=i386-ibm
		;;
	pw32)
		basic_machine=i586-unknown
		os=-pw32
		;;
	rdos | rdos64)
		basic_machine=x86_64-pc
		os=-rdos
		;;
	rdos32)
		basic_machine=i386-pc
		os=-rdos
		;;
	rom68k)
		basic_machine=m68k-rom68k
		os=-coff
		;;
	rm[46]00)
		basic_machine=mips-siemens
		;;
	rtpc | rtpc-*)
		basic_machine=romp-ibm
		;;
	s390 | s390-*)
		basic_machine=s390-ibm
		;;
	s390x | s390x-*)
		basic_machine=s390x-ibm
		;;
	sa29200)
		basic_machine=a29k-amd
		os=-udi
		;;
	sb1)
		basic_machine=mipsisa64sb1-unknown
		;;
	sb1el)
		basic_machine=mipsisa64sb1el-unknown
		;;
	sde)
		basic_machine=mipsisa32-sde
		os=-elf
		;;
	sei)
		basic_machine=mips-sei
		os=-seiux
		;;
	sequent)
		basic_machine=i386-sequent
		;;
	sh)
		basic_machine=sh-hitachi
		os=-hms
		;;
	sh5el)
		basic_machine=sh5le-unknown
		;;
	sh64)
		basic_machine=sh64-unknown
		;;
	sparclite-wrs | simso-wrs)
		basic_machine=sparclite-wrs
		os=-vxworks
		;;
	sps7)
		basic_machine=m68k-bull
		os=-sysv2
		;;
	spur)
		basic_machine=spur-unknown
		;;
	st2000)
		basic_machine=m68k-tandem
		;;
	stratus)
		basic_machine=i860-stratus
		os=-sysv4
		;;
	strongarm-* | thumb-*)
		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
		;;
	sun2)
		basic_machine=m68000-sun
		;;
	sun2os3)
		basic_machine=m68000-sun
		os=-sunos3
		;;
	sun2os4)
		basic_machine=m68000-sun
		os=-sunos4
		;;
	sun3os3)
		basic_machine=m68k-sun
		os=-sunos3
		;;
	sun3os4)
		basic_machine=m68k-sun
		os=-sunos4
		;;
	sun4os3)
		basic_machine=sparc-sun
		os=-sunos3
		;;
	sun4os4)
		basic_machine=sparc-sun
		os=-sunos4
		;;
	sun4sol2)
		basic_machine=sparc-sun
		os=-solaris2
		;;
	sun3 | sun3-*)
		basic_machine=m68k-sun
		;;
	sun4)
		basic_machine=sparc-sun
		;;
	sun386 | sun386i | roadrunner)
		basic_machine=i386-sun
		;;
	sv1)
		basic_machine=sv1-cray
		os=-unicos
		;;
	symmetry)
		basic_machine=i386-sequent
		os=-dynix
		;;
	t3e)
		basic_machine=alphaev5-cray
		os=-unicos
		;;
	t90)
		basic_machine=t90-cray
		os=-unicos
		;;
	tile*)
		basic_machine=$basic_machine-unknown
		os=-linux-gnu
		;;
	tx39)
		basic_machine=mipstx39-unknown
		;;
	tx39el)
		basic_machine=mipstx39el-unknown
		;;
	toad1)
		basic_machine=pdp10-xkl
		os=-tops20
		;;
	tower | tower-32)
		basic_machine=m68k-ncr
		;;
	tpf)
		basic_machine=s390x-ibm
		os=-tpf
		;;
	udi29k)
		basic_machine=a29k-amd
		os=-udi
		;;
	ultra3)
		basic_machine=a29k-nyu
		os=-sym1
		;;
	v810 | necv810)
		basic_machine=v810-nec
		os=-none
		;;
	vaxv)
		basic_machine=vax-dec
		os=-sysv
		;;
	vms)
		basic_machine=vax-dec
		os=-vms
		;;
	vpp*|vx|vx-*)
		basic_machine=f301-fujitsu
		;;
	vxworks960)
		basic_machine=i960-wrs
		os=-vxworks
		;;
	vxworks68)
		basic_machine=m68k-wrs
		os=-vxworks
		;;
	vxworks29k)
		basic_machine=a29k-wrs
		os=-vxworks
		;;
	w65*)
		basic_machine=w65-wdc
		os=-none
		;;
	w89k-*)
		basic_machine=hppa1.1-winbond
		os=-proelf
		;;
	xbox)
		basic_machine=i686-pc
		os=-mingw32
		;;
	xps | xps100)
		basic_machine=xps100-honeywell
		;;
	xscale-* | xscalee[bl]-*)
		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
		;;
	ymp)
		basic_machine=ymp-cray
		os=-unicos
		;;
	z8k-*-coff)
		basic_machine=z8k-unknown
		os=-sim
		;;
	z80-*-coff)
		basic_machine=z80-unknown
		os=-sim
		;;
	none)
		basic_machine=none-none
		os=-none
		;;

# Here we handle the default manufacturer of certain CPU types.  It is in
# some cases the only manufacturer, in others, it is the most popular.
	w89k)
		basic_machine=hppa1.1-winbond
		;;
	op50n)
		basic_machine=hppa1.1-oki
		;;
	op60c)
		basic_machine=hppa1.1-oki
		;;
	romp)
		basic_machine=romp-ibm
		;;
	mmix)
		basic_machine=mmix-knuth
		;;
	rs6000)
		basic_machine=rs6000-ibm
		;;
	vax)
		basic_machine=vax-dec
		;;
	pdp10)
		# there are many clones, so DEC is not a safe bet
		basic_machine=pdp10-unknown
		;;
	pdp11)
		basic_machine=pdp11-dec
		;;
	we32k)
		basic_machine=we32k-att
		;;
	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
		basic_machine=sh-unknown
		;;
	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
		basic_machine=sparc-sun
		;;
	cydra)
		basic_machine=cydra-cydrome
		;;
	orion)
		basic_machine=orion-highlevel
		;;
	orion105)
		basic_machine=clipper-highlevel
		;;
	mac | mpw | mac-mpw)
		basic_machine=m68k-apple
		;;
	pmac | pmac-mpw)
		basic_machine=powerpc-apple
		;;
	*-unknown)
		# Make sure to match an already-canonicalized machine name.
		;;
	*)
		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
		exit 1
		;;
esac

# Here we canonicalize certain aliases for manufacturers.
case $basic_machine in
	*-digital*)
		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
		;;
	*-commodore*)
		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
		;;
	*)
		;;
esac

# Decode manufacturer-specific aliases for certain operating systems.

if [ x"$os" != x"" ]
then
case $os in
	# First match some system type aliases
	# that might get confused with valid system types.
	# -solaris* is a basic system type, with this one exception.
	-auroraux)
		os=-auroraux
		;;
	-solaris1 | -solaris1.*)
		os=`echo $os | sed -e 's|solaris1|sunos4|'`
		;;
	-solaris)
		os=-solaris2
		;;
	-svr4*)
		os=-sysv4
		;;
	-unixware*)
		os=-sysv4.2uw
		;;
	-gnu/linux*)
		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
		;;
	# First accept the basic system types.
	# The portable systems comes first.
	# Each alternative MUST END IN A *, to match a version number.
	# -sysv* is not here because it comes later, after sysvr4.
	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
	      | -sym* | -kopensolaris* | -plan9* \
	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
	      | -aos* | -aros* \
	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
	      | -bitrig* | -openbsd* | -solidbsd* \
	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
	      | -chorusos* | -chorusrdb* | -cegcc* \
	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
	# Remember, each alternative MUST END IN *, to match a version number.
		;;
	-qnx*)
		case $basic_machine in
		    x86-* | i*86-*)
			;;
		    *)
			os=-nto$os
			;;
		esac
		;;
	-nto-qnx*)
		;;
	-nto*)
		os=`echo $os | sed -e 's|nto|nto-qnx|'`
		;;
	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
		;;
	-mac*)
		os=`echo $os | sed -e 's|mac|macos|'`
		;;
	-linux-dietlibc)
		os=-linux-dietlibc
		;;
	-linux*)
		os=`echo $os | sed -e 's|linux|linux-gnu|'`
		;;
	-sunos5*)
		os=`echo $os | sed -e 's|sunos5|solaris2|'`
		;;
	-sunos6*)
		os=`echo $os | sed -e 's|sunos6|solaris3|'`
		;;
	-opened*)
		os=-openedition
		;;
	-os400*)
		os=-os400
		;;
	-wince*)
		os=-wince
		;;
	-osfrose*)
		os=-osfrose
		;;
	-osf*)
		os=-osf
		;;
	-utek*)
		os=-bsd
		;;
	-dynix*)
		os=-bsd
		;;
	-acis*)
		os=-aos
		;;
	-atheos*)
		os=-atheos
		;;
	-syllable*)
		os=-syllable
		;;
	-386bsd)
		os=-bsd
		;;
	-ctix* | -uts*)
		os=-sysv
		;;
	-nova*)
		os=-rtmk-nova
		;;
	-ns2 )
		os=-nextstep2
		;;
	-nsk*)
		os=-nsk
		;;
	# Preserve the version number of sinix5.
	-sinix5.*)
		os=`echo $os | sed -e 's|sinix|sysv|'`
		;;
	-sinix*)
		os=-sysv4
		;;
	-tpf*)
		os=-tpf
		;;
	-triton*)
		os=-sysv3
		;;
	-oss*)
		os=-sysv3
		;;
	-svr4)
		os=-sysv4
		;;
	-svr3)
		os=-sysv3
		;;
	-sysvr4)
		os=-sysv4
		;;
	# This must come after -sysvr4.
	-sysv*)
		;;
	-ose*)
		os=-ose
		;;
	-es1800*)
		os=-ose
		;;
	-xenix)
		os=-xenix
		;;
	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
		os=-mint
		;;
	-aros*)
		os=-aros
		;;
	-zvmoe)
		os=-zvmoe
		;;
	-dicos*)
		os=-dicos
		;;
	-nacl*)
		;;
	-none)
		;;
	*)
		# Get rid of the `-' at the beginning of $os.
		os=`echo $os | sed 's/[^-]*-//'`
		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
		exit 1
		;;
esac
else

# Here we handle the default operating systems that come with various machines.
# The value should be what the vendor currently ships out the door with their
# machine or put another way, the most popular os provided with the machine.

# Note that if you're going to try to match "-MANUFACTURER" here (say,
# "-sun"), then you have to tell the case statement up towards the top
# that MANUFACTURER isn't an operating system.  Otherwise, code above
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.

case $basic_machine in
	score-*)
		os=-elf
		;;
	spu-*)
		os=-elf
		;;
	*-acorn)
		os=-riscix1.2
		;;
	arm*-rebel)
		os=-linux
		;;
	arm*-semi)
		os=-aout
		;;
	c4x-* | tic4x-*)
		os=-coff
		;;
	c8051-*)
		os=-elf
		;;
	hexagon-*)
		os=-elf
		;;
	tic54x-*)
		os=-coff
		;;
	tic55x-*)
		os=-coff
		;;
	tic6x-*)
		os=-coff
		;;
	# This must come before the *-dec entry.
	pdp10-*)
		os=-tops20
		;;
	pdp11-*)
		os=-none
		;;
	*-dec | vax-*)
		os=-ultrix4.2
		;;
	m68*-apollo)
		os=-domain
		;;
	i386-sun)
		os=-sunos4.0.2
		;;
	m68000-sun)
		os=-sunos3
		;;
	m68*-cisco)
		os=-aout
		;;
	mep-*)
		os=-elf
		;;
	mips*-cisco)
		os=-elf
		;;
	mips*-*)
		os=-elf
		;;
	or32-*)
		os=-coff
		;;
	*-tti)	# must be before sparc entry or we get the wrong os.
		os=-sysv3
		;;
	sparc-* | *-sun)
		os=-sunos4.1.1
		;;
	*-be)
		os=-beos
		;;
	*-haiku)
		os=-haiku
		;;
	*-ibm)
		os=-aix
		;;
	*-knuth)
		os=-mmixware
		;;
	*-wec)
		os=-proelf
		;;
	*-winbond)
		os=-proelf
		;;
	*-oki)
		os=-proelf
		;;
	*-hp)
		os=-hpux
		;;
	*-hitachi)
		os=-hiux
		;;
	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
		os=-sysv
		;;
	*-cbm)
		os=-amigaos
		;;
	*-dg)
		os=-dgux
		;;
	*-dolphin)
		os=-sysv3
		;;
	m68k-ccur)
		os=-rtu
		;;
	m88k-omron*)
		os=-luna
		;;
	*-next )
		os=-nextstep
		;;
	*-sequent)
		os=-ptx
		;;
	*-crds)
		os=-unos
		;;
	*-ns)
		os=-genix
		;;
	i370-*)
		os=-mvs
		;;
	*-next)
		os=-nextstep3
		;;
	*-gould)
		os=-sysv
		;;
	*-highlevel)
		os=-bsd
		;;
	*-encore)
		os=-bsd
		;;
	*-sgi)
		os=-irix
		;;
	*-siemens)
		os=-sysv4
		;;
	*-masscomp)
		os=-rtu
		;;
	f30[01]-fujitsu | f700-fujitsu)
		os=-uxpv
		;;
	*-rom68k)
		os=-coff
		;;
	*-*bug)
		os=-coff
		;;
	*-apple)
		os=-macos
		;;
	*-atari*)
		os=-mint
		;;
	*)
		os=-none
		;;
esac
fi

# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer.  We pick the logical manufacturer.
vendor=unknown
case $basic_machine in
	*-unknown)
		case $os in
			-riscix*)
				vendor=acorn
				;;
			-sunos*)
				vendor=sun
				;;
			-cnk*|-aix*)
				vendor=ibm
				;;
			-beos*)
				vendor=be
				;;
			-hpux*)
				vendor=hp
				;;
			-mpeix*)
				vendor=hp
				;;
			-hiux*)
				vendor=hitachi
				;;
			-unos*)
				vendor=crds
				;;
			-dgux*)
				vendor=dg
				;;
			-luna*)
				vendor=omron
				;;
			-genix*)
				vendor=ns
				;;
			-mvs* | -opened*)
				vendor=ibm
				;;
			-os400*)
				vendor=ibm
				;;
			-ptx*)
				vendor=sequent
				;;
			-tpf*)
				vendor=ibm
				;;
			-vxsim* | -vxworks* | -windiss*)
				vendor=wrs
				;;
			-aux*)
				vendor=apple
				;;
			-hms*)
				vendor=hitachi
				;;
			-mpw* | -macos*)
				vendor=apple
				;;
			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
				vendor=atari
				;;
			-vos*)
				vendor=stratus
				;;
		esac
		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
		;;
esac

echo $basic_machine$os
exit

# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted autosetup/default.auto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Auto-load module for 'make' build system integration

use init

autosetup_add_init_type make {Simple "make" build system} {
	autosetup_check_create auto.def \
{# Initial auto.def created by 'autosetup --init=make'

use cc

# Add any user options here
options {
}

make-config-header config.h
make-template Makefile.in
}

	if {![file exists Makefile.in]} {
		puts "Note: I don't see Makefile.in. You will probably need to create one."
	}
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































Deleted autosetup/find-tclsh.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/sh
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh from source
d=`dirname "$0"`
{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
PATH="$PATH:$d"; export PATH
for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do
	{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
	{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
	"$d/jimsh0" "$d/test-tclsh" && exit 0
done
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
echo false
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































Deleted autosetup/jimsh0.c.

more than 10,000 changes

Deleted autosetup/pkg-config.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'pkg-config' module allows package information to be found via pkg-config
#
# If not cross-compiling, the package path should be determined automatically
# by pkg-config.
# If cross-compiling, the default package path is the compiler sysroot.
# If the C compiler doesn't support -print-sysroot, the path can be supplied
# by the --sysroot option or by defining SYSROOT.
#
# PKG_CONFIG may be set to use an alternative to pkg-config

use cc

module-options {
	sysroot:dir => "Override compiler sysroot for pkg-config search path"
}

# @pkg-config-init ?required?
#
# Initialises the pkg-config system. Unless required is set to 0,
# it is a fatal error if the pkg-config
# This command will normally be called automatically as required,
# but it may be invoked explicitly if lack of pkg-config is acceptable.
#
# Returns 1 if ok, or 0 if pkg-config not found/usable (only if required=0)
#
proc pkg-config-init {{required 1}} {
	if {[is-defined HAVE_PKG_CONFIG]} {
		return [get-define HAVE_PKG_CONFIG]
	}
	set found 0

	define PKG_CONFIG [get-env PKG_CONFIG pkg-config]
	msg-checking "Checking for pkg-config..."

	if {[catch {exec [get-define PKG_CONFIG] --version} version]} {
		msg-result "[get-define PKG_CONFIG] (not found)"
		if {$required} {
			user-error "No usable pkg-config"
		}
	} else {
		msg-result $version
		define PKG_CONFIG_VERSION $version

		set found 1

		if {[opt-val sysroot] ne ""} {
			define SYSROOT [file-normalize [opt-val sysroot]]
			msg-result "Using specified sysroot [get-define SYSROOT]"
		} elseif {[get-define build] ne [get-define host]} {
			if {[catch {exec-with-stderr [get-define CC] -print-sysroot} result errinfo] == 0} {
				# Use the compiler sysroot, if there is one
				define SYSROOT $result
				msg-result "Found compiler sysroot $result"
			} else {
				set msg "pkg-config: Cross compiling, but no compiler sysroot and no --sysroot supplied"
				if {$required} {
					user-error $msg
				} else {
					msg-result $msg
				}
				set found 0
			}
		}
		if {[is-defined SYSROOT]} {
			set sysroot [get-define SYSROOT]

			# XXX: It's possible that these should be set only when invoking pkg-config
			global env
			set env(PKG_CONFIG_DIR) ""
			# Do we need to try /usr/local as well or instead?
			set env(PKG_CONFIG_LIBDIR) $sysroot/usr/lib/pkgconfig:$sysroot/usr/share/pkgconfig
			set env(PKG_CONFIG_SYSROOT_DIR) $sysroot
		}
	}
	define HAVE_PKG_CONFIG $found
	return $found
}

# @pkg-config module ?requirements?
#
# Use pkg-config to find the given module meeting the given requirements.
# e.g.
#
## pkg-config pango >= 1.37.0
#
# If found, returns 1 and sets HAVE_PKG_PANGO to 1 along with:
#
## PKG_PANGO_VERSION to the found version
## PKG_PANGO_LIBS to the required libs (--libs-only-l)
## PKG_PANGO_LDFLAGS to the required linker flags (--libs-only-L)
## PKG_PANGO_CFLAGS to the required compiler flags (--cflags)
#
# If not found, returns 0.
#
proc pkg-config {module args} {
	set ok [pkg-config-init]

	msg-checking "Checking for $module $args..."

	if {!$ok} {
		msg-result "no pkg-config"
		return 0
	}

	if {[catch {exec [get-define PKG_CONFIG] --modversion "$module $args"} version]} {
		msg-result "not found"
		configlog "pkg-config --modversion $module $args: $version"
		return 0
	}
	msg-result $version
	set prefix [feature-define-name $module PKG_]
	define HAVE_${prefix}
	define ${prefix}_VERSION $version
	define ${prefix}_LIBS [exec pkg-config --libs-only-l $module]
	define ${prefix}_LDFLAGS [exec pkg-config --libs-only-L $module]
	define ${prefix}_CFLAGS [exec pkg-config --cflags $module]
	return 1
}

# @pkg-config-get module setting
#
# Convenience access to the results of pkg-config
#
# For example, [pkg-config-get pango CFLAGS] returns
# the value of PKG_PANGO_CFLAGS, or "" if not defined.
proc pkg-config-get {module name} {
	set prefix [feature-define-name $module PKG_]
	get-define ${prefix}_${name} ""
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































Deleted autosetup/system.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# This module supports common system interrogation and options
# such as --host, --build, --prefix, and setting srcdir, builddir, and EXEEXT
#
# It also support the 'feature' naming convention, where searching
# for a feature such as sys/type.h defines HAVE_SYS_TYPES_H
#
# It defines the following variables, based on --prefix unless overridden by the user:
#
## datadir
## sysconfdir
## sharedstatedir
## localstatedir
## infodir
## mandir
## includedir

# Do "define defaultprefix myvalue" to set the default prefix *before* the first "use"
set defaultprefix [get-define defaultprefix /usr/local]

module-options [subst -noc -nob {
	host:host-alias =>		{a complete or partial cpu-vendor-opsys for the system where
							the application will run (defaults to the same value as --build)}
	build:build-alias =>	{a complete or partial cpu-vendor-opsys for the system
							where the application will be built (defaults to the
							result of running config.guess)}
	prefix:dir =>			{the target directory for the build (defaults to '$defaultprefix')}

	# These (hidden) options are supported for autoconf/automake compatibility
	exec-prefix:
	bindir:
	sbindir:
	includedir:
	mandir:
	infodir:
	libexecdir:
	datadir:
	libdir:
	sysconfdir:
	sharedstatedir:
	localstatedir:
	maintainer-mode=0
	dependency-tracking=0
}]

# Returns 1 if exists, or 0 if  not
#
proc check-feature {name code} {
	msg-checking "Checking for $name..."
	set r [uplevel 1 $code]
	define-feature $name $r
	if {$r} {
		msg-result "ok"
	} else {
		msg-result "not found"
	}
	return $r
}

# @have-feature name ?default=0?
#
# Returns the value of the feature if defined, or $default if not.
# See 'feature-define-name' for how the feature name
# is translated into the define name.
#
proc have-feature {name {default 0}} {
	get-define [feature-define-name $name] $default
}

# @define-feature name ?value=1?
#
# Sets the feature 'define' to the given value.
# See 'feature-define-name' for how the feature name
# is translated into the define name.
#
proc define-feature {name {value 1}} {
	define [feature-define-name $name] $value
}

# @feature-checked name
#
# Returns 1 if the feature has been checked, whether true or not
#
proc feature-checked {name} {
	is-defined [feature-define-name $name]
}

# @feature-define-name name ?prefix=HAVE_?
#
# Converts a name to the corresponding define,
# e.g. sys/stat.h becomes HAVE_SYS_STAT_H.
#
# Converts * to P and all non-alphanumeric to underscore.
#
proc feature-define-name {name {prefix HAVE_}} {
	string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
}

# If $file doesn't exist, or it's contents are different than $buf,
# the file is written and $script is executed.
# Otherwise a "file is unchanged" message is displayed.
proc write-if-changed {file buf {script {}}} {
	set old [readfile $file ""]
	if {$old eq $buf && [file exists $file]} {
		msg-result "$file is unchanged"
	} else {
		writefile $file $buf\n
		uplevel 1 $script
	}
}

# @make-template template ?outfile?
#
# Reads the input file <srcdir>/$template and writes the output file $outfile.
# If $outfile is blank/omitted, $template should end with ".in" which
# is removed to create the output file name.
#
# Each pattern of the form @define@ is replaced with the corresponding
# define, if it exists, or left unchanged if not.
# 
# The special value @srcdir@ is substituted with the relative
# path to the source directory from the directory where the output
# file is created, while the special value @top_srcdir@ is substituted
# with the relative path to the top level source directory.
#
# Conditional sections may be specified as follows:
## @if name == value
## lines
## @else
## lines
## @endif
#
# Where 'name' is a defined variable name and @else is optional.
# If the expression does not match, all lines through '@endif' are ignored.
#
# The alternative forms may also be used:
## @if name
## @if name != value
#
# Where the first form is true if the variable is defined, but not empty or 0
#
# Currently these expressions can't be nested.
#
proc make-template {template {out {}}} {
	set infile [file join $::autosetup(srcdir) $template]

	if {![file exists $infile]} {
		user-error "Template $template is missing"
	}

	# Define this as late as possible
	define AUTODEPS $::autosetup(deps)

	if {$out eq ""} {
		if {[file ext $template] ne ".in"} {
			autosetup-error "make_template $template has no target file and can't guess"
		}
		set out [file rootname $template]
	}

	set outdir [file dirname $out]

	# Make sure the directory exists
	file mkdir $outdir

	# Set up srcdir and top_srcdir to be relative to the target dir
	define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
	define top_srcdir [relative-path $::autosetup(srcdir) $outdir]

	set mapping {}
	foreach {n v} [array get ::define] {
		lappend mapping @$n@ $v
	}
	set result {}
	foreach line [split [readfile $infile] \n] {
		if {[info exists cond]} {
			set l [string trimright $line]
			if {$l eq "@endif"} {
				unset cond
				continue
			}
			if {$l eq "@else"} {
				set cond [expr {!$cond}]
				continue
			}
			if {$cond} {
				lappend result $line
			}
			continue
		}
		if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} {
			lassign $expression equal value
			set varval [get-define $name ""]
			if {$equal eq ""} {
				set cond [expr {$varval ni {"" 0}}]
			} else {
				set cond [expr {$varval eq $value}]
				if {$equal ne "=="} {
					set cond [expr {!$cond}]
				}
			}
			continue
		}
		lappend result $line
	}
	writefile $out [string map $mapping [join $result \n]]\n

	msg-result "Created [relative-path $out] from [relative-path $template]"
}

# build/host tuples and cross-compilation prefix
set build [opt-val build]
define build_alias $build
if {$build eq ""} {
	define build [config_guess]
} else {
	define build [config_sub $build]
}

set host [opt-val host]
define host_alias $host
if {$host eq ""} {
	define host [get-define build]
	set cross ""
} else {
	define host [config_sub $host]
	set cross $host-
}
define cross [get-env CROSS $cross]

set prefix [opt-val prefix $defaultprefix]

# These are for compatibility with autoconf
define target [get-define host]
define prefix $prefix
define builddir $autosetup(builddir)
define srcdir $autosetup(srcdir)
# Allow this to come from the environment
define top_srcdir [get-env top_srcdir [get-define srcdir]]

# autoconf supports all of these
set exec_prefix [opt-val exec-prefix $prefix]
define exec_prefix $exec_prefix
foreach {name defpath} {
	bindir /bin
	sbindir /sbin
	libexecdir /libexec
	libdir /lib
} {
	define $name [opt-val $name $exec_prefix$defpath]
}
foreach {name defpath} {
	datadir /share
	sysconfdir /etc
	sharedstatedir /com
	localstatedir /var
	infodir /share/info
	mandir /share/man
	includedir /include
} {
	define $name [opt-val $name $prefix$defpath]
}

define SHELL [get-env SHELL [find-an-executable sh bash ksh]]

# Windows vs. non-Windows
switch -glob -- [get-define host] {
	*-*-ming* - *-*-cygwin - *-*-msys {
		define-feature windows
		define EXEEXT .exe
	}
	default {
		define EXEEXT ""
	}
}

# Display
msg-result "Host System...[get-define host]"
msg-result "Build System...[get-define build]"
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































































































































































































































































































































Deleted autosetup/test-tclsh.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# A small Tcl script to verify that the chosen
# interpreter works. Sometimes we might e.g. pick up
# an interpreter for a different arch.
# Outputs the full path to the interpreter

if {[catch {info version} version] == 0} {
	# This is Jim Tcl
	if {$version >= 0.72} {
		# Ensure that regexp works
		regexp (a.*?) a
		puts [info nameofexecutable]
		exit 0
	}
} elseif {[catch {info tclversion} version] == 0} {
	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
		puts [info nameofexecutable]
		exit 0
	}
}
exit 1
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































Deleted autosetup/tmake.auto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# Auto-load module for 'tmake' build system integration

use init

autosetup_add_init_type tmake "Tcl-based tmake build system" {
	autosetup_check_create auto.def \
{# Initial auto.def created by 'autosetup --init=tmake'
# vim:set syntax=tcl:

use cc cc-lib cc-db cc-shared
use tmake

# Add any user options here
# Really want a --configure that takes over the rest of the command line
options {
}

cc-check-tools ar ranlib

set objdir [get-env BUILDDIR objdir]

make-config-header $objdir/include/autoconf.h
make-tmake-settings $objdir/settings.conf {[A-Z]*}
}

	autosetup_check_create project.spec \
{# Initial project.spec created by 'autosetup --init=tmake'

# vim:set syntax=tcl:
define? DESTDIR _install

# XXX If configure creates additional/different files than include/autoconf.h
#     that should be reflected here

# We use [set AUTOREMAKE] here to avoid rebuilding settings.conf
# if the AUTOREMAKE command changes
Depends {settings.conf include/autoconf.h} auto.def -msg {note Configuring...} -do {
	run [set AUTOREMAKE] >$build/config.out
} -onerror {puts [readfile $build/config.out]} -fatal
Clean config.out
DistClean --source config.log
DistClean settings.conf include/autoconf.h

# If not configured, configure with default options
# Note that it is expected that configure will normally be run
# separately. This is just a convenience for a host build
define? AUTOREMAKE configure TOPBUILDDIR=$TOPBUILDDIR --conf=auto.def

Load settings.conf

# e.g. for up autoconf.h
IncludePaths include

ifconfig CONFIGURED

# Hmmm, but should we turn off AutoSubDirs?
#AutoSubDirs off
}

	if {![file exists build.spec]} {
		puts "Note: I don't see build.spec. Try running: tmake --genie"
	}
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































Deleted autosetup/tmake.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'tmake' module makes it easy to support the tmake build system.
#
# The following variables are set:
#
## CONFIGURED  - to indicate that the project is configured

use system

module-options {}

define CONFIGURED

# @make-tmake-settings outfile patterns ...
#
# Examines all defined variables which match the given patterns (defaults to "*")
# and writes a tmake-compatible .conf file defining those variables.
# For example, if ABC is "3 monkeys" and ABC matches a pattern, then the file will include:
#
## define ABC {3 monkeys}
#
# If the file would be unchanged, it is not written.
#
# Typical usage is:
#
# make-tmake-settings [get-env BUILDDIR objdir]/settings.conf {[A-Z]*}
proc make-tmake-settings {file args} {
	file mkdir [file dirname $file]
	set lines {}

	if {[llength $args] == 0} {
		set args *
	}

	foreach n [lsort [dict keys [all-defines]]] {
		foreach p $args {
			if {[string match $p $n]} {
				set value [get-define $n]
				lappend lines "define $n [list $value]"
				break
			}
		}
	}
	set buf [join $lines \n]
	write-if-changed $file $buf {
		msg-result "Created $file"
	}
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































Deleted bin/pidp8i.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/sh
########################################################################
# pidp8i.in - Attach the current terminal to the screen(1) session
#	started by the SysV init script in etc/pidp8i-ini.
#
# Copyright © 2015-2017 Oscar Vermeulen and Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

if [ "$USER" != "@INSTUSR@" ] ; then exec su -c "$0" @INSTUSR@ ; fi

procs=`screen -ls pidp8i | egrep '[0-9]+\.pidp8i' | wc -l`
if [ $procs -ne 0 ]; then
	echo Joining simulator session already in progress...
	screen -r
else
	cat <<ERROR
Either the simulator isn't running, or it isn't running under a screen(1)
session owned by @INSTUSR@.  Did you start it via the init script?

ERROR
fi
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































Deleted boot/0.script.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
; This script initializes a populated OS/8 environment on an
; RK05 cartridge disk pack.  That's 10 whole megabytes, so big 
; the OS requires that you split it into two partitions in order
; to address the whole disk!  Thus the "RKB0:" references you
; will find in tutorials, as that refers to the second half ("B")
; of the first ("0") RK05 cartridge disk.  The default location
; the OS uses is formally called "RKA0:", alias "SYS:".
;
; See 3.script if you want to load OS/8 via DECtape instead.
;
; This file is read on simulator startup when the IF switches are
; set to 0, so it defines the default starting environment for the
; simulator.
;
; If you need to soft-restart the simulator back into OS/8 from some
; other state -- that is, you initially started the simulator with
; IF != 0 -- you can set IF = 7 and toggle the Sing_Step switch on
; and back off, which restarts the simulator with 7.script, which in
; turn loads this one.  This somewhat clumsy arrangement is required
; because toggling Sing_Step with IF = 0 must not be made to restart
; the simulator, else there would be no way to use Sing_Step for any
; of its other functions.  See the PiDP-8/I instructions for details.
;
reset
echo Loading OS/8 from the RK05 cartridge disk...
set cpu 32k
set cpu noidle
set df disabled
@SET_THROTTLE@
att rk0 @MEDIADIR@/os8/os8.rk05
boot rk0
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































Deleted boot/2.script.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
; This script initializes a populated TSS/8 environment on an
; RS08 fixed-head hard disk drive (384 kB!) controlled by the
; RF08 disk controller.
;
echo Loading TSS/8 from the RS08 fixed-head disk...
load @MEDIADIR@/tss8/tss8_init.bin
set rf enabled
set df disabled
set cpu noidle
@SET_THROTTLE@
attach rf @MEDIADIR@/tss8/tss8_rf.dsk
attach ttix 4000
run 24200
<
<
<
<
<
<
<
<
<
<
<
<
<


























Deleted boot/3.script.in.
1
2
3
4
5
6
7
8
9
10
11
; Loads OS/8 from DECtape, as opposed to the RK05 based environment
; in 0.script.
;
echo Loading OS/8 from DECtape...
set df disabled
set dt disabled
set td enabled
set cpu noidle
@SET_THROTTLE@
attach td0 @MEDIADIR@/os8/os8.tu56
boot td0
<
<
<
<
<
<
<
<
<
<
<






















Deleted boot/4.script.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
; This script loads Spacewar! directly into core, without a supporting
; OS.
;
echo Spacewar!
echo
echo Keyboard controls from the VC8E program:
echo
echo Player 1  Player 2  Command
echo 1         9         fire weapon
echo 2         0         rotate CCW
echo 3         -         rotate CW
echo 4         =         thrusters
echo
echo Press both rotate keys simulatenously to warp into hyperspace.
echo
echo Press Ctrl-E to pause the simulator and return to the SimH
echo command prompt, where you can say "quit", "help" and other
echo things.  See the SimH manual for details.
echo
l @MEDIADIR@/spacewar/spacewar.bin
set cpu noidle
@SET_THROTTLE@
set df disabled
at ttix 2222
set ttox0 8b

g 200
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































Deleted boot/6.script.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
; This script loads ETOS V5B from the RK05 cartridge disk drive.
;
echo Loading ETOS from the RK05 cartridge disk drive...
reset
set cpu 32k
set cpu noidle
@SET_THROTTLE@
set df disabled
set tsc enabled
attach ttix 4000
att rk0 @MEDIADIR@/etos/etosv5b-demo.rk05
boot -d rk0

<
<
<
<
<
<
<
<
<
<
<
<
<


























Deleted boot/7.script.in.
1
2
echo Restarting the PiDP-8/I into its default operating environment...
do @BOOTDIR@/0.script
<
<




Deleted boot/readme.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
On startup, scanswitch passes the script number to run on to pidp8,
based on the IF switch settings.

Standard boot scripts:

IF switches   filename   description
----------------------------------------------------------------------
   000        0.script : OS/8 on 32K PDP-8 with RK05 disk cartridge
   001        1.script : RIM Loader installed at 7756
   010        2.script : TSS/8
   011        3.script : OS/8 on DECtape. This uses SLOW td0, not dt0
   100        4.script : spacewar! with vc8e output on localhost:2222
   101        5.script : (empty)
   110        6.script : ETOS Multi-user on OS/8 boot disk
   111        7.script : OS/8. Same as 0.script.
----------------------------------------------------------------------
Default initial startup script - when no IF switches are set is 0.script
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































Deleted configure.
1
2
3
#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
<
<
<






Deleted doc/OS-images.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
The Raspbian OS images you can downlod from [the PiDP-8/I development
site][1] install to an SD card in the same way as the [official Raspbian
images][2].  Follow the [installation guide][3] published by the
Raspberry Pi Foundation.  You will need to use a 2 GB or larger SD card.

The contents of the Zip file are:

| File Name         | Description
|--------------------------------
| `README.md`       | this file
| `pidp8i-*.img`    | the OS image, based on Raspbian Jessie Lite
| `MANIFEST.txt`    | SHA 256 hash and file size for the OS image file

One small difference between these OS images and the ones that come from
the Raspberry Pi Foundation is that mine have already booted once, so
they won't automatically expand to fill your SD card's space. Simply run
`sudo raspi-config` after your first boot and select the **Expand
Filesystem** option, then reboot.

Another difference is the default user name and password:

*   **username:** `pidp8i`
*   **password:** `edsonDeCastro1968`

You will be made to change that password on first login.

Remember, [the S in IoT stands for Security.][5]  If we want security,
we have to see to it ourselves!

If you do not want your PiDP-8/I to be secure, see my other guide, "[How
to Run a Nekkid PiDP-8/I][6]."


[1]: https://tangentsoft.com/pidp8i/
[2]: https://raspberrypi.org/downloads/raspbian/
[3]: https://raspberrypi.org/documentation/installation/installing-images/
[4]: https://en.wikipedia.org/wiki/Internet_of_things
[5]: http://www.testandverification.com/iot/s-iot-stands-security/
[6]: https://tangentsoft.com/pidp8i/wiki?name=How+to+Run+a+Naked+PiDP-8/I
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































Deleted doc/dec-sch-pdp8i-1968.jpg.

cannot compute difference between binary files

Deleted doc/led-decay.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/***********************************************************************
 led-decay.cpp - Proof of concept for an LED brightness decay algorithm 
	that simulates the appearance of incandescent light bulbs when fed
	a stream of samples over a given time period.

 Copyright © 2016 Warren Young
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be included
 in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 Except as contained in this notice, the names of the authors above
 shall not be used in advertising or otherwise to promote the sale, use
 or other dealings in this Software without prior written authorization
 from those authors.
***********************************************************************/

#include <iostream>
#include <vector>

using namespace std;

typedef vector<bool> vb;
typedef vb::const_iterator vbc;

// Keeping n samples.  To think about this concretely, imagine that it
// is 1 sample per millisecond over 0.1 sec, but realize that this is
// scaleable, so that how long 1/n seconds is doesn't affect the math.
static const size_t n = 100;

// Decay function is 1 - x^2, meaning the most recent event is
// considered 100%, with older events having increasingly lesser effect
// on the overall brightness until we hit 0% consideration at the end of
// the sample set.
//
// We need to scale that so that the total area under the decay
// function's curve is 1, so that if we feed a 50% duty cycle in, we
// get 50% out, but if we skew the 1s toward the front of the sample
// set (i.e. closer to "now"), we get greater brightness than if they
// are skewed toward the past.
//
// The Pi ships with Mathematica, which answers this question with:
//
//    Solve[Integrate[z * (1 - x^2), {x, 0, 1}] == 1, z]
//
// We get z = 1.5.
//
// If you want a different decay function, it needs to substitute for
// the 1 - x^2 bit.  It needs to start at 1 and decay to 0 over the
// range [0 <= x <= 1].  Run that through Mathematica to find the
// resulting value of z that gives a total of 1 over the sample span.
static double f(double x, bool v)
{
	return v ? (1.5 * (1 - x * x)) : 0;
}

// Given n bits representing the state of the LED at time x=1/n, return
// the total of applications of f on each bit.  Order is most recent
// event first, so it takes the strongest effect.
static double cdf(const vb& vl)
{
	double t = 0;
	for (size_t i = 0; i < n; ++i) {
		// We divide each f() return by n because it represents only 1/n
		// of the total area under the curve.  This is a crude form of
		// numeric integration.
		t += f(i / double(n), vl[i]) / n;
	}
	return t;
}

// Generate a series of sampled LED values, then run those sample sets
// through the above and show what brightness level that would generate.
int main()
{
	vb values(n);

	values.clear();
	for (size_t i = 0; i < n; ++i) {
		 values.push_back(true);
	}
	cout << "100% duty cycle: CDF = " << cdf(values) << endl;

	values.clear();
	for (size_t i = 0; i < n; ++i) {
		 values.push_back(i % 2 == 0);
	}
	cout << "50% duty cycle: CDF = " << cdf(values) << endl;

	values.clear();
	for (size_t i = 0; i < n; ++i) {
		 values.push_back(i % 4 == 0);
	}
	cout << "25% duty cycle: CDF = " << cdf(values) << endl;

	values.clear();
	for (size_t i = 0; i < n; ++i) {
		 values.push_back(i % 10 == 0);
	}
	cout << "10% duty cycle: CDF = " << cdf(values) << endl;

	values.assign(n, false);
	for (size_t i = 0; i < n / 2; ++i) {
		 values[i] = true;
	}
	cout << "First half 'on': CDF = " << cdf(values) << endl;

	values.assign(n, false);
	for (size_t i = n / 2; i < n; ++i) {
		 values[i] = true;
	}
	cout << "Second half 'on': CDF = " << cdf(values) << endl;

	values.assign(n, false);
	values[0] = true;
	cout << "1ms spike at the start: CDF = " << cdf(values) << endl;

	values.assign(n, false);
	values[n - 1] = true;
	cout << "1ms spike at the end: CDF = " << cdf(values) << endl;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































































Deleted doc/pidp8i-test.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# PCB Test Program


## Compiling and Installing

`pidp8i-test` is a simple program to test [Oscar Vermeulen's PiDP-8/I
Kit][project] during construction. It is built and installed alongside
the other software with the normal `make` process.


## Running It

If you are building the software on the Pi for the first time, log out
of your user account after installing it, then back in so that the
install script's changes to your user's `PATH` take effect.

Thereafter, simply give these commands:

    $ sudo systemctl stop pidp8i
	$ pidp8i-test

The first command ensures that the modified PDP-8 simulator is stopped
during the test, since only one program can be talking to the switch and
LED array at a given time. (This also applies to other programs like
[Deeper Thought 2][dt2].)


## Test Procedure

You can at any time hit Ctrl-C to stop the test.

The test proceeds as follows:

*   All On test:

    It turns on all LEDs for 5 seconds.

*   All Off test:

    It turns off all LEDs for 5 seconds.

*   Row test:

    It turns on one full row of LEDs and pauses for 5 seconds, then
    switches to the next row.  There are eight rows of LEDs of up to 12
    LEDs each.

*   Column test:

    It then turns on one full column of LEDs and pauses for 5 seconds,
    then switches to the next column.  There are 12 columns of LEDs with
    up to 8 LEDs each.  (Some of the LEDs positions in a column are
    sometimes rather chaotic, it will require intimate knowledge of the
    schematic to verify.  It's somewhat of a useless test but it might
    turn up an assembly error for someone.)

*   Switch test:

    It then goes into a single LED chase pattern and starts looking at
    switches.  This loop is infinite.  Every time it detects a change in
    the switch positions it prints out the full Octal bit pattern for
    the three switch banks.  No attempt is made to name the actual
    switch that has been flipped.  The goal is to verify switch
    functionality, not to debug the design of the circuit or the driver.

    When running this test, if you get a new line printed with a single
    bit change when you flip a single switch, the switch in question is
    working.  If you get no output printed or multiple bits changed in
    the output printed something is wrong.

    If for some reason you need to decode the output bits to physical
    switches they appear as follows:

    | A    | B    | C   
    |-------------------
    | 4000 | 0000 | 0000

    The first twelve bits (labelled A) is the Switch Register.  The bits
    left to right correspond to the SR switches also left to right.  So
    above the SR1 switch is toggled down, ie 1.  Every other SR switch
    is up, ie 0.

    The leftmost 6 bits (labelled B) are the 3 DF switches followed by
    the 3 IF switches.  Again left to right.  The rest of the bits are
    unused in the B section.

    The leftmost 8 bits (labelled C) are the remaining 8 switches
    starting at "START" and ending at "SING INST".  Again Left to right.


## License

This document is licensed under the same terms as the associated
[`src/test.c` program][program].


[project]: http://obsolescence.wix.com/obsolescence#!pidp-8
[dt2]:     https://github.com/VentureKing/Deeper-Thought-2
[program]: https://tangentsoft.com/pidp8i/doc/trunk/src/test.c
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































Deleted doc/vtedit-keypad.png.

cannot compute difference between binary files

Deleted doc/vtedit-keypad.svg.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="673.51404"
   height="613.08057"
   viewBox="0 0 673.51405 613.08058"
   id="svg2"
   version="1.1"
   inkscape:version="0.91 r13725"
   sodipodi:docname="vtedit-keypad.svg"
   inkscape:export-filename="/usr/local/src/pidp8i/trunk/doc/vtedit-keypad.png"
   inkscape:export-xdpi="80.18"
   inkscape:export-ydpi="80.18">
  <title
     id="title4295">VTEDIT Keypad Diagram</title>
  <defs
     id="defs4">
    <linearGradient
       inkscape:collect="always"
       id="linearGradient4138">
      <stop
         style="stop-color:#dbb56a;stop-opacity:0.70833331"
         offset="0"
         id="stop4140" />
      <stop
         style="stop-color:#f0e6da;stop-opacity:1"
         offset="1"
         id="stop4142" />
    </linearGradient>
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4144"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(-72.931483,8.918583)" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4254"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(39.142981,8.918583)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4272"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(151.21744,8.918583)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4324"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(-72.931483,120.43745)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4326"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(39.142981,120.43745)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4328"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(151.21744,120.43745)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4380"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(-72.931483,231.9563)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4382"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(39.142981,231.9563)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4384"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(151.21744,231.9563)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4434"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(263.2919,8.761662)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4436"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(263.2919,120.1236)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4438"
       gradientUnits="userSpaceOnUse"
       gradientTransform="matrix(1,0,0,2.1178002,263.2919,83.80932)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4504"
       gradientUnits="userSpaceOnUse"
       gradientTransform="matrix(2.1255986,0,0,1,-190.0452,343.47519)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4508"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(151.21744,343.47519)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4611"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(-72.931483,-102.60028)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4613"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(39.142981,-102.60028)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4615"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(151.21744,-102.60028)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#linearGradient4138"
       id="linearGradient4617"
       gradientUnits="userSpaceOnUse"
       gradientTransform="translate(263.2919,-102.60028)"
       x1="153.5432"
       y1="135.14371"
       x2="154.55334"
       y2="231.10818" />
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#fcfaf0"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="1"
     inkscape:pageshadow="2"
     inkscape:zoom="1.4"
     inkscape:cx="237.26909"
     inkscape:cy="345.9566"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="2560"
     inkscape:window-height="1391"
     inkscape:window-x="0"
     inkscape:window-y="1"
     inkscape:window-maximized="1"
     showguides="true"
     inkscape:guide-bbox="true"
     units="px"
     fit-margin-top="32"
     fit-margin-left="32"
     fit-margin-right="32"
     fit-margin-bottom="32" />
  <metadata
     id="metadata7">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title>VTEDIT Keypad Diagram</dc:title>
        <cc:license
           rdf:resource="https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md" />
        <dc:date>December 2016</dc:date>
        <dc:creator>
          <cc:Agent>
            <dc:title>Warren Young</dc:title>
          </cc:Agent>
        </dc:creator>
        <dc:contributor>
          <cc:Agent>
            <dc:title>This graphical diagram was created based on an ASCII diagram that came with the version of VTEDIT patched for VT100/ANSI terminals.</dc:title>
          </cc:Agent>
        </dc:contributor>
        <dc:rights>
          <cc:Agent>
            <dc:title>see ../SIMH-LICENSE.md</dc:title>
          </cc:Agent>
        </dc:rights>
        <dc:language>Englis</dc:language>
        <dc:subject>
          <rdf:Bag>
            <rdf:li>VTEDIT</rdf:li>
            <rdf:li>PDP-8</rdf:li>
            <rdf:li>diagram</rdf:li>
            <rdf:li>keypad</rdf:li>
          </rdf:Bag>
        </dc:subject>
        <dc:description>Diagram showing the function of the keypad keys when pressed in the version of VTEDIT patched for VT100/ANSI terminals.</dc:description>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:groupmode="layer"
     id="layer5"
     inkscape:label="key caps"
     style="display:inline"
     transform="translate(17.282791,22)">
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4144);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4136"
       width="98.994949"
       height="100.0051"
       x="31.114243"
       y="141.03181"
       ry="10.357149"
       rx="11.25" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="141.03181"
       x="143.18871"
       height="100.0051"
       width="98.994949"
       id="rect4240"
       style="opacity:1;fill:url(#linearGradient4254);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4272);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4258"
       width="98.994949"
       height="100.0051"
       x="255.26317"
       y="141.03181"
       ry="10.357149"
       rx="11.25" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="252.55069"
       x="31.114243"
       height="100.0051"
       width="98.994949"
       id="rect4278"
       style="opacity:1;fill:url(#linearGradient4324);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4326);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4294"
       width="98.994949"
       height="100.0051"
       x="143.18871"
       y="252.55069"
       ry="10.357149"
       rx="11.25" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="252.55069"
       x="255.26317"
       height="100.0051"
       width="98.994949"
       id="rect4310"
       style="opacity:1;fill:url(#linearGradient4328);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4380);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4334"
       width="98.994949"
       height="100.0051"
       x="31.114243"
       y="364.06955"
       ry="10.357149"
       rx="11.25" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="364.06955"
       x="143.18871"
       height="100.0051"
       width="98.994949"
       id="rect4350"
       style="opacity:1;fill:url(#linearGradient4382);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4384);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4366"
       width="98.994949"
       height="100.0051"
       x="255.26317"
       y="364.06955"
       ry="10.357149"
       rx="11.25" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="140.87489"
       x="367.33762"
       height="100.0051"
       width="98.994949"
       id="rect4388"
       style="opacity:1;fill:url(#linearGradient4434);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4436);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4404"
       width="98.994949"
       height="100.0051"
       x="367.33762"
       y="252.23683"
       ry="10.357149"
       rx="11.25" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.35715"
       y="363.59879"
       x="367.33762"
       height="211.79082"
       width="98.994949"
       id="rect4420"
       style="opacity:1;fill:url(#linearGradient4438);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3.00000024;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.249999"
       ry="10.357149"
       y="475.58841"
       x="31.114243"
       height="100.0051"
       width="210.42351"
       id="rect4442"
       style="opacity:1;fill:url(#linearGradient4504);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:2.99999976;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="475.58844"
       x="255.26317"
       height="100.0051"
       width="98.994949"
       id="rect4474"
       style="opacity:1;fill:url(#linearGradient4508);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="29.512959"
       x="31.114243"
       height="100.0051"
       width="98.994949"
       id="rect4549"
       style="opacity:1;fill:url(#linearGradient4611);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4613);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4565"
       width="98.994949"
       height="100.0051"
       x="143.18871"
       y="29.512959"
       ry="10.357149"
       rx="11.25" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       rx="11.25"
       ry="10.357149"
       y="29.512959"
       x="255.26317"
       height="100.0051"
       width="98.994949"
       id="rect4581"
       style="opacity:1;fill:url(#linearGradient4615);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
    <rect
       transform="translate(-14.897034,-18.012959)"
       style="opacity:1;fill:url(#linearGradient4617);fill-opacity:1;fill-rule:nonzero;stroke:#eee0ca;stroke-width:3;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4597"
       width="98.994949"
       height="100.0051"
       x="367.33762"
       y="29.512959"
       ry="10.357149"
       rx="11.25" />
  </g>
  <g
     inkscape:groupmode="layer"
     id="layer6"
     inkscape:label="key labels"
     style="display:inline"
     transform="translate(17.282791,22)">
    <flowRoot
       xml:space="preserve"
       id="flowRoot4217"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(-86.06075,-4.043613)"><flowRegion
         id="flowRegion4219"><rect
           id="rect4221"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         id="flowPara4223"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">7</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4227">Open</flowPara><flowPara
         id="flowPara4623"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Line◆</flowPara></flowRoot>    <flowRoot
       transform="translate(26.013714,-4.043613)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4242"
       xml:space="preserve"><flowRegion
         id="flowRegion4244"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4246"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4248">8</flowPara><flowPara
         id="flowPara4252"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Page◆</flowPara></flowRoot>    <flowRoot
       xml:space="preserve"
       id="flowRoot4260"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(138.08818,-4.043613)"><flowRegion
         id="flowRegion4262"><rect
           id="rect4264"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         id="flowPara4266"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">9</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4270">Mark/</flowPara><flowPara
         id="flowPara4629"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Quote◆</flowPara></flowRoot>    <flowRoot
       transform="translate(-86.06075,107.47526)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4280"
       xml:space="preserve"><flowRegion
         id="flowRegion4282"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4284"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4286">4</flowPara><flowPara
         id="flowPara4290"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Up</flowPara><flowPara
         id="flowPara4633"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Line◆</flowPara></flowRoot>    <flowRoot
       xml:space="preserve"
       id="flowRoot4296"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(26.013714,107.47526)"><flowRegion
         id="flowRegion4298"><rect
           id="rect4300"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         id="flowPara4302"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">5</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4306">Delete</flowPara><flowPara
         id="flowPara4637"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Char◆</flowPara></flowRoot>    <flowRoot
       transform="translate(138.08818,107.47526)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4312"
       xml:space="preserve"><flowRegion
         id="flowRegion4314"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4316"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4318">6</flowPara><flowPara
         id="flowPara4322"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Delete/</flowPara><flowPara
         id="flowPara4641"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Restore</flowPara></flowRoot>    <flowRoot
       xml:space="preserve"
       id="flowRoot4336"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(-86.06075,218.99411)"><flowRegion
         id="flowRegion4338"><rect
           id="rect4340"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         id="flowPara4342"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">1</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4344">Top of</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4346">Page◆•</flowPara></flowRoot>    <flowRoot
       transform="translate(26.013714,218.99411)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4352"
       xml:space="preserve"><flowRegion
         id="flowRegion4354"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4356"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4358">2</flowPara><flowPara
         id="flowPara4360"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Bottom</flowPara><flowPara
         id="flowPara4362"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">of Page</flowPara></flowRoot>    <flowRoot
       xml:space="preserve"
       id="flowRoot4368"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(138.08818,218.99411)"><flowRegion
         id="flowRegion4370"><rect
           id="rect4372"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         id="flowPara4374"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">3</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4376">Start</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4378">of Line</flowPara></flowRoot>    <flowRoot
       transform="translate(250.16264,-4.200534)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4390"
       xml:space="preserve"><flowRegion
         id="flowRegion4392"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4394"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4396">-</flowPara><flowPara
         id="flowPara4398"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Search</flowPara><flowPara
         id="flowPara4400"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Arg◆</flowPara></flowRoot>    <flowRoot
       xml:space="preserve"
       id="flowRoot4406"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(250.16264,107.16141)"><flowRegion
         id="flowRegion4408"><rect
           id="rect4410"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         id="flowPara4412"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">,</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4414">End of</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4416">Line</flowPara></flowRoot>    <flowRoot
       transform="translate(250.16264,276.73764)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4422"
       xml:space="preserve"><flowRegion
         id="flowRegion4424"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4426"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4428">Enter</flowPara><flowPara
         id="flowPara4430"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Search</flowPara><flowPara
         id="flowPara4432"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Arg◆</flowPara></flowRoot>    <flowRoot
       transform="translate(-33.203607,330.513)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4444"
       xml:space="preserve"><flowRegion
         id="flowRegion4446"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4448"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4450">0</flowPara><flowPara
         id="flowPara4454"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Down</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4523">Line◆</flowPara></flowRoot>    <flowRoot
       transform="translate(138.08818,330.513)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4476"
       xml:space="preserve"><flowRegion
         id="flowRegion4478"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4480"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4482">.</flowPara><flowPara
         id="flowPara4484"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Search</flowPara><flowPara
         id="flowPara4486"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Again◆</flowPara></flowRoot>    <flowRoot
       transform="translate(-86.06075,-115.56247)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4551"
       xml:space="preserve"><flowRegion
         id="flowRegion4553"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4555"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4557">PF1</flowPara><flowPara
         id="flowPara4559"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Save</flowPara><flowPara
         id="flowPara4561"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Text◆•</flowPara></flowRoot>    <flowRoot
       xml:space="preserve"
       id="flowRoot4567"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(26.013714,-115.56247)"><flowRegion
         id="flowRegion4569"><rect
           id="rect4571"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         id="flowPara4573"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">PF2</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4575">TECO</flowPara><flowPara
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4577">Cmd◆</flowPara></flowRoot>    <flowRoot
       transform="translate(138.08818,-115.56247)"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="flowRoot4583"
       xml:space="preserve"><flowRegion
         id="flowRegion4585"><rect
           y="137.71935"
           x="110"
           height="87.678574"
           width="86.785713"
           id="rect4587"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4589">PF3</flowPara><flowPara
         id="flowPara4591"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Paste</flowPara><flowPara
         id="flowPara4593"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1">Text</flowPara></flowRoot>    <flowRoot
       xml:space="preserve"
       id="flowRoot4599"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       transform="translate(250.16264,-115.56247)"><flowRegion
         id="flowRegion4601"><rect
           id="rect4603"
           width="86.785713"
           height="87.678574"
           x="110"
           y="137.71935"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1" /></flowRegion><flowPara
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:22.5px;font-family:Verdana;-inkscape-font-specification:Verdana;text-align:center;text-anchor:middle;fill:#422b00;fill-opacity:1"
         id="flowPara4609">PF4</flowPara></flowRoot>  </g>
  <g
     inkscape:label="KEY"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(2.3857574,3.9870415)"
     style="display:inline">
    <text
       xml:space="preserve"
       style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       x="153.57143"
       y="180.93362"
       id="text4213"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         id="tspan4215"
         x="153.57143"
         y="180.93362" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       x="503.61438"
       y="56.824276"
       id="text4643"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         x="503.61438"
         y="56.824276"
         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         id="tspan4701">KEY</tspan></text>
    <text
       sodipodi:linespacing="125%"
       id="text5371"
       y="183.68143"
       x="503.61438"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       xml:space="preserve"><tspan
         id="tspan5385"
         dy="1"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         y="183.68143"
         x="503.61438"
         sodipodi:role="line">•  command</tspan><tspan
         id="tspan5387"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         y="205.55643"
         x="503.61438"
         sodipodi:role="line">    operates</tspan><tspan
         id="tspan5389"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         y="227.43143"
         x="503.61438"
         sodipodi:role="line">    from Dot to</tspan><tspan
         id="tspan5391"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         y="249.30643"
         x="503.61438"
         sodipodi:role="line">    Mark if Mark</tspan><tspan
         id="tspan5393"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         y="271.18143"
         x="503.61438"
         sodipodi:role="line">    is set</tspan></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:Verdana;-inkscape-font-specification:Verdana;letter-spacing:0px;word-spacing:0px;opacity:1;fill:#422b00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       x="503.61438"
       y="88.967133"
       id="text5395"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         x="503.61438"
         y="88.967133"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         id="tspan5399">◆  takes opt arg</tspan><tspan
         sodipodi:role="line"
         x="503.61438"
         y="111.48743"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         id="tspan5401">    as: ESC [-]</tspan><tspan
         sodipodi:role="line"
         x="503.61438"
         y="133.36243"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         id="tspan5403">    &lt;digits&gt;</tspan><tspan
         sodipodi:role="line"
         x="503.61438"
         y="155.23743"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         id="tspan5405">    &lt;key(s)&gt;</tspan><tspan
         sodipodi:role="line"
         x="503.61438"
         y="177.11243"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;font-family:Verdana;-inkscape-font-specification:Verdana;fill:#422b00;fill-opacity:1"
         id="tspan5417" /></text>
  </g>
</svg>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted etc/pidp8i-init.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/bin/sh
### BEGIN INIT INFO
# Provides:		pidp8i
# Required-Start:	$syslog
# Required-Stop:	$syslog
# Default-Start:	2 3 4 5
# Default-Stop:		0 6
# Short-Description:PiDP-8/I simulator
# Description:      The PiDP-8/I simulator is a modified version of
#                   the SimH PDP-8 simulator for the PiDP-8/I front
#                   panel project for the Raspberry Pi.
### END INIT INFO

########################################################################
# Init script for Oscar Vermeulen's PiDP-8/I emulator front panel.  
#
# Original author: Mark G Thomas <mark@misty.com> 2015-05-09
#
# Copyright © 2015 Mark G Thomas
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

PATH=/sbin:/usr/sbin:/bin:/usr/bin
umask 022
. /lib/lsb/init-functions

prefix="@ABSPREFIX@"
sim="$prefix/bin/pidp8i-sim"
scanswitch="$prefix/libexec/scanswitch"

# Requires screen utility for detached pidp8i console functionality.
test -x /usr/bin/screen || ( echo "screen not found" && exit 0 )

# Also check for other needed binaries
test -x $scanswitch || ( echo "$scanswitch not found" && exit 0 )
test -x $sim || ( echo "$sim not found" && exit 0 )

# Check if pidp8i is already runnning under screen.
#
is_running() {
	procs=`screenu -ls pidp8i | egrep '[0-9]+\.pidp8i' | wc -l`
	test $procs -gt 0 && return 0 || return 1
}

# Wrapper around screen(1) to drop privileges and pass given args
screenu() {
	if [ "$USER" = "@INSTUSR@" ]
	then
		/usr/bin/screen $*
	else
		su -c "/usr/bin/screen $*" @INSTUSR@
	fi
}

do_start() {
	if is_running ; then
	    echo "PiDP-8/I is already running, not starting again." >&2
	    exit 0
	fi

    # Regenerate SSH host keys if this is the first run on a fresh image
    if [ ! -f /etc/ssh/ssh_host_ecdsa_key -a -x /usr/sbin/dpkg-reconfigure ]
    then
        log_daemon_msg "Regenerating SSH host keys..." "pidp8i"
        /usr/sbin/dpkg-reconfigure openssh-server
    fi

	$scanswitch >/dev/null 2>&1
	script=$?
	if [ $script -eq 8 ]; then
	    echo "PiDP-8/I STOP switch detected, aborting." >&2
	    exit 0
	elif [ $script -lt 8 ]; then
	    bscript="@BOOTDIR@/""$script"".script"
	    echo "Booting from $bscript..."
	else
		echo "Bad return value $script from $scanswitch!"
		exit 1
	fi

    # We want SIMH to have a sensible working directory: somewhere the
    # user can write files and which makes sense when giving SIMH
    # commands involving file paths.  This default is chosen because it
    # satisfies both criteria, plus it makes tools/mk-os8-rk05s happy.
    # If you change the default here, change that script as well.
    cd "$prefix/share/media"

	log_daemon_msg "Starting PiDP-8/I simulator" "pidp8i"
	screenu -dmS pidp8i "$sim" $bscript
	status=$?
	log_end_msg $status
	return $status
}

do_stop() {
	if ! is_running ; then
	    echo "PiDP-8/I is already stopped." >&2
	    status=1
	else
	    log_daemon_msg "Stopping PiDP-8/I simulator" "pidp8i"
	    screenu -S pidp8i -X quit
	    status=$?
	    log_end_msg $status
	fi
	return $status
}

case "$1" in
  start)
	do_start
	;;

  stop)
	do_stop
	;;

  restart)
	do_stop
	do_start
	;;

  status)
	screenu -ls pidp8i | egrep '[0-9]+\.pidp8i'
	;;

  *)
	log_action_msg "Usage: /etc/init.d/pidp8i {start|stop|restart|status}" || true
	exit 1
esac

exit 0
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































































Deleted etc/sudoers.in.
1
2
@INSTUSR@ ALL=NOPASSWD: /bin/systemctl poweroff
@INSTUSR@ ALL=NOPASSWD: /bin/systemctl reboot
<
<




Deleted examples/Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
########################################################################
# Makefile.in - Processed by autosetup's configure script to generate
#    an intermediate GNU make(1) file for building the PiDP-8/I software
#    from within its examples/ subdirectory.
#
# The resulting Makefile will redirect simple "make" calls to the top
# level as well as the major top-level targets (e.g. "make clean") but
# purposefully will not redirect anything like an installation or "run
# the system" type target.  Its only purpose is to help out those who
# are working on the examples from within this directory.  If you need
# to work on the wider system, do it from the project's top level.
#
# If you are seeing this at the top of a file called Makefile and you
# intend to make edits, do that in Makefile.in.  Saying "make" will then
# re-build Makefile from that modified Makefile.in before proceeding to
# do the "make" operation.
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

all clean ctags distclean tags reconfig:
	cd @builddir@; make $@
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































Deleted examples/README.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# Example Programs

## What's Provided

The `examples` directory holds short example programs for your PiDP-8/I,
plus a number of subroutines you may find helpful in writing your own
programs:

| Example           | What It Does
-----------------------------
| `add.pal`         | 2 + 3 = 5  The simplest program here; used below as a meta-example
| `hello.pal`       | writes "HELLO, WORLD!" to the console; tests PRINTS subroutine
| `pep001.*`        | Project Euler Problem #1 solutions, various languages
| `routines/decprt` | prints an unsigned 12-bit decimal integer to the console
| `routines/prints` | prints an ASCIIZ string stored as a series of 8-bit bytes to the console

The `pep001.*` files are a case study series in solving a simple
problem, which lets you compare the solutions along several axes. Some
are much longer than others, but some will run faster and/or take less
memory. It is interesting to compare them. There are writeups on each of
these:

*   [**`pep001.pal`**][pal] — PAL8 Assembly Language
*   [**`pep001.bas`**][bas] — OS/8 BASIC

[pal]:  https://tangentsoft.com/pidp8i/wiki?name=PEP001.PA
[bas]:  https://tangentsoft.com/pidp8i/wiki?name=PEP001.BA


## How to Use the BASIC Examples

To use the example BASIC program, simply transcribe it into OS/8 BASIC:

    .R BASIC
	NEW OR OLD--NEW
	FILE NAME--PAL001.BA

	READY
	10 FOR I = 1 TO 999
	10 FOR I = 1 TO 999
	20 A = I / 3 \ B = I / 5
	30 IF INT(A) = A GOTO 60
	40 IF INT(B) = B GOTO 60
	50 GOTO 70
	60 T = T + I
	70 NEXT I
	80 PRINT "TOTAL: "; T
	90 END
	SAVE

	READY
	RUN

	PAL001  BA    4A    

	TOTAL:  xxxxxxx

	READY
	BYE

If you're SSH'd into the PiDP-8/I, "transcribing" is simply a matter of
cut-and-paste into the terminal window.

I've obscured the output on purpose, since I don't want this page to be
a spoiler for the Project Euler site.

If you get a 2-letter code from BASIC in response to your `RUN` command,
it means you have an error in the program. See the BASIC section of the
OS/8 Handbook for a decoding guide.


## How to Use the Assembly Language Examples

For each PAL8 assembly program in `examples/*.pal`, there are two
additional files:

| Extension | Meaning
-----------------------------
| `*.pal`   | the PAL8 assembly source code for the program
| `*.lst`   | the human-readable assembler output
| `*.pt`    | the machine-readable assembler output (RIM format)

There are three ways to run these on your PiDP-8/I, each starting with
one of the above three files:

1.  Transcribe the assembly program text to a file within a PDP-8
    operating system and assemble it inside the simulator.

2.  Toggle the program in from the front panel. I can recommend this
    method only for very short programs.

3.  Copy the `*.pt` file to a USB stick and use the PiDP-8/I's
    [automatic media mounting feature][howto]. This is the fastest method.

I cover each of these options below, in the same order as the list
above.


## Option 1: Transcribing the Assembly Code into an OS/8 Session

To transcribe [`examples/add.pal`][pal] into the OS/8 simulation on a
PiDP-8/I:

    .R EDIT
    *ADD.PA<

    #A                          ← append to ADD.PA
    *0200   CLA CLL
    MAIN,   TAD A
            TAD B
            DCA C
            HLT
    A,      2
    B,      3
    C,
                                ← hit Ctrl-L to leave text edit mode
    #E                          ← saves program text to disk

    .PAL ADD-LS
    ERRORS DETECTED: 0
    LINKS GENERATED: 0

    .DIR ADD.* /A

    ADD   .PA   1             ADD   .BN   1             ADD   .LS    1

     399 FREE BLOCKS

If you see some cryptic line from the assembler like `DE C` instead
of the `ERRORS DETECTED: 0` bit, an error has occurred. Table 3-3 in
my copy the OS/8 Handbook explains these. You will also have an `ADD.ER`
file explaining what happened.

You can instead say `EXE ADD` to assemble and execute that program in a
single step, but beware that because the program halts the processor,
your OS/8 session also halts. If you take the opportunity as intended to
examine memory location `C` — 0207 — pressing `Start` to resume will
cause the processor to try executing the instruction at 0210, and who
knows what that will do? Even if you pass up the opportunity to examine
`C`, pressing `Start` immediately after the halt will do the same,
except that we know what it will do: it will try to execute the 0002
value stored at `A` as an instruction! (I believe it means `AND` the
accumulator with memory location 2.)

The solution to these problems is simple:

    .EDIT ADD                   ← don't need "R" because file exists
    #R                          ← read first page in; isn't automatic!
    #4D                         ← get rid of that pesky DCA line
    #5I                         ← insert above "A" def'n, now on line 5
            JMP 7600            ← Ctrl-L again to exit edit mode
    #E                          ← save and exit

    .EXE ADD

As before, the processor stops, but this time because we didn't move the
result from the accumulator to memory location `C`, we can see the
answer on the accumulator line on the front panel. Pressing `Start` this
time continues to the next instruction which re-enters OS/8. Much nicer!

As you can see, this option is the most educational, as it matches
the working experience of PDP-8 assembly language programmers back
in the day. The tools may differ — the user may prefer `TECO` over
`EDIT` or MACRO-8 over PAL8 — but the idea is the same regardless.

If you have the finished assembly code already on your computer and are
SSH'd into the PiDP-8/I machine, there is a shortcut for all of the
above. At the OS/8 command line, say:

    .R PIP
	*ADD.PA<TTY:

Now you can simply copy the assembly language text in your desktop PC's
text editor, paste it into the SSH window, and then hit Ctrl-Z to tell
`PIP` that the text input from the terminal (`TTY:`) is finished. This
is not only a smidge simpler than doing the same thing via `EDIT`, it
also avoids a certain limitation of `EDIT` that starts to bite you once
your program text exceeds about 5,600 characters.


## Option 2: Toggling a Programs in Via the Front Panel

After building the PiDP-8/I software, each of the `examples/*.pal` files
is assembled by `palbart` which writes out a human-readable listing file
to `obj/*.lst`, named after the source file.

Take [`obj/add.lst`][lst] as an example, in which you will find three
columns of numbers on the code-bearing lines:

    10 00200 7300
    11 00201 1205
    12 00202 1206
    13 00203 3207
    14 00204 7402
    16 00205 0002
    17 00206 0003

The first number refers to the corresponding line number in
[`add.pal`][pal], the second is a PDP-8 memory address, and the third is
the value stored at that address.

To toggle the `add` program in, press `Stop` to halt the processor, then
twiddle the switches like so:

| Set SR Switches To... | Then Toggle...
|------------------------------------------------
| 000 010 000 000       | `Load Add`
| 111 011 000 000       | `Dep`
| 001 010 000 101       | `Dep`
| 001 010 000 110       | `Dep`
| 011 010 000 111       | `Dep`
| 111 100 000 010       | `Dep`
| 000 000 000 010       | `Dep`
| 000 000 000 011       | `Dep`

To run it, repeat the first step in the table above, loading the
program's starting address (0200) first into the switch register (SR)
and then into the PDP-8's program counter (PC) via `Load Add`. Then
toggle `Start` to run the program. If you then:

If you then toggle 000 010 000 111 into SR, press `Load Add` followed by
`Exam`, you should see 000 000 000 101 in the third row of lights, the
bit pattern for five at memory location 0207, that being the correct
answer for "2 + 3" in the expected location, which is what we expected
`add.pal` to do. You could load that address back up again and `Dep` a
different value into that location, then start the program over again at
0200 to observe that this memory location does, indeed, get overwritten
with 0005.

We only need one `Load Add` operation in the table above because all of
the memory addresses in this program are sequential; there are no jumps
in the values in the second column. Not all programs are that way, so
pay attention!

Beware that this program does not contain an explicit value for memory
location 0207 at the start, but it does overwrite this location with the
answer, since location `C` is defined as having the address just after
the last value you entered via SR above, 0206. That is the source of the
"07" in the lower two digits of the fourth instruction, 3207.


## Option 3: Loading a Program from Paper Tape

The `palbart` assembly process described above also produces paper tape
output files in RIM format in `bin/*.pt`.

The simplest way to load these assembly examples into your PiDP-8/I is
to copy each such file to a USB stick, one file per stick.  Then, load
the paper tape into the simulated PDP-8/I's core memory.

The following is distilled from the [How to Use the PiDP-8/I][howto]
section of the PiDP-8/I documentation:

1.  Set the IF switches (first white group) to 001, and toggle `Sing
    Step` to reboot the simulator into the high-speed RIM loader. If the
    simulator wasn't already running, restarting the simulator with IF=1
    will achieve the same end as toggling `Sing Step` while it's
    running. Reset the IF switches to 0.

2.  Insert the USB stick containing the `*.pt` file you want to load
    into the Pi.

3.  Set the DF switches (first brown group) to 001, then toggle `Sing
    Step` again. This attaches the tape to the high-speed paper tape
    reader peripheral within the PDP-8 simulator. Set DF back to 0.

4.  Set the switch register (SR) to 7756 (111 111 101 110) then press
    `Load Add`, then `Start`.

5.  Hit `Stop`, then reset SR to 0200 (000 010 000 000), that being the
    starting location of these example programs. Press `Load Add`, then
    `Start` to run the program.

There is an SVG template for USB stick labels in the distribution under
the [`labels/`][label] directory, for use if you find yourself creating
long-lived USB sticks. See [`labels/README.md`][lread] for more
information.


## License

Copyright © 2016-2017 by Warren Young. This document is licensed under
the terms of [the SIMH license][sl].


[lst]:   https://tangentsoft.com/pidp8i/doc/trunk/examples/add.lst
[pal]:   https://tangentsoft.com/pidp8i/doc/trunk/examples/add.pal
[label]: https://tangentsoft.com/pidp8i/dir?ci=trunk&name=labels
[lread]: https://tangentsoft.com/pidp8i/doc/trunk/labels/README.md
[howto]: http://obsolescence.wixsite.com/obsolescence/how-to-use-the-pidp-8
[sl]:    https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































































































































































































































































































































































































































Deleted examples/ac-mq-blinker.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/ ac-mq-blinker.pal - Rapidly modify AC and MQ
/
/ This program twiddles AC and MQ rapidly, with a small amount of delay
/ between each update so the lights aren't just a solid blur.
/
/ While this program runs at full speed, only AC and MQ appear to a
/ human to really change.  PC also changes, of course, but since the
/ program spends so much of its time in the delay loop at the top, it
/ appears to be stuck at PC=1.
/
/ It also modifies MB rapidly, but the pattern we use means it looks
/ like the lamps aren't changing, but are all on, dimmed by varying
/ amounts.
/
/ From: http://dustyoldcomputers.com/pdp8/pdp8i/testprogs/acmqblinker.html
/
/ SIMH: set throttle 30k
/ SIMH: set df disabled
/ SIMH: set cpu noidle
/
/ Copyright © 2000 Robert Krten
/
/ Permission is hereby granted, free of charge, to any person obtaining a
/ copy of this software and associated documentation files (the "Software"),
/ to deal in the Software without restriction, including without limitation
/ the rights to use, copy, modify, merge, publish, distribute, sublicense,
/ and/or sell copies of the Software, and to permit persons to whom the
/ Software is furnished to do so, subject to the following conditions:
/
/ The above copyright notice and this permission notice shall be included in
/ all copies or substantial portions of the Software.
/
/ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
/ THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/ DEALINGS IN THE SOFTWARE.
/
/ Except as contained in this notice, the names of the authors above shall
/ not be used in advertising or otherwise to promote the sale, use or other
/ dealings in this Software without prior written authorization from those
/ authors.
////////////////////////////////////////////////////////////////////////

	PAGE 0
loop,	ISZ delay	/ create a delay
	JMP loop
	CLA		/ clear AC so we can load it
	TAD value	/ get value
	MQL		/ stash AC into MQ
	TAD value	/ fetch value again
	CMA		/ complement AC
	ISZ value	/ get to next value
	NOP		/ ignore possible "skip" from ISZ
	JMP loop	/ and do it all again

	*20		/ skip over the autoincrement registers
delay,	0
value,	0
$
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































Deleted examples/add.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/ add.pal - Add two numbers and halt, with sum in location 0207
/
/ This is a more space-efficient alternative to the program given at:
/
/ http://mrhowson.edublogs.org/2016/11/27/pidp-8i-second-toggle-some-assembly-code/

	PAGE 1		/ code starts at core page 1; must avoid page 0
	CLA CLL		/ clear AC and Link; two OPRs, one instruction!
	TAD A		/ add A to AC, which is zero, so "load A"
	TAD B		/ add B to AC
	DCA C		/ store sum in AC at C 
	HLT		/ halt program 

A,      2		/ set "A" variable to 2
B,      3		/ and "B" to 3
C,	   		/ "C" result variable lives immediately past B,
			/ and has no initial value because it is always
			/ overwritten with the answer
$
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































Deleted examples/bit-rotate.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/ bit-rotate.pal - Bit rotation and HLT demo
/
/ This example demonstrates the bit rotation and HLT instructions of the
/ processor.  It is meant to be run with the simulator in free-running
/ mode, since the embedded HLT instruction lets you see the state of AC
/ after each rotation.  There are two HLT instructions so that you can
/ see the initial 1 value, and then see it change after each rotation.

	PAGE 1
	CLA CLL IAC     / clear link and AC, then bump AC: AC=1
	HLT		/ let user see initial AC=1 value
LOOP,	RAL		/ rotate AC left
	HLT             / and halt again
	JMP LOOP        / on CONT, around it goes...
$
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























Deleted examples/hello.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/ HELLO - "Hello, World!" program for PAL8 assembly, which also
/         happens to test the PRINTS routine, included inline below.
/
/ Created by Warren Young of tangentsoft.com, 2016.11.30
/
/ Copyright © 2016 Warren Young
/
/ Permission is hereby granted, free of charge, to any person obtaining a
/ copy of this software and associated documentation files (the "Software"),
/ to deal in the Software without restriction, including without limitation
/ the rights to use, copy, modify, merge, publish, distribute, sublicense,
/ and/or sell copies of the Software, and to permit persons to whom the
/ Software is furnished to do so, subject to the following conditions:
/
/ The above copyright notice and this permission notice shall be included in
/ all copies or substantial portions of the Software.
/
/ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
/ THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/ DEALINGS IN THE SOFTWARE.
/
/ Except as contained in this notice, the names of the authors above shall
/ not be used in advertising or otherwise to promote the sale, use or other
/ dealings in this Software without prior written authorization from those
/ authors.
////////////////////////////////////////////////////////////////////////


//// MAIN /////////////////////////////////////////////////////////////

PAGE 1
	CLA
	TLS		/ send null character to terminal to prepare it
	TAD (HWSTR)
	JMS PRINTS
	HLT

// "HELLO, WORLD!\r\n" in octal ASCIIZ
HWSTR,	110; 105; 114; 114; 117;	/ HELLO
	54;				/ comma
	40;				/ space
	127; 117; 122; 114; 104;	/ WORLD
	41;				/ bang
	15; 12;				/ CRLF
	0				/ null string terminator


//// PRINTS ////////////////////////////////////////////////////////////

PRINTS,0
	DCA SADDR	/ save AC as string address
PSNEXT,	TAD I SADDR	/ load next character
	SNA
	JMP I PRINTS	/ found the null terminator; leave

	TSF		/ wait for terminal to be ready
	JMP .-1
	TLS		/ write character to the terminal

	CLA		/ increment string address pointer
	TAD SADDR
	IAC
	DCA SADDR
		
	JMP PSNEXT	/ look at next character
SADDR,	0


//// END ///////////////////////////////////////////////////////////////
$
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































Deleted examples/pep001.bas.
1
2
3
4
5
6
7
8
9
10
11
12
1 REM Copyright (c) 2016 by Warren Young
2 REM Released under the terms of ../SIMH-LICENSE.md
3 REM ------------------------------------------------------------------
10 FOR I = 1 TO 999
20 A = I / 3 \ B = I / 5
30 IF INT(A) = A GOTO 60
40 IF INT(B) = B GOTO 60
50 GOTO 70
60 T = T + I
70 NEXT I
80 PRINT "TOTAL: "; T
90 END
<
<
<
<
<
<
<
<
<
<
<
<
























Deleted examples/pep001.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/ Project Euler Problem #1, Multiples of 3 and 5:
/
/   If we list all the natural numbers below 10 that are multiples of
/   3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
/   Find the sum of all the multiples of 3 or 5 below 1000.
/
/ Initial solution by Warren Young of tangentsoft.com, 2016.11.30
/ Optimized by Rick Murphy of the mailing list, 2016.12.04
/
/ Copyright © 2016-2017 Warren Young and Rick Murphy
/
/ Permission is hereby granted, free of charge, to any person obtaining a
/ copy of this software and associated documentation files (the "Software"),
/ to deal in the Software without restriction, including without limitation
/ the rights to use, copy, modify, merge, publish, distribute, sublicense,
/ and/or sell copies of the Software, and to permit persons to whom the
/ Software is furnished to do so, subject to the following conditions:
/
/ The above copyright notice and this permission notice shall be included in
/ all copies or substantial portions of the Software.
/
/ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
/ THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/ DEALINGS IN THE SOFTWARE.
/
/ Except as contained in this notice, the names of the authors above shall
/ not be used in advertising or otherwise to promote the sale, use or other
/ dealings in this Software without prior written authorization from those
/ authors.
////////////////////////////////////////////////////////////////////////


//// DIY Assembler Instructions ////////////////////////////////////////

/ Our assembler doesn't know the EAE instructions, so teach it
DVI=7407		/ integer divide .+1 into {AC:MQ}, answer in MQ

/ Combined microcoded instruction aliases
CLR=CLA CLL		/ clear both AC and L
AC3=CLA CLL CML IAC RAL	/ set AC to 3


//// MAIN //////////////////////////////////////////////////////////////
/ Program entry point.   We purposely reinitialize global variables and
/ processor state in case we're restarting this program in-core.

PAGE 1
MAIN,   AC3		/ start with 3, because we know 1 & 2 can't work
	DCA CURR		
	DCA STOTAL	/ reset total to 0
	TAD (ANSWER-1)	/ write "ANSWER: " to the terminal
	JMS PRINTS


//// MLCORE ////////////////////////////////////////////////////////////
/ The core of the main loop.  MAIN just inits the globals and falls
/ through to us.
 
MLCORE, AC3		/ try dividing 3 into CURR first
	JMS ISMOD0
	SNA CLA		/ if ISMOD0 left AC = 0, CURR divided evenly by
	JMP NXITER	/ 3, so skip 5 lest we count multiples of 15 2x

	TAD (5)		/ no good; try dividing 5 into CURR instead
	JMS ISMOD0

NXITER, CLA		/ loop cleanup
	TAD CURR
	CIA
	TAD MAX		/ = 0 if CURR == MAX
	SNA CLA		/ if so, leave calculation loop
	JMP MLDONE

	ISZ CURR	/ CURR still < MAX, so increment CURR; never skips

	TAD STOTAL	/ if STOTAL is getting too big, print...
	CIA		/ a subtotal and zero STOTAL so we don't...
	TAD STMAX	/ overflow the 12-bit limit
	SNL
	JMP MLCORE	/ STMAX - STOTAL > 0 so re-enter loop core
	JMS SHOWST	/ exceeded threshold, so display subtotal and " + "
	DCA STOTAL	/ take advantage of free zero left by SHOWST
	TAD (PLUS-1)
	JMS PRINTS
	JMP MLCORE

MLDONE, JMS SHOWST	/ done; show answer
	TAD (CRLF-1)	/ don't need CLA; SHOWST left AC = 0
	JMS PRINTS

	/ End program gracefully, either re-entering OS/8 if we can see
	/ that its entry point looks sane, or halting with the answer in
	/ AC so the user can see the answer on the front panel.
OS8ENT,			/ 7600, OS/8's entry point, happens to also be...
ENDG,   7600		/ ...the group 2 variant of CLA; yes, we know, yuck!
	TAD I OS8ENT
	TAD OS8INS1	/ add its negative
	SNA CLA		/ if it's zero'd out, then...
	JMP I OS8ENT	/ re-enter OS/8
	TAD STOTAL	/ else not running under OS/8...
	HLT		/ so halt with STOTAL displayed in AC lights
OS8INS1,-4207		/ first OS/8 instruction at entry point, negated


//// ISMOD0 ////////////////////////////////////////////////////////////
/ If passed AC divides evenly into CURR (in C-speak, CURR % AC == 0)
/ add CURR to STOTAL and return 0 in AC.  Else, return nonzero in AC and
/ leave STOTAL untouched.

ISMOD0, 0
	DCA DIVISOR	/ Divide CURR by DIVISOR, passed as AC
	TAD CURR	/ load CURR into just-cleared AC
	MQL DVI		/ move CURR to MQ, divide by DIVISOR...
DIVISOR,0		/ ...quotient in MQ, remainder in AC
	SZA
	JMP I ISMOD0	/ remainder nonzero, so leave early

	/ Division left AC empty, so CURR divides evenly by DIVISOR!
	TAD CURR	/ don't need to clear AC; prior test says AC == 0
	TAD STOTAL
	DCA STOTAL
	JMP I ISMOD0


//// SHOWST ////////////////////////////////////////////////////////////
/ Write STOTAL value to terminal in decimal.  We purposely do not follow
/ it with anything, as our callers variously follow it with " + " or a
/ CRLF pair.  Leaves AC = 0 because DECRPT does.

SHOWST, 0
	CLR
	TAD STOTAL
	JMS DECPRT	/ print answer on console, in decimal
	JMP I SHOWST	/ and done


//// TYPE //////////////////////////////////////////////////////////////
/ Send a character out to the terminal.  Shared core of PRINTS and
/ DECPRT.

TYPE,   0
	TSF
	JMP .-1
	TLS
	CLA
	JMP I TYPE


//// PRINTS ////////////////////////////////////////////////////////////
/ Write an ASCIIZ string to the terminal.  Expects to receive the
/ address of the string - 1 in AC.  (The -1 hassle saves an instruction
/ or two in our use of an autoincrement register.)  Uses the autoinc
/ register at location 10.

SADDR=10		/ autoinc register for walking the string
PRINTS, 0
	DCA SADDR	/ save AC as string address
PSNEXT, TAD I SADDR	/ load next character
	SNA
	JMP I PRINTS	/ found the null terminator; leave
	JMS TYPE	/ Print that character
	JMP PSNEXT	/ look at next character


//// DECPRT ////////////////////////////////////////////////////////////
/ Decimal number printer; variant of examples/routines/decprt.pal
/ Leaves AC = 0.

DECPRT, 0
	DCA VALUE	/SAVE INPUT
	DCA DIGIT	/CLEAR
	TAD CNTRZA
	DCA CNTRZB	/SET COUNTER TO FOUR
	TAD ADDRZA
	DCA ARROW	/SET TABLE POINTER
	SKP
	DCA VALUE	/SAVE
	CLL
	TAD VALUE
ARROW,  TAD TENPWR	/SUBTRACT POWER OF TEN
	SZL
	ISZ DIGIT	/DEVELOP BCD DIGIT
	SZL
	JMP ARROW-3	/LOOP
	CLA		/HAVE BCD DIGIT
	TAD DIGIT	/GET DIGIT
	TAD K260	/MAKE IT ASCII
	JMS TYPE
	DCA DIGIT	/CLEAR
	ISZ ARROW	/UPDATE POINTER
	ISZ CNTRZB	/DONE ALL FOUR?
	JMP ARROW-1	/NO: CONTINUE
	JMP I DECPRT	/YES: EXIT

ADDRZA, TAD TENPWR
CNTRZA, -4
TENPWR, -1750		/ONE THOUSAND
	-0144		/ONE HUNDRED
	-0012		/TEN
	-0001		/ONE
K260,   260
VALUE,  0
DIGIT,  0
CNTRZB, 0


//// Global Variables //////////////////////////////////////////////////

CURR,   0		/ current number we're checking
STOTAL, 0		/ subtotal, printed and reset occasionally


//// Constants /////////////////////////////////////////////////////////

	DECIMAL
MAX,    999		/ check natural numbers CURR to MAX; must be < 2048!
STMAX,  1024		/ subtotal max; avoids overflow of 12-bit signed int

	OCTAL
CRLF,   15;12;0		/ ASCII character values, zero-terminated
PLUS,   40;53;40;0
ANSWER, 101;116;123;127;105;122;72;40;0


//// END ///////////////////////////////////////////////////////////////
/ Assembler-generated constants will appear below this in the list file
$
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































Deleted examples/routines/decprt.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/COPYRIGHT 1971, DIGITAL EQUIPMENT CORPORATION
/MAYNARD, MASSACHUSETTS
/DIGITAL 8-22-U
/UNSIGNED DECIMAL PRINT
/CALL WITH NUMBER TO BE TYPED IN C(AC)
/RETURN TO LOCATION FOLLOWING THE JMS
DECPRT,	0
	DCA VALUE	/SAVE INPUT
	DCA DIGIT	/CLEAR
	TAD CNTRZA
	DCA CNTRZB	/SET COUNTER TO FOUR
	TAD ADDRZA
	DCA ARROW	/SET TABLE POINTER
	SKP
	DCA VALUE	/SAVE
	CLL
	TAD VALUE
ARROW,	TAD TENPWR	/SUBTRACT POWER OF TEN
	SZL
	ISZ DIGIT	/DEVELOP BCD DIGIT
	SZL
	JMP ARROW-3	/LOOP
	CLA		/HAVE BCD DIGIT
	TAD DIGIT	/GET DIGIT
	TAD K260	/MAKE IT ASCII
	TSF		/OR TAD DIGIT
	JMP .-1		/JMS TDIGIT(SEE 8-19-U)
	TLS		/TYPE DIGIT
	CLA
	DCA DIGIT	/CLEAR
	ISZ ARROW	/UPDATE POINTER
	ISZ CNTRZB	/DONE ALL FOUR?
	JMP ARROW-1	/NO: CONTINUE
	JMP I DECPRT	/YES: EXIT
ADDRZA,	TAD TENPWR
CNTRZA,	-4
TENPWR,	-1750		/ONE THOUSAND
	-0144		/ONE HUNDRED
	-0012		/TEN
	-0001		/ONE
K260,	260
VALUE,	0
DIGIT,	0
CNTRZB,	0
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































Deleted examples/routines/prints.pal.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/ PRINTS - Print an ASCIIZ string to the terminal
/
/ It expects to receive the address of the string - 1 in AC.  (The -1
/ hassle saves an instruction or two in our use of an autoincrement
/ register.)
/
/ This routine uses the autoinc register at location 10.
/
/ Created by Warren Young of tangentsoft.com, 2016.11.30
/ Improved by Rick Murphy of the PiDP-8/I mailing list, 2016.12.03
/
/ Copyright © 2016 Warren Young and Rick Murphy
/
/ Permission is hereby granted, free of charge, to any person obtaining a
/ copy of this software and associated documentation files (the "Software"),
/ to deal in the Software without restriction, including without limitation
/ the rights to use, copy, modify, merge, publish, distribute, sublicense,
/ and/or sell copies of the Software, and to permit persons to whom the
/ Software is furnished to do so, subject to the following conditions:
/
/ The above copyright notice and this permission notice shall be included in
/ all copies or substantial portions of the Software.
/
/ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
/ THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/ DEALINGS IN THE SOFTWARE.
/
/ Except as contained in this notice, the names of the authors above shall
/ not be used in advertising or otherwise to promote the sale, use or other
/ dealings in this Software without prior written authorization from those
/ authors.
////////////////////////////////////////////////////////////////////////

TYPE,   0		/ helper routine for sending a single character
	TSF
	JMP .-1
	TLS
	CLA
	JMP I TYPE

SADDR=10		/ autoinc register for walking the string
PRINTS, 0
	DCA SADDR	/ save AC as string address
PSNEXT, TAD I SADDR	/ load next character
	SNA
	JMP I PRINTS	/ found the null terminator; leave
	JMS TYPE	/ print that character
	JMP PSNEXT	/ look at next character
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































Deleted hardware/pdp8i/PDP8-cache.lib.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
EESchema-LIBRARY Version 2.3  Date: 11/05/2015 22:48:50
#encoding utf-8
#
# +3.3V
#
DEF +3.3V #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 -40 30 H I C CNN
F1 "+3.3V" 0 110 30 H V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
ALIAS +3,3V
DRAW
X +3.3V 1 0 0 0 U 30 30 0 0 W N
C 0 60 20 0 1 0 N
P 3 0 1 0  0 0  0 40  0 40 N
ENDDRAW
ENDDEF
#
# +5V
#
DEF +5V #PWR 0 40 Y Y 1 F P
F0 "#PWR" 0 90 20 H I C CNN
F1 "+5V" 0 90 30 H V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
X +5V 1 0 0 0 U 20 20 0 0 W N
C 0 50 20 0 1 0 N
P 4 0 1 0  0 0  0 30  0 30  0 30 N
ENDDRAW
ENDDEF
#
# CONN_1
#
DEF ~CONN_1 P 0 30 N N 1 F N
F0 "P" 80 0 40 H V L CNN
F1 "CONN_1" 0 55 30 H I C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
C 0 0 31 0 1 0 N
P 2 0 1 0  -30 0  -50 0 N
X 1 1 -150 0 100 R 60 60 1 1 P
ENDDRAW
ENDDEF
#
# CONN_20X2
#
DEF CONN_20X2 P 0 10 Y N 1 F N
F0 "P" 0 1050 60 H V C CNN
F1 "CONN_20X2" 0 0 50 V V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -100 1000 100 -1000 0 1 0 N
X P1 1 -400 950 300 R 60 30 1 1 P I
X P2 2 400 950 300 L 60 30 1 1 P I
X P3 3 -400 850 300 R 60 30 1 1 P I
X P4 4 400 850 300 L 60 30 1 1 P I
X P5 5 -400 750 300 R 60 30 1 1 P I
X P6 6 400 750 300 L 60 30 1 1 P I
X P7 7 -400 650 300 R 60 30 1 1 P I
X P8 8 400 650 300 L 60 30 1 1 P I
X P9 9 -400 550 300 R 60 30 1 1 P I
X P10 10 400 550 300 L 60 30 1 1 P I
X P20 20 400 50 300 L 60 30 1 1 P I
X P30 30 400 -450 300 L 60 30 1 1 P I
X P40 40 400 -950 300 L 60 30 1 1 P I
X P11 11 -400 450 300 R 60 30 1 1 P I
X P21 21 -400 -50 300 R 60 30 1 1 P I
X P31 31 -400 -550 300 R 60 30 1 1 P I
X P12 12 400 450 300 L 60 30 1 1 P I
X P22 22 400 -50 300 L 60 30 1 1 P I
X P32 32 400 -550 300 L 60 30 1 1 P I
X P13 13 -400 350 300 R 60 30 1 1 P I
X P23 23 -400 -150 300 R 60 30 1 1 P I
X P33 33 -400 -650 300 R 60 30 1 1 P I
X P14 14 400 350 300 L 60 30 1 1 P I
X P24 24 400 -150 300 L 60 30 1 1 P I
X P34 34 400 -650 300 L 60 30 1 1 P I
X P15 15 -400 250 300 R 60 30 1 1 P I
X ~ 25 -400 -250 300 R 60 30 1 1 P I
X P35 35 -400 -750 300 R 60 30 1 1 P I
X P16 16 400 250 300 L 60 30 1 1 P I
X P26 26 400 -250 300 L 60 30 1 1 P I
X P36 36 400 -750 300 L 60 30 1 1 P I
X P17 17 -400 150 300 R 60 30 1 1 P I
X P27 27 -400 -350 300 R 60 30 1 1 P I
X P37 37 -400 -850 300 R 60 30 1 1 P I
X P18 18 400 150 300 L 60 30 1 1 P I
X P28 28 400 -350 300 L 60 30 1 1 P I
X P38 38 400 -850 300 L 60 30 1 1 P I
X P19 19 -400 50 300 R 60 30 1 1 P I
X P29 29 -400 -450 300 R 60 30 1 1 P I
X P39 39 -400 -950 300 R 60 30 1 1 P I
ENDDRAW
ENDDEF
#
# CONN_3
#
DEF CONN_3 K 0 40 Y N 1 F N
F0 "K" -50 0 50 V V C CNN
F1 "CONN_3" 50 0 40 V V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -100 150 100 -150 0 1 0 N
X P1 1 -350 100 250 R 60 60 1 1 P I
X PM 2 -350 0 250 R 60 60 1 1 P I
X P3 3 -350 -100 250 R 60 60 1 1 P I
ENDDRAW
ENDDEF
#
# CONN_4
#
DEF CONN_4 P 0 40 Y N 1 F N
F0 "P" -50 0 50 V V C CNN
F1 "CONN_4" 50 0 50 V V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -100 200 100 -200 0 1 0 N
X P1 1 -350 150 250 R 50 50 1 1 P I
X P2 2 -350 50 250 R 50 50 1 1 P I
X P3 3 -350 -50 250 R 50 50 1 1 P I
X P4 4 -350 -150 250 R 50 50 1 1 P I
ENDDRAW
ENDDEF
#
# DIODE
#
DEF DIODE D 0 40 N N 1 F N
F0 "D" 0 100 40 H V C CNN
F1 "DIODE" 0 -100 40 H V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
$FPLIST
 D?
 S*
$ENDFPLIST
DRAW
P 2 0 1 6  50 50  50 -50 N
P 3 0 1 0  -50 50  50 0  -50 -50 F
X A 1 -200 0 150 R 40 40 1 1 P
X K 2 200 0 150 L 40 40 1 1 P
ENDDRAW
ENDDEF
#
# GND
#
DEF ~GND #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 0 30 H I C CNN
F1 "GND" 0 -70 30 H I C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
P 4 0 1 0  -50 0  0 -50  50 0  -50 0 N
X GND 1 0 0 0 U 30 30 1 1 W N
ENDDRAW
ENDDEF
#
# LED
#
DEF LED D 0 40 Y N 1 F N
F0 "D" 0 100 50 H V C CNN
F1 "LED" 0 -100 50 H V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
$FPLIST
 LED-3MM
 LED-5MM
 LED-10MM
 LED-0603
 LED-0805
 LED-1206
 LEDV
$ENDFPLIST
DRAW
P 2 0 1 0  50 50  50 -50 N
P 3 0 1 0  -50 50  50 0  -50 -50 F
P 3 0 1 0  65 -40  110 -80  105 -55 N
P 3 0 1 0  80 -25  125 -65  120 -40 N
X A 1 -200 0 150 R 40 40 1 1 P
X K 2 200 0 150 L 40 40 1 1 P
ENDDRAW
ENDDEF
#
# R
#
DEF R R 0 0 N Y 1 F N
F0 "R" 80 0 40 V V C CNN
F1 "R" 7 1 40 V V C CNN
F2 "~" -70 0 30 V V C CNN
F3 "~" 0 0 30 H V C CNN
$FPLIST
 R?
 SM0603
 SM0805
 R?-*
 SM1206
$ENDFPLIST
DRAW
S -40 150 40 -150 0 1 12 N
X ~ 1 0 250 100 D 60 60 1 1 P
X ~ 2 0 -250 100 U 60 60 1 1 P
ENDDRAW
ENDDEF
#
# RASPI_MODEL_B_PLUS_GPIO
#
DEF RASPI_MODEL_B_PLUS_GPIO P 0 10 Y Y 1 F N
F0 "P" 0 1050 60 H V C CNN
F1 "RASPI_MODEL_B_PLUS_GPIO" 0 0 20 V V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -100 1000 100 -1000 0 1 0 N
X 3.3v 1 -400 950 300 R 60 30 1 1 w I
X 5v 2 400 950 300 L 60 30 1 1 w I
X g2 3 -400 850 300 R 60 30 1 1 P I
X 5v 4 400 850 300 L 60 30 1 1 P I
X g3 5 -400 750 300 R 60 30 1 1 P I
X GND 6 400 750 300 L 60 30 1 1 w I
X g4 7 -400 650 300 R 60 30 1 1 P I
X g14 8 400 650 300 L 60 30 1 1 P I
X GND 9 -400 550 300 R 60 30 1 1 P I
X g15 10 400 550 300 L 60 30 1 1 P I
X GND 20 400 50 300 L 60 30 1 1 P I
X GND 30 400 -450 300 L 60 30 1 1 P I
X g21 40 400 -950 300 L 60 30 1 1 P I
X g17 11 -400 450 300 R 60 30 1 1 P I
X g9 21 -400 -50 300 R 60 30 1 1 P I
X g6 31 -400 -550 300 R 60 30 1 1 P I
X g18 12 400 450 300 L 60 30 1 1 P I
X g25 22 400 -50 300 L 60 30 1 1 P I
X g12 32 400 -550 300 L 60 30 1 1 P I
X g27 13 -400 350 300 R 60 30 1 1 P I
X g11 23 -400 -150 300 R 60 30 1 1 P I
X g13 33 -400 -650 300 R 60 30 1 1 P I
X GND 14 400 350 300 L 60 30 1 1 P I
X g8 24 400 -150 300 L 60 30 1 1 P I
X GND 34 400 -650 300 L 60 30 1 1 P I
X g22 15 -400 250 300 R 60 30 1 1 P I
X GND 25 -400 -250 300 R 60 30 1 1 P I
X g19 35 -400 -750 300 R 60 30 1 1 P I
X g23 16 400 250 300 L 60 30 1 1 P I
X g7 26 400 -250 300 L 60 30 1 1 P I
X g16 36 400 -750 300 L 60 30 1 1 P I
X 3.3v 17 -400 150 300 R 60 30 1 1 P I
X n/c 27 -400 -350 300 R 60 30 1 1 P I
X g26 37 -400 -850 300 R 60 30 1 1 P I
X g24 18 400 150 300 L 60 30 1 1 P I
X n/c 28 400 -350 300 L 60 30 1 1 P I
X g20 38 400 -850 300 L 60 30 1 1 P I
X g10 19 -400 50 300 R 60 30 1 1 P I
X g5 29 -400 -450 300 R 60 30 1 1 P I
X GND 39 -400 -950 300 R 60 30 1 1 P I
ENDDRAW
ENDDEF
#
# SWITCH_INV
#
DEF SWITCH_INV SW 0 0 N Y 1 F N
F0 "SW" -200 150 50 H V C CNN
F1 "SWITCH_INV" -150 -150 50 H V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
C -150 0 50 0 0 0 N
C 150 -100 50 0 0 0 N
C 150 100 50 0 1 0 N
P 2 0 1 0  -100 0  150 50 N
X 1 1 500 100 300 L 60 60 1 1 P
X 2 2 -500 0 300 R 60 60 1 1 P
X 3 3 500 -100 300 L 60 60 1 1 P
ENDDRAW
ENDDEF
#
# UDN2981A
#
DEF UDN2981A P 0 40 Y Y 1 F N
F0 "P" 0 550 30 H V C CNN
F1 "UDN2981A" 0 -550 30 H V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -150 500 150 -500 0 1 0 N
X IN1 1 -350 400 200 R 40 20 1 1 I I
X IN2 2 -350 300 200 R 40 20 1 1 I I
X IN3 3 -350 200 200 R 40 20 1 1 I I
X IN4 4 -350 100 200 R 40 20 1 1 I I
X IN5 5 -350 0 200 R 40 20 1 1 I I
X IN6 6 -350 -100 200 R 40 20 1 1 I I
X IN7 7 -350 -200 200 R 40 20 1 1 I I
X IN8 8 -350 -300 200 R 40 20 1 1 I I
X Vs 9 -350 -400 200 R 40 20 1 1 P I
X GND 10 350 -400 200 L 40 20 1 1 P I
X OUT8 11 350 -300 200 L 40 20 1 1 O I
X OUT7 12 350 -200 200 L 40 20 1 1 O I
X OUT6 13 350 -100 200 L 40 20 1 1 O I
X OUT5 14 350 0 200 L 40 20 1 1 O I
X OUT4 15 350 100 200 L 40 20 1 1 O I
X OUT3 16 350 200 200 L 40 20 1 1 O I
X OUT2 17 350 300 200 L 40 20 1 1 O I
X OUT1 18 350 400 200 L 40 20 1 1 O I
ENDDRAW
ENDDEF
#
#End Library
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































Deleted hardware/pdp8i/PDP8.cmp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
Cmp-Mod V01 Created by CvPcb (2013-07-07 BZR 4022)-stable date = 10/05/2015 13:43:50

BeginCmp
TimeStamp = /54904DF0;
Reference = D1;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /5490504C;
Reference = D2;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905056;
Reference = D3;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /5490505E;
Reference = D4;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905068;
Reference = D5;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /5490506E;
Reference = D6;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549055F9;
Reference = D7;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549055FF;
Reference = D8;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905605;
Reference = D9;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /5490560B;
Reference = D10;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905611;
Reference = D11;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905640;
Reference = D12;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905646;
Reference = D13;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /5490564C;
Reference = D14;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905652;
Reference = D15;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905658;
Reference = D16;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /5490565E;
Reference = D17;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /54905664;
Reference = D18;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070C3;
Reference = D19;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070C9;
Reference = D20;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070CF;
Reference = D21;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070D5;
Reference = D22;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070DB;
Reference = D23;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070E1;
Reference = D24;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070E7;
Reference = D25;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /549070ED;
Reference = D26;
ValeurCmp = 1N4148;
IdModule  = D2;
EndCmp

BeginCmp
TimeStamp = /548EF5CC;
Reference = DAC1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5E5;
Reference = DAC2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5EB;
Reference = DAC3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5F1;
Reference = DAC4;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5F7;
Reference = DAC5;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5FD;
Reference = DAC6;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF603;
Reference = DAC7;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF609;
Reference = DAC8;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF60F;
Reference = DAC9;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF615;
Reference = DAC10;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF61B;
Reference = DAC11;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF621;
Reference = DAC12;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF728;
Reference = DAND1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF7E9;
Reference = DBREAK1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF7E3;
Reference = DCURAD1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF741;
Reference = DDCA1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF7D7;
Reference = DDEFER1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF6DA;
Reference = DDF1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF6F3;
Reference = DDF2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF6F9;
Reference = DDF3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF7D1;
Reference = DEXEC1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF7CB;
Reference = DFETCH1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF701;
Reference = DIF1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF71A;
Reference = DIF2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF720;
Reference = DIF3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF837;
Reference = DION1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF783;
Reference = DIOT1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF73B;
Reference = DISZ1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF77D;
Reference = DJMP1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF777;
Reference = DJMS1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF686;
Reference = DLINK1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF463;
Reference = DMA1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF47C;
Reference = DMA2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF482;
Reference = DMA3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF488;
Reference = DMA4;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF48E;
Reference = DMA5;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF494;
Reference = DMA6;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF49A;
Reference = DMA7;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF4A0;
Reference = DMA8;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF4A6;
Reference = DMA9;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF4AC;
Reference = DMA10;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF4B2;
Reference = DMA11;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF4B8;
Reference = DMA12;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF56F;
Reference = DMB1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF588;
Reference = DMB2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF58E;
Reference = DMB3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF594;
Reference = DMB4;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF59A;
Reference = DMB5;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5A0;
Reference = DMB6;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5A6;
Reference = DMB7;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5AC;
Reference = DMB8;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5B2;
Reference = DMB9;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5B8;
Reference = DMB10;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5BE;
Reference = DMB11;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF5C4;
Reference = DMB12;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF629;
Reference = DMQ1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF642;
Reference = DMQ2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF648;
Reference = DMQ3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF64E;
Reference = DMQ4;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF654;
Reference = DMQ5;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF65A;
Reference = DMQ6;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF660;
Reference = DMQ7;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF666;
Reference = DMQ8;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF66C;
Reference = DMQ9;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF672;
Reference = DMQ10;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF678;
Reference = DMQ11;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF67E;
Reference = DMQ12;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF789;
Reference = DOPR1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF83D;
Reference = DPAUSE1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /554E5897;
Reference = DPAUSE2;
ValeurCmp = LED;
IdModule  = LED-3-StrEight;
EndCmp

BeginCmp
TimeStamp = /548EF34A;
Reference = DPC1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF399;
Reference = DPC2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3AC;
Reference = DPC3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3B2;
Reference = DPC4;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3B8;
Reference = DPC5;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3BE;
Reference = DPC6;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3C4;
Reference = DPC7;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3CA;
Reference = DPC8;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3D0;
Reference = DPC9;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3D6;
Reference = DPC10;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3DC;
Reference = DPC11;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF3E2;
Reference = DPC12;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF843;
Reference = DRUN1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /554E589D;
Reference = DRUN2;
ValeurCmp = LED;
IdModule  = LED-3-StrEight;
EndCmp

BeginCmp
TimeStamp = /548EF6A1;
Reference = DSC1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF6BA;
Reference = DSC2;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF6C0;
Reference = DSC3;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF6C6;
Reference = DSC4;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF6CC;
Reference = DSC5;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF735;
Reference = DTAD1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /548EF7DD;
Reference = DWRDCT1;
ValeurCmp = LED;
IdModule  = LED-3-PDP;
EndCmp

BeginCmp
TimeStamp = /54BD85A3;
Reference = DZ1;
ValeurCmp = ZENER;
IdModule  = D3;
EndCmp

BeginCmp
TimeStamp = /554F46DF;
Reference = J_COL1;
ValeurCmp = CONN_3;
IdModule  = PIN_ARRAY_3X1;
EndCmp

BeginCmp
TimeStamp = /554F46EE;
Reference = J_COL2;
ValeurCmp = CONN_3;
IdModule  = PIN_ARRAY_3X1;
EndCmp

BeginCmp
TimeStamp = /54B1CC4A;
Reference = M1;
ValeurCmp = M;
IdModule  = 1pin;
EndCmp

BeginCmp
TimeStamp = /54B1CC76;
Reference = M2;
ValeurCmp = M;
IdModule  = 1pin;
EndCmp

BeginCmp
TimeStamp = /54B1CC7C;
Reference = M3;
ValeurCmp = M;
IdModule  = 1pin;
EndCmp

BeginCmp
TimeStamp = /54B1CC82;
Reference = M4;
ValeurCmp = M;
IdModule  = 1pin;
EndCmp

BeginCmp
TimeStamp = /54BD36C6;
Reference = M5;
ValeurCmp = M;
IdModule  = 1pin;
EndCmp

BeginCmp
TimeStamp = /54BD36CC;
Reference = M6;
ValeurCmp = M;
IdModule  = 1pin;
EndCmp

BeginCmp
TimeStamp = /54BD36D2;
Reference = M7;
ValeurCmp = M;
IdModule  = 1pin;
EndCmp

BeginCmp
TimeStamp = /548F13F7;
Reference = P1;
ValeurCmp = RASPI_MODEL_B_PLUS_GPIO;
IdModule  = RASPI_BPLUS_MIRRORED;
EndCmp

BeginCmp
TimeStamp = /54B17386;
Reference = P2;
ValeurCmp = UDN2981A;
IdModule  = DIP-18__300;
EndCmp

BeginCmp
TimeStamp = /554E0D39;
Reference = P3;
ValeurCmp = EXPANSION_20X2;
IdModule  = PIN_ARRAY_20X2;
EndCmp

BeginCmp
TimeStamp = /554E5206;
Reference = P5;
ValeurCmp = SERIAL 5V TTL;
IdModule  = PIN_ARRAY_4x1;
EndCmp

BeginCmp
TimeStamp = /5490833D;
Reference = R1;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /5490834A;
Reference = R2;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /54908350;
Reference = R3;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /54908356;
Reference = R4;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /5490835C;
Reference = R5;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /54908362;
Reference = R6;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /54908368;
Reference = R7;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /5490836E;
Reference = R8;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /54908374;
Reference = R9;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /5490837A;
Reference = R10;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /54908380;
Reference = R11;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /54908386;
Reference = R12;
ValeurCmp = 390;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /5490838C;
Reference = R_ROW1;
ValeurCmp = 1K;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /5490839E;
Reference = R_ROW2;
ValeurCmp = 1K;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /549083A4;
Reference = R_ROW3;
ValeurCmp = 1K;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /554E5219;
Reference = R_S1;
ValeurCmp = 300;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /554E5233;
Reference = R_S2;
ValeurCmp = 620;
IdModule  = R3;
EndCmp

BeginCmp
TimeStamp = /548EFBFD;
Reference = SW1;
ValeurCmp = DF1;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFC03;
Reference = SW2;
ValeurCmp = DF2;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFC09;
Reference = SW3;
ValeurCmp = DF3;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFC0F;
Reference = SW4;
ValeurCmp = IF1;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFC15;
Reference = SW5;
ValeurCmp = IF2;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFC1B;
Reference = SW6;
ValeurCmp = IF3;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFAF8;
Reference = SW7;
ValeurCmp = SR1;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB27;
Reference = SW8;
ValeurCmp = SR2;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB2D;
Reference = SW9;
ValeurCmp = SR3;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB33;
Reference = SW10;
ValeurCmp = SR4;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB42;
Reference = SW11;
ValeurCmp = SR5;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB48;
Reference = SW12;
ValeurCmp = SR6;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB4E;
Reference = SW13;
ValeurCmp = SR7;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB54;
Reference = SW14;
ValeurCmp = SR8;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB5A;
Reference = SW15;
ValeurCmp = SR9;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB60;
Reference = SW16;
ValeurCmp = SR10;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB66;
Reference = SW17;
ValeurCmp = SR11;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EFB6C;
Reference = SW18;
ValeurCmp = SR12;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF86F;
Reference = SW19;
ValeurCmp = START;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF87C;
Reference = SW20;
ValeurCmp = LOAD_ADD;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF882;
Reference = SW21;
ValeurCmp = DEP;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF888;
Reference = SW22;
ValeurCmp = EXAM;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF88E;
Reference = SW23;
ValeurCmp = CONT;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF894;
Reference = SW24;
ValeurCmp = STOP;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF89A;
Reference = SW25;
ValeurCmp = SING_STEP;
IdModule  = SW_KND2_PDP2;
EndCmp

BeginCmp
TimeStamp = /548EF8A0;
Reference = SW26;
ValeurCmp = SING_INST;
IdModule  = SW_KND2_PDP2;
EndCmp

EndListe
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted hardware/pdp8i/PDP8.dsn.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
(pcb C:\temp29\PDP8KICAD\PDP8.dsn
  (parser
    (string_quote ")
    (space_in_quoted_tokens on)
    (host_cad "KiCad's Pcbnew")
    (host_version "(2013-07-07 BZR 4022)-stable")
  )
  (resolution um 10)
  (unit um)
  (structure
    (layer F.Cu
      (type signal)
      (property
        (index 0)
      )
    )
    (layer B.Cu
      (type signal)
      (property
        (index 1)
      )
    )
    (boundary
      (path pcb 0  8500 -64000  288500 -64000  288500 -163000  8500 -163000
            8500 -64000)
    )
    (keepout "" (polygon B.Cu 0  288000 -140000  284000 -140000  284000 -156000  288000 -156000))
    (keepout "" (polygon F.Cu 0  288000 -140000  284000 -140000  284000 -156000  288000 -156000))
    (keepout "" (polygon B.Cu 0  9000 -142000  14000 -142000  14000 -140000  23000 -140000
            24000 -141000  24000 -162000  16000 -162000  16000 -157000  15000 -156000
            9000 -156000))
    (keepout "" (polygon F.Cu 0  9000 -142000  14000 -142000  14000 -140000  23000 -140000
            24000 -141000  24000 -162000  16000 -162000  16000 -157000  15000 -156000
            9000 -156000))
    (keepout "" (polygon F.Cu 0  64500 -111000  66500 -111000  66000 -111500  66000 -112000
            66000 -112500  65000 -112500  65250 -111750  65000 -111250  64500 -111000))
    (keepout "" (polygon F.Cu 0  65000 -114750  66000 -114750  66000 -115750  65000 -115750
            65250 -115250))
    (via "Via[0-1]_889:635_um" "Via[0-1]_889:0_um")
    (rule
      (width 254)
      (clearance 254.1)
      (clearance 254.1 (type default_smd))
      (clearance 63.5 (type smd_smd))
    )
  )
  (placement
    (component R3
      (place R9 57920 -102940 back 270 (PN 390))
      (place R1 37600 -102940 back 90 (PN 390))
      (place R2 40140 -102940 back 90 (PN 390))
      (place R3 42680 -102940 back 90 (PN 390))
      (place R4 45220 -102940 back 90 (PN 390))
      (place R5 47760 -102940 back 90 (PN 390))
      (place R6 50300 -102940 back 90 (PN 390))
      (place R7 52840 -102940 back 270 (PN 390))
      (place R8 55380 -102940 back 270 (PN 390))
      (place R10 60460 -102940 back 270 (PN 390))
      (place R11 63000 -102940 back 270 (PN 390))
      (place R12 65540 -102940 back 270 (PN 390))
      (place R_ROW1 78900 -133080 front 0 (PN 1K))
      (place R_ROW2 18750 -129500 front 180 (PN 1K))
      (place R_ROW3 218600 -133080 front 0 (PN 1K))
      (place R_S1 18750 -133000 front 0 (PN 300))
      (place R_S2 18750 -136500 front 0 (PN 620))
    )
    (component "DIP-18__300"
      (place P2 219050 -100970 back 270 (PN UDN2981A))
    )
    (component 1pin
      (place M1 13000 -68000 front 0 (PN M))
      (place M2 13000 -159000 front 0 (PN M))
      (place M3 285000 -68000 front 0 (PN M))
      (place M4 286000 -159000 front 0 (PN M))
      (place M5 208000 -68000 front 0 (PN M))
      (place M6 285000 -132000 front 0 (PN M))
      (place M7 208000 -132000 front 0 (PN M))
    )
    (component D2
      (place D23 249000 -136500 front 0 (PN 1N4148))
      (place D24 259000 -136500 front 0 (PN 1N4148))
      (place D22 239000 -136500 front 0 (PN 1N4148))
      (place D25 269000 -136500 front 0 (PN 1N4148))
      (place D26 279000 -136500 front 0 (PN 1N4148))
      (place D12 139000 -136500 front 0 (PN 1N4148))
      (place D2 39000 -136500 front 0 (PN 1N4148))
      (place D3 49000 -136500 front 0 (PN 1N4148))
      (place D4 59000 -136500 front 0 (PN 1N4148))
      (place D5 69000 -136500 front 0 (PN 1N4148))
      (place D6 79000 -136500 front 0 (PN 1N4148))
      (place D7 89000 -136500 front 0 (PN 1N4148))
      (place D8 99000 -136500 front 0 (PN 1N4148))
      (place D9 109000 -136500 front 0 (PN 1N4148))
      (place D10 119000 -136500 front 0 (PN 1N4148))
      (place D11 129000 -136500 front 0 (PN 1N4148))
      (place D1 29000 -136500 front 0 (PN 1N4148))
      (place D13 149000 -136500 front 0 (PN 1N4148))
      (place D14 159000 -136500 front 0 (PN 1N4148))
      (place D15 169000 -136500 front 0 (PN 1N4148))
      (place D16 179000 -136500 front 0 (PN 1N4148))
      (place D17 189000 -136500 front 0 (PN 1N4148))
      (place D18 199000 -136500 front 0 (PN 1N4148))
      (place D19 209000 -136500 front 0 (PN 1N4148))
      (place D20 219000 -136500 front 0 (PN 1N4148))
      (place D21 229000 -136500 front 0 (PN 1N4148))
    )
    (component RASPI_BPLUS_MIRRORED
      (place P1 64000 -124000 back 0 (PN RASPI_MODEL_B_PLUS_GPIO))
    )
    (component D3
      (place DZ1 219000 -117000 front 0 (PN ZENER))
    )
    (component "LED-3-PDP"
      (place DMB9 169000 -99800 front 0 (PN LED))
      (place DMB10 179000 -99800 front 0 (PN LED))
      (place DMB11 189000 -99800 front 0 (PN LED))
      (place DMB12 199000 -99800 front 0 (PN LED))
      (place DAC1 89000 -114400 front 0 (PN LED))
      (place DAC2 99000 -114400 front 0 (PN LED))
      (place DAC3 109000 -114400 front 0 (PN LED))
      (place DAC4 119000 -114400 front 0 (PN LED))
      (place DAC5 129000 -114400 front 0 (PN LED))
      (place DAC6 139000 -114400 front 0 (PN LED))
      (place DAC7 149000 -114400 front 0 (PN LED))
      (place DAC8 159000 -114400 front 0 (PN LED))
      (place DAC9 169000 -114400 front 0 (PN LED))
      (place DAC10 179000 -114400 front 0 (PN LED))
      (place DPC1 89000 -70600 front 0 (PN LED))
      (place DAC12 199000 -114400 front 0 (PN LED))
      (place DMQ1 89000 -129000 front 0 (PN LED))
      (place DMQ2 99000 -129000 front 0 (PN LED))
      (place DMQ3 109000 -129000 front 0 (PN LED))
      (place DMQ4 119000 -129000 front 0 (PN LED))
      (place DMQ5 129000 -129000 front 0 (PN LED))
      (place DMQ6 139000 -129000 front 0 (PN LED))
      (place DMQ7 149000 -129000 front 0 (PN LED))
      (place DMQ8 159000 -129000 front 0 (PN LED))
      (place DMQ9 169000 -129000 front 0 (PN LED))
      (place DMQ10 179000 -129000 front 0 (PN LED))
      (place DMQ11 189000 -129000 front 0 (PN LED))
      (place DMQ12 199000 -129000 front 0 (PN LED))
      (place DLINK1 79000 -114400 front 0 (PN LED))
      (place DSC1 29000 -129000 front 0 (PN LED))
      (place DAC11 189000 -114400 front 0 (PN LED))
      (place DPC2 99000 -70600 front 0 (PN LED))
      (place DPC3 109000 -70600 front 0 (PN LED))
      (place DPC4 119000 -70600 front 0 (PN LED))
      (place DPC5 129000 -70600 front 0 (PN LED))
      (place DPC6 139000 -70600 front 0 (PN LED))
      (place DPC7 149000 -70600 front 0 (PN LED))
      (place DPC8 159000 -70600 front 0 (PN LED))
      (place DPC9 169000 -70600 front 0 (PN LED))
      (place DPC10 179000 -70600 front 0 (PN LED))
      (place DPC11 189000 -70600 front 0 (PN LED))
      (place DPC12 199000 -70600 front 0 (PN LED))
      (place DMA1 89000 -85200 front 0 (PN LED))
      (place DMA2 99000 -85200 front 0 (PN LED))
      (place DMA3 109000 -85200 front 0 (PN LED))
      (place DMB8 159000 -99800 front 0 (PN LED))
      (place DMA5 129000 -85200 front 0 (PN LED))
      (place DMA6 139000 -85200 front 0 (PN LED))
      (place DMA7 149000 -85200 front 0 (PN LED))
      (place DMA8 159000 -85200 front 0 (PN LED))
      (place DMA9 169000 -85200 front 0 (PN LED))
      (place DMA10 179000 -85200 front 0 (PN LED))
      (place DMA11 189000 -85200 front 0 (PN LED))
      (place DMA12 199000 -85200 front 0 (PN LED))
      (place DMB1 89000 -99800 front 0 (PN LED))
      (place DMB2 99000 -99800 front 0 (PN LED))
      (place DMB3 109000 -99800 front 0 (PN LED))
      (place DMB4 119000 -99800 front 0 (PN LED))
      (place DMB5 129000 -99800 front 0 (PN LED))
      (place DMB6 139000 -99800 front 0 (PN LED))
      (place DMB7 149000 -99800 front 0 (PN LED))
      (place DMA4 119000 -85200 front 0 (PN LED))
      (place DRUN1 279000 -85200 front 0 (PN LED))
      (place DPAUSE1 279000 -77900 front 0 (PN LED))
      (place DION1 279000 -70600 front 0 (PN LED))
      (place DBREAK1 259000 -107100 front 0 (PN LED))
      (place DCURAD1 259000 -99800 front 0 (PN LED))
      (place DWRDCT1 259000 -92500 front 0 (PN LED))
      (place DDEFER1 259000 -85200 front 0 (PN LED))
      (place DEXEC1 259000 -77900 front 0 (PN LED))
      (place DFETCH1 259000 -70600 front 0 (PN LED))
      (place DOPR1 239000 -121700 front 0 (PN LED))
      (place DIOT1 239000 -114400 front 0 (PN LED))
      (place DJMP1 239000 -107100 front 0 (PN LED))
      (place DJMS1 239000 -99800 front 0 (PN LED))
      (place DDCA1 239000 -92500 front 0 (PN LED))
      (place DSC2 39000 -129000 front 0 (PN LED))
      (place DSC4 59000 -129000 front 0 (PN LED))
      (place DSC5 69000 -129000 front 0 (PN LED))
      (place DDF1 29000 -70600 front 0 (PN LED))
      (place DDF2 39000 -70600 front 0 (PN LED))
      (place DDF3 49000 -70600 front 0 (PN LED))
      (place DSC3 49000 -129000 front 0 (PN LED))
      (place DTAD1 239000 -77900 front 0 (PN LED))
      (place DAND1 239000 -70600 front 0 (PN LED))
      (place DISZ1 239000 -85200 front 0 (PN LED))
      (place DIF2 69000 -70600 front 0 (PN LED))
      (place DIF3 79000 -70600 front 0 (PN LED))
      (place DIF1 59000 -70600 front 0 (PN LED))
    )
    (component SW_KND2_PDP2
      (place SW6 79000 -159500 front 0 (PN IF3))
      (place SW5 69000 -159500 front 0 (PN IF2))
      (place SW4 59000 -159500 front 0 (PN IF1))
      (place SW3 49000 -159500 front 0 (PN DF3))
      (place SW2 39000 -159500 front 0 (PN DF2))
      (place SW1 29000 -159500 front 0 (PN DF1))
      (place SW18 199000 -159500 front 0 (PN SR12))
      (place SW17 189000 -159500 front 0 (PN SR11))
      (place SW15 169000 -159500 front 0 (PN SR9))
      (place SW14 159000 -159500 front 0 (PN SR8))
      (place SW13 149000 -159500 front 0 (PN SR7))
      (place SW12 139000 -159500 front 0 (PN SR6))
      (place SW19 209000 -159500 front 0 (PN START))
      (place SW20 219000 -159500 front 0 (PN LOAD_ADD))
      (place SW16 179000 -159500 front 0 (PN SR10))
      (place SW22 239000 -159500 front 0 (PN EXAM))
      (place SW23 249000 -159500 front 0 (PN CONT))
      (place SW24 259000 -159500 front 0 (PN STOP))
      (place SW25 269000 -159500 front 0 (PN SING_STEP))
      (place SW26 279000 -159500 front 0 (PN SING_INST))
      (place SW7 89000 -159500 front 0 (PN SR1))
      (place SW8 99000 -159500 front 0 (PN SR2))
      (place SW9 109000 -159500 front 0 (PN SR3))
      (place SW10 119000 -159500 front 0 (PN SR4))
      (place SW11 129000 -159500 front 0 (PN SR5))
      (place SW21 229000 -159500 front 0 (PN DEP))
    )
    (component PIN_ARRAY_4x1
      (place P5 11500 -136000 front 270 (PN "SERIAL 5V TTL"))
    )
    (component PIN_ARRAY_20X2
      (place P3 253900 -130050 back 180 (PN EXPANSION_20X2))
    )
    (component "LED-3-StrEight"
      (place DPAUSE2 259000 -114400 front 0 (PN LED))
      (place DRUN2 259000 -121700 front 0 (PN LED))
    )
    (component PIN_ARRAY_3X1
      (place J_COL1 64300 -111800 back 180 (PN CONN_3))
      (place J_COL2 64300 -115200 back 180 (PN CONN_3))
    )
  )
  (library
    (image R3
      (outline (path signal 203.2  -3810 0  -3302 0))
      (outline (path signal 203.2  3810 0  3302 0))
      (outline (path signal 203.2  3302 0  3302 1016))
      (outline (path signal 203.2  3302 1016  -3302 1016))
      (outline (path signal 203.2  -3302 1016  -3302 -1016))
      (outline (path signal 203.2  -3302 -1016  3302 -1016))
      (outline (path signal 203.2  3302 -1016  3302 0))
      (outline (path signal 203.2  -3302 508  -2794 1016))
      (pin Round[A]Pad_1397_um 1 -3810 0)
      (pin Round[A]Pad_1397_um 2 3810 0)
    )
    (image "DIP-18__300"
      (outline (path signal 381  -12700 1270  -11430 1270))
      (outline (path signal 381  -11430 1270  -11430 -1270))
      (outline (path signal 381  -11430 -1270  -12700 -1270))
      (outline (path signal 381  -12700 2540  12700 2540))
      (outline (path signal 381  12700 2540  12700 -2540))
      (outline (path signal 381  12700 -2540  -12700 -2540))
      (outline (path signal 381  -12700 -2540  -12700 2540))
      (pin Rect[A]Pad_1397x1397_um 1 -10160 -3810)
      (pin Round[A]Pad_1397_um 2 -7620 -3810)
      (pin Round[A]Pad_1397_um 3 -5080 -3810)
      (pin Round[A]Pad_1397_um 4 -2540 -3810)
      (pin Round[A]Pad_1397_um 5 0 -3810)
      (pin Round[A]Pad_1397_um 6 2540 -3810)
      (pin Round[A]Pad_1397_um 7 5080 -3810)
      (pin Round[A]Pad_1397_um 8 7620 -3810)
      (pin Round[A]Pad_1397_um 9 10160 -3810)
      (pin Round[A]Pad_1397_um 10 10160 3810)
      (pin Round[A]Pad_1397_um 11 7620 3810)
      (pin Round[A]Pad_1397_um 12 5080 3810)
      (pin Round[A]Pad_1397_um 13 2540 3810)
      (pin Round[A]Pad_1397_um 14 0 3810)
      (pin Round[A]Pad_1397_um 15 -2540 3810)
      (pin Round[A]Pad_1397_um 16 -5080 3810)
      (pin Round[A]Pad_1397_um 17 -7620 3810)
      (pin Round[A]Pad_1397_um 18 -10160 3810)
    )
    (image 1pin
      (outline (path signal 381  2286 0  2174.11 -706.412  1849.41 -1343.68  1343.68 -1849.41
            706.412 -2174.11  0 -2286  -706.412 -2174.11  -1343.68 -1849.41
            -1849.41 -1343.68  -2174.11 -706.412  -2286 0  -2174.11 706.412
            -1849.41 1343.68  -1343.68 1849.41  -706.412 2174.11  0 2286
            706.412 2174.11  1343.68 1849.41  1849.41 1343.68  2174.11 706.412))
      (pin Round[A]Pad_4064_um 1 0 0)
    )
    (image D2
      (outline (path signal 304.8  -2032 -1016  2032 -1016))
      (outline (path signal 304.8  -2032 1016  2032 1016))
      (outline (path signal 304.8  2794 0  2032 0))
      (outline (path signal 304.8  2032 0  2032 1016))
      (outline (path signal 304.8  -2032 1016  -2032 0))
      (outline (path signal 304.8  -2032 0  -2794 0))
      (outline (path signal 304.8  -2032 0  -2032 -1016))
      (outline (path signal 304.8  2032 -1016  2032 0))
      (outline (path signal 304.8  1524 1016  1524 -1016))
      (outline (path signal 304.8  1270 -1016  1270 1016))
      (pin Rect[A]Pad_1397x1397_um 2 3556 0)
      (pin Round[A]Pad_1397_um 1 -3810 0)
    )
    (image RASPI_BPLUS_MIRRORED
      (outline (path signal 150  48768 49022  53594 49022))
      (outline (path signal 150  53594 49022  53594 38354))
      (outline (path signal 150  53594 38354  49784 38354))
      (outline (path signal 150  -22000 49008  -22000 52508))
      (outline (path signal 150  -16000 49008  -16000 52508))
      (outline (path signal 150  -7000 48500  -7000 52500))
      (outline (path signal 150  6000 48500  6000 52500))
      (outline (path signal 150  49500 11032  54000 11032))
      (outline (path signal 150  54000 11032  54000 32))
      (outline (path signal 150  54000 32  50000 32))
      (outline (path signal 150  49500 28032  54000 28032))
      (outline (path signal 150  54000 28032  54000 16532))
      (outline (path signal 150  54000 16532  49500 16532))
      (outline (path signal 150  -32500 -3500  52500 -3500))
      (outline (path signal 150  52500 52500  52500 -3500))
      (outline (path signal 150  52500 52500  32000 52500))
      (outline (path signal 150  -32500 52500  -32500 -3500))
      (outline (path signal 150  -32500 52500  32500 52500))
      (outline (path signal 304.8  25400 -2540  -25400 -2540))
      (outline (path signal 304.8  25400 2540  -25400 2540))
      (outline (path signal 304.8  25400 2540  25400 -2540))
      (outline (path signal 304.8  -25400 2540  -25400 -2540))
      (pin Rect[A]Pad_1524x1524_um 1 -24130 1270)
      (pin Round[A]Pad_1524_um 2 -24130 -1270)
      (pin Round[A]Pad_1524_um 11 -11430 1270)
      (pin Round[A]Pad_1524_um 4 -21590 -1270)
      (pin Round[A]Pad_1524_um 13 -8890 1270)
      (pin Round[A]Pad_1524_um 6 -19050 -1270)
      (pin Round[A]Pad_1524_um 15 -6350 1270)
      (pin Round[A]Pad_1524_um 8 -16510 -1270)
      (pin Round[A]Pad_1524_um 17 -3810 1270)
      (pin Round[A]Pad_1524_um 10 -13970 -1270)
      (pin Round[A]Pad_1524_um 19 -1270 1270)
      (pin Round[A]Pad_1524_um 12 -11430 -1270)
      (pin Round[A]Pad_1524_um 21 1270 1270)
      (pin Round[A]Pad_1524_um 14 -8890 -1270)
      (pin Round[A]Pad_1524_um 23 3810 1270)
      (pin Round[A]Pad_1524_um 16 -6350 -1270)
      (pin Round[A]Pad_1524_um 25 6350 1270)
      (pin Round[A]Pad_1524_um 18 -3810 -1270)
      (pin Round[A]Pad_1524_um 27 8890 1270)
      (pin Round[A]Pad_1524_um 20 -1270 -1270)
      (pin Round[A]Pad_1524_um 29 11430 1270)
      (pin Round[A]Pad_1524_um 22 1270 -1270)
      (pin Round[A]Pad_1524_um 31 13970 1270)
      (pin Round[A]Pad_1524_um 24 3810 -1270)
      (pin Round[A]Pad_1524_um 26 6350 -1270)
      (pin Round[A]Pad_1524_um 33 16510 1270)
      (pin Round[A]Pad_1524_um 28 8890 -1270)
      (pin Round[A]Pad_1524_um 32 13970 -1270)
      (pin Round[A]Pad_1524_um 34 16510 -1270)
      (pin Round[A]Pad_1524_um 36 19050 -1270)
      (pin Round[A]Pad_1524_um 38 21590 -1270)
      (pin Round[A]Pad_1524_um 35 19050 1270)
      (pin Round[A]Pad_1524_um 37 21590 1270)
      (pin Round[A]Pad_1524_um 3 -21590 1270)
      (pin Round[A]Pad_1524_um 5 -19050 1270)
      (pin Round[A]Pad_1524_um 7 -16510 1270)
      (pin Round[A]Pad_1524_um 9 -13970 1270)
      (pin Round[A]Pad_1524_um 39 24130 1270)
      (pin Round[A]Pad_1524_um 40 24130 -1270)
      (pin Round[A]Pad_1524_um 30 11430 -1270)
      (pin Round[A]Pad_5700_um H2 -29000 0)
      (pin Round[A]Pad_5700_um H3 29000 0)
      (pin Round[A]Pad_5700_um H4 29000 49000)
      (pin Round[A]Pad_5700_um H1 -29000 49000)
    )
    (image D3
      (outline (path signal 304.8  3810 0  3048 0))
      (outline (path signal 304.8  3048 0  3048 1016))
      (outline (path signal 304.8  3048 1016  -3048 1016))
      (outline (path signal 304.8  -3048 1016  -3048 0))
      (outline (path signal 304.8  -3048 0  -3810 0))
      (outline (path signal 304.8  -3048 0  -3048 -1016))
      (outline (path signal 304.8  -3048 -1016  3048 -1016))
      (outline (path signal 304.8  3048 -1016  3048 0))
      (outline (path signal 304.8  2540 1016  2540 -1016))
      (outline (path signal 304.8  2286 -1016  2286 1016))
      (pin Rect[A]Pad_1397x1397_um 2 3810 0)
      (pin Round[A]Pad_1397_um 1 -3810 0)
    )
    (image "LED-3-PDP"
      (outline (path signal 150  -2400 -1500  -2400 1500))
      (outline (path signal 150  1500 -2400  -1500 -2400))
      (outline (path signal 150  2400 1500  2400 -1500))
      (outline (path signal 150  -1500 2400  1500 2400))
      (pin Round[A]Pad_1676.4_um 1 -1270 0)
      (pin Round[A]Pad_1676.4_um 2 1270 0)
    )
    (image SW_KND2_PDP2
      (outline (path signal 150  -4750 -1950  -4750 10350))
      (outline (path signal 150  4750 10300  4750 -1950))
      (outline (path signal 150  -4750 -1958  4750 -1958))
      (outline (path signal 150  -4750 10300  -4750 18900))
      (outline (path signal 150  4750 10300  4750 18900))
      (outline (path signal 150  4750 18900  -4750 18900))
      (outline (path signal 150  4750 10300  -4750 10300))
      (pin Oval[A]Pad_5080x2540_um 1 0 0)
      (pin Oval[A]Pad_5080x2540_um 2 0 5580)
      (pin Round[A]Pad_4000_um 3 0 15000)
    )
    (image PIN_ARRAY_4x1
      (outline (path signal 254  5080 -1270  -5080 -1270))
      (outline (path signal 254  5080 1270  -5080 1270))
      (outline (path signal 254  -5080 1270  -5080 -1270))
      (outline (path signal 254  5080 -1270  5080 1270))
      (pin Rect[A]Pad_1524x1524_um 1 -3810 0)
      (pin Round[A]Pad_1524_um 2 -1270 0)
      (pin Round[A]Pad_1524_um 3 1270 0)
      (pin Round[A]Pad_1524_um 4 3810 0)
    )
    (image PIN_ARRAY_20X2
      (outline (path signal 304.8  25400 -2540  -25400 -2540))
      (outline (path signal 304.8  25400 2540  -25400 2540))
      (outline (path signal 304.8  25400 2540  25400 -2540))
      (outline (path signal 304.8  -25400 2540  -25400 -2540))
      (pin Rect[A]Pad_1524x1524_um 1 -24130 -1270)
      (pin Round[A]Pad_1524_um 2 -24130 1270)
      (pin Round[A]Pad_1524_um 11 -11430 -1270)
      (pin Round[A]Pad_1524_um 4 -21590 1270)
      (pin Round[A]Pad_1524_um 13 -8890 -1270)
      (pin Round[A]Pad_1524_um 6 -19050 1270)
      (pin Round[A]Pad_1524_um 15 -6350 -1270)
      (pin Round[A]Pad_1524_um 8 -16510 1270)
      (pin Round[A]Pad_1524_um 17 -3810 -1270)
      (pin Round[A]Pad_1524_um 10 -13970 1270)
      (pin Round[A]Pad_1524_um 19 -1270 -1270)
      (pin Round[A]Pad_1524_um 12 -11430 1270)
      (pin Round[A]Pad_1524_um 21 1270 -1270)
      (pin Round[A]Pad_1524_um 14 -8890 1270)
      (pin Round[A]Pad_1524_um 23 3810 -1270)
      (pin Round[A]Pad_1524_um 16 -6350 1270)
      (pin Round[A]Pad_1524_um 25 6350 -1270)
      (pin Round[A]Pad_1524_um 18 -3810 1270)
      (pin Round[A]Pad_1524_um 27 8890 -1270)
      (pin Round[A]Pad_1524_um 20 -1270 1270)
      (pin Round[A]Pad_1524_um 29 11430 -1270)
      (pin Round[A]Pad_1524_um 22 1270 1270)
      (pin Round[A]Pad_1524_um 31 13970 -1270)
      (pin Round[A]Pad_1524_um 24 3810 1270)
      (pin Round[A]Pad_1524_um 26 6350 1270)
      (pin Round[A]Pad_1524_um 33 16510 -1270)
      (pin Round[A]Pad_1524_um 28 8890 1270)
      (pin Round[A]Pad_1524_um 32 13970 1270)
      (pin Round[A]Pad_1524_um 34 16510 1270)
      (pin Round[A]Pad_1524_um 36 19050 1270)
      (pin Round[A]Pad_1524_um 38 21590 1270)
      (pin Round[A]Pad_1524_um 35 19050 -1270)
      (pin Round[A]Pad_1524_um 37 21590 -1270)
      (pin Round[A]Pad_1524_um 3 -21590 -1270)
      (pin Round[A]Pad_1524_um 5 -19050 -1270)
      (pin Round[A]Pad_1524_um 7 -16510 -1270)
      (pin Round[A]Pad_1524_um 9 -13970 -1270)
      (pin Round[A]Pad_1524_um 39 24130 -1270)
      (pin Round[A]Pad_1524_um 40 24130 1270)
      (pin Round[A]Pad_1524_um 30 11430 1270)
    )
    (image "LED-3-StrEight"
      (pin Round[A]Pad_1676.4_um 1 -1270 0)
      (pin Round[A]Pad_1676.4_um 2 1270 0)
    )
    (image PIN_ARRAY_3X1
      (outline (path signal 152.4  -3810 -1270  -3810 1270))
      (outline (path signal 152.4  -3810 1270  3810 1270))
      (outline (path signal 152.4  3810 1270  3810 -1270))
      (outline (path signal 152.4  3810 -1270  -3810 -1270))
      (outline (path signal 152.4  -1270 1270  -1270 -1270))
      (pin Rect[A]Pad_1524x1524_um 1 -2540 0)
      (pin Round[A]Pad_1524_um 2 0 0)
      (pin Round[A]Pad_1524_um 3 2540 0)
    )
    (padstack Round[A]Pad_1397_um
      (shape (circle F.Cu 1397))
      (shape (circle B.Cu 1397))
      (attach off)
    )
    (padstack Round[A]Pad_1524_um
      (shape (circle F.Cu 1524))
      (shape (circle B.Cu 1524))
      (attach off)
    )
    (padstack Round[A]Pad_1676.4_um
      (shape (circle F.Cu 1676.4))
      (shape (circle B.Cu 1676.4))
      (attach off)
    )
    (padstack Round[A]Pad_4000_um
      (shape (circle F.Cu 4000))
      (shape (circle B.Cu 4000))
      (attach off)
    )
    (padstack Round[A]Pad_4064_um
      (shape (circle F.Cu 4064))
      (shape (circle B.Cu 4064))
      (attach off)
    )
    (padstack Round[A]Pad_5700_um
      (shape (circle F.Cu 5700))
      (shape (circle B.Cu 5700))
      (attach off)
    )
    (padstack Oval[A]Pad_5080x2540_um
      (shape (path F.Cu 2540  -1270 0  1270 0))
      (shape (path B.Cu 2540  -1270 0  1270 0))
      (attach off)
    )
    (padstack Rect[A]Pad_1397x1397_um
      (shape (rect F.Cu -698.5 -698.5 698.5 698.5))
      (shape (rect B.Cu -698.5 -698.5 698.5 698.5))
      (attach off)
    )
    (padstack Rect[A]Pad_1524x1524_um
      (shape (rect F.Cu -762 -762 762 762))
      (shape (rect B.Cu -762 -762 762 762))
      (attach off)
    )
    (padstack "Via[0-1]_889:635_um"
      (shape (circle F.Cu 889))
      (shape (circle B.Cu 889))
      (attach off)
    )
    (padstack "Via[0-1]_889:0_um"
      (shape (circle F.Cu 889))
      (shape (circle B.Cu 889))
      (attach off)
    )
  )
  (network
    (net +3.3V
      (pins P1-1 P3-6 P3-5)
    )
    (net +5V
      (pins P1-2 P1-4 DZ1-1 P5-2 P3-1 P3-2)
    )
    (net GND
      (pins P2-10 P1-6 P1-20 P1-9 P1-39 P1-30 R_S2-1 P5-1 P3-8 P3-7)
    )
    (net "N-0000023"
      (pins P2-9 DZ1-2)
    )
    (net "N-0000028"
      (pins R1-2 J_COL1-2)
    )
    (net "N-0000029"
      (pins R2-2 J_COL2-2)
    )
    (net "N-0000035"
      (pins R_S1-1 R_S2-2 P5-3)
    )
    (net "N-0000039"
      (pins R6-2 P1-26)
    )
    (net "N-0000040"
      (pins R10-1 P1-23)
    )
    (net "N-0000041"
      (pins R_ROW1-1 P1-36)
    )
    (net "N-0000042"
      (pins R11-1 P1-32)
    )
    (net "N-0000043"
      (pins R7-1 P1-24)
    )
    (net "N-0000046"
      (pins R_ROW3-1 P1-12)
    )
    (net "N-0000048"
      (pins R12-1 P1-33)
    )
    (net "N-0000049"
      (pins R5-2 P1-31)
    )
    (net "N-0000050"
      (pins R4-2 P1-29)
    )
    (net "N-0000053"
      (pins D6-2 SW6-2)
    )
    (net "N-0000054"
      (pins R8-1 P1-21)
    )
    (net "N-0000055"
      (pins R9-1 P1-19)
    )
    (net "N-0000056"
      (pins R_ROW2-1 P1-11)
    )
    (net "N-0000057"
      (pins R3-2 P1-7)
    )
    (net "N-0000059"
      (pins D5-2 SW5-2)
    )
    (net "N-0000060"
      (pins D4-2 SW4-2)
    )
    (net "N-0000061"
      (pins D3-2 SW3-2)
    )
    (net "N-0000062"
      (pins D2-2 SW2-2)
    )
    (net "N-0000063"
      (pins D1-2 SW1-2)
    )
    (net "N-0000065"
      (pins D22-2 SW22-2)
    )
    (net "N-0000066"
      (pins D23-2 SW23-2)
    )
    (net "N-0000067"
      (pins D24-2 SW24-2)
    )
    (net "N-0000068"
      (pins D25-2 SW25-2)
    )
    (net "N-0000069"
      (pins D26-2 SW26-2)
    )
    (net "N-0000070"
      (pins D21-2 SW21-2)
    )
    (net "N-0000071"
      (pins D7-2 SW7-2)
    )
    (net "N-0000072"
      (pins D8-2 SW8-2)
    )
    (net "N-0000073"
      (pins D9-2 SW9-2)
    )
    (net "N-0000074"
      (pins D10-2 SW10-2)
    )
    (net "N-0000079"
      (pins D11-2 SW11-2)
    )
    (net "N-0000085"
      (pins D19-2 SW19-2)
    )
    (net "N-0000086"
      (pins D20-2 SW20-2)
    )
    (net "N-0000087"
      (pins D12-2 SW12-2)
    )
    (net "N-0000088"
      (pins D13-2 SW13-2)
    )
    (net "N-0000089"
      (pins D14-2 SW14-2)
    )
    (net "N-0000090"
      (pins D15-2 SW15-2)
    )
    (net "N-0000091"
      (pins D16-2 SW16-2)
    )
    (net "N-0000092"
      (pins D17-2 SW17-2)
    )
    (net "N-0000093"
      (pins D18-2 SW18-2)
    )
    (net RX
      (pins P1-10 R_S1-2 J_COL2-3)
    )
    (net SPARE_IO
      (pins P1-35 P3-15 P3-16)
    )
    (net TX
      (pins P1-8 P5-4 J_COL1-3)
    )
    (net col1
      (pins R1-1 D7-1 D1-1 D19-1 DAC1-2 DPC1-2 DMQ1-2 DMA1-2 DMB1-2 DCURAD1-2 DDF1-2
        DAND1-2 P3-17 P3-18)
    )
    (net col10
      (pins R10-2 D16-1 DMB10-2 DAC10-2 DMQ10-2 DPC10-2 DMA10-2 DEXEC1-2 DSC5-2 P3-36
        P3-35)
    )
    (net col11
      (pins R11-2 D17-1 DMB11-2 DMQ11-2 DAC11-2 DPC11-2 DMA11-2 DDEFER1-2 P3-38 P3-37)
    )
    (net col12
      (pins R12-2 D18-1 DMB12-2 DAC12-2 DMQ12-2 DPC12-2 DMA12-2 DWRDCT1-2 P3-39 P3-40)
    )
    (net col1a
      (pins P1-3 J_COL1-1)
    )
    (net col2
      (pins R2-1 D2-1 D8-1 D20-1 DAC2-2 DMQ2-2 DPC2-2 DMA2-2 DMB2-2 DBREAK1-2 DDF2-2
        DTAD1-2 P3-19 P3-20)
    )
    (net col2a
      (pins P1-5 J_COL2-1)
    )
    (net col3
      (pins R3-1 D3-1 D9-1 D21-1 DAC3-2 DMQ3-2 DPC3-2 DMA3-2 DMB3-2 DION1-2 DDF3-2
        DISZ1-2 P3-21 P3-22)
    )
    (net col4
      (pins R4-1 D22-1 D4-1 D10-1 DAC4-2 DMQ4-2 DPC4-2 DMB4-2 DMA4-2 DPAUSE1-2 DDCA1-2
        DIF1-2 P3-23 P3-24 DPAUSE2-2)
    )
    (net col5
      (pins R5-1 D23-1 D5-1 D11-1 DAC5-2 DMQ5-2 DPC5-2 DMA5-2 DMB5-2 DRUN1-2 DJMS1-2
        DIF2-2 P3-25 P3-26 DRUN2-2)
    )
    (net col6
      (pins R6-1 D24-1 D12-1 D6-1 DAC6-2 DMQ6-2 DSC1-2 DPC6-2 DMA6-2 DMB6-2 DJMP1-2
        DIF3-2 P3-27 P3-28)
    )
    (net col7
      (pins R7-2 D25-1 D13-1 DAC7-2 DMQ7-2 DLINK1-2 DPC7-2 DMA7-2 DMB7-2 DIOT1-2 DSC2-2
        P3-29 P3-30)
    )
    (net col8
      (pins R8-2 D26-1 D14-1 DAC8-2 DMQ8-2 DPC8-2 DMB8-2 DMA8-2 DOPR1-2 DSC3-2 P3-31
        P3-32)
    )
    (net col9
      (pins R9-2 D15-1 DMB9-2 DAC9-2 DMQ9-2 DPC9-2 DMA9-2 DFETCH1-2 DSC4-2 P3-33 P3-34)
    )
    (net led1
      (pins P2-18 DPC1-1 DPC2-1 DPC3-1 DPC4-1 DPC5-1 DPC6-1 DPC7-1 DPC8-1 DPC9-1 DPC10-1
        DPC11-1 DPC12-1)
    )
    (net led2
      (pins P2-17 DMA1-1 DMA2-1 DMA3-1 DMA5-1 DMA6-1 DMA7-1 DMA8-1 DMA9-1 DMA10-1
        DMA11-1 DMA12-1 DMA4-1)
    )
    (net led3
      (pins P2-16 DMB9-1 DMB10-1 DMB11-1 DMB12-1 DMB8-1 DMB1-1 DMB2-1 DMB3-1 DMB4-1
        DMB5-1 DMB6-1 DMB7-1)
    )
    (net led4
      (pins P2-15 DAC1-1 DAC2-1 DAC3-1 DAC4-1 DAC5-1 DAC6-1 DAC7-1 DAC8-1 DAC9-1 DAC10-1
        DAC12-1 DAC11-1)
    )
    (net led5
      (pins P2-14 DMQ1-1 DMQ2-1 DMQ3-1 DMQ4-1 DMQ5-1 DMQ6-1 DMQ7-1 DMQ8-1 DMQ9-1 DMQ10-1
        DMQ11-1 DMQ12-1)
    )
    (net led6
      (pins P2-13 DWRDCT1-1 DDEFER1-1 DEXEC1-1 DFETCH1-1 DOPR1-1 DIOT1-1 DJMP1-1 DJMS1-1
        DDCA1-1 DTAD1-1 DAND1-1 DISZ1-1)
    )
    (net led7
      (pins P2-12 DSC1-1 DRUN1-1 DPAUSE1-1 DION1-1 DBREAK1-1 DCURAD1-1 DSC2-1 DSC4-1
        DSC5-1 DSC3-1 P3-10 P3-9 DPAUSE2-1 DRUN2-1)
    )
    (net led8
      (pins P2-11 DLINK1-1 DDF1-1 DDF2-1 DDF3-1 DIF2-1 DIF3-1 DIF1-1 P3-11 P3-12)
    )
    (net row1
      (pins R_ROW1-2 SW18-1 SW17-1 SW15-1 SW14-1 SW13-1 SW12-1 SW16-1 SW7-1 SW8-1
        SW9-1 SW10-1 SW11-1)
    )
    (net row2
      (pins R_ROW2-2 SW6-1 SW5-1 SW4-1 SW3-1 SW2-1 SW1-1 P3-13 P3-14)
    )
    (net row3
      (pins R_ROW3-2 SW19-1 SW20-1 SW22-1 SW23-1 SW24-1 SW25-1 SW26-1 SW21-1)
    )
    (net xled1
      (pins P2-1 P1-38)
    )
    (net xled2
      (pins P2-2 P1-40)
    )
    (net xled3
      (pins P2-3 P1-15)
    )
    (net xled4
      (pins P2-4 P1-16)
    )
    (net xled5
      (pins P2-5 P1-18)
    )
    (net xled6
      (pins P2-6 P1-22)
    )
    (net xled7
      (pins P2-7 P1-37)
    )
    (net xled8
      (pins P2-8 P1-13)
    )
    (class kicad_default "" +3.3V +5V GND "N-0000023" "N-0000028" "N-0000029"
      "N-0000035" "N-0000039" "N-0000040" "N-0000041" "N-0000042" "N-0000043"
      "N-0000046" "N-0000048" "N-0000049" "N-0000050" "N-0000053" "N-0000054"
      "N-0000055" "N-0000056" "N-0000057" "N-0000059" "N-0000060" "N-0000061"
      "N-0000062" "N-0000063" "N-0000065" "N-0000066" "N-0000067" "N-0000068"
      "N-0000069" "N-0000070" "N-0000071" "N-0000072" "N-0000073" "N-0000074"
      "N-0000079" "N-0000085" "N-0000086" "N-0000087" "N-0000088" "N-0000089"
      "N-0000090" "N-0000091" "N-0000092" "N-0000093" RX SPARE_IO TX col1
      col10 col11 col12 col1a col2 col2a col3 col4 col5 col6 col7 col8 col9
      led1 led2 led3 led4 led5 led6 led7 led8 row1 row2 row3 xled1 xled2 xled3
      xled4 xled5 xled6 xled7 xled8
      (circuit
        (use_via Via[0-1]_889:635_um)
      )
      (rule
        (width 254)
        (clearance 254.1)
      )
    )
  )
  (wiring
  )
)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted hardware/pdp8i/PDP8.kicad_pcb.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
6463
6464
6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
6775
6776
6777
6778
6779
6780
6781
6782
6783
6784
6785
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
6875
6876
6877
6878
6879
6880
6881
6882
6883
6884
6885
6886
6887
6888
6889
6890
6891
6892
6893
6894
6895
6896
6897
6898
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912
6913
6914
6915
6916
6917
6918
6919
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
6937
6938
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077
7078
7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
(kicad_pcb (version 3) (host pcbnew "(2013-07-07 BZR 4022)-stable")

  (general
    (links 343)
    (no_connects 0)
    (area 8.0964 63.949999 288.550001 163.050001)
    (thickness 1.6)
    (drawings 11)
    (tracks 1226)
    (zones 0)
    (modules 174)
    (nets 80)
  )

  (page A4)
  (layers
    (15 F.Cu signal)
    (0 B.Cu signal)
    (16 B.Adhes user hide)
    (17 F.Adhes user hide)
    (18 B.Paste user hide)
    (19 F.Paste user hide)
    (20 B.SilkS user hide)
    (21 F.SilkS user)
    (22 B.Mask user hide)
    (23 F.Mask user hide)
    (24 Dwgs.User user)
    (25 Cmts.User user)
    (26 Eco1.User user)
    (27 Eco2.User user)
    (28 Edge.Cuts user)
  )

  (setup
    (last_trace_width 0.254)
    (trace_clearance 0.254)
    (zone_clearance 0.508)
    (zone_45_only no)
    (trace_min 0.254)
    (segment_width 0.2)
    (edge_width 0.1)
    (via_size 0.889)
    (via_drill 0.635)
    (via_min_size 0.889)
    (via_min_drill 0.508)
    (uvia_size 0.508)
    (uvia_drill 0.127)
    (uvias_allowed no)
    (uvia_min_size 0.508)
    (uvia_min_drill 0.127)
    (pcb_text_width 0.3)
    (pcb_text_size 1.5 1.5)
    (mod_edge_width 0.15)
    (mod_text_size 1 1)
    (mod_text_width 0.15)
    (pad_size 5.08 2.54)
    (pad_drill 3.45)
    (pad_to_mask_clearance 0)
    (aux_axis_origin 0 0)
    (visible_elements 7FFFEB31)
    (pcbplotparams
      (layerselection 284196865)
      (usegerberextensions true)
      (excludeedgelayer false)
      (linewidth 0.150000)
      (plotframeref false)
      (viasonmask false)
      (mode 1)
      (useauxorigin false)
      (hpglpennumber 1)
      (hpglpenspeed 20)
      (hpglpendiameter 15)
      (hpglpenoverlay 2)
      (psnegative false)
      (psa4output false)
      (plotreference true)
      (plotvalue true)
      (plotothertext true)
      (plotinvisibletext false)
      (padsonsilk false)
      (subtractmaskfromsilk true)
      (outputformat 1)
      (mirror false)
      (drillshape 0)
      (scaleselection 1)
      (outputdirectory gerber/))
  )

  (net 0 "")
  (net 1 +3.3V)
  (net 2 +5V)
  (net 3 GND)
  (net 4 N-0000029)
  (net 5 N-0000036)
  (net 6 N-0000037)
  (net 7 N-0000038)
  (net 8 N-0000039)
  (net 9 N-0000040)
  (net 10 N-0000041)
  (net 11 N-0000043)
  (net 12 N-0000044)
  (net 13 N-0000045)
  (net 14 N-0000047)
  (net 15 N-0000048)
  (net 16 N-0000049)
  (net 17 N-0000050)
  (net 18 N-0000051)
  (net 19 N-0000052)
  (net 20 N-0000053)
  (net 21 N-0000055)
  (net 22 N-0000056)
  (net 23 N-0000057)
  (net 24 N-0000059)
  (net 25 N-0000062)
  (net 26 N-0000063)
  (net 27 N-0000064)
  (net 28 N-0000065)
  (net 29 N-0000066)
  (net 30 N-0000067)
  (net 31 N-0000068)
  (net 32 N-0000074)
  (net 33 N-0000080)
  (net 34 N-0000081)
  (net 35 N-0000082)
  (net 36 N-0000083)
  (net 37 N-0000084)
  (net 38 N-0000085)
  (net 39 N-0000086)
  (net 40 N-0000087)
  (net 41 N-0000088)
  (net 42 N-0000089)
  (net 43 N-0000090)
  (net 44 RX)
  (net 45 SPARE_IO)
  (net 46 TX)
  (net 47 col1)
  (net 48 col10)
  (net 49 col11)
  (net 50 col12)
  (net 51 col1a)
  (net 52 col2)
  (net 53 col2a)
  (net 54 col3)
  (net 55 col4)
  (net 56 col5)
  (net 57 col6)
  (net 58 col7)
  (net 59 col8)
  (net 60 col9)
  (net 61 led1)
  (net 62 led2)
  (net 63 led3)
  (net 64 led4)
  (net 65 led5)
  (net 66 led6)
  (net 67 led7)
  (net 68 led8)
  (net 69 row1)
  (net 70 row2)
  (net 71 row3)
  (net 72 xled1)
  (net 73 xled2)
  (net 74 xled3)
  (net 75 xled4)
  (net 76 xled5)
  (net 77 xled6)
  (net 78 xled7)
  (net 79 xled8)

  (net_class Default "This is the default net class."
    (clearance 0.254)
    (trace_width 0.254)
    (via_dia 0.889)
    (via_drill 0.635)
    (uvia_dia 0.508)
    (uvia_drill 0.127)
    (add_net "")
    (add_net +3.3V)
    (add_net +5V)
    (add_net GND)
    (add_net N-0000029)
    (add_net N-0000036)
    (add_net N-0000037)
    (add_net N-0000038)
    (add_net N-0000039)
    (add_net N-0000040)
    (add_net N-0000041)
    (add_net N-0000043)
    (add_net N-0000044)
    (add_net N-0000045)
    (add_net N-0000047)
    (add_net N-0000048)
    (add_net N-0000049)
    (add_net N-0000050)
    (add_net N-0000051)
    (add_net N-0000052)
    (add_net N-0000053)
    (add_net N-0000055)
    (add_net N-0000056)
    (add_net N-0000057)
    (add_net N-0000059)
    (add_net N-0000062)
    (add_net N-0000063)
    (add_net N-0000064)
    (add_net N-0000065)
    (add_net N-0000066)
    (add_net N-0000067)
    (add_net N-0000068)
    (add_net N-0000074)
    (add_net N-0000080)
    (add_net N-0000081)
    (add_net N-0000082)
    (add_net N-0000083)
    (add_net N-0000084)
    (add_net N-0000085)
    (add_net N-0000086)
    (add_net N-0000087)
    (add_net N-0000088)
    (add_net N-0000089)
    (add_net N-0000090)
    (add_net RX)
    (add_net SPARE_IO)
    (add_net TX)
    (add_net col1)
    (add_net col10)
    (add_net col11)
    (add_net col12)
    (add_net col1a)
    (add_net col2)
    (add_net col2a)
    (add_net col3)
    (add_net col4)
    (add_net col5)
    (add_net col6)
    (add_net col7)
    (add_net col8)
    (add_net col9)
    (add_net led1)
    (add_net led2)
    (add_net led3)
    (add_net led4)
    (add_net led5)
    (add_net led6)
    (add_net led7)
    (add_net led8)
    (add_net row1)
    (add_net row2)
    (add_net row3)
    (add_net xled1)
    (add_net xled2)
    (add_net xled3)
    (add_net xled4)
    (add_net xled5)
    (add_net xled6)
    (add_net xled7)
    (add_net xled8)
  )

  (module D3 (layer B.Cu) (tedit 5551184A) (tstamp 54BD7076)
    (at 219 117)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54BD85A3)
    (fp_text reference DZ1 (at 0 0) (layer B.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value ZENER (at 0 0) (layer B.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.048 0) (end 3.048 0) (layer B.SilkS) (width 0.3048))
    (fp_line (start 3.81 0) (end 3.048 0) (layer B.SilkS) (width 0.3048))
    (fp_line (start -3.048 0) (end -3.81 0) (layer B.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 2 +5V)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 2 +5V)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17F96)
    (at 57.92 102.94 90)
    (descr "Resitance 3 pas")
    (tags R)
    (path /54908374)
    (autoplace_cost180 10)
    (fp_text reference R9 (at 0 -0.127 90) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 90) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 19 N-0000052)
    )
    (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 60 col9)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17F87)
    (at 37.6 102.94 270)
    (descr "Resitance 3 pas")
    (tags R)
    (path /5490833D)
    (autoplace_cost180 10)
    (fp_text reference R1 (at 0 -0.127 270) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 270) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 47 col1)
    )
    (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 46 TX)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17F67)
    (at 40.14 102.94 270)
    (descr "Resitance 3 pas")
    (tags R)
    (path /5490834A)
    (autoplace_cost180 10)
    (fp_text reference R2 (at 0 -0.127 270) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 270) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 52 col2)
    )
    (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 44 RX)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17C46)
    (at 42.68 102.94 270)
    (descr "Resitance 3 pas")
    (tags R)
    (path /54908350)
    (autoplace_cost180 10)
    (fp_text reference R3 (at 0 -0.127 270) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 270) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 54 col3)
    )
    (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 20 N-0000053)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17C54)
    (at 45.22 102.94 270)
    (descr "Resitance 3 pas")
    (tags R)
    (path /54908356)
    (autoplace_cost180 10)
    (fp_text reference R4 (at 0 -0.127 270) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 270) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 55 col4)
    )
    (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 17 N-0000050)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17C62)
    (at 47.76 102.94 270)
    (descr "Resitance 3 pas")
    (tags R)
    (path /5490835C)
    (autoplace_cost180 10)
    (fp_text reference R5 (at 0 -0.127 270) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 270) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 56 col5)
    )
    (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 16 N-0000049)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17C70)
    (at 50.3 102.94 270)
    (descr "Resitance 3 pas")
    (tags R)
    (path /54908362)
    (autoplace_cost180 10)
    (fp_text reference R6 (at 0 -0.127 270) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 270) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 57 col6)
    )
    (pad 2 thru_hole circle (at 3.81 0 270) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 5 N-0000036)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17C7E)
    (at 52.84 102.94 90)
    (descr "Resitance 3 pas")
    (tags R)
    (path /54908368)
    (autoplace_cost180 10)
    (fp_text reference R7 (at 0 -0.127 90) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 90) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 9 N-0000040)
    )
    (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 58 col7)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17C8C)
    (at 55.38 102.94 90)
    (descr "Resitance 3 pas")
    (tags R)
    (path /5490836E)
    (autoplace_cost180 10)
    (fp_text reference R8 (at 0 -0.127 90) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 90) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 18 N-0000051)
    )
    (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 59 col8)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B1C0BD)
    (at 60.46 102.94 90)
    (descr "Resitance 3 pas")
    (tags R)
    (path /5490837A)
    (autoplace_cost180 10)
    (fp_text reference R10 (at 0 -0.127 90) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 90) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 6 N-0000037)
    )
    (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 48 col10)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17CA8)
    (at 63 102.94 90)
    (descr "Resitance 3 pas")
    (tags R)
    (path /54908380)
    (autoplace_cost180 10)
    (fp_text reference R11 (at 0 -0.127 90) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 90) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 8 N-0000039)
    )
    (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 49 col11)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer B.Cu) (tedit 4E4C0E65) (tstamp 54B17CB6)
    (at 65.54 102.94 90)
    (descr "Resitance 3 pas")
    (tags R)
    (path /54908386)
    (autoplace_cost180 10)
    (fp_text reference R12 (at 0 -0.127 90) (layer B.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_text value 390 (at 0 -0.127 90) (layer B.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end -3.302 1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end -3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end 3.302 -1.016) (layer B.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end 3.302 0) (layer B.SilkS) (width 0.2032))
    (fp_line (start -3.302 0.508) (end -2.794 1.016) (layer B.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 15 N-0000048)
    )
    (pad 2 thru_hole circle (at 3.81 0 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 50 col12)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer F.Cu) (tedit 4E4C0E65) (tstamp 54B17CC4)
    (at 78.9 133.08)
    (descr "Resitance 3 pas")
    (tags R)
    (path /5490838C)
    (autoplace_cost180 10)
    (fp_text reference R_ROW1 (at 0 0.127) (layer F.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_text value 1K (at 0 0.127) (layer F.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 7 N-0000038)
    )
    (pad 2 thru_hole circle (at 3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer F.Cu) (tedit 4E4C0E65) (tstamp 54B17CD2)
    (at 18.75 129.5 180)
    (descr "Resitance 3 pas")
    (tags R)
    (path /5490839E)
    (autoplace_cost180 10)
    (fp_text reference R_ROW2 (at 0 0.127 180) (layer F.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_text value 1K (at 0 0.127 180) (layer F.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0 180) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 14 N-0000047)
    )
    (pad 2 thru_hole circle (at 3.81 0 180) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 70 row2)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer F.Cu) (tedit 4E4C0E65) (tstamp 54B17CE0)
    (at 218.6 133.08)
    (descr "Resitance 3 pas")
    (tags R)
    (path /549083A4)
    (autoplace_cost180 10)
    (fp_text reference R_ROW3 (at 0 0.127) (layer F.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_text value 1K (at 0 0.127) (layer F.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 10 N-0000041)
    )
    (pad 2 thru_hole circle (at 3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module DIP-18__300 (layer B.Cu) (tedit 200000) (tstamp 54B17CFD)
    (at 219.05 100.97 90)
    (descr "8 pins DIL package, round pads")
    (path /54B17386)
    (fp_text reference P2 (at -7.62 1.27 90) (layer B.SilkS)
      (effects (font (size 1.778 1.143) (thickness 0.3048)) (justify mirror))
    )
    (fp_text value UDN2981A (at 5.08 -1.27 90) (layer B.SilkS)
      (effects (font (size 1.778 1.143) (thickness 0.3048)) (justify mirror))
    )
    (fp_line (start -12.7 1.27) (end -11.43 1.27) (layer B.SilkS) (width 0.381))
    (fp_line (start -11.43 1.27) (end -11.43 -1.27) (layer B.SilkS) (width 0.381))
    (fp_line (start -11.43 -1.27) (end -12.7 -1.27) (layer B.SilkS) (width 0.381))
    (fp_line (start -12.7 2.54) (end 12.7 2.54) (layer B.SilkS) (width 0.381))
    (fp_line (start 12.7 2.54) (end 12.7 -2.54) (layer B.SilkS) (width 0.381))
    (fp_line (start 12.7 -2.54) (end -12.7 -2.54) (layer B.SilkS) (width 0.381))
    (fp_line (start -12.7 -2.54) (end -12.7 2.54) (layer B.SilkS) (width 0.381))
    (pad 1 thru_hole rect (at -10.16 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 72 xled1)
    )
    (pad 2 thru_hole circle (at -7.62 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 73 xled2)
    )
    (pad 3 thru_hole circle (at -5.08 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 74 xled3)
    )
    (pad 4 thru_hole circle (at -2.54 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 75 xled4)
    )
    (pad 5 thru_hole circle (at 0 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 76 xled5)
    )
    (pad 6 thru_hole circle (at 2.54 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 77 xled6)
    )
    (pad 7 thru_hole circle (at 5.08 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 78 xled7)
    )
    (pad 8 thru_hole circle (at 7.62 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 79 xled8)
    )
    (pad 9 thru_hole circle (at 10.16 -3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 2 +5V)
    )
    (pad 10 thru_hole circle (at 10.16 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad 11 thru_hole circle (at 7.62 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 68 led8)
    )
    (pad 12 thru_hole circle (at 5.08 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 67 led7)
    )
    (pad 13 thru_hole circle (at 2.54 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 66 led6)
    )
    (pad 14 thru_hole circle (at 0 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 65 led5)
    )
    (pad 15 thru_hole circle (at -2.54 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 64 led4)
    )
    (pad 16 thru_hole circle (at -5.08 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 63 led3)
    )
    (pad 17 thru_hole circle (at -7.62 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 62 led2)
    )
    (pad 18 thru_hole circle (at -10.16 3.81 90) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask B.SilkS)
      (net 61 led1)
    )
    (model dil/dil_18.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module 1pin (layer F.Cu) (tedit 200000) (tstamp 54B1C854)
    (at 13.5 68)
    (descr "module 1 pin (ou trou mecanique de percage)")
    (tags DEV)
    (path /54B1CC4A)
    (fp_text reference M1 (at 0 -3.048) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_text value M (at 0 2.794) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381))
    (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module 1pin (layer F.Cu) (tedit 200000) (tstamp 554E4F5F)
    (at 13.5 159)
    (descr "module 1 pin (ou trou mecanique de percage)")
    (tags DEV)
    (path /54B1CC76)
    (fp_text reference M2 (at 0 -3.048) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_text value M (at 0 2.794) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381))
    (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module 1pin (layer F.Cu) (tedit 200000) (tstamp 54B1C860)
    (at 284.5 68)
    (descr "module 1 pin (ou trou mecanique de percage)")
    (tags DEV)
    (path /54B1CC7C)
    (fp_text reference M3 (at 0 -3.048) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_text value M (at 0 2.794) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381))
    (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module 1pin (layer F.Cu) (tedit 200000) (tstamp 54B1C866)
    (at 285.5 159)
    (descr "module 1 pin (ou trou mecanique de percage)")
    (tags DEV)
    (path /54B1CC82)
    (fp_text reference M4 (at 0 -3.048) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_text value M (at 0 2.794) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381))
    (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17F78)
    (at 249 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070DB)
    (fp_text reference D23 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 29 N-0000066)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D1D)
    (at 259 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070E1)
    (fp_text reference D24 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 30 N-0000067)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D2D)
    (at 239 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070D5)
    (fp_text reference D22 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 28 N-0000065)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D3D)
    (at 269 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070E7)
    (fp_text reference D25 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 31 N-0000068)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D4D)
    (at 279 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070ED)
    (fp_text reference D26 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 24 N-0000059)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D5D)
    (at 139 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905640)
    (fp_text reference D12 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 38 N-0000085)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D6D)
    (at 39 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /5490504C)
    (fp_text reference D2 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 11 N-0000043)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D7D)
    (at 49 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905056)
    (fp_text reference D3 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 13 N-0000045)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D8D)
    (at 59 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /5490505E)
    (fp_text reference D4 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 23 N-0000057)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17D9D)
    (at 69 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905068)
    (fp_text reference D5 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 22 N-0000056)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17DAD)
    (at 79 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /5490506E)
    (fp_text reference D6 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 21 N-0000055)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17DBD)
    (at 89 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549055F9)
    (fp_text reference D7 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 32 N-0000074)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17DCD)
    (at 99 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549055FF)
    (fp_text reference D8 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 34 N-0000081)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17DDD)
    (at 109 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905605)
    (fp_text reference D9 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 35 N-0000082)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17DED)
    (at 119 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /5490560B)
    (fp_text reference D10 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 36 N-0000083)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17DFD)
    (at 129 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905611)
    (fp_text reference D11 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 37 N-0000084)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E0D)
    (at 29 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54904DF0)
    (fp_text reference D1 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 12 N-0000044)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E1D)
    (at 149 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905646)
    (fp_text reference D13 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 39 N-0000086)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E2D)
    (at 159 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /5490564C)
    (fp_text reference D14 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 40 N-0000087)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E3D)
    (at 169 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905652)
    (fp_text reference D15 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 41 N-0000088)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E4D)
    (at 179 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905658)
    (fp_text reference D16 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 33 N-0000080)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E5D)
    (at 189 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /5490565E)
    (fp_text reference D17 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 42 N-0000089)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 49 col11)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E6D)
    (at 199 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /54905664)
    (fp_text reference D18 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 43 N-0000090)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 50 col12)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E7D)
    (at 209 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070C3)
    (fp_text reference D19 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 25 N-0000062)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E8D)
    (at 219 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070C9)
    (fp_text reference D20 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 26 N-0000063)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module D2 (layer F.Cu) (tedit 54B29F05) (tstamp 54B17E9D)
    (at 229 136.5)
    (descr "Diode 3 pas")
    (tags "DIODE DEV")
    (path /549070CF)
    (fp_text reference D21 (at 0 -0.508) (layer F.SilkS)
      (effects (font (size 0.25 0.25) (thickness 0.05)))
    )
    (fp_text value 1N4148 (at -0.508 0.508) (layer F.SilkS) hide
      (effects (font (size 0.381 0.381) (thickness 0.0762)))
    )
    (fp_line (start -2.032 1.016) (end 2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.794 0) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 0) (end 2.032 -1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 -1.016) (end -2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.794 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start -2.032 0) (end -2.032 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 2.032 1.016) (end 2.032 0) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.524 -1.016) (end 1.524 1.016) (layer F.SilkS) (width 0.3048))
    (fp_line (start 1.27 1.016) (end 1.27 -1.016) (layer F.SilkS) (width 0.3048))
    (pad 2 thru_hole rect (at 3.556 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 27 N-0000064)
    )
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/diode.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module RASPI_BPLUS_MIRRORED (layer B.Cu) (tedit 54BD7BC3) (tstamp 54B1C6FA)
    (at 64 124 180)
    (descr "Double rangee de contacts 2 x 12 pins")
    (tags CONN)
    (path /548F13F7)
    (fp_text reference P1 (at 0 3.81 180) (layer B.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.27432)) (justify mirror))
    )
    (fp_text value RASPI_MODEL_B_PLUS_GPIO (at 0 -3.81 180) (layer B.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.2032)) (justify mirror))
    )
    (fp_text user ETH (at 49.53 43.18 450) (layer B.SilkS)
      (effects (font (size 1 1) (thickness 0.15)) (justify mirror))
    )
    (fp_line (start 48.768 49.022) (end 53.594 49.022) (layer B.SilkS) (width 0.15))
    (fp_line (start 53.594 49.022) (end 53.594 38.354) (layer B.SilkS) (width 0.15))
    (fp_line (start 53.594 38.354) (end 49.784 38.354) (layer B.SilkS) (width 0.15))
    (fp_text user "GPIO and mount holes exact, port placement approx." (at 8 40.5 180) (layer B.SilkS)
      (effects (font (size 1 1) (thickness 0.15)) (justify mirror))
    )
    (fp_text user "RASPI B PLUS (MIRROR IMAGE)" (at 7.5 43 180) (layer B.SilkS)
      (effects (font (size 1 1) (thickness 0.15)) (justify mirror))
    )
    (fp_text user microUSB (at -19 47 180) (layer B.SilkS)
      (effects (font (size 1 1) (thickness 0.15)) (justify mirror))
    )
    (fp_line (start -22 49.008) (end -22 52.508) (layer B.SilkS) (width 0.15))
    (fp_line (start -16 49.008) (end -16 52.508) (layer B.SilkS) (width 0.15))
    (fp_text user HDMI (at 0 47 180) (layer B.SilkS)
      (effects (font (size 1 1) (thickness 0.15)) (justify mirror))
    )
    (fp_line (start -7 48.5) (end -7 52.5) (layer B.SilkS) (width 0.15))
    (fp_line (start 6 48.5) (end 6 52.5) (layer B.SilkS) (width 0.15))
    (fp_text user USB (at 49.5 3.5 450) (layer B.SilkS)
      (effects (font (size 1 1) (thickness 0.15)) (justify mirror))
    )
    (fp_text user USB (at 49.5 20.5 450) (layer B.SilkS)
      (effects (font (size 1 1) (thickness 0.15)) (justify mirror))
    )
    (fp_line (start 49.5 11.032) (end 54 11.032) (layer B.SilkS) (width 0.15))
    (fp_line (start 54 11.032) (end 54 0.032) (layer B.SilkS) (width 0.15))
    (fp_line (start 54 0.032) (end 50 0.032) (layer B.SilkS) (width 0.15))
    (fp_line (start 49.5 28.032) (end 54 28.032) (layer B.SilkS) (width 0.15))
    (fp_line (start 54 28.032) (end 54 16.532) (layer B.SilkS) (width 0.15))
    (fp_line (start 54 16.532) (end 49.5 16.532) (layer B.SilkS) (width 0.15))
    (fp_line (start -32.5 -3.5) (end 52.5 -3.5) (layer B.SilkS) (width 0.15))
    (fp_line (start 52.5 52.5) (end 52.5 -3.5) (layer B.SilkS) (width 0.15))
    (fp_line (start 52.5 52.5) (end 32 52.5) (layer B.SilkS) (width 0.15))
    (fp_line (start -32.5 52.5) (end -32.5 -3.5) (layer B.SilkS) (width 0.15))
    (fp_line (start -32.5 52.5) (end 32.5 52.5) (layer B.SilkS) (width 0.15))
    (fp_line (start 25.4 -2.54) (end -25.4 -2.54) (layer B.SilkS) (width 0.3048))
    (fp_line (start 25.4 2.54) (end -25.4 2.54) (layer B.SilkS) (width 0.3048))
    (fp_line (start 25.4 2.54) (end 25.4 -2.54) (layer B.SilkS) (width 0.3048))
    (fp_line (start -25.4 2.54) (end -25.4 -2.54) (layer B.SilkS) (width 0.3048))
    (pad 1 thru_hole rect (at -24.13 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 1 +3.3V)
    )
    (pad 2 thru_hole circle (at -24.13 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 2 +5V)
    )
    (pad 11 thru_hole circle (at -11.43 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 14 N-0000047)
    )
    (pad 4 thru_hole circle (at -21.59 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 2 +5V)
    )
    (pad 13 thru_hole circle (at -8.89 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 79 xled8)
    )
    (pad 6 thru_hole circle (at -19.05 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad 15 thru_hole circle (at -6.35 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 74 xled3)
    )
    (pad 8 thru_hole circle (at -16.51 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 46 TX)
    )
    (pad 17 thru_hole circle (at -3.81 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 10 thru_hole circle (at -13.97 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 44 RX)
    )
    (pad 19 thru_hole circle (at -1.27 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 19 N-0000052)
    )
    (pad 12 thru_hole circle (at -11.43 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 10 N-0000041)
    )
    (pad 21 thru_hole circle (at 1.27 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 18 N-0000051)
    )
    (pad 14 thru_hole circle (at -8.89 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 23 thru_hole circle (at 3.81 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 6 N-0000037)
    )
    (pad 16 thru_hole circle (at -6.35 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 75 xled4)
    )
    (pad 25 thru_hole circle (at 6.35 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 18 thru_hole circle (at -3.81 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 76 xled5)
    )
    (pad 27 thru_hole circle (at 8.89 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 20 thru_hole circle (at -1.27 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad 29 thru_hole circle (at 11.43 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 17 N-0000050)
    )
    (pad 22 thru_hole circle (at 1.27 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 77 xled6)
    )
    (pad 31 thru_hole circle (at 13.97 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 16 N-0000049)
    )
    (pad 24 thru_hole circle (at 3.81 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 9 N-0000040)
    )
    (pad 26 thru_hole circle (at 6.35 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 5 N-0000036)
    )
    (pad 33 thru_hole circle (at 16.51 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 15 N-0000048)
    )
    (pad 28 thru_hole circle (at 8.89 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 32 thru_hole circle (at 13.97 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 8 N-0000039)
    )
    (pad 34 thru_hole circle (at 16.51 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 36 thru_hole circle (at 19.05 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 7 N-0000038)
    )
    (pad 38 thru_hole circle (at 21.59 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 72 xled1)
    )
    (pad 35 thru_hole circle (at 19.05 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 45 SPARE_IO)
    )
    (pad 37 thru_hole circle (at 21.59 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 78 xled7)
    )
    (pad 3 thru_hole circle (at -21.59 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 51 col1a)
    )
    (pad 5 thru_hole circle (at -19.05 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 53 col2a)
    )
    (pad 7 thru_hole circle (at -16.51 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 20 N-0000053)
    )
    (pad 9 thru_hole circle (at -13.97 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad 39 thru_hole circle (at 24.13 1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad 40 thru_hole circle (at 24.13 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 73 xled2)
    )
    (pad 30 thru_hole circle (at 11.43 -1.27 180) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad H2 thru_hole circle (at -29 0 180) (size 5.7 5.7) (drill 2.75)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad H3 thru_hole circle (at 29 0 180) (size 5.7 5.7) (drill 2.75)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad H4 thru_hole circle (at 29 49 180) (size 5.7 5.7) (drill 2.75)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad H1 thru_hole circle (at -29 49 180) (size 5.7 5.7) (drill 2.75)
      (layers *.Cu *.Mask B.SilkS)
    )
    (model pin_array/pins_array_20x2.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module 1pin (layer F.Cu) (tedit 200000) (tstamp 54BD0940)
    (at 208 68)
    (descr "module 1 pin (ou trou mecanique de percage)")
    (tags DEV)
    (path /54BD36C6)
    (fp_text reference M5 (at 0 -3.048) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_text value M (at 0 2.794) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381))
    (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module 1pin (layer F.Cu) (tedit 200000) (tstamp 54BD0946)
    (at 284.5 132)
    (descr "module 1 pin (ou trou mecanique de percage)")
    (tags DEV)
    (path /54BD36CC)
    (fp_text reference M6 (at 0 -3.048) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_text value M (at 0 2.794) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381))
    (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module 1pin (layer F.Cu) (tedit 200000) (tstamp 54BD094C)
    (at 208 132)
    (descr "module 1 pin (ou trou mecanique de percage)")
    (tags DEV)
    (path /54BD36D2)
    (fp_text reference M7 (at 0 -3.048) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_text value M (at 0 2.794) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.254)))
    )
    (fp_circle (center 0 0) (end 0 -2.286) (layer F.SilkS) (width 0.381))
    (pad 1 thru_hole circle (at 0 0) (size 4.064 4.064) (drill 3.048)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F22E4)
    (at 169 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5B2)
    (fp_text reference DMB9 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F22CB)
    (at 179 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5B8)
    (fp_text reference DMB10 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F22B2)
    (at 189 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5BE)
    (fp_text reference DMB11 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 49 col11)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2299)
    (at 199 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5C4)
    (fp_text reference DMB12 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 50 col12)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2280)
    (at 89 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5CC)
    (fp_text reference DAC1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2267)
    (at 99 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5E5)
    (fp_text reference DAC2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F224E)
    (at 109 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5EB)
    (fp_text reference DAC3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2235)
    (at 119 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5F1)
    (fp_text reference DAC4 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F221C)
    (at 129 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5F7)
    (fp_text reference DAC5 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2203)
    (at 139 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5FD)
    (fp_text reference DAC6 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F21EA)
    (at 149 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF603)
    (fp_text reference DAC7 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F21D1)
    (at 159 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF609)
    (fp_text reference DAC8 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F21B8)
    (at 169 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF60F)
    (fp_text reference DAC9 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F219F)
    (at 179 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF615)
    (fp_text reference DAC10 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2186)
    (at 89 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF34A)
    (fp_text reference DPC1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F216D)
    (at 199 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF621)
    (fp_text reference DAC12 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 50 col12)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2154)
    (at 89 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF629)
    (fp_text reference DMQ1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F213B)
    (at 99 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF642)
    (fp_text reference DMQ2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2122)
    (at 109 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF648)
    (fp_text reference DMQ3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2109)
    (at 119 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF64E)
    (fp_text reference DMQ4 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F20F0)
    (at 129 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF654)
    (fp_text reference DMQ5 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F20D7)
    (at 139 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF65A)
    (fp_text reference DMQ6 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F20BE)
    (at 149 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF660)
    (fp_text reference DMQ7 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F20A5)
    (at 159 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF666)
    (fp_text reference DMQ8 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F208C)
    (at 169 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF66C)
    (fp_text reference DMQ9 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2073)
    (at 179 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF672)
    (fp_text reference DMQ10 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F205A)
    (at 189 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF678)
    (fp_text reference DMQ11 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 49 col11)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2041)
    (at 199 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF67E)
    (fp_text reference DMQ12 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 65 led5)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 50 col12)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F2028)
    (at 79 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF686)
    (fp_text reference DLINK1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 68 led8)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F200F)
    (at 29 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6A1)
    (fp_text reference DSC1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1FF6)
    (at 189 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF61B)
    (fp_text reference DAC11 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 64 led4)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 49 col11)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1FDD)
    (at 99 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF399)
    (fp_text reference DPC2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1FC4)
    (at 109 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3AC)
    (fp_text reference DPC3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1FAB)
    (at 119 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3B2)
    (fp_text reference DPC4 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1F92)
    (at 129 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3B8)
    (fp_text reference DPC5 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1F79)
    (at 139 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3BE)
    (fp_text reference DPC6 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1F60)
    (at 149 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3C4)
    (fp_text reference DPC7 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1F47)
    (at 159 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3CA)
    (fp_text reference DPC8 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1F2E)
    (at 169 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3D0)
    (fp_text reference DPC9 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1F15)
    (at 179 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3D6)
    (fp_text reference DPC10 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1EFC)
    (at 189 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3DC)
    (fp_text reference DPC11 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 49 col11)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1EE3)
    (at 199 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF3E2)
    (fp_text reference DPC12 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 61 led1)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 50 col12)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1ECA)
    (at 89 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF463)
    (fp_text reference DMA1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1EB1)
    (at 99 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF47C)
    (fp_text reference DMA2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1E98)
    (at 109 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF482)
    (fp_text reference DMA3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1E7F)
    (at 159 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5AC)
    (fp_text reference DMB8 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1E66)
    (at 129 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF48E)
    (fp_text reference DMA5 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1E4D)
    (at 139 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF494)
    (fp_text reference DMA6 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1E34)
    (at 149 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF49A)
    (fp_text reference DMA7 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1E1B)
    (at 159 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF4A0)
    (fp_text reference DMA8 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1E02)
    (at 169 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF4A6)
    (fp_text reference DMA9 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1DE9)
    (at 179 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF4AC)
    (fp_text reference DMA10 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1DD0)
    (at 189 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF4B2)
    (fp_text reference DMA11 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 49 col11)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1DB7)
    (at 199 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF4B8)
    (fp_text reference DMA12 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 50 col12)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1D9E)
    (at 89 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF56F)
    (fp_text reference DMB1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1D85)
    (at 99 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF588)
    (fp_text reference DMB2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1D6C)
    (at 109 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF58E)
    (fp_text reference DMB3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1D53)
    (at 119 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF594)
    (fp_text reference DMB4 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1D3A)
    (at 129 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF59A)
    (fp_text reference DMB5 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1D21)
    (at 139 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5A0)
    (fp_text reference DMB6 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1D08)
    (at 149 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF5A6)
    (fp_text reference DMB7 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 63 led3)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1CEF)
    (at 119 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF488)
    (fp_text reference DMA4 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 62 led2)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD77AA) (tstamp 548F1CD6)
    (at 279 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF843)
    (fp_text reference DRUN1 (at -9 -1.7) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD77A3) (tstamp 548F1CBD)
    (at 279 77.9)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF83D)
    (fp_text reference DPAUSE1 (at -8.5 -1.9) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD77A5) (tstamp 548F1CA4)
    (at 279 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF837)
    (fp_text reference DION1 (at -9.5 -2.1) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD778C) (tstamp 548F1C8B)
    (at 259 107.1)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF7E9)
    (fp_text reference DBREAK1 (at -8.5 -1.6) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7784) (tstamp 548F1C72)
    (at 259 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF7E3)
    (fp_text reference DCURAD1 (at -8.5 -1.8) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD777C) (tstamp 548F1C59)
    (at 259 92.5)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF7DD)
    (fp_text reference DWRDCT1 (at -8.5 -2) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 50 col12)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7779) (tstamp 548F1C40)
    (at 259 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF7D7)
    (fp_text reference DDEFER1 (at -8.5 -1.7) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 49 col11)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7795) (tstamp 548F1C27)
    (at 259 77.9)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF7D1)
    (fp_text reference DEXEC1 (at -9 -1.9) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7797) (tstamp 548F1C0E)
    (at 259 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF7CB)
    (fp_text reference DFETCH1 (at -9 -2.1) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD774F) (tstamp 548F1BF5)
    (at 239 121.7)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF789)
    (fp_text reference DOPR1 (at -7.5 -1.7) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD773D) (tstamp 548F1BDC)
    (at 239 114.4)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF783)
    (fp_text reference DIOT1 (at -7.5 -1.9) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7737) (tstamp 548F1BC3)
    (at 239 107.1)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF77D)
    (fp_text reference DJMP1 (at -7.5 -1.6) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD772E) (tstamp 548F1BAA)
    (at 239 99.8)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF777)
    (fp_text reference DJMS1 (at -8 -1.8) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7708) (tstamp 548F1B91)
    (at 239 92.5)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF741)
    (fp_text reference DDCA1 (at -8 -1.5) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1B78)
    (at 39 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6BA)
    (fp_text reference DSC2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 58 col7)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1B5F)
    (at 59 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6C6)
    (fp_text reference DSC4 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 60 col9)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1B46)
    (at 69 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6CC)
    (fp_text reference DSC5 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 48 col10)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1B14)
    (at 29 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6DA)
    (fp_text reference DDF1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 68 led8)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1AFB)
    (at 39 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6F3)
    (fp_text reference DDF2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 68 led8)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1AE2)
    (at 49 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6F9)
    (fp_text reference DDF3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 68 led8)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1AC9)
    (at 49 129)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF6C0)
    (fp_text reference DSC3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 59 col8)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7714) (tstamp 548F1AB0)
    (at 239 77.9)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF735)
    (fp_text reference DTAD1 (at -8 -1.9) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 52 col2)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7712) (tstamp 548F1A97)
    (at 239 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF728)
    (fp_text reference DAND1 (at -8 -2.1) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 47 col1)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD771B) (tstamp 548F1A7E)
    (at 239 85.2)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF73B)
    (fp_text reference DISZ1 (at -8 -1.7) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 66 led6)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 54 col3)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1A65)
    (at 69 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF71A)
    (fp_text reference DIF2 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 68 led8)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1A4C)
    (at 79 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF720)
    (fp_text reference DIF3 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 68 led8)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 57 col6)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-PDP (layer F.Cu) (tedit 54BD7621) (tstamp 548F1A33)
    (at 59 70.6)
    (descr "LED 3mm - Lead pitch 100mil (2,54mm)")
    (tags "LED led 3mm 3MM 100mil 2,54mm")
    (path /548EF701)
    (fp_text reference DIF1 (at 0 -5.5372) (layer F.SilkS)
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (fp_line (start -2.4 1.5) (end -2.4 -1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start 1.5 2.4) (end -1.5 2.4) (layer F.SilkS) (width 0.15))
    (fp_line (start 2.4 -1.5) (end 2.4 1.5) (layer F.SilkS) (width 0.15))
    (fp_line (start -1.5 -2.4) (end 1.5 -2.4) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 1.5) (end -1.5 2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 1.5) (end 2.4 1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start -1.5 -1.5) (end -2.4 -1.5) (angle 90) (layer F.SilkS) (width 0.15))
    (fp_arc (start 1.5 -1.5) (end 1.5 -2.4) (angle 90) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 68 led8)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F19EA)
    (at 79 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFC1B)
    (fp_text reference SW6 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value IF3 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 70 row2)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 21 N-0000055)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F19D9)
    (at 69 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFC15)
    (fp_text reference SW5 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value IF2 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 70 row2)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 22 N-0000056)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F19C8)
    (at 59 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFC0F)
    (fp_text reference SW4 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value IF1 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 70 row2)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 23 N-0000057)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F19B7)
    (at 49 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFC09)
    (fp_text reference SW3 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value DF3 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 70 row2)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 13 N-0000045)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F19A6)
    (at 39 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFC03)
    (fp_text reference SW2 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value DF2 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 70 row2)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 11 N-0000043)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1995)
    (at 29 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFBFD)
    (fp_text reference SW1 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value DF1 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 70 row2)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 12 N-0000044)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1984)
    (at 199 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB6C)
    (fp_text reference SW18 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR12 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 43 N-0000090)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1973)
    (at 189 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB66)
    (fp_text reference SW17 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR11 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 42 N-0000089)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1962)
    (at 169 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB5A)
    (fp_text reference SW15 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR9 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 41 N-0000088)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1951)
    (at 159 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB54)
    (fp_text reference SW14 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR8 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 40 N-0000087)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1940)
    (at 149 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB4E)
    (fp_text reference SW13 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR7 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 39 N-0000086)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F192F)
    (at 139 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB48)
    (fp_text reference SW12 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR6 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 38 N-0000085)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F191E)
    (at 209 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF86F)
    (fp_text reference SW19 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value START (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 25 N-0000062)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F190D)
    (at 219 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF87C)
    (fp_text reference SW20 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value LOAD_ADD (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 26 N-0000063)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F18FC)
    (at 179 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB60)
    (fp_text reference SW16 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR10 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 33 N-0000080)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F18EB)
    (at 239 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF888)
    (fp_text reference SW22 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value EXAM (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 28 N-0000065)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F18DA)
    (at 249 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF88E)
    (fp_text reference SW23 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value CONT (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 29 N-0000066)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F18C9)
    (at 259 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF894)
    (fp_text reference SW24 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value STOP (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 30 N-0000067)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F18B8)
    (at 269 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF89A)
    (fp_text reference SW25 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SING_STEP (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 31 N-0000068)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F18A7)
    (at 279 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF8A0)
    (fp_text reference SW26 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SING_INST (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 24 N-0000059)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1896)
    (at 89 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFAF8)
    (fp_text reference SW7 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR1 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 32 N-0000074)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1885)
    (at 99 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB27)
    (fp_text reference SW8 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR2 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 34 N-0000081)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1874)
    (at 109 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB2D)
    (fp_text reference SW9 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR3 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 35 N-0000082)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1863)
    (at 119 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB33)
    (fp_text reference SW10 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR4 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 36 N-0000083)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1852)
    (at 129 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EFB42)
    (fp_text reference SW11 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value SR5 (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 69 row1)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 37 N-0000084)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module SW_KND2_PDP2 (layer F.Cu) (tedit 554E2AD7) (tstamp 548F1841)
    (at 229 159.5)
    (descr "Switch inverseur")
    (tags "SWITCH DEV")
    (path /548EF882)
    (fp_text reference SW21 (at 3.429 -3.683 90) (layer F.SilkS) hide
      (effects (font (size 0.3 0.3) (thickness 0.05)))
    )
    (fp_text value DEP (at -0.05 -20.3) (layer F.SilkS)
      (effects (font (size 1.2 1.2) (thickness 0.2032)))
    )
    (fp_line (start -4.75 1.95) (end -4.75 -10.35) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 1.95) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 1.958) (end 4.75 1.958) (layer F.SilkS) (width 0.15))
    (fp_line (start -4.75 -10.3) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end 4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -18.9) (end -4.75 -18.9) (layer F.SilkS) (width 0.15))
    (fp_line (start 4.75 -10.3) (end -4.75 -10.3) (layer F.SilkS) (width 0.15))
    (pad 1 thru_hole oval (at 0 0) (size 5.08 2.54) (drill oval 3.45 1.18)
      (layers *.Cu *.Mask F.SilkS)
      (net 71 row3)
    )
    (pad 2 thru_hole oval (at 0 -5.58) (size 5.08 2.54) (drill oval 3.45 1.15)
      (layers *.Cu *.Mask F.SilkS)
      (net 27 N-0000064)
    )
    (pad 3 thru_hole circle (at 0 -15) (size 4 4) (drill 3)
      (layers *.Cu *.Mask F.SilkS)
    )
  )

  (module R3 (layer F.Cu) (tedit 4E4C0E65) (tstamp 554E2BA1)
    (at 18.75 133)
    (descr "Resitance 3 pas")
    (tags R)
    (path /554E5219)
    (autoplace_cost180 10)
    (fp_text reference R_S1 (at 0 0.127) (layer F.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_text value 300 (at 0 0.127) (layer F.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 4 N-0000029)
    )
    (pad 2 thru_hole circle (at 3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 44 RX)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module R3 (layer F.Cu) (tedit 4E4C0E65) (tstamp 554E2BAF)
    (at 18.75 136.5)
    (descr "Resitance 3 pas")
    (tags R)
    (path /554E5233)
    (autoplace_cost180 10)
    (fp_text reference R_S2 (at 0 0.127) (layer F.SilkS) hide
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_text value 620 (at 0 0.127) (layer F.SilkS)
      (effects (font (size 1.397 1.27) (thickness 0.2032)))
    )
    (fp_line (start -3.81 0) (end -3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.81 0) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 0) (end 3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 -1.016) (end -3.302 -1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -1.016) (end -3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 1.016) (end 3.302 1.016) (layer F.SilkS) (width 0.2032))
    (fp_line (start 3.302 1.016) (end 3.302 0) (layer F.SilkS) (width 0.2032))
    (fp_line (start -3.302 -0.508) (end -2.794 -1.016) (layer F.SilkS) (width 0.2032))
    (pad 1 thru_hole circle (at -3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 3 GND)
    )
    (pad 2 thru_hole circle (at 3.81 0) (size 1.397 1.397) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 4 N-0000029)
    )
    (model discret/resistor.wrl
      (at (xyz 0 0 0))
      (scale (xyz 0.3 0.3 0.3))
      (rotate (xyz 0 0 0))
    )
  )

  (module PIN_ARRAY_4x1 (layer F.Cu) (tedit 4C10F42E) (tstamp 554E2BBB)
    (at 11.5 136 270)
    (descr "Double rangee de contacts 2 x 5 pins")
    (tags CONN)
    (path /554E5206)
    (fp_text reference P5 (at 0 -2.54 270) (layer F.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.2032)))
    )
    (fp_text value "SERIAL 5V TTL" (at 0 2.54 270) (layer F.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.2032)))
    )
    (fp_line (start 5.08 1.27) (end -5.08 1.27) (layer F.SilkS) (width 0.254))
    (fp_line (start 5.08 -1.27) (end -5.08 -1.27) (layer F.SilkS) (width 0.254))
    (fp_line (start -5.08 -1.27) (end -5.08 1.27) (layer F.SilkS) (width 0.254))
    (fp_line (start 5.08 1.27) (end 5.08 -1.27) (layer F.SilkS) (width 0.254))
    (pad 1 thru_hole rect (at -3.81 0 270) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask F.SilkS)
      (net 3 GND)
    )
    (pad 2 thru_hole circle (at -1.27 0 270) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask F.SilkS)
      (net 2 +5V)
    )
    (pad 3 thru_hole circle (at 1.27 0 270) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask F.SilkS)
      (net 4 N-0000029)
    )
    (pad 4 thru_hole circle (at 3.81 0 270) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask F.SilkS)
      (net 46 TX)
    )
    (model pin_array\pins_array_4x1.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module PIN_ARRAY_20X2 (layer B.Cu) (tedit 5031D84E) (tstamp 54BD2EE9)
    (at 253.9 130.05)
    (descr "Double rangee de contacts 2 x 12 pins")
    (tags CONN)
    (path /554E0D39)
    (fp_text reference P3 (at 0 3.81) (layer B.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.27432)) (justify mirror))
    )
    (fp_text value EXPANSION_20X2 (at 0 -3.81) (layer B.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.2032)) (justify mirror))
    )
    (fp_line (start 25.4 -2.54) (end -25.4 -2.54) (layer B.SilkS) (width 0.3048))
    (fp_line (start 25.4 2.54) (end -25.4 2.54) (layer B.SilkS) (width 0.3048))
    (fp_line (start 25.4 2.54) (end 25.4 -2.54) (layer B.SilkS) (width 0.3048))
    (fp_line (start -25.4 2.54) (end -25.4 -2.54) (layer B.SilkS) (width 0.3048))
    (pad 1 thru_hole rect (at -24.13 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 2 +5V)
    )
    (pad 2 thru_hole circle (at -24.13 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 2 +5V)
    )
    (pad 11 thru_hole circle (at -11.43 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 68 led8)
    )
    (pad 4 thru_hole circle (at -21.59 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 13 thru_hole circle (at -8.89 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 70 row2)
    )
    (pad 6 thru_hole circle (at -19.05 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 1 +3.3V)
    )
    (pad 15 thru_hole circle (at -6.35 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 45 SPARE_IO)
    )
    (pad 8 thru_hole circle (at -16.51 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad 17 thru_hole circle (at -3.81 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 47 col1)
    )
    (pad 10 thru_hole circle (at -13.97 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 67 led7)
    )
    (pad 19 thru_hole circle (at -1.27 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 52 col2)
    )
    (pad 12 thru_hole circle (at -11.43 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 68 led8)
    )
    (pad 21 thru_hole circle (at 1.27 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 54 col3)
    )
    (pad 14 thru_hole circle (at -8.89 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 70 row2)
    )
    (pad 23 thru_hole circle (at 3.81 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 55 col4)
    )
    (pad 16 thru_hole circle (at -6.35 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 45 SPARE_IO)
    )
    (pad 25 thru_hole circle (at 6.35 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 56 col5)
    )
    (pad 18 thru_hole circle (at -3.81 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 47 col1)
    )
    (pad 27 thru_hole circle (at 8.89 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 57 col6)
    )
    (pad 20 thru_hole circle (at -1.27 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 52 col2)
    )
    (pad 29 thru_hole circle (at 11.43 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 58 col7)
    )
    (pad 22 thru_hole circle (at 1.27 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 54 col3)
    )
    (pad 31 thru_hole circle (at 13.97 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 59 col8)
    )
    (pad 24 thru_hole circle (at 3.81 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 55 col4)
    )
    (pad 26 thru_hole circle (at 6.35 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 56 col5)
    )
    (pad 33 thru_hole circle (at 16.51 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 60 col9)
    )
    (pad 28 thru_hole circle (at 8.89 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 57 col6)
    )
    (pad 32 thru_hole circle (at 13.97 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 59 col8)
    )
    (pad 34 thru_hole circle (at 16.51 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 60 col9)
    )
    (pad 36 thru_hole circle (at 19.05 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 48 col10)
    )
    (pad 38 thru_hole circle (at 21.59 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 49 col11)
    )
    (pad 35 thru_hole circle (at 19.05 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 48 col10)
    )
    (pad 37 thru_hole circle (at 21.59 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 49 col11)
    )
    (pad 3 thru_hole circle (at -21.59 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
    )
    (pad 5 thru_hole circle (at -19.05 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 1 +3.3V)
    )
    (pad 7 thru_hole circle (at -16.51 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 3 GND)
    )
    (pad 9 thru_hole circle (at -13.97 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 67 led7)
    )
    (pad 39 thru_hole circle (at 24.13 -1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 50 col12)
    )
    (pad 40 thru_hole circle (at 24.13 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 50 col12)
    )
    (pad 30 thru_hole circle (at 11.43 1.27) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 58 col7)
    )
    (model pin_array/pins_array_20x2.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-StrEight (layer F.Cu) (tedit 554E561D) (tstamp 554E5741)
    (at 259 114.4)
    (descr LED)
    (tags LED)
    (path /554E5897)
    (fp_text reference DPAUSE2 (at 0 -5.5372) (layer F.SilkS) hide
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 55 col4)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module LED-3-StrEight (layer F.Cu) (tedit 554E561D) (tstamp 554E5747)
    (at 259 121.7)
    (descr LED)
    (tags LED)
    (path /554E589D)
    (fp_text reference DRUN2 (at 0 -5.5372) (layer F.SilkS) hide
      (effects (font (size 0.7 0.7) (thickness 0.025)))
    )
    (fp_text value LED (at 0 2.54) (layer F.SilkS) hide
      (effects (font (size 0.762 0.762) (thickness 0.0889)))
    )
    (pad 1 thru_hole circle (at -1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 67 led7)
    )
    (pad 2 thru_hole circle (at 1.27 0) (size 1.6764 1.6764) (drill 0.8128)
      (layers *.Cu *.Mask F.SilkS)
      (net 56 col5)
    )
    (model discret/leds/led3_vertical_verde.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module PIN_ARRAY_3X1 (layer B.Cu) (tedit 554F4504) (tstamp 554F4492)
    (at 64.3 111.8)
    (descr "Connecteur 3 pins")
    (tags "CONN DEV")
    (path /554F46DF)
    (fp_text reference J_COL1 (at -6.7 0) (layer B.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.1524)) (justify mirror))
    )
    (fp_text value CONN_3 (at 0 2.159) (layer B.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.1524)) (justify mirror))
    )
    (fp_line (start -3.81 -1.27) (end -3.81 1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start -3.81 1.27) (end 3.81 1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start 3.81 1.27) (end 3.81 -1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start 3.81 -1.27) (end -3.81 -1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start -1.27 1.27) (end -1.27 -1.27) (layer B.SilkS) (width 0.1524))
    (pad 1 thru_hole rect (at -2.54 0) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 51 col1a)
    )
    (pad 2 thru_hole circle (at 0 0) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 46 TX)
    )
    (pad 3 thru_hole circle (at 2.54 0) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 46 TX)
    )
    (model pin_array/pins_array_3x1.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (module PIN_ARRAY_3X1 (layer B.Cu) (tedit 554F4512) (tstamp 554F449E)
    (at 64.3 115.2)
    (descr "Connecteur 3 pins")
    (tags "CONN DEV")
    (path /554F46EE)
    (fp_text reference J_COL2 (at -6.7 0) (layer B.SilkS)
      (effects (font (size 1.016 1.016) (thickness 0.1524)) (justify mirror))
    )
    (fp_text value CONN_3 (at 0 2.159) (layer B.SilkS) hide
      (effects (font (size 1.016 1.016) (thickness 0.1524)) (justify mirror))
    )
    (fp_line (start -3.81 -1.27) (end -3.81 1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start -3.81 1.27) (end 3.81 1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start 3.81 1.27) (end 3.81 -1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start 3.81 -1.27) (end -3.81 -1.27) (layer B.SilkS) (width 0.1524))
    (fp_line (start -1.27 1.27) (end -1.27 -1.27) (layer B.SilkS) (width 0.1524))
    (pad 1 thru_hole rect (at -2.54 0) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 53 col2a)
    )
    (pad 2 thru_hole circle (at 0 0) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 44 RX)
    )
    (pad 3 thru_hole circle (at 2.54 0) (size 1.524 1.524) (drill 1.016)
      (layers *.Cu *.Mask B.SilkS)
      (net 44 RX)
    )
    (model pin_array/pins_array_3x1.wrl
      (at (xyz 0 0 0))
      (scale (xyz 1 1 1))
      (rotate (xyz 0 0 0))
    )
  )

  (gr_line (start 288.5 64) (end 9.5 64) (angle 90) (layer Edge.Cuts) (width 0.1))
  (gr_line (start 9.5 163) (end 288.5 163) (angle 90) (layer Edge.Cuts) (width 0.1))
  (gr_line (start 9.5 64) (end 9.5 163) (angle 90) (layer Edge.Cuts) (width 0.1))
  (gr_line (start 65.1002 115.2144) (end 65.9892 115.2144) (angle 90) (layer B.SilkS) (width 0.2))
  (gr_line (start 65.1002 111.8108) (end 65.9892 111.8108) (angle 90) (layer B.SilkS) (width 0.2))
  (gr_text "2 optional LEDs for \nStraight Eight only" (at 262.5598 118.4148 90) (layer B.SilkS)
    (effects (font (size 0.6 0.6) (thickness 0.1)) (justify mirror))
  )
  (gr_line (start 259.0038 121.7168) (end 258.953 121.7168) (angle 90) (layer B.SilkS) (width 0.2))
  (gr_line (start 261.5946 114.4524) (end 261.5946 121.793) (angle 90) (layer B.SilkS) (width 0.2))
  (gr_text "To enable serial port: mod RPi,\ncut traces 1-2 & jumper 2-3" (at 52.7304 112.9792) (layer B.SilkS)
    (effects (font (size 0.6 0.6) (thickness 0.1)) (justify mirror))
  )
  (gr_line (start 288.5 163) (end 288.5 64) (angle 90) (layer Edge.Cuts) (width 0.1))
  (gr_text "PiDP-8/I\nFront Panel" (at 275 95 90) (layer B.SilkS)
    (effects (font (size 3 3) (thickness 0.6)) (justify left mirror))
  )

  (segment (start 234.85 128.78) (end 234.85 131.32) (width 0.381) (layer B.Cu) (net 1))
  (segment (start 88.13 122.73) (end 89.3368 122.73) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 233.6431 127.5731) (end 234.85 128.78) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 204.418 127.5731) (end 233.6431 127.5731) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 201.1889 130.8022) (end 204.418 127.5731) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 137.7069 130.8022) (end 201.1889 130.8022) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 130.8107 123.906) (end 137.7069 130.8022) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 130.8107 122.4756) (end 130.8107 123.906) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 129.0368 120.7017) (end 130.8107 122.4756) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 91.3651 120.7017) (end 129.0368 120.7017) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 89.3368 122.73) (end 91.3651 120.7017) (width 0.381) (layer F.Cu) (net 1))
  (segment (start 215.19 117) (end 222.81 117) (width 0.254) (layer F.Cu) (net 2))
  (segment (start 216.7832 117) (end 215.19 117) (width 0.381) (layer B.Cu) (net 2))
  (segment (start 228.5632 128.78) (end 216.7832 117) (width 0.381) (layer B.Cu) (net 2))
  (segment (start 229.77 128.78) (end 228.5632 128.78) (width 0.381) (layer B.Cu) (net 2))
  (segment (start 229.77 131.32) (end 229.77 129.9868) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 229.77 128.78) (end 229.77 129.9868) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 88.13 125.27) (end 85.59 125.27) (width 0.381) (layer B.Cu) (net 2))
  (segment (start 76.13 134.73) (end 11.5 134.73) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 85.59 125.27) (end 76.13 134.73) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 86.9231 124.0631) (end 88.13 125.27) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 86.9231 121.744) (end 86.9231 124.0631) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 88.641 120.0261) (end 86.9231 121.744) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 137.9892 120.0261) (end 88.641 120.0261) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 138.4946 120.5315) (end 137.9892 120.0261) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 211.6585 120.5315) (end 138.4946 120.5315) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 215.19 117) (end 211.6585 120.5315) (width 0.381) (layer F.Cu) (net 2))
  (segment (start 216.7001 92.2701) (end 215.24 90.81) (width 0.254) (layer B.Cu) (net 2))
  (segment (start 222.81 117) (end 222.81 115.9202) (width 0.254) (layer B.Cu) (net 2))
  (segment (start 222.81 115.9202) (end 216.7001 109.8103) (width 0.254) (layer B.Cu) (net 2))
  (segment (start 216.7001 109.8103) (end 216.7001 92.2701) (width 0.254) (layer B.Cu) (net 2))
  (segment (start 11.5 132.19) (end 12.7068 132.19) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 36.4101 98.6598) (end 36.4101 120.6624) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 51.1529 83.917) (end 36.4101 98.6598) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 101.9637 83.917) (end 51.1529 83.917) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 110.0418 91.9951) (end 101.9637 83.917) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 221.6749 91.9951) (end 110.0418 91.9951) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 222.86 90.81) (end 221.6749 91.9951) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 25.466 120.6624) (end 36.4101 120.6624) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 13.9384 132.19) (end 25.466 120.6624) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 12.7068 132.19) (end 13.9384 132.19) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 53.7769 126.4769) (end 52.57 125.27) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 64.0631 126.4769) (end 53.7769 126.4769) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 65.27 125.27) (end 64.0631 126.4769) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 37.8024 120.6624) (end 39.87 122.73) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 36.4101 120.6624) (end 37.8024 120.6624) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 51.3 124) (end 52.57 125.27) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 41.14 124) (end 51.3 124) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 39.87 122.73) (end 41.14 124) (width 0.381) (layer F.Cu) (net 3))
  (segment (start 16.0929 135.3471) (end 14.94 136.5) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 16.0929 132.5232) (end 16.0929 135.3471) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 15.4053 131.8356) (end 16.0929 132.5232) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 13.0612 131.8356) (end 15.4053 131.8356) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 12.7068 132.19) (end 13.0612 131.8356) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 11.5 132.19) (end 12.7068 132.19) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 81.8243 126.4957) (end 83.05 125.27) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 80.0256 126.4957) (end 81.8243 126.4957) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 79.24 125.7101) (end 80.0256 126.4957) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 79.24 124) (end 77.97 122.73) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 79.24 125.7101) (end 79.24 124) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 66.4863 126.4863) (end 65.27 125.27) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 78.4638 126.4863) (end 66.4863 126.4863) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 79.24 125.7101) (end 78.4638 126.4863) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 237.39 131.32) (end 237.39 128.78) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 229.8356 97.7856) (end 222.86 90.81) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 229.8356 121.2256) (end 229.8356 97.7856) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 237.39 128.78) (end 229.8356 121.2256) (width 0.381) (layer B.Cu) (net 3))
  (segment (start 14.94 133.83) (end 14.94 133) (width 0.254) (layer B.Cu) (net 4))
  (segment (start 11.5 137.27) (end 14.94 133.83) (width 0.254) (layer B.Cu) (net 4))
  (segment (start 21.4481 137.6119) (end 22.56 136.5) (width 0.254) (layer F.Cu) (net 4))
  (segment (start 11.8419 137.6119) (end 21.4481 137.6119) (width 0.254) (layer F.Cu) (net 4))
  (segment (start 11.5 137.27) (end 11.8419 137.6119) (width 0.254) (layer F.Cu) (net 4))
  (segment (start 50.3 116.2723) (end 50.3 106.75) (width 0.254) (layer B.Cu) (net 5))
  (segment (start 56.38 122.3523) (end 50.3 116.2723) (width 0.254) (layer B.Cu) (net 5))
  (segment (start 56.38 124) (end 56.38 122.3523) (width 0.254) (layer B.Cu) (net 5))
  (segment (start 57.65 125.27) (end 56.38 124) (width 0.254) (layer B.Cu) (net 5))
  (segment (start 59.3736 105.6636) (end 60.46 106.75) (width 0.254) (layer B.Cu) (net 6))
  (segment (start 54.9319 105.6636) (end 59.3736 105.6636) (width 0.254) (layer B.Cu) (net 6))
  (segment (start 54.2629 106.3326) (end 54.9319 105.6636) (width 0.254) (layer B.Cu) (net 6))
  (segment (start 54.2629 116.8029) (end 54.2629 106.3326) (width 0.254) (layer B.Cu) (net 6))
  (segment (start 60.19 122.73) (end 54.2629 116.8029) (width 0.254) (layer B.Cu) (net 6))
  (segment (start 52.618 133.08) (end 75.09 133.08) (width 0.254) (layer B.Cu) (net 7))
  (segment (start 49 129.462) (end 52.618 133.08) (width 0.254) (layer B.Cu) (net 7))
  (segment (start 49 128.4389) (end 49 129.462) (width 0.254) (layer B.Cu) (net 7))
  (segment (start 45.8311 125.27) (end 49 128.4389) (width 0.254) (layer B.Cu) (net 7))
  (segment (start 44.95 125.27) (end 45.8311 125.27) (width 0.254) (layer B.Cu) (net 7))
  (segment (start 61.4039 105.1539) (end 63 106.75) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 50.3589 105.1539) (end 61.4039 105.1539) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 49.2201 106.2927) (end 50.3589 105.1539) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 49.2201 117.556) (end 49.2201 106.2927) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 53.7535 122.0894) (end 49.2201 117.556) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 53.7535 123.1633) (end 53.7535 122.0894) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 53.0434 123.8734) (end 53.7535 123.1633) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 51.4266 123.8734) (end 53.0434 123.8734) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 50.03 125.27) (end 51.4266 123.8734) (width 0.254) (layer B.Cu) (net 8))
  (segment (start 52.84 116.099) (end 52.84 106.75) (width 0.254) (layer B.Cu) (net 9))
  (segment (start 58.92 122.179) (end 52.84 116.099) (width 0.254) (layer B.Cu) (net 9))
  (segment (start 58.92 124) (end 58.92 122.179) (width 0.254) (layer B.Cu) (net 9))
  (segment (start 60.19 125.27) (end 58.92 124) (width 0.254) (layer B.Cu) (net 9))
  (segment (start 211.8529 133.08) (end 214.79 133.08) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 210.5187 134.4142) (end 211.8529 133.08) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 206.2707 134.4142) (end 210.5187 134.4142) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 203.2306 131.3741) (end 206.2707 134.4142) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 100.8747 131.3741) (end 203.2306 131.3741) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 99 129.4994) (end 100.8747 131.3741) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 99 128.4743) (end 99 129.4994) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 97.757 127.2313) (end 99 128.4743) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 88.4342 127.2313) (end 97.757 127.2313) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 86.86 125.6571) (end 88.4342 127.2313) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 86.86 124.9006) (end 86.86 125.6571) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 86.0806 124.1212) (end 86.86 124.9006) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 76.5788 124.1212) (end 86.0806 124.1212) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 75.43 125.27) (end 76.5788 124.1212) (width 0.254) (layer F.Cu) (net 10))
  (segment (start 42.556 148.7127) (end 42.556 136.5) (width 0.254) (layer F.Cu) (net 11))
  (segment (start 39 152.2687) (end 42.556 148.7127) (width 0.254) (layer F.Cu) (net 11))
  (segment (start 39 153.92) (end 39 152.2687) (width 0.254) (layer F.Cu) (net 11))
  (segment (start 32.556 148.7127) (end 32.556 136.5) (width 0.254) (layer B.Cu) (net 12))
  (segment (start 29 152.2687) (end 32.556 148.7127) (width 0.254) (layer B.Cu) (net 12))
  (segment (start 29 153.92) (end 29 152.2687) (width 0.254) (layer B.Cu) (net 12))
  (segment (start 52.556 148.7127) (end 52.556 136.5) (width 0.254) (layer B.Cu) (net 13))
  (segment (start 49 152.2687) (end 52.556 148.7127) (width 0.254) (layer B.Cu) (net 13))
  (segment (start 49 153.92) (end 49 152.2687) (width 0.254) (layer B.Cu) (net 13))
  (segment (start 24.8265 127.2335) (end 22.56 129.5) (width 0.254) (layer F.Cu) (net 14))
  (segment (start 67.4806 127.2335) (end 24.8265 127.2335) (width 0.254) (layer F.Cu) (net 14))
  (segment (start 69.08 125.6341) (end 67.4806 127.2335) (width 0.254) (layer F.Cu) (net 14))
  (segment (start 69.08 124.9232) (end 69.08 125.6341) (width 0.254) (layer F.Cu) (net 14))
  (segment (start 69.8766 124.1266) (end 69.08 124.9232) (width 0.254) (layer F.Cu) (net 14))
  (segment (start 74.0334 124.1266) (end 69.8766 124.1266) (width 0.254) (layer F.Cu) (net 14))
  (segment (start 75.43 122.73) (end 74.0334 124.1266) (width 0.254) (layer F.Cu) (net 14))
  (segment (start 47.5614 122.6586) (end 47.49 122.73) (width 0.254) (layer B.Cu) (net 15))
  (segment (start 47.5614 113.2398) (end 47.5614 122.6586) (width 0.254) (layer B.Cu) (net 15))
  (segment (start 41.5681 107.2465) (end 47.5614 113.2398) (width 0.254) (layer B.Cu) (net 15))
  (segment (start 41.5681 106.2783) (end 41.5681 107.2465) (width 0.254) (layer B.Cu) (net 15))
  (segment (start 43.2397 104.6067) (end 41.5681 106.2783) (width 0.254) (layer B.Cu) (net 15))
  (segment (start 63.3967 104.6067) (end 43.2397 104.6067) (width 0.254) (layer B.Cu) (net 15))
  (segment (start 65.54 106.75) (end 63.3967 104.6067) (width 0.254) (layer B.Cu) (net 15))
  (segment (start 46.6389 105.6289) (end 47.76 106.75) (width 0.254) (layer B.Cu) (net 16))
  (segment (start 44.7939 105.6289) (end 46.6389 105.6289) (width 0.254) (layer B.Cu) (net 16))
  (segment (start 44.1005 106.3223) (end 44.7939 105.6289) (width 0.254) (layer B.Cu) (net 16))
  (segment (start 44.1005 107.2817) (end 44.1005 106.3223) (width 0.254) (layer B.Cu) (net 16))
  (segment (start 48.0697 111.2509) (end 44.1005 107.2817) (width 0.254) (layer B.Cu) (net 16))
  (segment (start 48.0697 120.7697) (end 48.0697 111.2509) (width 0.254) (layer B.Cu) (net 16))
  (segment (start 50.03 122.73) (end 48.0697 120.7697) (width 0.254) (layer B.Cu) (net 16))
  (segment (start 48.5781 110.1081) (end 45.22 106.75) (width 0.254) (layer B.Cu) (net 17))
  (segment (start 48.5781 118.7381) (end 48.5781 110.1081) (width 0.254) (layer B.Cu) (net 17))
  (segment (start 52.57 122.73) (end 48.5781 118.7381) (width 0.254) (layer B.Cu) (net 17))
  (segment (start 58.7011 110.0711) (end 55.38 106.75) (width 0.254) (layer B.Cu) (net 18))
  (segment (start 58.7011 118.7011) (end 58.7011 110.0711) (width 0.254) (layer B.Cu) (net 18))
  (segment (start 62.73 122.73) (end 58.7011 118.7011) (width 0.254) (layer B.Cu) (net 18))
  (segment (start 59.4636 108.2936) (end 57.92 106.75) (width 0.254) (layer B.Cu) (net 19))
  (segment (start 59.4636 116.9236) (end 59.4636 108.2936) (width 0.254) (layer B.Cu) (net 19))
  (segment (start 65.27 122.73) (end 59.4636 116.9236) (width 0.254) (layer B.Cu) (net 19))
  (segment (start 79.0762 121.2962) (end 80.51 122.73) (width 0.254) (layer F.Cu) (net 20))
  (segment (start 49.6975 121.2962) (end 79.0762 121.2962) (width 0.254) (layer F.Cu) (net 20))
  (segment (start 42.68 114.2787) (end 49.6975 121.2962) (width 0.254) (layer F.Cu) (net 20))
  (segment (start 42.68 106.75) (end 42.68 114.2787) (width 0.254) (layer F.Cu) (net 20))
  (segment (start 82.556 148.7127) (end 82.556 136.5) (width 0.254) (layer B.Cu) (net 21))
  (segment (start 79 152.2687) (end 82.556 148.7127) (width 0.254) (layer B.Cu) (net 21))
  (segment (start 79 153.92) (end 79 152.2687) (width 0.254) (layer B.Cu) (net 21))
  (segment (start 72.556 148.7127) (end 72.556 136.5) (width 0.254) (layer B.Cu) (net 22))
  (segment (start 69 152.2687) (end 72.556 148.7127) (width 0.254) (layer B.Cu) (net 22))
  (segment (start 69 153.92) (end 69 152.2687) (width 0.254) (layer B.Cu) (net 22))
  (segment (start 62.556 148.7127) (end 62.556 136.5) (width 0.254) (layer B.Cu) (net 23))
  (segment (start 59 152.2687) (end 62.556 148.7127) (width 0.254) (layer B.Cu) (net 23))
  (segment (start 59 153.92) (end 59 152.2687) (width 0.254) (layer B.Cu) (net 23))
  (segment (start 282.556 148.7127) (end 282.556 136.5) (width 0.254) (layer F.Cu) (net 24))
  (segment (start 279 152.2687) (end 282.556 148.7127) (width 0.254) (layer F.Cu) (net 24))
  (segment (start 279 153.92) (end 279 152.2687) (width 0.254) (layer F.Cu) (net 24))
  (segment (start 212.556 148.7127) (end 212.556 136.5) (width 0.254) (layer B.Cu) (net 25))
  (segment (start 209 152.2687) (end 212.556 148.7127) (width 0.254) (layer B.Cu) (net 25))
  (segment (start 209 153.92) (end 209 152.2687) (width 0.254) (layer B.Cu) (net 25))
  (segment (start 222.556 148.7127) (end 222.556 136.5) (width 0.254) (layer B.Cu) (net 26))
  (segment (start 219 152.2687) (end 222.556 148.7127) (width 0.254) (layer B.Cu) (net 26))
  (segment (start 219 153.92) (end 219 152.2687) (width 0.254) (layer B.Cu) (net 26))
  (segment (start 232.556 148.7127) (end 232.556 136.5) (width 0.254) (layer F.Cu) (net 27))
  (segment (start 229 152.2687) (end 232.556 148.7127) (width 0.254) (layer F.Cu) (net 27))
  (segment (start 229 153.92) (end 229 152.2687) (width 0.254) (layer F.Cu) (net 27))
  (segment (start 242.556 148.7127) (end 242.556 136.5) (width 0.254) (layer B.Cu) (net 28))
  (segment (start 239 152.2687) (end 242.556 148.7127) (width 0.254) (layer B.Cu) (net 28))
  (segment (start 239 153.92) (end 239 152.2687) (width 0.254) (layer B.Cu) (net 28))
  (segment (start 252.556 148.7127) (end 252.556 136.5) (width 0.254) (layer B.Cu) (net 29))
  (segment (start 249 152.2687) (end 252.556 148.7127) (width 0.254) (layer B.Cu) (net 29))
  (segment (start 249 153.92) (end 249 152.2687) (width 0.254) (layer B.Cu) (net 29))
  (segment (start 262.556 148.7127) (end 262.556 136.5) (width 0.254) (layer B.Cu) (net 30))
  (segment (start 259 152.2687) (end 262.556 148.7127) (width 0.254) (layer B.Cu) (net 30))
  (segment (start 259 153.92) (end 259 152.2687) (width 0.254) (layer B.Cu) (net 30))
  (segment (start 272.556 148.7127) (end 272.556 136.5) (width 0.254) (layer B.Cu) (net 31))
  (segment (start 269 152.2687) (end 272.556 148.7127) (width 0.254) (layer B.Cu) (net 31))
  (segment (start 269 153.92) (end 269 152.2687) (width 0.254) (layer B.Cu) (net 31))
  (segment (start 92.556 148.7127) (end 92.556 136.5) (width 0.254) (layer B.Cu) (net 32))
  (segment (start 89 152.2687) (end 92.556 148.7127) (width 0.254) (layer B.Cu) (net 32))
  (segment (start 89 153.92) (end 89 152.2687) (width 0.254) (layer B.Cu) (net 32))
  (segment (start 182.556 148.7127) (end 182.556 136.5) (width 0.254) (layer B.Cu) (net 33))
  (segment (start 179 152.2687) (end 182.556 148.7127) (width 0.254) (layer B.Cu) (net 33))
  (segment (start 179 153.92) (end 179 152.2687) (width 0.254) (layer B.Cu) (net 33))
  (segment (start 102.556 148.7127) (end 102.556 136.5) (width 0.254) (layer B.Cu) (net 34))
  (segment (start 99 152.2687) (end 102.556 148.7127) (width 0.254) (layer B.Cu) (net 34))
  (segment (start 99 153.92) (end 99 152.2687) (width 0.254) (layer B.Cu) (net 34))
  (segment (start 112.556 148.7127) (end 112.556 136.5) (width 0.254) (layer B.Cu) (net 35))
  (segment (start 109 152.2687) (end 112.556 148.7127) (width 0.254) (layer B.Cu) (net 35))
  (segment (start 109 153.92) (end 109 152.2687) (width 0.254) (layer B.Cu) (net 35))
  (segment (start 122.556 148.7127) (end 122.556 136.5) (width 0.254) (layer B.Cu) (net 36))
  (segment (start 119 152.2687) (end 122.556 148.7127) (width 0.254) (layer B.Cu) (net 36))
  (segment (start 119 153.92) (end 119 152.2687) (width 0.254) (layer B.Cu) (net 36))
  (segment (start 129 153.92) (end 129 152.2687) (width 0.254) (layer B.Cu) (net 37))
  (segment (start 132.556 136.5) (end 132.556 137.5798) (width 0.254) (layer B.Cu) (net 37))
  (segment (start 132.556 148.7127) (end 132.556 137.5798) (width 0.254) (layer B.Cu) (net 37))
  (segment (start 129 152.2687) (end 132.556 148.7127) (width 0.254) (layer B.Cu) (net 37))
  (segment (start 142.556 148.7127) (end 142.556 136.5) (width 0.254) (layer F.Cu) (net 38))
  (segment (start 139 152.2687) (end 142.556 148.7127) (width 0.254) (layer F.Cu) (net 38))
  (segment (start 139 153.92) (end 139 152.2687) (width 0.254) (layer F.Cu) (net 38))
  (segment (start 152.556 148.7127) (end 152.556 136.5) (width 0.254) (layer B.Cu) (net 39))
  (segment (start 149 152.2687) (end 152.556 148.7127) (width 0.254) (layer B.Cu) (net 39))
  (segment (start 149 153.92) (end 149 152.2687) (width 0.254) (layer B.Cu) (net 39))
  (segment (start 162.556 148.7127) (end 162.556 136.5) (width 0.254) (layer F.Cu) (net 40))
  (segment (start 159 152.2687) (end 162.556 148.7127) (width 0.254) (layer F.Cu) (net 40))
  (segment (start 159 153.92) (end 159 152.2687) (width 0.254) (layer F.Cu) (net 40))
  (segment (start 172.556 148.7127) (end 172.556 136.5) (width 0.254) (layer F.Cu) (net 41))
  (segment (start 169 152.2687) (end 172.556 148.7127) (width 0.254) (layer F.Cu) (net 41))
  (segment (start 169 153.92) (end 169 152.2687) (width 0.254) (layer F.Cu) (net 41))
  (segment (start 192.556 148.7127) (end 192.556 136.5) (width 0.254) (layer B.Cu) (net 42))
  (segment (start 189 152.2687) (end 192.556 148.7127) (width 0.254) (layer B.Cu) (net 42))
  (segment (start 189 153.92) (end 189 152.2687) (width 0.254) (layer B.Cu) (net 42))
  (segment (start 202.556 148.7127) (end 202.556 136.5) (width 0.254) (layer B.Cu) (net 43))
  (segment (start 199 152.2687) (end 202.556 148.7127) (width 0.254) (layer B.Cu) (net 43))
  (segment (start 199 153.92) (end 199 152.2687) (width 0.254) (layer B.Cu) (net 43))
  (segment (start 64.3 115.2) (end 66.84 115.2) (width 0.254) (layer F.Cu) (net 44))
  (segment (start 42.7916 104.0984) (end 40.14 106.75) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 64.4354 104.0984) (end 42.7916 104.0984) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 66.62 106.283) (end 64.4354 104.0984) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 66.62 107.2192) (end 66.62 106.283) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 65.0924 108.7468) (end 66.62 107.2192) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 62.6625 108.7468) (end 65.0924 108.7468) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 60.6166 110.7927) (end 62.6625 108.7468) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 60.6166 112.7519) (end 60.6166 110.7927) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 61.9213 114.0566) (end 60.6166 112.7519) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 63.1566 114.0566) (end 61.9213 114.0566) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 64.3 115.2) (end 63.1566 114.0566) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 70.24 133) (end 22.56 133) (width 0.254) (layer F.Cu) (net 44))
  (segment (start 77.97 125.27) (end 70.24 133) (width 0.254) (layer F.Cu) (net 44))
  (segment (start 76.7 124) (end 77.97 125.27) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 66.84 115.2) (end 67.1787 114.8613) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 67.1787 114.8613) (end 73.2959 114.8613) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 73.2959 114.8613) (end 76.7 118.2654) (width 0.254) (layer B.Cu) (net 44))
  (segment (start 76.7 118.2654) (end 76.7 124) (width 0.254) (layer B.Cu) (net 44))
  (via (at 162.2826 127.0012) (size 0.889) (layers F.Cu B.Cu) (net 45))
  (segment (start 247.55 128.78) (end 247.55 131.32) (width 0.254) (layer F.Cu) (net 45))
  (segment (start 245.7712 127.0012) (end 162.2826 127.0012) (width 0.254) (layer F.Cu) (net 45))
  (segment (start 247.55 128.78) (end 245.7712 127.0012) (width 0.254) (layer F.Cu) (net 45))
  (segment (start 161.9792 126.6978) (end 162.2826 127.0012) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 98.254 126.6978) (end 161.9792 126.6978) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 92.6456 132.3062) (end 98.254 126.6978) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 85.7128 132.3062) (end 92.6456 132.3062) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 84.8598 131.4532) (end 85.7128 132.3062) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 72.1583 131.4532) (end 84.8598 131.4532) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 71.867 131.7445) (end 72.1583 131.4532) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 54.8876 131.7445) (end 71.867 131.7445) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 48.76 125.6169) (end 54.8876 131.7445) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 48.76 124.9205) (end 48.76 125.6169) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 47.9661 124.1266) (end 48.76 124.9205) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 46.3466 124.1266) (end 47.9661 124.1266) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 44.95 122.73) (end 46.3466 124.1266) (width 0.254) (layer B.Cu) (net 45))
  (segment (start 64.3 111.8) (end 66.84 111.8) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 39.2496 105.1004) (end 37.6 106.75) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 50.2323 105.1004) (end 39.2496 105.1004) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 51.57 106.4381) (end 50.2323 105.1004) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 51.57 107.0356) (end 51.57 106.4381) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 55.1911 110.6567) (end 51.57 107.0356) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 63.1567 110.6567) (end 55.1911 110.6567) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 64.3 111.8) (end 63.1567 110.6567) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 10.3482 138.6582) (end 11.5 139.81) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 10.3482 134.2582) (end 10.3482 138.6582) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 11.0826 133.5238) (end 10.3482 134.2582) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 12.991 133.5238) (end 11.0826 133.5238) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 13.5623 134.0951) (end 12.991 133.5238) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 71.6849 134.0951) (end 13.5623 134.0951) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 80.51 125.27) (end 71.6849 134.0951) (width 0.254) (layer F.Cu) (net 46))
  (segment (start 81.7006 124.0794) (end 80.51 125.27) (width 0.254) (layer B.Cu) (net 46))
  (segment (start 66.84 111.8) (end 71.2498 111.8) (width 0.254) (layer B.Cu) (net 46))
  (segment (start 71.2498 111.8) (end 81.7006 122.2508) (width 0.254) (layer B.Cu) (net 46))
  (segment (start 81.7006 122.2508) (end 81.7006 124.0794) (width 0.254) (layer B.Cu) (net 46))
  (segment (start 89.7475 114.9225) (end 90.27 114.4) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 89.7475 128.4775) (end 89.7475 114.9225) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 90.27 129) (end 89.7475 128.4775) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 30.27 91.8) (end 37.6 99.13) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 30.27 70.6) (end 30.27 91.8) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 25.19 111.54) (end 25.19 136.5) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 37.6 99.13) (end 25.19 111.54) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 90.27 114.4) (end 90.27 99.8) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 89.7645 71.1055) (end 90.27 70.6) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 89.7645 84.6945) (end 89.7645 71.1055) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 90.27 85.2) (end 89.7645 84.6945) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 250.09 131.32) (end 250.09 128.78) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 240.27 76.6805) (end 240.27 70.6) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 240.7751 76.6805) (end 240.27 76.6805) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 245.0476 80.953) (end 240.7751 76.6805) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 245.0476 88.8697) (end 245.0476 80.953) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 257.2282 101.0503) (end 245.0476 88.8697) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 259.0197 101.0503) (end 257.2282 101.0503) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 260.27 99.8) (end 259.0197 101.0503) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 250.09 98.6192) (end 250.09 128.78) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 242.4985 91.0277) (end 250.09 98.6192) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 242.4985 84.1909) (end 242.4985 91.0277) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 239.0505 80.7429) (end 242.4985 84.1909) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 239.0505 77.395) (end 239.0505 80.7429) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 239.765 76.6805) (end 239.0505 77.395) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 240.27 76.6805) (end 239.765 76.6805) (width 0.254) (layer B.Cu) (net 47))
  (segment (start 38.724 98.006) (end 37.6 99.13) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 90.27 98.006) (end 38.724 98.006) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 90.27 99.8) (end 90.27 98.006) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 90.27 98.006) (end 90.27 85.2) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 246.9958 134.4142) (end 250.09 131.32) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 211.5968 134.4142) (end 246.9958 134.4142) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 209.511 136.5) (end 211.5968 134.4142) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 205.19 136.5) (end 209.511 136.5) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 90.27 131.9828) (end 90.27 129) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 200.6728 131.9828) (end 90.27 131.9828) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 205.19 136.5) (end 200.6728 131.9828) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 89.7072 131.9828) (end 85.19 136.5) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 90.27 131.9828) (end 89.7072 131.9828) (width 0.254) (layer F.Cu) (net 47))
  (segment (start 180.27 70.6) (end 180.27 85.2) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 180.27 99.8) (end 180.27 114.4) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 180.27 114.4) (end 180.27 129) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 180.27 131.42) (end 175.19 136.5) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 180.27 129) (end 180.27 131.42) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 272.95 131.32) (end 272.95 128.78) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 180.27 85.2) (end 180.27 99.8) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 62.0927 100.7627) (end 60.46 99.13) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 68.4168 100.7627) (end 62.0927 100.7627) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 86.7466 119.0925) (end 68.4168 100.7627) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 86.7466 123.2801) (end 86.7466 119.0925) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 86.0267 124) (end 86.7466 123.2801) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 85.2432 124) (end 86.0267 124) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 84.4466 124.7966) (end 85.2432 124) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 84.4466 129) (end 84.4466 124.7966) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 84.4466 129) (end 70.27 129) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 86.0054 129) (end 84.4466 129) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 87.2621 130.2567) (end 86.0054 129) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 91.3517 130.2567) (end 87.2621 130.2567) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 97.9385 123.6699) (end 91.3517 130.2567) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 162.1397 123.6699) (end 97.9385 123.6699) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 169.0327 116.7769) (end 162.1397 123.6699) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 169.0327 116.7521) (end 169.0327 116.7769) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 170.1121 115.6727) (end 169.0327 116.7521) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 170.77 115.6727) (end 170.1121 115.6727) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 180.27 106.1727) (end 170.77 115.6727) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 180.27 99.8) (end 180.27 106.1727) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 259 76.63) (end 260.27 77.9) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 259 70.049) (end 259 76.63) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 258.3066 69.3556) (end 259 70.049) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 214.99 69.3556) (end 258.3066 69.3556) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 211.9706 72.375) (end 214.99 69.3556) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 182.045 72.375) (end 211.9706 72.375) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 180.27 70.6) (end 182.045 72.375) (width 0.254) (layer F.Cu) (net 48))
  (segment (start 272.95 109.9576) (end 272.95 128.78) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 256.4706 93.4782) (end 272.95 109.9576) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 256.4706 81.6994) (end 256.4706 93.4782) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 260.27 77.9) (end 256.4706 81.6994) (width 0.254) (layer B.Cu) (net 48))
  (segment (start 190.27 114.4) (end 190.27 129) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 190.27 131.42) (end 185.19 136.5) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 190.27 129) (end 190.27 131.42) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 64.0912 100.2212) (end 63 99.13) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 65.9879 100.2212) (end 64.0912 100.2212) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 68.3427 97.8664) (end 65.9879 100.2212) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 68.3427 88.2627) (end 68.3427 97.8664) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 87.7805 68.8249) (end 68.3427 88.2627) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 188.4949 68.8249) (end 87.7805 68.8249) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 190.27 70.6) (end 188.4949 68.8249) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 190.27 99.8) (end 190.27 114.4) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 190.27 70.6) (end 190.27 85.2) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 190.27 85.2) (end 190.27 99.8) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 192.5263 87.4563) (end 190.27 85.2) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 244.0222 87.4563) (end 192.5263 87.4563) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 250.2897 93.7238) (end 244.0222 87.4563) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 260.773 93.7238) (end 250.2897 93.7238) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 261.5335 92.9633) (end 260.773 93.7238) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 261.5335 86.4635) (end 261.5335 92.9633) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 260.27 85.2) (end 261.5335 86.4635) (width 0.254) (layer F.Cu) (net 49))
  (segment (start 275.49 131.32) (end 275.49 128.78) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 259 86.47) (end 260.27 85.2) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 259 93.1606) (end 259 86.47) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 275.49 109.6506) (end 259 93.1606) (width 0.254) (layer B.Cu) (net 49))
  (segment (start 275.49 128.78) (end 275.49 109.6506) (width 0.254) (layer B.Cu) (net 49))
  (via (at 203.034 110.2619) (size 0.889) (layers F.Cu B.Cu) (net 50))
  (segment (start 199.029 130.241) (end 200.27 129) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 197.0417 130.241) (end 199.029 130.241) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 196.5005 129.6998) (end 197.0417 130.241) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 196.5005 118.1695) (end 196.5005 129.6998) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 200.27 114.4) (end 196.5005 118.1695) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 197.0417 134.6483) (end 195.19 136.5) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 197.0417 130.241) (end 197.0417 134.6483) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 202.0039 86.9339) (end 200.27 85.2) (width 0.254) (layer F.Cu) (net 50))
  (segment (start 254.7039 86.9339) (end 202.0039 86.9339) (width 0.254) (layer F.Cu) (net 50))
  (segment (start 260.27 92.5) (end 254.7039 86.9339) (width 0.254) (layer F.Cu) (net 50))
  (segment (start 278.03 131.32) (end 278.03 128.78) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 278.03 110.26) (end 260.27 92.5) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 278.03 128.78) (end 278.03 110.26) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 193.8351 71.8196) (end 199.4465 71.8196) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 190.332 68.3165) (end 193.8351 71.8196) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 87.5205 68.3165) (end 190.332 68.3165) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 65.54 90.297) (end 87.5205 68.3165) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 65.54 99.13) (end 65.54 90.297) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 200.27 70.9961) (end 200.27 70.6) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 199.4465 71.8196) (end 200.27 70.9961) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 199.4465 71.8196) (end 199.4465 83.9286) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 199.4465 84.3765) (end 200.27 85.2) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 199.4465 83.9286) (end 199.4465 84.3765) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 196.5105 96.0405) (end 200.27 99.8) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 196.5105 84.6626) (end 196.5105 96.0405) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 197.2445 83.9286) (end 196.5105 84.6626) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 199.4465 83.9286) (end 197.2445 83.9286) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 200.27 107.4979) (end 203.034 110.2619) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 200.27 99.8) (end 200.27 107.4979) (width 0.254) (layer B.Cu) (net 50))
  (segment (start 200.27 113.0259) (end 203.034 110.2619) (width 0.254) (layer F.Cu) (net 50))
  (segment (start 200.27 114.4) (end 200.27 113.0259) (width 0.254) (layer F.Cu) (net 50))
  (segment (start 61.76 111.8) (end 62.9033 111.8) (width 0.254) (layer B.Cu) (net 51))
  (segment (start 62.9033 111.5142) (end 62.9033 111.8) (width 0.254) (layer B.Cu) (net 51))
  (segment (start 63.7609 110.6566) (end 62.9033 111.5142) (width 0.254) (layer B.Cu) (net 51))
  (segment (start 71.4668 110.6566) (end 63.7609 110.6566) (width 0.254) (layer B.Cu) (net 51))
  (segment (start 81.1814 120.3712) (end 71.4668 110.6566) (width 0.254) (layer B.Cu) (net 51))
  (segment (start 83.2312 120.3712) (end 81.1814 120.3712) (width 0.254) (layer B.Cu) (net 51))
  (segment (start 85.59 122.73) (end 83.2312 120.3712) (width 0.254) (layer B.Cu) (net 51))
  (via (at 100.27 122.844) (size 0.889) (layers F.Cu B.Cu) (net 52))
  (segment (start 100.27 85.2) (end 100.27 70.6) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 100.27 131.42) (end 95.19 136.5) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 100.27 129) (end 100.27 131.42) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 252.63 131.32) (end 252.63 128.78) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 100.27 99.8) (end 100.27 85.2) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 41.5103 71.8403) (end 40.27 70.6) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 62.954 71.8403) (end 41.5103 71.8403) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 65.4471 69.3472) (end 62.954 71.8403) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 99.0172 69.3472) (end 65.4471 69.3472) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 100.27 70.6) (end 99.0172 69.3472) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 100.27 114.4) (end 100.27 99.8) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 100.27 122.844) (end 100.27 114.4) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 100.27 129) (end 100.27 122.844) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 40.27 99) (end 40.14 99.13) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 40.27 70.6) (end 40.27 99) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 30.814 132.124) (end 35.19 136.5) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 29.1142 132.124) (end 30.814 132.124) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 26.4733 129.4831) (end 29.1142 132.124) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 26.4733 112.7967) (end 26.4733 129.4831) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 40.14 99.13) (end 26.4733 112.7967) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 244.5392 82.1692) (end 240.27 77.9) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 244.5392 89.0801) (end 244.5392 82.1692) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 257.2572 101.7981) (end 244.5392 89.0801) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 257.2572 105.8449) (end 257.2572 101.7981) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 252.63 110.4721) (end 257.2572 105.8449) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 252.63 128.78) (end 252.63 110.4721) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 259.0149 105.8449) (end 260.27 107.1) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 257.2572 105.8449) (end 259.0149 105.8449) (width 0.254) (layer B.Cu) (net 52))
  (segment (start 216.5134 135.1766) (end 215.19 136.5) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 248.7734 135.1766) (end 216.5134 135.1766) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 252.63 131.32) (end 248.7734 135.1766) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 97.3006 134.3894) (end 95.19 136.5) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 195.3253 134.3894) (end 97.3006 134.3894) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 198.5324 137.5965) (end 195.3253 134.3894) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 214.0935 137.5965) (end 198.5324 137.5965) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 215.19 136.5) (end 214.0935 137.5965) (width 0.254) (layer F.Cu) (net 52))
  (segment (start 80.9148 120.5948) (end 83.05 122.73) (width 0.254) (layer F.Cu) (net 53))
  (segment (start 68.0123 120.5948) (end 80.9148 120.5948) (width 0.254) (layer F.Cu) (net 53))
  (segment (start 62.9033 115.4858) (end 68.0123 120.5948) (width 0.254) (layer F.Cu) (net 53))
  (segment (start 62.9033 115.2) (end 62.9033 115.4858) (width 0.254) (layer F.Cu) (net 53))
  (segment (start 61.76 115.2) (end 62.9033 115.2) (width 0.254) (layer F.Cu) (net 53))
  (via (at 110.27 122.844) (size 0.889) (layers F.Cu B.Cu) (net 54))
  (segment (start 110.27 131.42) (end 105.19 136.5) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 110.27 129) (end 110.27 131.42) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 110.27 70.6) (end 110.27 85.2) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 277.9404 72.9296) (end 280.27 70.6) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 270.8089 72.9296) (end 277.9404 72.9296) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 259 84.7385) (end 270.8089 72.9296) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 259 85.6562) (end 259 84.7385) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 258.2306 86.4256) (end 259 85.6562) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 241.4956 86.4256) (end 258.2306 86.4256) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 240.27 85.2) (end 241.4956 86.4256) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 52.5394 68.3306) (end 50.27 70.6) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 108.0006 68.3306) (end 52.5394 68.3306) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 110.27 70.6) (end 108.0006 68.3306) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 110.27 85.2) (end 110.27 99.8) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 110.27 99.8) (end 110.27 114.4) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 110.27 114.4) (end 110.27 122.844) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 110.27 129) (end 110.27 122.844) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 255.17 128.78) (end 255.17 131.32) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 228.0301 133.6599) (end 225.19 136.5) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 246.8371 133.6599) (end 228.0301 133.6599) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 248.82 131.677) (end 246.8371 133.6599) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 249.6549 132.5119) (end 248.82 131.677) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 253.9781 132.5119) (end 249.6549 132.5119) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 255.17 131.32) (end 253.9781 132.5119) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 240.27 90.043) (end 240.27 85.2) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 248.82 98.593) (end 240.27 90.043) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 248.82 131.677) (end 248.82 98.593) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 106.7922 134.8978) (end 105.19 136.5) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 195.1149 134.8978) (end 106.7922 134.8978) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 198.322 138.1049) (end 195.1149 134.8978) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 223.5851 138.1049) (end 198.322 138.1049) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 225.19 136.5) (end 223.5851 138.1049) (width 0.254) (layer F.Cu) (net 54))
  (segment (start 42.68 78.19) (end 42.68 99.13) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 50.27 70.6) (end 42.68 78.19) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 43.0937 134.4037) (end 45.19 136.5) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 33.8877 134.4037) (end 43.0937 134.4037) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 29 129.516) (end 33.8877 134.4037) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 29 112.3634) (end 29 129.516) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 42.2334 99.13) (end 29 112.3634) (width 0.254) (layer B.Cu) (net 54))
  (segment (start 42.68 99.13) (end 42.2334 99.13) (width 0.254) (layer B.Cu) (net 54))
  (via (at 120.27 122.844) (size 0.889) (layers F.Cu B.Cu) (net 55))
  (segment (start 120.27 70.6) (end 120.27 85.2) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 120.27 85.2) (end 120.27 99.8) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 120.27 99.8) (end 120.27 114.4) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 254.8311 134.1989) (end 257.71 131.32) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 237.4911 134.1989) (end 254.8311 134.1989) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 235.19 136.5) (end 237.4911 134.1989) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 62.0311 68.8389) (end 60.27 70.6) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 100.907 68.8389) (end 62.0311 68.8389) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 103.8889 71.8208) (end 100.907 68.8389) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 119.0492 71.8208) (end 103.8889 71.8208) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 120.27 70.6) (end 119.0492 71.8208) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 120.27 131.42) (end 115.19 136.5) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 120.27 129) (end 120.27 131.42) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 120.27 114.4) (end 120.27 122.844) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 120.27 129) (end 120.27 122.844) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 45.22 85.65) (end 60.27 70.6) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 45.22 99.13) (end 45.22 85.65) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 237.3336 89.5636) (end 240.27 92.5) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 124.6336 89.5636) (end 237.3336 89.5636) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 120.27 85.2) (end 124.6336 89.5636) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 279 79.17) (end 280.27 77.9) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 279 90.12) (end 279 79.17) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 258.445 110.675) (end 279 90.12) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 240.27 92.5) (end 258.445 110.675) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 260.27 112.5) (end 260.27 114.4) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 258.445 110.675) (end 260.27 112.5) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 259 127.49) (end 257.71 128.78) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 259 115.67) (end 259 127.49) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 260.27 114.4) (end 259 115.67) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 257.71 128.78) (end 257.71 131.32) (width 0.254) (layer B.Cu) (net 55))
  (segment (start 56.2699 135.4201) (end 55.19 136.5) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 77.6829 135.4201) (end 56.2699 135.4201) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 79.8427 137.5799) (end 77.6829 135.4201) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 114.1101 137.5799) (end 79.8427 137.5799) (width 0.254) (layer F.Cu) (net 55))
  (segment (start 115.19 136.5) (end 114.1101 137.5799) (width 0.254) (layer F.Cu) (net 55))
  (via (at 129.9214 122.844) (size 0.889) (layers F.Cu B.Cu) (net 56))
  (segment (start 130.27 85.2) (end 130.27 99.8) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 130.27 99.8) (end 130.27 114.4) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 256.565 135.005) (end 260.25 131.32) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 246.685 135.005) (end 256.565 135.005) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 245.19 136.5) (end 246.685 135.005) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 129.9214 128.6514) (end 129.9214 122.844) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 130.27 129) (end 129.9214 128.6514) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 130.27 122.4954) (end 129.9214 122.844) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 130.27 114.4) (end 130.27 122.4954) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 130.27 131.42) (end 125.19 136.5) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 130.27 129) (end 130.27 131.42) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 67.294 138.604) (end 65.19 136.5) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 123.086 138.604) (end 67.294 138.604) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 125.19 136.5) (end 123.086 138.604) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 260.25 121.72) (end 260.25 128.78) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 260.27 121.7) (end 260.25 121.72) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 260.25 128.78) (end 260.25 131.32) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 70.27 76.62) (end 47.76 99.13) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 70.27 70.6) (end 70.27 76.62) (width 0.254) (layer B.Cu) (net 56))
  (segment (start 280.27 96.1423) (end 258.4412 117.9711) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 280.27 85.2) (end 280.27 96.1423) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 260.27 119.8) (end 258.4412 117.9711) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 260.27 121.7) (end 260.27 119.8) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 130.27 74.0582) (end 128.5409 72.3291) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 130.27 85.2) (end 130.27 74.0582) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 97.0709 72.3291) (end 128.5409 72.3291) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 96.4914 71.7496) (end 97.0709 72.3291) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 91.5172 71.7496) (end 96.4914 71.7496) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 91.441 71.8258) (end 91.5172 71.7496) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 71.4958 71.8258) (end 91.441 71.8258) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 70.27 70.6) (end 71.4958 71.8258) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 128.5409 72.3291) (end 130.27 70.6) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 258.4412 117.9711) (end 240.27 99.8) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 235.2726 94.8026) (end 240.27 99.8) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 135.2674 94.8026) (end 235.2726 94.8026) (width 0.254) (layer F.Cu) (net 56))
  (segment (start 130.27 99.8) (end 135.2674 94.8026) (width 0.254) (layer F.Cu) (net 56))
  (via (at 140.27 122.805) (size 0.889) (layers F.Cu B.Cu) (net 57))
  (segment (start 262.79 128.78) (end 262.79 131.32) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 257.61 136.5) (end 255.19 136.5) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 262.79 131.32) (end 257.61 136.5) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 140.27 70.6) (end 140.27 85.2) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 140.27 99.8) (end 140.27 85.2) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 31.1683 129) (end 30.27 129) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 76.7848 138.0948) (end 75.19 136.5) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 116.7935 138.0948) (end 76.7848 138.0948) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 119.4682 135.4201) (end 116.7935 138.0948) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 134.1101 135.4201) (end 119.4682 135.4201) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 135.19 136.5) (end 134.1101 135.4201) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 241.11 107.1) (end 240.27 107.1) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 262.79 128.78) (end 241.11 107.1) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 140.27 131.42) (end 135.19 136.5) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 140.27 129) (end 140.27 131.42) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 140.27 99.8) (end 140.27 114.4) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 36.0636 133.8953) (end 31.1683 129) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 72.5853 133.8953) (end 36.0636 133.8953) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 75.19 136.5) (end 72.5853 133.8953) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 140.27 114.4) (end 140.27 122.805) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 140.27 122.805) (end 140.27 129) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 47.3653 102.0647) (end 50.3 99.13) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 40.0177 102.0647) (end 47.3653 102.0647) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 31.1683 110.9141) (end 40.0177 102.0647) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 31.1683 129) (end 31.1683 110.9141) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 77.9693 72.9007) (end 80.27 70.6) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 76.5293 72.9007) (end 77.9693 72.9007) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 50.3 99.13) (end 76.5293 72.9007) (width 0.254) (layer B.Cu) (net 57))
  (segment (start 238.1754 105.0054) (end 240.27 107.1) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 228.7164 105.0054) (end 238.1754 105.0054) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 223.5908 99.8798) (end 228.7164 105.0054) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 214.8688 99.8798) (end 223.5908 99.8798) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 212.5019 97.5129) (end 214.8688 99.8798) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 165.3282 97.5129) (end 212.5019 97.5129) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 161.2551 101.586) (end 165.3282 97.5129) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 142.056 101.586) (end 161.2551 101.586) (width 0.254) (layer F.Cu) (net 57))
  (segment (start 140.27 99.8) (end 142.056 101.586) (width 0.254) (layer F.Cu) (net 57))
  (via (at 158.0419 121.5844) (size 0.889) (layers F.Cu B.Cu) (net 58))
  (segment (start 150.27 85.2) (end 150.27 70.6) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 265.33 136.36) (end 265.19 136.5) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 265.33 131.32) (end 265.33 136.36) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 81.4988 115.6288) (end 80.27 114.4) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 149.0412 115.6288) (end 81.4988 115.6288) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 150.27 114.4) (end 149.0412 115.6288) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 150.27 85.2) (end 150.27 99.8) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 150.27 99.8) (end 150.27 114.4) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 150.8575 114.4) (end 158.0419 121.5844) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 150.27 114.4) (end 150.8575 114.4) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 247.4947 114.4) (end 240.27 114.4) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 261.52 128.4253) (end 247.4947 114.4) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 261.52 129.1267) (end 261.52 128.4253) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 262.3462 129.9529) (end 261.52 129.1267) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 264.1571 129.9529) (end 262.3462 129.9529) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 265.33 128.78) (end 264.1571 129.9529) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 264.1571 130.1471) (end 265.33 131.32) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 264.1571 129.9529) (end 264.1571 130.1471) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 157.6856 121.5844) (end 158.0419 121.5844) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 150.27 129) (end 157.6856 121.5844) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 233.0856 121.5844) (end 240.27 114.4) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 158.0419 121.5844) (end 233.0856 121.5844) (width 0.254) (layer F.Cu) (net 58))
  (segment (start 150.27 131.42) (end 145.19 136.5) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 150.27 129) (end 150.27 131.42) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 38.7266 127.4566) (end 40.27 129) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 38.7266 106.6156) (end 38.7266 127.4566) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 41.8307 103.5115) (end 38.7266 106.6156) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 48.4585 103.5115) (end 41.8307 103.5115) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 52.84 99.13) (end 48.4585 103.5115) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 56.7912 103.0812) (end 52.84 99.13) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 64.6395 103.0812) (end 56.7912 103.0812) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 77.178 115.6197) (end 64.6395 103.0812) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 79.0503 115.6197) (end 77.178 115.6197) (width 0.254) (layer B.Cu) (net 58))
  (segment (start 80.27 114.4) (end 79.0503 115.6197) (width 0.254) (layer B.Cu) (net 58))
  (via (at 34.4426 128.0754) (size 0.889) (layers F.Cu B.Cu) (net 59))
  (via (at 162.2028 122.439) (size 0.889) (layers F.Cu B.Cu) (net 59))
  (segment (start 273.7505 135.0605) (end 275.19 136.5) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 271.6105 135.0605) (end 273.7505 135.0605) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 267.87 131.32) (end 271.6105 135.0605) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 267.87 128.78) (end 267.87 131.32) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 245.0628 126.4928) (end 240.27 121.7) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 245.0628 126.4929) (end 245.0628 126.4928) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 257.052 126.4929) (end 245.0628 126.4929) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 258.98 128.4209) (end 257.052 126.4929) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 258.98 129.1268) (end 258.98 128.4209) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 259.7766 129.9234) (end 258.98 129.1268) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 260.4702 129.9234) (end 259.7766 129.9234) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 261.3934 130.8466) (end 260.4702 129.9234) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 261.3934 131.5737) (end 261.3934 130.8466) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 262.3 132.4803) (end 261.3934 131.5737) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 266.7097 132.4803) (end 262.3 132.4803) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 267.87 131.32) (end 266.7097 132.4803) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 160.27 131.42) (end 155.19 136.5) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 160.27 129) (end 160.27 131.42) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 34.7376 127.7804) (end 34.4426 128.0754) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 42.5862 127.7804) (end 34.7376 127.7804) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 45.0282 130.2224) (end 42.5862 127.7804) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 49.0476 130.2224) (end 45.0282 130.2224) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 50.27 129) (end 49.0476 130.2224) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 158.4779 127.2079) (end 160.27 129) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 110.309 127.2079) (end 158.4779 127.2079) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 109 128.5169) (end 110.309 127.2079) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 109 129.464) (end 109 128.5169) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 107.4969 130.9671) (end 109 129.464) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 104.7575 130.9671) (end 107.4969 130.9671) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 98.0985 137.6261) (end 104.7575 130.9671) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 94.7424 137.6261) (end 98.0985 137.6261) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 93.6932 136.5769) (end 94.7424 137.6261) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 93.6932 135.6392) (end 93.6932 136.5769) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 93.072 135.018) (end 93.6932 135.6392) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 86.4229 135.018) (end 93.072 135.018) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 83.3665 131.9616) (end 86.4229 135.018) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 72.3687 131.9616) (end 83.3665 131.9616) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 72.0775 132.2528) (end 72.3687 131.9616) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 53.5228 132.2528) (end 72.0775 132.2528) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 50.27 129) (end 53.5228 132.2528) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 160.27 114.4) (end 160.27 101.0468) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 160.27 101.0468) (end 160.27 99.8) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 163.0305 123.2667) (end 162.2028 122.439) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 238.7033 123.2667) (end 163.0305 123.2667) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 240.27 121.7) (end 238.7033 123.2667) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 160.27 126.0272) (end 160.27 129) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 163.0305 123.2667) (end 160.27 126.0272) (width 0.254) (layer F.Cu) (net 59))
  (segment (start 160.27 120.5062) (end 160.27 114.4) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 162.2028 122.439) (end 160.27 120.5062) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 31.7164 125.3492) (end 34.4426 128.0754) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 31.7164 111.0923) (end 31.7164 125.3492) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 40.2357 102.573) (end 31.7164 111.0923) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 48.3842 102.573) (end 40.2357 102.573) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 51.7499 99.2073) (end 48.3842 102.573) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 51.7499 98.693) (end 51.7499 99.2073) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 52.3962 98.0467) (end 51.7499 98.693) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 54.2967 98.0467) (end 52.3962 98.0467) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 55.38 99.13) (end 54.2967 98.0467) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 156.4896 88.9804) (end 160.27 85.2) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 156.4896 100.2923) (end 156.4896 88.9804) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 157.2441 101.0468) (end 156.4896 100.2923) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 160.27 101.0468) (end 157.2441 101.0468) (width 0.254) (layer B.Cu) (net 59))
  (segment (start 160.27 85.2) (end 160.27 70.6) (width 0.254) (layer B.Cu) (net 59))
  (via (at 170.8751 117.5151) (size 0.889) (layers F.Cu B.Cu) (net 60))
  (via (at 56.7816 109.3605) (size 0.889) (layers F.Cu B.Cu) (net 60))
  (segment (start 170.27 114.4) (end 170.27 99.8) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 170.27 70.6) (end 170.27 85.2) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 170.27 85.2) (end 170.27 99.8) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 170.27 131.42) (end 165.19 136.5) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 170.27 129) (end 170.27 131.42) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 170.8751 115.0051) (end 170.8751 117.5151) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 170.27 114.4) (end 170.8751 115.0051) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 169.3295 119.0607) (end 169.3295 126.1413) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 170.8751 117.5151) (end 169.3295 119.0607) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 169.3295 128.0595) (end 169.3295 126.1413) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 170.27 129) (end 169.3295 128.0595) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 270.41 131.32) (end 270.41 128.78) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 255.9498 74.9202) (end 260.27 70.6) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 255.9498 93.6765) (end 255.9498 74.9202) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 270.41 108.1367) (end 255.9498 93.6765) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 270.41 128.78) (end 270.41 108.1367) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 63.6218 131.2362) (end 61.3856 129) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 71.6565 131.2362) (end 63.6218 131.2362) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 71.9571 130.9356) (end 71.6565 131.2362) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 85.0612 130.9356) (end 71.9571 130.9356) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 85.9234 131.7978) (end 85.0612 130.9356) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 92.0876 131.7978) (end 85.9234 131.7978) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 97.7441 126.1413) (end 92.0876 131.7978) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 169.3295 126.1413) (end 97.7441 126.1413) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 61.3856 129) (end 60.27 129) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 171.5398 69.3302) (end 170.27 70.6) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 205.5364 69.3302) (end 171.5398 69.3302) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 206.6267 70.4205) (end 205.5364 69.3302) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 210.9943 70.4205) (end 206.6267 70.4205) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 212.5676 68.8472) (end 210.9943 70.4205) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 258.5172 68.8472) (end 212.5676 68.8472) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 260.27 70.6) (end 258.5172 68.8472) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 56.7816 117.7046) (end 56.7816 109.3605) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 61.3856 122.3086) (end 56.7816 117.7046) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 61.3856 129) (end 61.3856 122.3086) (width 0.254) (layer B.Cu) (net 60))
  (segment (start 56.7816 100.2684) (end 57.92 99.13) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 56.7816 109.3605) (end 56.7816 100.2684) (width 0.254) (layer F.Cu) (net 60))
  (segment (start 188.9652 71.8352) (end 187.73 70.6) (width 0.254) (layer F.Cu) (net 61))
  (segment (start 196.4948 71.8352) (end 188.9652 71.8352) (width 0.254) (layer F.Cu) (net 61))
  (segment (start 197.73 70.6) (end 196.4948 71.8352) (width 0.254) (layer F.Cu) (net 61))
  (segment (start 88.9495 69.3805) (end 87.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 96.5105 69.3805) (end 88.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 97.73 70.6) (end 96.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 98.9495 69.3805) (end 97.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 106.5105 69.3805) (end 98.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 107.73 70.6) (end 106.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 108.9495 69.3805) (end 107.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 116.5105 69.3805) (end 108.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 117.73 70.6) (end 116.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 118.9495 69.3805) (end 117.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 126.5105 69.3805) (end 118.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 127.73 70.6) (end 126.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 128.9495 69.3805) (end 127.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 136.5105 69.3805) (end 128.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 137.73 70.6) (end 136.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 138.9495 69.3805) (end 137.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 146.5105 69.3805) (end 138.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 147.73 70.6) (end 146.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 148.9495 69.3805) (end 147.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 156.5105 69.3805) (end 148.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 157.73 70.6) (end 156.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 158.9495 69.3805) (end 157.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 166.5105 69.3805) (end 158.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 167.73 70.6) (end 166.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 168.9495 69.3805) (end 167.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 176.5105 69.3805) (end 168.9495 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 177.73 70.6) (end 176.5105 69.3805) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 186.4901 69.3601) (end 187.73 70.6) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 178.9699 69.3601) (end 186.4901 69.3601) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 177.73 70.6) (end 178.9699 69.3601) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 224.4891 109.5009) (end 222.86 111.13) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 224.4891 95.9211) (end 224.4891 109.5009) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 223.188 94.62) (end 224.4891 95.9211) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 222.568 94.62) (end 223.188 94.62) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 214.6246 86.6766) (end 222.568 94.62) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 214.6246 83.1806) (end 214.6246 86.6766) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 200.8244 69.3804) (end 214.6246 83.1806) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 198.9496 69.3804) (end 200.8244 69.3804) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 197.73 70.6) (end 198.9496 69.3804) (width 0.254) (layer B.Cu) (net 61))
  (segment (start 96.5104 86.4196) (end 97.73 85.2) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 88.9496 86.4196) (end 96.5104 86.4196) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 87.73 85.2) (end 88.9496 86.4196) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 98.9496 86.4196) (end 97.73 85.2) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 106.5104 86.4196) (end 98.9496 86.4196) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 107.73 85.2) (end 106.5104 86.4196) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 108.9605 86.4305) (end 107.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 116.4995 86.4305) (end 108.9605 86.4305) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 117.73 85.2) (end 116.4995 86.4305) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 221.3999 107.1299) (end 222.86 108.59) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 221.3999 95.4147) (end 221.3999 107.1299) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 215.4577 89.4725) (end 221.3999 95.4147) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 202.0025 89.4725) (end 215.4577 89.4725) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 197.73 85.2) (end 202.0025 89.4725) (width 0.254) (layer B.Cu) (net 62))
  (segment (start 138.9496 83.9804) (end 137.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 146.5104 83.9804) (end 138.9496 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 147.73 85.2) (end 146.5104 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 148.9943 86.4643) (end 147.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 156.4657 86.4643) (end 148.9943 86.4643) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 157.73 85.2) (end 156.4657 86.4643) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 158.9496 83.9804) (end 157.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 166.5104 83.9804) (end 158.9496 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 167.73 85.2) (end 166.5104 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 168.9943 86.4643) (end 167.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 176.4657 86.4643) (end 168.9943 86.4643) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 177.73 85.2) (end 176.4657 86.4643) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 178.9496 83.9804) (end 177.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 186.5104 83.9804) (end 178.9496 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 187.73 85.2) (end 186.5104 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 188.9887 83.9413) (end 187.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 196.4713 83.9413) (end 188.9887 83.9413) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 197.73 85.2) (end 196.4713 83.9413) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 126.5104 83.9804) (end 127.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 118.9496 83.9804) (end 126.5104 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 117.73 85.2) (end 118.9496 83.9804) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 136.5104 86.4196) (end 137.73 85.2) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 128.9496 86.4196) (end 136.5104 86.4196) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 127.73 85.2) (end 128.9496 86.4196) (width 0.254) (layer F.Cu) (net 62))
  (segment (start 98.9835 98.5465) (end 97.73 99.8) (width 0.254) (layer B.Cu) (net 63))
  (segment (start 106.4765 98.5465) (end 98.9835 98.5465) (width 0.254) (layer B.Cu) (net 63))
  (segment (start 107.73 99.8) (end 106.4765 98.5465) (width 0.254) (layer B.Cu) (net 63))
  (segment (start 196.487 98.557) (end 197.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 188.973 98.557) (end 196.487 98.557) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 187.73 99.8) (end 188.973 98.557) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 223.9433 104.9667) (end 222.86 106.05) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 223.9433 103.0561) (end 223.9433 104.9667) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 223.1272 102.24) (end 223.9433 103.0561) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 200.17 102.24) (end 223.1272 102.24) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 197.73 99.8) (end 200.17 102.24) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 88.959 101.029) (end 87.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 96.501 101.029) (end 88.959 101.029) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 97.73 99.8) (end 96.501 101.029) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 176.5104 101.0196) (end 177.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 168.9496 101.0196) (end 176.5104 101.0196) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 167.73 99.8) (end 168.9496 101.0196) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 186.4749 98.5449) (end 187.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 178.9851 98.5449) (end 186.4749 98.5449) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 177.73 99.8) (end 178.9851 98.5449) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 128.9496 101.0196) (end 127.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 136.5104 101.0196) (end 128.9496 101.0196) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 137.73 99.8) (end 136.5104 101.0196) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 108.9503 101.0203) (end 107.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 116.5097 101.0203) (end 108.9503 101.0203) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 117.73 99.8) (end 116.5097 101.0203) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 126.5104 101.0196) (end 127.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 118.9496 101.0196) (end 126.5104 101.0196) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 117.73 99.8) (end 118.9496 101.0196) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 166.5031 98.5731) (end 167.73 99.8) (width 0.254) (layer B.Cu) (net 63))
  (segment (start 158.9569 98.5731) (end 166.5031 98.5731) (width 0.254) (layer B.Cu) (net 63))
  (segment (start 157.73 99.8) (end 158.9569 98.5731) (width 0.254) (layer B.Cu) (net 63))
  (segment (start 139.4579 98.0721) (end 137.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 146.0021 98.0721) (end 139.4579 98.0721) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 147.73 99.8) (end 146.0021 98.0721) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 148.9941 98.5359) (end 147.73 99.8) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 156.4659 98.5359) (end 148.9941 98.5359) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 157.73 99.8) (end 156.4659 98.5359) (width 0.254) (layer F.Cu) (net 63))
  (segment (start 148.9496 113.1804) (end 147.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 156.5104 113.1804) (end 148.9496 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 157.73 114.4) (end 156.5104 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 158.9522 115.6222) (end 157.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 166.5078 115.6222) (end 158.9522 115.6222) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 167.73 114.4) (end 166.5078 115.6222) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 178.9717 113.1583) (end 177.73 114.4) (width 0.254) (layer B.Cu) (net 64))
  (segment (start 186.4883 113.1583) (end 178.9717 113.1583) (width 0.254) (layer B.Cu) (net 64))
  (segment (start 187.73 114.4) (end 186.4883 113.1583) (width 0.254) (layer B.Cu) (net 64))
  (segment (start 196.4923 113.1623) (end 197.73 114.4) (width 0.254) (layer B.Cu) (net 64))
  (segment (start 188.9677 113.1623) (end 196.4923 113.1623) (width 0.254) (layer B.Cu) (net 64))
  (segment (start 187.73 114.4) (end 188.9677 113.1623) (width 0.254) (layer B.Cu) (net 64))
  (segment (start 118.9496 113.1804) (end 117.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 126.5104 113.1804) (end 118.9496 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 127.73 114.4) (end 126.5104 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 108.9496 113.1804) (end 107.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 116.5104 113.1804) (end 108.9496 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 117.73 114.4) (end 116.5104 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 168.9564 113.1736) (end 167.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 176.5036 113.1736) (end 168.9564 113.1736) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 177.73 114.4) (end 176.5036 113.1736) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 98.9496 113.1804) (end 97.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 106.5104 113.1804) (end 98.9496 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 107.73 114.4) (end 106.5104 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 88.9496 113.1804) (end 87.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 96.5104 113.1804) (end 88.9496 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 97.73 114.4) (end 96.5104 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 138.9496 113.1804) (end 137.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 146.5104 113.1804) (end 138.9496 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 147.73 114.4) (end 146.5104 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 128.9496 113.1804) (end 127.73 114.4) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 136.5104 113.1804) (end 128.9496 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 137.73 114.4) (end 136.5104 113.1804) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 218.9886 107.3814) (end 222.86 103.51) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 218.9886 107.3815) (end 218.9886 107.3814) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 204.7067 107.3815) (end 218.9886 107.3815) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 197.73 114.3582) (end 204.7067 107.3815) (width 0.254) (layer F.Cu) (net 64))
  (segment (start 197.73 114.4) (end 197.73 114.3582) (width 0.254) (layer F.Cu) (net 64))
  (via (at 211.7167 117.5345) (size 0.889) (layers F.Cu B.Cu) (net 65))
  (segment (start 138.9495 127.7805) (end 137.73 129) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 146.5105 127.7805) (end 138.9495 127.7805) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 147.73 129) (end 146.5105 127.7805) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 178.9495 127.7805) (end 177.73 129) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 186.5105 127.7805) (end 178.9495 127.7805) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 187.73 129) (end 186.5105 127.7805) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 166.5104 130.2196) (end 167.73 129) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 158.9496 130.2196) (end 166.5104 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 157.73 129) (end 158.9496 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 168.9496 130.2196) (end 167.73 129) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 176.5104 130.2196) (end 168.9496 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 177.73 129) (end 176.5104 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 156.5105 127.7805) (end 157.73 129) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 148.9495 127.7805) (end 156.5105 127.7805) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 147.73 129) (end 148.9495 127.7805) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 128.9719 127.7581) (end 127.73 129) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 136.4881 127.7581) (end 128.9719 127.7581) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 137.73 129) (end 136.4881 127.7581) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 98.9713 127.7587) (end 97.73 129) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 106.4887 127.7587) (end 98.9713 127.7587) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 107.73 129) (end 106.4887 127.7587) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 88.9496 127.7804) (end 87.73 129) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 96.5104 127.7804) (end 88.9496 127.7804) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 97.73 129) (end 96.5104 127.7804) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 188.9603 130.2303) (end 187.73 129) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 196.4997 130.2303) (end 188.9603 130.2303) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 197.73 129) (end 196.4997 130.2303) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 116.5104 130.2196) (end 117.73 129) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 108.9496 130.2196) (end 116.5104 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 107.73 129) (end 108.9496 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 118.9496 130.2196) (end 117.73 129) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 126.5104 130.2196) (end 118.9496 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 127.73 129) (end 126.5104 130.2196) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 209.1955 117.5345) (end 211.7167 117.5345) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 197.73 129) (end 209.1955 117.5345) (width 0.254) (layer B.Cu) (net 65))
  (segment (start 224.5007 102.6107) (end 222.86 100.97) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 224.5007 105.9974) (end 224.5007 102.6107) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 223.1781 107.32) (end 224.5007 105.9974) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 221.9312 107.32) (end 223.1781 107.32) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 211.7167 117.5345) (end 221.9312 107.32) (width 0.254) (layer F.Cu) (net 65))
  (segment (start 237.73 77.9) (end 237.73 85.2) (width 0.254) (layer B.Cu) (net 66))
  (segment (start 237.73 85.2) (end 237.73 92.5) (width 0.254) (layer B.Cu) (net 66))
  (segment (start 237.73 92.5) (end 237.73 99.8) (width 0.254) (layer B.Cu) (net 66))
  (segment (start 237.73 99.8) (end 237.73 107.1) (width 0.254) (layer B.Cu) (net 66))
  (segment (start 257.73 85.2) (end 257.73 92.5) (width 0.254) (layer B.Cu) (net 66))
  (segment (start 257.73 77.9) (end 257.73 85.2) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 237.73 107.1) (end 237.73 114.4) (width 0.254) (layer B.Cu) (net 66))
  (segment (start 237.73 114.4) (end 237.73 121.7) (width 0.254) (layer B.Cu) (net 66))
  (segment (start 256.5049 76.6749) (end 257.73 77.9) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 256.5049 71.8251) (end 256.5049 76.6749) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 256.5049 71.8251) (end 257.73 70.6) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 237.73 73.0502) (end 238.9551 71.8251) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 237.73 77.9) (end 237.73 73.0502) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 237.73 70.6) (end 238.9551 71.8251) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 238.9551 71.8251) (end 256.5049 71.8251) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 224.23 99.8) (end 222.86 98.43) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 237.73 99.8) (end 224.23 99.8) (width 0.254) (layer F.Cu) (net 66))
  (segment (start 257.73 114.4) (end 257.73 107.1) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 239.93 128.78) (end 239.93 131.32) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 28.9496 130.2196) (end 27.73 129) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 36.5104 130.2196) (end 28.9496 130.2196) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 37.73 129) (end 36.5104 130.2196) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 225.8905 118.1052) (end 223.8917 118.1052) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 236.12 128.3347) (end 225.8905 118.1052) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 236.12 131.736) (end 236.12 128.3347) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 236.896 132.512) (end 236.12 131.736) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 238.738 132.512) (end 236.896 132.512) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 239.93 131.32) (end 238.738 132.512) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 58.9496 127.7804) (end 57.73 129) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 66.5104 127.7804) (end 58.9496 127.7804) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 67.73 129) (end 66.5104 127.7804) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 48.9597 127.7703) (end 47.73 129) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 56.5003 127.7703) (end 48.9597 127.7703) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 57.73 129) (end 56.5003 127.7703) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 39.0049 130.2749) (end 37.73 129) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 46.4551 130.2749) (end 39.0049 130.2749) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 47.73 129) (end 46.4551 130.2749) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 69.4579 130.7279) (end 67.73 129) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 71.446 130.7279) (end 69.4579 130.7279) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 71.7637 130.4102) (end 71.446 130.7279) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 85.2546 130.4102) (end 71.7637 130.4102) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 86.1276 131.2832) (end 85.2546 130.4102) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 91.8681 131.2832) (end 86.1276 131.2832) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 97.5183 125.633) (end 91.8681 131.2832) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 161.6142 125.633) (end 97.5183 125.633) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 170.0493 117.1979) (end 161.6142 125.633) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 170.0493 117.1731) (end 170.0493 117.1979) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 170.5331 116.6893) (end 170.0493 117.1731) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 173.049 116.6893) (end 170.5331 116.6893) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 177.131 112.6073) (end 173.049 116.6893) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 214.4442 112.6073) (end 177.131 112.6073) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 219.9421 118.1052) (end 214.4442 112.6073) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 223.8917 118.1052) (end 219.9421 118.1052) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 223.8917 115.2401) (end 223.8917 118.1052) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 221.7524 113.1008) (end 223.8917 115.2401) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 221.7524 110.6961) (end 221.7524 113.1008) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 222.5885 109.86) (end 221.7524 110.6961) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 223.122 109.86) (end 222.5885 109.86) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 223.9609 109.0211) (end 223.122 109.86) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 223.9609 96.9909) (end 223.9609 109.0211) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 222.86 95.89) (end 223.9609 96.9909) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 257.73 107.1) (end 257.73 99.8) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 277.73 70.6) (end 277.73 77.9) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 277.73 77.9) (end 277.73 85.2) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 272.33 85.2) (end 257.73 99.8) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 277.73 85.2) (end 272.33 85.2) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 257.73 114.4) (end 257.73 121.7) (width 0.254) (layer B.Cu) (net 67))
  (segment (start 239 102.97) (end 257.73 121.7) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 239 99.336) (end 239 102.97) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 235.554 95.89) (end 239 99.336) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 222.86 95.89) (end 235.554 95.89) (width 0.254) (layer F.Cu) (net 67))
  (segment (start 66.5104 69.3804) (end 67.73 70.6) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 58.9496 69.3804) (end 66.5104 69.3804) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 57.73 70.6) (end 58.9496 69.3804) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 68.9496 69.3804) (end 67.73 70.6) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 76.5104 69.3804) (end 68.9496 69.3804) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 77.73 70.6) (end 76.5104 69.3804) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 28.9976 69.3324) (end 27.73 70.6) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 36.4624 69.3324) (end 28.9976 69.3324) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 37.73 70.6) (end 36.4624 69.3324) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 48.9976 69.3324) (end 47.73 70.6) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 56.4624 69.3324) (end 48.9976 69.3324) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 57.73 70.6) (end 56.4624 69.3324) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 38.9976 69.3324) (end 37.73 70.6) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 46.4624 69.3324) (end 38.9976 69.3324) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 47.73 70.6) (end 46.4624 69.3324) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 81.5189 72.3375) (end 81.5189 69.408) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 59.3711 94.4853) (end 81.5189 72.3375) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 59.3711 99.6096) (end 59.3711 94.4853) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 62.0804 102.3189) (end 59.3711 99.6096) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 65.6489 102.3189) (end 62.0804 102.3189) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 77.73 114.4) (end 65.6489 102.3189) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 78.9515 69.3785) (end 77.73 70.6) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 81.4894 69.3785) (end 78.9515 69.3785) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 81.5189 69.408) (end 81.4894 69.3785) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 242.47 131.32) (end 242.47 128.78) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 223.3435 89.7061) (end 221.7649 89.7061) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 236.5104 102.873) (end 223.3435 89.7061) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 236.5104 122.8204) (end 236.5104 102.873) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 242.47 128.78) (end 236.5104 122.8204) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 221.7649 89.5881) (end 221.7649 89.7061) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 199.9705 67.7937) (end 221.7649 89.5881) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 83.1332 67.7937) (end 199.9705 67.7937) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 81.5189 69.408) (end 83.1332 67.7937) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 221.7649 92.2549) (end 222.86 93.35) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 221.7649 89.7061) (end 221.7649 92.2549) (width 0.254) (layer B.Cu) (net 68))
  (segment (start 119 159.5) (end 109 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 109 159.5) (end 99 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 99 159.5) (end 89 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 119 159.5) (end 129 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 129 159.5) (end 139 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 139 159.5) (end 149 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 169 159.5) (end 179 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 179 159.5) (end 189 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 189 159.5) (end 199 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 149 159.5) (end 159 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 159 159.5) (end 169 159.5) (width 0.381) (layer F.Cu) (net 69))
  (segment (start 83.6994 134.0694) (end 82.71 133.08) (width 0.381) (layer B.Cu) (net 69))
  (segment (start 83.6994 152.4846) (end 83.6994 134.0694) (width 0.381) (layer B.Cu) (net 69))
  (segment (start 89 157.7852) (end 83.6994 152.4846) (width 0.381) (layer B.Cu) (net 69))
  (segment (start 89 159.5) (end 89 157.7852) (width 0.381) (layer B.Cu) (net 69))
  (segment (start 39 159.5) (end 49 159.5) (width 0.381) (layer F.Cu) (net 70))
  (segment (start 59 159.5) (end 69 159.5) (width 0.381) (layer F.Cu) (net 70))
  (segment (start 29 159.5) (end 39 159.5) (width 0.381) (layer F.Cu) (net 70))
  (segment (start 19.2122 133.7722) (end 14.94 129.5) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 19.2122 135.5578) (end 19.2122 133.7722) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 24.5925 140.9381) (end 19.2122 135.5578) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 24.5925 153.3777) (end 24.5925 140.9381) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 29 157.7852) (end 24.5925 153.3777) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 29 159.5) (end 29 157.7852) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 245.01 128.78) (end 245.01 131.32) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 143.5019 161.2148) (end 79 161.2148) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 149.0818 155.6349) (end 143.5019 161.2148) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 191.0458 155.6349) (end 149.0818 155.6349) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 194 152.6807) (end 191.0458 155.6349) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 194 143.03) (end 194 152.6807) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 202.5437 134.4863) (end 194 143.03) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 211.4032 134.4863) (end 202.5437 134.4863) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 213.9587 131.9308) (end 211.4032 134.4863) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 223.9137 131.9308) (end 213.9587 131.9308) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 225.0709 133.088) (end 223.9137 131.9308) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 243.242 133.088) (end 225.0709 133.088) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 245.01 131.32) (end 243.242 133.088) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 59 159.5) (end 49 159.5) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 79 159.5) (end 79 160.3574) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 79 160.3574) (end 79 161.2148) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 72.8422 160.3574) (end 71.9848 159.5) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 79 160.3574) (end 72.8422 160.3574) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 69 159.5) (end 71.9848 159.5) (width 0.381) (layer B.Cu) (net 70))
  (segment (start 219 159.5) (end 209 159.5) (width 0.381) (layer F.Cu) (net 71))
  (segment (start 229 159.5) (end 229 157.7852) (width 0.381) (layer B.Cu) (net 71))
  (segment (start 219 159.5) (end 219 157.7852) (width 0.381) (layer B.Cu) (net 71))
  (segment (start 224.0804 152.8656) (end 223.9196 152.8656) (width 0.381) (layer B.Cu) (net 71))
  (segment (start 229 157.7852) (end 224.0804 152.8656) (width 0.381) (layer B.Cu) (net 71))
  (segment (start 223.9196 134.5896) (end 223.9196 152.8656) (width 0.381) (layer B.Cu) (net 71))
  (segment (start 222.41 133.08) (end 223.9196 134.5896) (width 0.381) (layer B.Cu) (net 71))
  (segment (start 223.9196 152.8656) (end 219 157.7852) (width 0.381) (layer B.Cu) (net 71))
  (segment (start 229 159.5) (end 239 159.5) (width 0.381) (layer F.Cu) (net 71))
  (segment (start 259 159.5) (end 269 159.5) (width 0.381) (layer F.Cu) (net 71))
  (segment (start 269 159.5) (end 279 159.5) (width 0.381) (layer F.Cu) (net 71))
  (segment (start 239 159.5) (end 249 159.5) (width 0.381) (layer F.Cu) (net 71))
  (segment (start 249 159.5) (end 259 159.5) (width 0.381) (layer F.Cu) (net 71))
  (via (at 46.7355 117.1664) (size 0.889) (layers F.Cu B.Cu) (net 72))
  (segment (start 215.24 111.13) (end 214.1602 111.13) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 43.68 124) (end 42.41 125.27) (width 0.254) (layer B.Cu) (net 72))
  (segment (start 43.68 120.2219) (end 43.68 124) (width 0.254) (layer B.Cu) (net 72))
  (segment (start 46.7355 117.1664) (end 43.68 120.2219) (width 0.254) (layer B.Cu) (net 72))
  (segment (start 205.3363 119.9539) (end 214.1602 111.13) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 163.7895 119.9539) (end 205.3363 119.9539) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 163.2898 119.4542) (end 163.7895 119.9539) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 75.686 119.4542) (end 163.2898 119.4542) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 75.0777 120.0625) (end 75.686 119.4542) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 73.1045 120.0625) (end 75.0777 120.0625) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 70.7115 117.6695) (end 73.1045 120.0625) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 70.7115 117.4112) (end 70.7115 117.6695) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 67.3533 114.053) (end 70.7115 117.4112) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 49.8489 114.053) (end 67.3533 114.053) (width 0.254) (layer F.Cu) (net 72))
  (segment (start 46.7355 117.1664) (end 49.8489 114.053) (width 0.254) (layer F.Cu) (net 72))
  (via (at 46.7255 113.9784) (size 0.889) (layers F.Cu B.Cu) (net 73))
  (segment (start 41.14 119.5639) (end 46.7255 113.9784) (width 0.254) (layer B.Cu) (net 73))
  (segment (start 41.14 124) (end 41.14 119.5639) (width 0.254) (layer B.Cu) (net 73))
  (segment (start 39.87 125.27) (end 41.14 124) (width 0.254) (layer B.Cu) (net 73))
  (segment (start 204.396 119.434) (end 215.24 108.59) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 164.8008 119.434) (end 204.396 119.434) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 164.3127 118.9459) (end 164.8008 119.434) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 75.4755 118.9459) (end 164.3127 118.9459) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 74.8672 119.5542) (end 75.4755 118.9459) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 73.315 119.5542) (end 74.8672 119.5542) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 71.2198 117.459) (end 73.315 119.5542) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 71.2198 117.2007) (end 71.2198 117.459) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 67.5638 113.5447) (end 71.2198 117.2007) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 47.1592 113.5447) (end 67.5638 113.5447) (width 0.254) (layer F.Cu) (net 73))
  (segment (start 46.7255 113.9784) (end 47.1592 113.5447) (width 0.254) (layer F.Cu) (net 73))
  (via (at 74.3516 118.7284) (size 0.889) (layers F.Cu B.Cu) (net 74))
  (segment (start 70.35 122.73) (end 74.3516 118.7284) (width 0.254) (layer B.Cu) (net 74))
  (segment (start 74.6581 118.4219) (end 74.3516 118.7284) (width 0.254) (layer F.Cu) (net 74))
  (segment (start 165.8133 118.4219) (end 74.6581 118.4219) (width 0.254) (layer F.Cu) (net 74))
  (segment (start 166.279 118.8876) (end 165.8133 118.4219) (width 0.254) (layer F.Cu) (net 74))
  (segment (start 189.6176 118.8876) (end 166.279 118.8876) (width 0.254) (layer F.Cu) (net 74))
  (segment (start 202.4552 106.05) (end 189.6176 118.8876) (width 0.254) (layer F.Cu) (net 74))
  (segment (start 215.24 106.05) (end 202.4552 106.05) (width 0.254) (layer F.Cu) (net 74))
  (via (at 73.5094 117.8863) (size 0.889) (layers F.Cu B.Cu) (net 75))
  (segment (start 69.189 122.2067) (end 73.5094 117.8863) (width 0.254) (layer B.Cu) (net 75))
  (segment (start 69.189 124.109) (end 69.189 122.2067) (width 0.254) (layer B.Cu) (net 75))
  (segment (start 70.35 125.27) (end 69.189 124.109) (width 0.254) (layer B.Cu) (net 75))
  (segment (start 166.7756 117.8863) (end 73.5094 117.8863) (width 0.254) (layer F.Cu) (net 75))
  (segment (start 167.2685 118.3792) (end 166.7756 117.8863) (width 0.254) (layer F.Cu) (net 75))
  (segment (start 188.0154 118.3792) (end 167.2685 118.3792) (width 0.254) (layer F.Cu) (net 75))
  (segment (start 202.8846 103.51) (end 188.0154 118.3792) (width 0.254) (layer F.Cu) (net 75))
  (segment (start 215.24 103.51) (end 202.8846 103.51) (width 0.254) (layer F.Cu) (net 75))
  (via (at 72.0456 117.117) (size 0.889) (layers F.Cu B.Cu) (net 76))
  (segment (start 71.7875 117.117) (end 72.0456 117.117) (width 0.254) (layer B.Cu) (net 76))
  (segment (start 66.6329 122.2716) (end 71.7875 117.117) (width 0.254) (layer B.Cu) (net 76))
  (segment (start 66.6329 124.0929) (end 66.6329 122.2716) (width 0.254) (layer B.Cu) (net 76))
  (segment (start 67.81 125.27) (end 66.6329 124.0929) (width 0.254) (layer B.Cu) (net 76))
  (segment (start 212.2913 98.0213) (end 215.24 100.97) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 166.9503 98.0213) (end 212.2913 98.0213) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 152.2996 112.672) (end 166.9503 98.0213) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 77.7335 112.672) (end 152.2996 112.672) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 74.3019 116.1036) (end 77.7335 112.672) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 74.3019 116.256) (end 74.3019 116.1036) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 73.5204 117.0375) (end 74.3019 116.256) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 72.1251 117.0375) (end 73.5204 117.0375) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 72.0456 117.117) (end 72.1251 117.0375) (width 0.254) (layer F.Cu) (net 76))
  (segment (start 215.24 99.2311) (end 215.24 98.43) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 203.3834 111.0877) (end 215.24 99.2311) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 176.5976 111.0877) (end 203.3834 111.0877) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 171.5043 116.181) (end 176.5976 111.0877) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 170.3226 116.181) (end 171.5043 116.181) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 169.541 116.9626) (end 170.3226 116.181) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 169.541 116.9874) (end 169.541 116.9626) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 161.7612 124.7672) (end 169.541 116.9874) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 97.6652 124.7672) (end 161.7612 124.7672) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 91.6673 130.7651) (end 97.6652 124.7672) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 86.3283 130.7651) (end 91.6673 130.7651) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 85.4209 129.8577) (end 86.3283 130.7651) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 71.3431 129.8577) (end 85.4209 129.8577) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 70.9812 130.2196) (end 71.3431 129.8577) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 69.7306 130.2196) (end 70.9812 130.2196) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 68.9496 129.4386) (end 69.7306 130.2196) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 68.9496 128.4343) (end 68.9496 129.4386) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 68.1614 127.6461) (end 68.9496 128.4343) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 65.1061 127.6461) (end 68.1614 127.6461) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 62.73 125.27) (end 65.1061 127.6461) (width 0.254) (layer B.Cu) (net 77))
  (segment (start 166 95.89) (end 215.24 95.89) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 160.8205 101.0695) (end 166 95.89) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 143.4703 101.0695) (end 160.8205 101.0695) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 140.9812 98.5804) (end 143.4703 101.0695) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 139.7115 98.5804) (end 140.9812 98.5804) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 138.9496 99.3423) (end 139.7115 98.5804) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 138.9496 100.3221) (end 138.9496 99.3423) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 128.537 110.7347) (end 138.9496 100.3221) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 78.9357 110.7347) (end 128.537 110.7347) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 73.7936 115.8768) (end 78.9357 110.7347) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 73.7936 116.0455) (end 73.7936 115.8768) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 73.3099 116.5292) (end 73.7936 116.0455) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 72.6258 116.5292) (end 73.3099 116.5292) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 69.0864 112.9898) (end 72.6258 116.5292) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 49.8972 112.9898) (end 69.0864 112.9898) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 43.95 107.0426) (end 49.8972 112.9898) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 43.95 106.4301) (end 43.95 107.0426) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 43.1391 105.6192) (end 43.95 106.4301) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 42.2341 105.6192) (end 43.1391 105.6192) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 41.571 106.2823) (end 42.2341 105.6192) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 41.571 121.891) (end 41.571 106.2823) (width 0.254) (layer F.Cu) (net 78))
  (segment (start 42.41 122.73) (end 41.571 121.891) (width 0.254) (layer F.Cu) (net 78))
  (via (at 72.9678 115.7034) (size 0.889) (layers F.Cu B.Cu) (net 79))
  (segment (start 85.9 102.7712) (end 72.9678 115.7034) (width 0.254) (layer F.Cu) (net 79))
  (segment (start 100.8346 102.7712) (end 85.9 102.7712) (width 0.254) (layer F.Cu) (net 79))
  (segment (start 110.2558 93.35) (end 100.8346 102.7712) (width 0.254) (layer F.Cu) (net 79))
  (segment (start 215.24 93.35) (end 110.2558 93.35) (width 0.254) (layer F.Cu) (net 79))
  (segment (start 75.1941 120.4259) (end 72.89 122.73) (width 0.254) (layer B.Cu) (net 79))
  (segment (start 75.1941 117.9297) (end 75.1941 120.4259) (width 0.254) (layer B.Cu) (net 79))
  (segment (start 72.9678 115.7034) (end 75.1941 117.9297) (width 0.254) (layer B.Cu) (net 79))

  (zone (net 0) (net_name "") (layer B.Cu) (tstamp 554E4CD1) (hatch edge 0.508)
    (connect_pads (clearance 0.508))
    (min_thickness 0.254)
    (keepout (tracks not_allowed) (vias not_allowed) (copperpour allowed))
    (fill (arc_segments 16) (thermal_gap 0.508) (thermal_bridge_width 0.508))
    (polygon
      (pts
        (xy 288 140) (xy 284 140) (xy 284 156) (xy 288 156)
      )
    )
  )
  (zone (net 0) (net_name "") (layer F.Cu) (tstamp 554E4CD1) (hatch edge 0.508)
    (connect_pads (clearance 0.508))
    (min_thickness 0.254)
    (keepout (tracks not_allowed) (vias not_allowed) (copperpour allowed))
    (fill (arc_segments 16) (thermal_gap 0.508) (thermal_bridge_width 0.508))
    (polygon
      (pts
        (xy 288 140) (xy 284 140) (xy 284 156) (xy 288 156)
      )
    )
  )
)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted hardware/pdp8i/PDP8.pro.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
update=17/05/2015 11:44:30
version=1
last_client=eeschema
[cvpcb]
version=1
NetIExt=net
[cvpcb/libraries]
EquName1=devcms
[pcbnew]
version=1
LastNetListRead=
UseCmpFile=1
PadDrill=0.600000000000
PadDrillOvalY=0.600000000000
PadSizeH=1.500000000000
PadSizeV=1.500000000000
PcbTextSizeV=1.500000000000
PcbTextSizeH=1.500000000000
PcbTextThickness=0.300000000000
ModuleTextSizeV=1.000000000000
ModuleTextSizeH=1.000000000000
ModuleTextSizeThickness=0.150000000000
SolderMaskClearance=0.000000000000
SolderMaskMinWidth=0.000000000000
DrawSegmentWidth=0.200000000000
BoardOutlineThickness=0.100000000000
ModuleOutlineThickness=0.150000000000
[pcbnew/libraries]
LibDir=customlibraries
LibName1=sockets
LibName2=connect
LibName3=discret
LibName4=pin_array
LibName5=divers
LibName6=smd_capacitors
LibName7=smd_resistors
LibName8=smd_crystal&oscillator
LibName9=smd_dil
LibName10=smd_transistors
LibName11=libcms
LibName12=display
LibName13=pdp8footprintlib2
LibName14=led
LibName15=dip_sockets
LibName16=pga_sockets
LibName17=valves
[general]
version=1
[eeschema]
version=1
LibDir=customlibraries
NetFmtName=
RptD_X=0
RptD_Y=100
RptLab=1
LabSize=60
[eeschema/libraries]
LibName1=power
LibName2=device
LibName3=transistors
LibName4=conn
LibName5=linear
LibName6=regul
LibName7=74xx
LibName8=cmos4000
LibName9=adc-dac
LibName10=memory
LibName11=xilinx
LibName12=special
LibName13=microcontrollers
LibName14=dsp
LibName15=microchip
LibName16=analog_switches
LibName17=motorola
LibName18=texas
LibName19=intel
LibName20=audio
LibName21=interface
LibName22=digital-audio
LibName23=philips
LibName24=display
LibName25=cypress
LibName26=siliconi
LibName27=opto
LibName28=atmel
LibName29=contrib
LibName30=valves
LibName31=pdp8_library
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































Deleted hardware/pdp8i/PDP8.rules.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

(rules PCB PDP8
  (snap_angle 
    fortyfive_degree
  )
  (autoroute_settings
    (fanout off)
    (autoroute on)
    (postroute on)
    (vias on)
    (via_costs 50)
    (plane_via_costs 5)
    (start_ripup_costs 100)
    (start_pass_no 19938)
    (layer_rule F.Cu
      (active on)
      (preferred_direction horizontal)
      (preferred_direction_trace_costs 1.0)
      (against_preferred_direction_trace_costs 3.9)
    )
    (layer_rule B.Cu
      (active on)
      (preferred_direction vertical)
      (preferred_direction_trace_costs 1.0)
      (against_preferred_direction_trace_costs 1.3)
    )
  )
  (rule
    (width 254.0)
    (clear 254.2)
    (clear 127.0 (type smd_to_turn_gap))
    (clear 63.6 (type smd_smd))
  )
  (padstack "Via[0-1]_889:635_um"
    (shape
      (circle F.Cu 889.0 0.0 0.0)
    )
    (shape
      (circle B.Cu 889.0 0.0 0.0)
    )
    (attach off)
  )
  (padstack "Via[0-1]_889:0_um"
    (shape
      (circle F.Cu 889.0 0.0 0.0)
    )
    (shape
      (circle B.Cu 889.0 0.0 0.0)
    )
    (attach off)
  )
  (via 
    "Via[0-1]_889:635_um" "Via[0-1]_889:635_um" default
  )
  (via 
    "Via[0-1]_889:0_um" "Via[0-1]_889:0_um" default
  )
  (via 
    "Via[0-1]_889:635_um-kicad_default" "Via[0-1]_889:635_um" "kicad_default"
  )
  (via 
    "Via[0-1]_889:0_um-kicad_default" "Via[0-1]_889:0_um" "kicad_default"
  )
  (via_rule
    default "Via[0-1]_889:635_um"
  )
  (via_rule
    "kicad_default" "Via[0-1]_889:635_um-kicad_default"
  )
  (class default
    (clearance_class default)
    (via_rule default)
    (rule
      (width 254.0)
    )
    (circuit 
      (use_layer F.Cu B.Cu)
    )
  )
  (class "kicad_default"
    "N-0000023" "N-0000028" "N-0000029" "N-0000035" "N-0000039" "N-0000040" "N-0000041" "N-0000042"
    "N-0000043" "N-0000046" "N-0000048" "N-0000049" "N-0000050" "N-0000053" "N-0000054" "N-0000055"
    "N-0000056" "N-0000057" "N-0000059" "N-0000060" "N-0000061" "N-0000062" "N-0000063" "N-0000065"
    "N-0000066" "N-0000067" "N-0000068" "N-0000069" "N-0000070" "N-0000071" "N-0000072" "N-0000073"
    "N-0000074" "N-0000079" "N-0000085" "N-0000086" "N-0000087" "N-0000088" "N-0000089" "N-0000090"
    "N-0000091" "N-0000092" "N-0000093" RX "SPARE_IO" TX col1 col10
    col11 col12 col1a col2 col2a col3 col4 col5
    col6 col7 col8 col9 led1 led2 led3 led4
    led5 led6 led7 led8 xled1 xled2 xled3 xled4
    xled5 xled6 xled7 xled8
    (clearance_class "kicad_default")
    (via_rule kicad_default)
    (rule
      (width 254.0)
    )
    (circuit 
      (use_layer F.Cu B.Cu)
    )
  )
  (class fat
    +3.3V +5V GND row1 row2 row3
    (clearance_class default)
    (via_rule default)
    (rule
      (width 381.0)
    )
    (circuit 
      (use_layer F.Cu B.Cu)
    )
  )
)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































































































































Deleted hardware/pdp8i/PDP8.sch.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
EESchema Schematic File Version 2
LIBS:power
LIBS:device
LIBS:transistors
LIBS:conn
LIBS:linear
LIBS:regul
LIBS:74xx
LIBS:cmos4000
LIBS:adc-dac
LIBS:memory
LIBS:xilinx
LIBS:special
LIBS:microcontrollers
LIBS:dsp
LIBS:microchip
LIBS:analog_switches
LIBS:motorola
LIBS:texas
LIBS:intel
LIBS:audio
LIBS:interface
LIBS:digital-audio
LIBS:philips
LIBS:display
LIBS:cypress
LIBS:siliconi
LIBS:opto
LIBS:atmel
LIBS:contrib
LIBS:valves
LIBS:pdp8_library
LIBS:PDP8-cache
EELAYER 27 0
EELAYER END
$Descr A4 11693 8268
encoding utf-8
Sheet 1 1
Title ""
Date "11 may 2015"
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
$Comp
L LED DPC1
U 1 1 548EF34A
P 5500 900
F 0 "DPC1" H 5500 1000 50  0000 C CNN
F 1 "LED" H 5500 800 50  0000 C CNN
F 2 "~" H 5500 900 60  0000 C CNN
F 3 "~" H 5500 900 60  0000 C CNN
	1    5500 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC2
U 1 1 548EF399
P 5800 900
F 0 "DPC2" H 5800 1000 50  0000 C CNN
F 1 "LED" H 5800 800 50  0000 C CNN
F 2 "~" H 5800 900 60  0000 C CNN
F 3 "~" H 5800 900 60  0000 C CNN
	1    5800 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC3
U 1 1 548EF3AC
P 6100 900
F 0 "DPC3" H 6100 1000 50  0000 C CNN
F 1 "LED" H 6100 800 50  0000 C CNN
F 2 "~" H 6100 900 60  0000 C CNN
F 3 "~" H 6100 900 60  0000 C CNN
	1    6100 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC4
U 1 1 548EF3B2
P 6400 900
F 0 "DPC4" H 6400 1000 50  0000 C CNN
F 1 "LED" H 6400 800 50  0000 C CNN
F 2 "~" H 6400 900 60  0000 C CNN
F 3 "~" H 6400 900 60  0000 C CNN
	1    6400 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC5
U 1 1 548EF3B8
P 6700 900
F 0 "DPC5" H 6700 1000 50  0000 C CNN
F 1 "LED" H 6700 800 50  0000 C CNN
F 2 "~" H 6700 900 60  0000 C CNN
F 3 "~" H 6700 900 60  0000 C CNN
	1    6700 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC6
U 1 1 548EF3BE
P 7000 900
F 0 "DPC6" H 7000 1000 50  0000 C CNN
F 1 "LED" H 7000 800 50  0000 C CNN
F 2 "~" H 7000 900 60  0000 C CNN
F 3 "~" H 7000 900 60  0000 C CNN
	1    7000 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC7
U 1 1 548EF3C4
P 7300 900
F 0 "DPC7" H 7300 1000 50  0000 C CNN
F 1 "LED" H 7300 800 50  0000 C CNN
F 2 "~" H 7300 900 60  0000 C CNN
F 3 "~" H 7300 900 60  0000 C CNN
	1    7300 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC8
U 1 1 548EF3CA
P 7600 900
F 0 "DPC8" H 7600 1000 50  0000 C CNN
F 1 "LED" H 7600 800 50  0000 C CNN
F 2 "~" H 7600 900 60  0000 C CNN
F 3 "~" H 7600 900 60  0000 C CNN
	1    7600 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC9
U 1 1 548EF3D0
P 7900 900
F 0 "DPC9" H 7900 1000 50  0000 C CNN
F 1 "LED" H 7900 800 50  0000 C CNN
F 2 "~" H 7900 900 60  0000 C CNN
F 3 "~" H 7900 900 60  0000 C CNN
	1    7900 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC10
U 1 1 548EF3D6
P 8200 900
F 0 "DPC10" H 8200 1000 50  0000 C CNN
F 1 "LED" H 8200 800 50  0000 C CNN
F 2 "~" H 8200 900 60  0000 C CNN
F 3 "~" H 8200 900 60  0000 C CNN
	1    8200 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC11
U 1 1 548EF3DC
P 8500 900
F 0 "DPC11" H 8500 1000 50  0000 C CNN
F 1 "LED" H 8500 800 50  0000 C CNN
F 2 "~" H 8500 900 60  0000 C CNN
F 3 "~" H 8500 900 60  0000 C CNN
	1    8500 900 
	0    1    1    0   
$EndComp
$Comp
L LED DPC12
U 1 1 548EF3E2
P 8800 900
F 0 "DPC12" H 8800 1000 50  0000 C CNN
F 1 "LED" H 8800 800 50  0000 C CNN
F 2 "~" H 8800 900 60  0000 C CNN
F 3 "~" H 8800 900 60  0000 C CNN
	1    8800 900 
	0    1    1    0   
$EndComp
$Comp
L LED DMA1
U 1 1 548EF463
P 5500 1550
F 0 "DMA1" H 5500 1650 50  0000 C CNN
F 1 "LED" H 5500 1450 50  0000 C CNN
F 2 "~" H 5500 1550 60  0000 C CNN
F 3 "~" H 5500 1550 60  0000 C CNN
	1    5500 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA2
U 1 1 548EF47C
P 5800 1550
F 0 "DMA2" H 5800 1650 50  0000 C CNN
F 1 "LED" H 5800 1450 50  0000 C CNN
F 2 "~" H 5800 1550 60  0000 C CNN
F 3 "~" H 5800 1550 60  0000 C CNN
	1    5800 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA3
U 1 1 548EF482
P 6100 1550
F 0 "DMA3" H 6100 1650 50  0000 C CNN
F 1 "LED" H 6100 1450 50  0000 C CNN
F 2 "~" H 6100 1550 60  0000 C CNN
F 3 "~" H 6100 1550 60  0000 C CNN
	1    6100 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA4
U 1 1 548EF488
P 6400 1550
F 0 "DMA4" H 6400 1650 50  0000 C CNN
F 1 "LED" H 6400 1450 50  0000 C CNN
F 2 "~" H 6400 1550 60  0000 C CNN
F 3 "~" H 6400 1550 60  0000 C CNN
	1    6400 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA5
U 1 1 548EF48E
P 6700 1550
F 0 "DMA5" H 6700 1650 50  0000 C CNN
F 1 "LED" H 6700 1450 50  0000 C CNN
F 2 "~" H 6700 1550 60  0000 C CNN
F 3 "~" H 6700 1550 60  0000 C CNN
	1    6700 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA6
U 1 1 548EF494
P 7000 1550
F 0 "DMA6" H 7000 1650 50  0000 C CNN
F 1 "LED" H 7000 1450 50  0000 C CNN
F 2 "~" H 7000 1550 60  0000 C CNN
F 3 "~" H 7000 1550 60  0000 C CNN
	1    7000 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA7
U 1 1 548EF49A
P 7300 1550
F 0 "DMA7" H 7300 1650 50  0000 C CNN
F 1 "LED" H 7300 1450 50  0000 C CNN
F 2 "~" H 7300 1550 60  0000 C CNN
F 3 "~" H 7300 1550 60  0000 C CNN
	1    7300 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA8
U 1 1 548EF4A0
P 7600 1550
F 0 "DMA8" H 7600 1650 50  0000 C CNN
F 1 "LED" H 7600 1450 50  0000 C CNN
F 2 "~" H 7600 1550 60  0000 C CNN
F 3 "~" H 7600 1550 60  0000 C CNN
	1    7600 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA9
U 1 1 548EF4A6
P 7900 1550
F 0 "DMA9" H 7900 1650 50  0000 C CNN
F 1 "LED" H 7900 1450 50  0000 C CNN
F 2 "~" H 7900 1550 60  0000 C CNN
F 3 "~" H 7900 1550 60  0000 C CNN
	1    7900 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA10
U 1 1 548EF4AC
P 8200 1550
F 0 "DMA10" H 8200 1650 50  0000 C CNN
F 1 "LED" H 8200 1450 50  0000 C CNN
F 2 "~" H 8200 1550 60  0000 C CNN
F 3 "~" H 8200 1550 60  0000 C CNN
	1    8200 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA11
U 1 1 548EF4B2
P 8500 1550
F 0 "DMA11" H 8500 1650 50  0000 C CNN
F 1 "LED" H 8500 1450 50  0000 C CNN
F 2 "~" H 8500 1550 60  0000 C CNN
F 3 "~" H 8500 1550 60  0000 C CNN
	1    8500 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMA12
U 1 1 548EF4B8
P 8800 1550
F 0 "DMA12" H 8800 1650 50  0000 C CNN
F 1 "LED" H 8800 1450 50  0000 C CNN
F 2 "~" H 8800 1550 60  0000 C CNN
F 3 "~" H 8800 1550 60  0000 C CNN
	1    8800 1550
	0    -1   -1   0   
$EndComp
$Comp
L LED DMB1
U 1 1 548EF56F
P 5500 2200
F 0 "DMB1" H 5500 2300 50  0000 C CNN
F 1 "LED" H 5500 2100 50  0000 C CNN
F 2 "~" H 5500 2200 60  0000 C CNN
F 3 "~" H 5500 2200 60  0000 C CNN
	1    5500 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB2
U 1 1 548EF588
P 5800 2200
F 0 "DMB2" H 5800 2300 50  0000 C CNN
F 1 "LED" H 5800 2100 50  0000 C CNN
F 2 "~" H 5800 2200 60  0000 C CNN
F 3 "~" H 5800 2200 60  0000 C CNN
	1    5800 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB3
U 1 1 548EF58E
P 6100 2200
F 0 "DMB3" H 6100 2300 50  0000 C CNN
F 1 "LED" H 6100 2100 50  0000 C CNN
F 2 "~" H 6100 2200 60  0000 C CNN
F 3 "~" H 6100 2200 60  0000 C CNN
	1    6100 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB4
U 1 1 548EF594
P 6400 2200
F 0 "DMB4" H 6400 2300 50  0000 C CNN
F 1 "LED" H 6400 2100 50  0000 C CNN
F 2 "~" H 6400 2200 60  0000 C CNN
F 3 "~" H 6400 2200 60  0000 C CNN
	1    6400 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB5
U 1 1 548EF59A
P 6700 2200
F 0 "DMB5" H 6700 2300 50  0000 C CNN
F 1 "LED" H 6700 2100 50  0000 C CNN
F 2 "~" H 6700 2200 60  0000 C CNN
F 3 "~" H 6700 2200 60  0000 C CNN
	1    6700 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB6
U 1 1 548EF5A0
P 7000 2200
F 0 "DMB6" H 7000 2300 50  0000 C CNN
F 1 "LED" H 7000 2100 50  0000 C CNN
F 2 "~" H 7000 2200 60  0000 C CNN
F 3 "~" H 7000 2200 60  0000 C CNN
	1    7000 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB7
U 1 1 548EF5A6
P 7300 2200
F 0 "DMB7" H 7300 2300 50  0000 C CNN
F 1 "LED" H 7300 2100 50  0000 C CNN
F 2 "~" H 7300 2200 60  0000 C CNN
F 3 "~" H 7300 2200 60  0000 C CNN
	1    7300 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB8
U 1 1 548EF5AC
P 7600 2200
F 0 "DMB8" H 7600 2300 50  0000 C CNN
F 1 "LED" H 7600 2100 50  0000 C CNN
F 2 "~" H 7600 2200 60  0000 C CNN
F 3 "~" H 7600 2200 60  0000 C CNN
	1    7600 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB9
U 1 1 548EF5B2
P 7900 2200
F 0 "DMB9" H 7900 2300 50  0000 C CNN
F 1 "LED" H 7900 2100 50  0000 C CNN
F 2 "~" H 7900 2200 60  0000 C CNN
F 3 "~" H 7900 2200 60  0000 C CNN
	1    7900 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB10
U 1 1 548EF5B8
P 8200 2200
F 0 "DMB10" H 8200 2300 50  0000 C CNN
F 1 "LED" H 8200 2100 50  0000 C CNN
F 2 "~" H 8200 2200 60  0000 C CNN
F 3 "~" H 8200 2200 60  0000 C CNN
	1    8200 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB11
U 1 1 548EF5BE
P 8500 2200
F 0 "DMB11" H 8500 2300 50  0000 C CNN
F 1 "LED" H 8500 2100 50  0000 C CNN
F 2 "~" H 8500 2200 60  0000 C CNN
F 3 "~" H 8500 2200 60  0000 C CNN
	1    8500 2200
	0    1    1    0   
$EndComp
$Comp
L LED DMB12
U 1 1 548EF5C4
P 8800 2200
F 0 "DMB12" H 8800 2300 50  0000 C CNN
F 1 "LED" H 8800 2100 50  0000 C CNN
F 2 "~" H 8800 2200 60  0000 C CNN
F 3 "~" H 8800 2200 60  0000 C CNN
	1    8800 2200
	0    1    1    0   
$EndComp
$Comp
L LED DAC1
U 1 1 548EF5CC
P 5500 2850
F 0 "DAC1" H 5500 2950 50  0000 C CNN
F 1 "LED" H 5500 2750 50  0000 C CNN
F 2 "~" H 5500 2850 60  0000 C CNN
F 3 "~" H 5500 2850 60  0000 C CNN
	1    5500 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC2
U 1 1 548EF5E5
P 5800 2850
F 0 "DAC2" H 5800 2950 50  0000 C CNN
F 1 "LED" H 5800 2750 50  0000 C CNN
F 2 "~" H 5800 2850 60  0000 C CNN
F 3 "~" H 5800 2850 60  0000 C CNN
	1    5800 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC3
U 1 1 548EF5EB
P 6100 2850
F 0 "DAC3" H 6100 2950 50  0000 C CNN
F 1 "LED" H 6100 2750 50  0000 C CNN
F 2 "~" H 6100 2850 60  0000 C CNN
F 3 "~" H 6100 2850 60  0000 C CNN
	1    6100 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC4
U 1 1 548EF5F1
P 6400 2850
F 0 "DAC4" H 6400 2950 50  0000 C CNN
F 1 "LED" H 6400 2750 50  0000 C CNN
F 2 "~" H 6400 2850 60  0000 C CNN
F 3 "~" H 6400 2850 60  0000 C CNN
	1    6400 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC5
U 1 1 548EF5F7
P 6700 2850
F 0 "DAC5" H 6700 2950 50  0000 C CNN
F 1 "LED" H 6700 2750 50  0000 C CNN
F 2 "~" H 6700 2850 60  0000 C CNN
F 3 "~" H 6700 2850 60  0000 C CNN
	1    6700 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC6
U 1 1 548EF5FD
P 7000 2850
F 0 "DAC6" H 7000 2950 50  0000 C CNN
F 1 "LED" H 7000 2750 50  0000 C CNN
F 2 "~" H 7000 2850 60  0000 C CNN
F 3 "~" H 7000 2850 60  0000 C CNN
	1    7000 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC7
U 1 1 548EF603
P 7300 2850
F 0 "DAC7" H 7300 2950 50  0000 C CNN
F 1 "LED" H 7300 2750 50  0000 C CNN
F 2 "~" H 7300 2850 60  0000 C CNN
F 3 "~" H 7300 2850 60  0000 C CNN
	1    7300 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC8
U 1 1 548EF609
P 7600 2850
F 0 "DAC8" H 7600 2950 50  0000 C CNN
F 1 "LED" H 7600 2750 50  0000 C CNN
F 2 "~" H 7600 2850 60  0000 C CNN
F 3 "~" H 7600 2850 60  0000 C CNN
	1    7600 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC9
U 1 1 548EF60F
P 7900 2850
F 0 "DAC9" H 7900 2950 50  0000 C CNN
F 1 "LED" H 7900 2750 50  0000 C CNN
F 2 "~" H 7900 2850 60  0000 C CNN
F 3 "~" H 7900 2850 60  0000 C CNN
	1    7900 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC10
U 1 1 548EF615
P 8200 2850
F 0 "DAC10" H 8200 2950 50  0000 C CNN
F 1 "LED" H 8200 2750 50  0000 C CNN
F 2 "~" H 8200 2850 60  0000 C CNN
F 3 "~" H 8200 2850 60  0000 C CNN
	1    8200 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC11
U 1 1 548EF61B
P 8500 2850
F 0 "DAC11" H 8500 2950 50  0000 C CNN
F 1 "LED" H 8500 2750 50  0000 C CNN
F 2 "~" H 8500 2850 60  0000 C CNN
F 3 "~" H 8500 2850 60  0000 C CNN
	1    8500 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DAC12
U 1 1 548EF621
P 8800 2850
F 0 "DAC12" H 8800 2950 50  0000 C CNN
F 1 "LED" H 8800 2750 50  0000 C CNN
F 2 "~" H 8800 2850 60  0000 C CNN
F 3 "~" H 8800 2850 60  0000 C CNN
	1    8800 2850
	0    -1   -1   0   
$EndComp
$Comp
L LED DMQ1
U 1 1 548EF629
P 5500 3600
F 0 "DMQ1" H 5500 3700 50  0000 C CNN
F 1 "LED" H 5500 3500 50  0000 C CNN
F 2 "~" H 5500 3600 60  0000 C CNN
F 3 "~" H 5500 3600 60  0000 C CNN
	1    5500 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ2
U 1 1 548EF642
P 5800 3600
F 0 "DMQ2" H 5800 3700 50  0000 C CNN
F 1 "LED" H 5800 3500 50  0000 C CNN
F 2 "~" H 5800 3600 60  0000 C CNN
F 3 "~" H 5800 3600 60  0000 C CNN
	1    5800 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ3
U 1 1 548EF648
P 6100 3600
F 0 "DMQ3" H 6100 3700 50  0000 C CNN
F 1 "LED" H 6100 3500 50  0000 C CNN
F 2 "~" H 6100 3600 60  0000 C CNN
F 3 "~" H 6100 3600 60  0000 C CNN
	1    6100 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ4
U 1 1 548EF64E
P 6400 3600
F 0 "DMQ4" H 6400 3700 50  0000 C CNN
F 1 "LED" H 6400 3500 50  0000 C CNN
F 2 "~" H 6400 3600 60  0000 C CNN
F 3 "~" H 6400 3600 60  0000 C CNN
	1    6400 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ5
U 1 1 548EF654
P 6700 3600
F 0 "DMQ5" H 6700 3700 50  0000 C CNN
F 1 "LED" H 6700 3500 50  0000 C CNN
F 2 "~" H 6700 3600 60  0000 C CNN
F 3 "~" H 6700 3600 60  0000 C CNN
	1    6700 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ6
U 1 1 548EF65A
P 7000 3600
F 0 "DMQ6" H 7000 3700 50  0000 C CNN
F 1 "LED" H 7000 3500 50  0000 C CNN
F 2 "~" H 7000 3600 60  0000 C CNN
F 3 "~" H 7000 3600 60  0000 C CNN
	1    7000 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ7
U 1 1 548EF660
P 7300 3600
F 0 "DMQ7" H 7300 3700 50  0000 C CNN
F 1 "LED" H 7300 3500 50  0000 C CNN
F 2 "~" H 7300 3600 60  0000 C CNN
F 3 "~" H 7300 3600 60  0000 C CNN
	1    7300 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ8
U 1 1 548EF666
P 7600 3600
F 0 "DMQ8" H 7600 3700 50  0000 C CNN
F 1 "LED" H 7600 3500 50  0000 C CNN
F 2 "~" H 7600 3600 60  0000 C CNN
F 3 "~" H 7600 3600 60  0000 C CNN
	1    7600 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ9
U 1 1 548EF66C
P 7900 3600
F 0 "DMQ9" H 7900 3700 50  0000 C CNN
F 1 "LED" H 7900 3500 50  0000 C CNN
F 2 "~" H 7900 3600 60  0000 C CNN
F 3 "~" H 7900 3600 60  0000 C CNN
	1    7900 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ10
U 1 1 548EF672
P 8200 3600
F 0 "DMQ10" H 8200 3700 50  0000 C CNN
F 1 "LED" H 8200 3500 50  0000 C CNN
F 2 "~" H 8200 3600 60  0000 C CNN
F 3 "~" H 8200 3600 60  0000 C CNN
	1    8200 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ11
U 1 1 548EF678
P 8500 3600
F 0 "DMQ11" H 8500 3700 50  0000 C CNN
F 1 "LED" H 8500 3500 50  0000 C CNN
F 2 "~" H 8500 3600 60  0000 C CNN
F 3 "~" H 8500 3600 60  0000 C CNN
	1    8500 3600
	0    1    1    0   
$EndComp
$Comp
L LED DMQ12
U 1 1 548EF67E
P 8800 3600
F 0 "DMQ12" H 8800 3700 50  0000 C CNN
F 1 "LED" H 8800 3500 50  0000 C CNN
F 2 "~" H 8800 3600 60  0000 C CNN
F 3 "~" H 8800 3600 60  0000 C CNN
	1    8800 3600
	0    1    1    0   
$EndComp
$Comp
L LED DLINK1
U 1 1 548EF686
P 5200 2850
F 0 "DLINK1" H 5200 2950 50  0000 C CNN
F 1 "LED" H 5200 2750 50  0000 C CNN
F 2 "~" H 5200 2850 60  0000 C CNN
F 3 "~" H 5200 2850 60  0000 C CNN
	1    5200 2850
	0    1    1    0   
$EndComp
$Comp
L LED DSC1
U 1 1 548EF6A1
P 3350 3600
F 0 "DSC1" H 3350 3700 50  0000 C CNN
F 1 "LED" H 3350 3500 50  0000 C CNN
F 2 "~" H 3350 3600 60  0000 C CNN
F 3 "~" H 3350 3600 60  0000 C CNN
	1    3350 3600
	0    1    1    0   
$EndComp
$Comp
L LED DSC2
U 1 1 548EF6BA
P 3650 3600
F 0 "DSC2" H 3650 3700 50  0000 C CNN
F 1 "LED" H 3650 3500 50  0000 C CNN
F 2 "~" H 3650 3600 60  0000 C CNN
F 3 "~" H 3650 3600 60  0000 C CNN
	1    3650 3600
	0    1    1    0   
$EndComp
$Comp
L LED DSC3
U 1 1 548EF6C0
P 3950 3600
F 0 "DSC3" H 3950 3700 50  0000 C CNN
F 1 "LED" H 3950 3500 50  0000 C CNN
F 2 "~" H 3950 3600 60  0000 C CNN
F 3 "~" H 3950 3600 60  0000 C CNN
	1    3950 3600
	0    1    1    0   
$EndComp
$Comp
L LED DSC4
U 1 1 548EF6C6
P 4250 3600
F 0 "DSC4" H 4250 3700 50  0000 C CNN
F 1 "LED" H 4250 3500 50  0000 C CNN
F 2 "~" H 4250 3600 60  0000 C CNN
F 3 "~" H 4250 3600 60  0000 C CNN
	1    4250 3600
	0    1    1    0   
$EndComp
$Comp
L LED DSC5
U 1 1 548EF6CC
P 4550 3600
F 0 "DSC5" H 4550 3700 50  0000 C CNN
F 1 "LED" H 4550 3500 50  0000 C CNN
F 2 "~" H 4550 3600 60  0000 C CNN
F 3 "~" H 4550 3600 60  0000 C CNN
	1    4550 3600
	0    1    1    0   
$EndComp
$Comp
L LED DDF1
U 1 1 548EF6DA
P 3350 900
F 0 "DDF1" H 3350 1000 50  0000 C CNN
F 1 "LED" H 3350 800 50  0000 C CNN
F 2 "~" H 3350 900 60  0000 C CNN
F 3 "~" H 3350 900 60  0000 C CNN
	1    3350 900 
	0    1    1    0   
$EndComp
$Comp
L LED DDF2
U 1 1 548EF6F3
P 3650 900
F 0 "DDF2" H 3650 1000 50  0000 C CNN
F 1 "LED" H 3650 800 50  0000 C CNN
F 2 "~" H 3650 900 60  0000 C CNN
F 3 "~" H 3650 900 60  0000 C CNN
	1    3650 900 
	0    1    1    0   
$EndComp
$Comp
L LED DDF3
U 1 1 548EF6F9
P 3950 900
F 0 "DDF3" H 3950 1000 50  0000 C CNN
F 1 "LED" H 3950 800 50  0000 C CNN
F 2 "~" H 3950 900 60  0000 C CNN
F 3 "~" H 3950 900 60  0000 C CNN
	1    3950 900 
	0    1    1    0   
$EndComp
$Comp
L LED DIF1
U 1 1 548EF701
P 4250 900
F 0 "DIF1" V 4250 1000 50  0000 C CNN
F 1 "LED" H 4250 800 50  0000 C CNN
F 2 "~" H 4250 900 60  0000 C CNN
F 3 "~" H 4250 900 60  0000 C CNN
	1    4250 900 
	0    1    1    0   
$EndComp
$Comp
L LED DIF2
U 1 1 548EF71A
P 4550 900
F 0 "DIF2" H 4550 1000 50  0000 C CNN
F 1 "LED" H 4550 800 50  0000 C CNN
F 2 "~" H 4550 900 60  0000 C CNN
F 3 "~" H 4550 900 60  0000 C CNN
	1    4550 900 
	0    1    1    0   
$EndComp
$Comp
L LED DIF3
U 1 1 548EF720
P 4850 900
F 0 "DIF3" H 4850 1000 50  0000 C CNN
F 1 "LED" H 4850 800 50  0000 C CNN
F 2 "~" H 4850 900 60  0000 C CNN
F 3 "~" H 4850 900 60  0000 C CNN
	1    4850 900 
	0    1    1    0   
$EndComp
$Comp
L LED DAND1
U 1 1 548EF728
P 9500 1150
F 0 "DAND1" H 9500 1250 50  0000 C CNN
F 1 "LED" H 9500 1050 50  0000 C CNN
F 2 "~" H 9500 1150 60  0000 C CNN
F 3 "~" H 9500 1150 60  0000 C CNN
	1    9500 1150
	1    0    0    -1  
$EndComp
$Comp
L LED DTAD1
U 1 1 548EF735
P 9500 1500
F 0 "DTAD1" H 9500 1600 50  0000 C CNN
F 1 "LED" H 9500 1400 50  0000 C CNN
F 2 "~" H 9500 1500 60  0000 C CNN
F 3 "~" H 9500 1500 60  0000 C CNN
	1    9500 1500
	1    0    0    -1  
$EndComp
$Comp
L LED DISZ1
U 1 1 548EF73B
P 9500 1850
F 0 "DISZ1" H 9500 1950 50  0000 C CNN
F 1 "LED" H 9500 1750 50  0000 C CNN
F 2 "~" H 9500 1850 60  0000 C CNN
F 3 "~" H 9500 1850 60  0000 C CNN
	1    9500 1850
	1    0    0    -1  
$EndComp
$Comp
L LED DDCA1
U 1 1 548EF741
P 9500 2200
F 0 "DDCA1" H 9500 2300 50  0000 C CNN
F 1 "LED" H 9500 2100 50  0000 C CNN
F 2 "~" H 9500 2200 60  0000 C CNN
F 3 "~" H 9500 2200 60  0000 C CNN
	1    9500 2200
	1    0    0    -1  
$EndComp
$Comp
L LED DJMS1
U 1 1 548EF777
P 9500 2550
F 0 "DJMS1" H 9500 2650 50  0000 C CNN
F 1 "LED" H 9500 2450 50  0000 C CNN
F 2 "~" H 9500 2550 60  0000 C CNN
F 3 "~" H 9500 2550 60  0000 C CNN
	1    9500 2550
	1    0    0    -1  
$EndComp
$Comp
L LED DJMP1
U 1 1 548EF77D
P 9500 2900
F 0 "DJMP1" H 9500 3000 50  0000 C CNN
F 1 "LED" H 9500 2800 50  0000 C CNN
F 2 "~" H 9500 2900 60  0000 C CNN
F 3 "~" H 9500 2900 60  0000 C CNN
	1    9500 2900
	1    0    0    -1  
$EndComp
$Comp
L LED DIOT1
U 1 1 548EF783
P 9500 3250
F 0 "DIOT1" H 9500 3350 50  0000 C CNN
F 1 "LED" H 9500 3150 50  0000 C CNN
F 2 "~" H 9500 3250 60  0000 C CNN
F 3 "~" H 9500 3250 60  0000 C CNN
	1    9500 3250
	1    0    0    -1  
$EndComp
$Comp
L LED DOPR1
U 1 1 548EF789
P 9500 3600
F 0 "DOPR1" H 9500 3700 50  0000 C CNN
F 1 "LED" H 9500 3500 50  0000 C CNN
F 2 "~" H 9500 3600 60  0000 C CNN
F 3 "~" H 9500 3600 60  0000 C CNN
	1    9500 3600
	1    0    0    -1  
$EndComp
$Comp
L LED DFETCH1
U 1 1 548EF7CB
P 10150 1150
F 0 "DFETCH1" H 10150 1250 50  0000 C CNN
F 1 "LED" H 10150 1050 50  0000 C CNN
F 2 "~" H 10150 1150 60  0000 C CNN
F 3 "~" H 10150 1150 60  0000 C CNN
	1    10150 1150
	1    0    0    -1  
$EndComp
$Comp
L LED DEXEC1
U 1 1 548EF7D1
P 10150 1500
F 0 "DEXEC1" H 10150 1600 50  0000 C CNN
F 1 "LED" H 10150 1400 50  0000 C CNN
F 2 "~" H 10150 1500 60  0000 C CNN
F 3 "~" H 10150 1500 60  0000 C CNN
	1    10150 1500
	1    0    0    -1  
$EndComp
$Comp
L LED DDEFER1
U 1 1 548EF7D7
P 10150 1850
F 0 "DDEFER1" H 10150 1950 50  0000 C CNN
F 1 "LED" H 10150 1750 50  0000 C CNN
F 2 "~" H 10150 1850 60  0000 C CNN
F 3 "~" H 10150 1850 60  0000 C CNN
	1    10150 1850
	1    0    0    -1  
$EndComp
$Comp
L LED DWRDCT1
U 1 1 548EF7DD
P 10150 2200
F 0 "DWRDCT1" H 10150 2300 50  0000 C CNN
F 1 "LED" H 10150 2100 50  0000 C CNN
F 2 "~" H 10150 2200 60  0000 C CNN
F 3 "~" H 10150 2200 60  0000 C CNN
	1    10150 2200
	1    0    0    -1  
$EndComp
$Comp
L LED DCURAD1
U 1 1 548EF7E3
P 10150 2900
F 0 "DCURAD1" H 10150 3000 50  0000 C CNN
F 1 "LED" H 10150 2800 50  0000 C CNN
F 2 "~" H 10150 2900 60  0000 C CNN
F 3 "~" H 10150 2900 60  0000 C CNN
	1    10150 2900
	1    0    0    -1  
$EndComp
$Comp
L LED DBREAK1
U 1 1 548EF7E9
P 10150 3250
F 0 "DBREAK1" H 10150 3350 50  0000 C CNN
F 1 "LED" H 10150 3150 50  0000 C CNN
F 2 "~" H 10150 3250 60  0000 C CNN
F 3 "~" H 10150 3250 60  0000 C CNN
	1    10150 3250
	1    0    0    -1  
$EndComp
$Comp
L LED DION1
U 1 1 548EF837
P 10800 1150
F 0 "DION1" H 10800 1250 50  0000 C CNN
F 1 "LED" H 10800 1050 50  0000 C CNN
F 2 "~" H 10800 1150 60  0000 C CNN
F 3 "~" H 10800 1150 60  0000 C CNN
	1    10800 1150
	1    0    0    -1  
$EndComp
$Comp
L LED DPAUSE1
U 1 1 548EF83D
P 10800 1500
F 0 "DPAUSE1" H 10800 1600 50  0000 C CNN
F 1 "LED" H 10800 1400 50  0000 C CNN
F 2 "~" H 10800 1500 60  0000 C CNN
F 3 "~" H 10800 1500 60  0000 C CNN
	1    10800 1500
	1    0    0    -1  
$EndComp
$Comp
L LED DRUN1
U 1 1 548EF843
P 10800 1850
F 0 "DRUN1" H 10800 1950 50  0000 C CNN
F 1 "LED" H 10800 1750 50  0000 C CNN
F 2 "~" H 10800 1850 60  0000 C CNN
F 3 "~" H 10800 1850 60  0000 C CNN
	1    10800 1850
	1    0    0    -1  
$EndComp
$Comp
L SWITCH_INV SW19
U 1 1 548EF86F
P 7400 4800
F 0 "SW19" H 7200 4950 50  0000 C CNN
F 1 "START" H 7250 4650 50  0000 C CNN
F 2 "~" H 7400 4800 60  0000 C CNN
F 3 "~" H 7400 4800 60  0000 C CNN
	1    7400 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW20
U 1 1 548EF87C
P 7900 4800
F 0 "SW20" H 7700 4950 50  0000 C CNN
F 1 "LOAD_ADD" H 7750 4650 50  0000 C CNN
F 2 "~" H 7900 4800 60  0000 C CNN
F 3 "~" H 7900 4800 60  0000 C CNN
	1    7900 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW21
U 1 1 548EF882
P 8400 4800
F 0 "SW21" H 8200 4950 50  0000 C CNN
F 1 "DEP" H 8250 4650 50  0000 C CNN
F 2 "~" H 8400 4800 60  0000 C CNN
F 3 "~" H 8400 4800 60  0000 C CNN
	1    8400 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW22
U 1 1 548EF888
P 8900 4800
F 0 "SW22" H 8700 4950 50  0000 C CNN
F 1 "EXAM" H 8750 4650 50  0000 C CNN
F 2 "~" H 8900 4800 60  0000 C CNN
F 3 "~" H 8900 4800 60  0000 C CNN
	1    8900 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW23
U 1 1 548EF88E
P 9400 4800
F 0 "SW23" H 9200 4950 50  0000 C CNN
F 1 "CONT" H 9250 4650 50  0000 C CNN
F 2 "~" H 9400 4800 60  0000 C CNN
F 3 "~" H 9400 4800 60  0000 C CNN
	1    9400 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW24
U 1 1 548EF894
P 9900 4800
F 0 "SW24" H 9700 4950 50  0000 C CNN
F 1 "STOP" H 9750 4650 50  0000 C CNN
F 2 "~" H 9900 4800 60  0000 C CNN
F 3 "~" H 9900 4800 60  0000 C CNN
	1    9900 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW25
U 1 1 548EF89A
P 10400 4800
F 0 "SW25" H 10200 4950 50  0000 C CNN
F 1 "SING_STEP" H 10250 4650 50  0000 C CNN
F 2 "~" H 10400 4800 60  0000 C CNN
F 3 "~" H 10400 4800 60  0000 C CNN
	1    10400 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW26
U 1 1 548EF8A0
P 10900 4800
F 0 "SW26" H 10700 4950 50  0000 C CNN
F 1 "SING_INST" H 10750 4650 50  0000 C CNN
F 2 "~" H 10900 4800 60  0000 C CNN
F 3 "~" H 10900 4800 60  0000 C CNN
	1    10900 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW7
U 1 1 548EFAF8
P 5050 6300
F 0 "SW7" H 4850 6450 50  0000 C CNN
F 1 "SR1" H 4900 6150 50  0000 C CNN
F 2 "~" H 5050 6300 60  0000 C CNN
F 3 "~" H 5050 6300 60  0000 C CNN
	1    5050 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW8
U 1 1 548EFB27
P 5500 6300
F 0 "SW8" H 5300 6450 50  0000 C CNN
F 1 "SR2" H 5350 6150 50  0000 C CNN
F 2 "~" H 5500 6300 60  0000 C CNN
F 3 "~" H 5500 6300 60  0000 C CNN
	1    5500 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW9
U 1 1 548EFB2D
P 5950 6300
F 0 "SW9" H 5750 6450 50  0000 C CNN
F 1 "SR3" H 5800 6150 50  0000 C CNN
F 2 "~" H 5950 6300 60  0000 C CNN
F 3 "~" H 5950 6300 60  0000 C CNN
	1    5950 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW10
U 1 1 548EFB33
P 6400 6300
F 0 "SW10" H 6200 6450 50  0000 C CNN
F 1 "SR4" H 6250 6150 50  0000 C CNN
F 2 "~" H 6400 6300 60  0000 C CNN
F 3 "~" H 6400 6300 60  0000 C CNN
	1    6400 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW11
U 1 1 548EFB42
P 6900 6300
F 0 "SW11" H 6700 6450 50  0000 C CNN
F 1 "SR5" H 6750 6150 50  0000 C CNN
F 2 "~" H 6900 6300 60  0000 C CNN
F 3 "~" H 6900 6300 60  0000 C CNN
	1    6900 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW12
U 1 1 548EFB48
P 7350 6300
F 0 "SW12" H 7150 6450 50  0000 C CNN
F 1 "SR6" H 7200 6150 50  0000 C CNN
F 2 "~" H 7350 6300 60  0000 C CNN
F 3 "~" H 7350 6300 60  0000 C CNN
	1    7350 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW13
U 1 1 548EFB4E
P 7800 6300
F 0 "SW13" H 7600 6450 50  0000 C CNN
F 1 "SR7" H 7650 6150 50  0000 C CNN
F 2 "~" H 7800 6300 60  0000 C CNN
F 3 "~" H 7800 6300 60  0000 C CNN
	1    7800 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW14
U 1 1 548EFB54
P 8250 6300
F 0 "SW14" H 8050 6450 50  0000 C CNN
F 1 "SR8" H 8100 6150 50  0000 C CNN
F 2 "~" H 8250 6300 60  0000 C CNN
F 3 "~" H 8250 6300 60  0000 C CNN
	1    8250 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW15
U 1 1 548EFB5A
P 8750 6300
F 0 "SW15" H 8550 6450 50  0000 C CNN
F 1 "SR9" H 8600 6150 50  0000 C CNN
F 2 "~" H 8750 6300 60  0000 C CNN
F 3 "~" H 8750 6300 60  0000 C CNN
	1    8750 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW16
U 1 1 548EFB60
P 9200 6300
F 0 "SW16" H 9000 6450 50  0000 C CNN
F 1 "SR10" H 9050 6150 50  0000 C CNN
F 2 "~" H 9200 6300 60  0000 C CNN
F 3 "~" H 9200 6300 60  0000 C CNN
	1    9200 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW17
U 1 1 548EFB66
P 9650 6300
F 0 "SW17" H 9450 6450 50  0000 C CNN
F 1 "SR11" H 9500 6150 50  0000 C CNN
F 2 "~" H 9650 6300 60  0000 C CNN
F 3 "~" H 9650 6300 60  0000 C CNN
	1    9650 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW18
U 1 1 548EFB6C
P 10100 6300
F 0 "SW18" H 9900 6450 50  0000 C CNN
F 1 "SR12" H 9950 6150 50  0000 C CNN
F 2 "~" H 10100 6300 60  0000 C CNN
F 3 "~" H 10100 6300 60  0000 C CNN
	1    10100 6300
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW1
U 1 1 548EFBFD
P 3900 4800
F 0 "SW1" H 3700 4950 50  0000 C CNN
F 1 "DF1" H 3750 4650 50  0000 C CNN
F 2 "~" H 3900 4800 60  0000 C CNN
F 3 "~" H 3900 4800 60  0000 C CNN
	1    3900 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW2
U 1 1 548EFC03
P 4350 4800
F 0 "SW2" H 4150 4950 50  0000 C CNN
F 1 "DF2" H 4200 4650 50  0000 C CNN
F 2 "~" H 4350 4800 60  0000 C CNN
F 3 "~" H 4350 4800 60  0000 C CNN
	1    4350 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW3
U 1 1 548EFC09
P 4800 4800
F 0 "SW3" H 4600 4950 50  0000 C CNN
F 1 "DF3" H 4650 4650 50  0000 C CNN
F 2 "~" H 4800 4800 60  0000 C CNN
F 3 "~" H 4800 4800 60  0000 C CNN
	1    4800 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW4
U 1 1 548EFC0F
P 5250 4800
F 0 "SW4" H 5050 4950 50  0000 C CNN
F 1 "IF1" H 5100 4650 50  0000 C CNN
F 2 "~" H 5250 4800 60  0000 C CNN
F 3 "~" H 5250 4800 60  0000 C CNN
	1    5250 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW5
U 1 1 548EFC15
P 5750 4800
F 0 "SW5" H 5550 4950 50  0000 C CNN
F 1 "IF2" H 5600 4650 50  0000 C CNN
F 2 "~" H 5750 4800 60  0000 C CNN
F 3 "~" H 5750 4800 60  0000 C CNN
	1    5750 4800
	0    -1   -1   0   
$EndComp
$Comp
L SWITCH_INV SW6
U 1 1 548EFC1B
P 6200 4800
F 0 "SW6" H 6000 4950 50  0000 C CNN
F 1 "IF3" H 6050 4650 50  0000 C CNN
F 2 "~" H 6200 4800 60  0000 C CNN
F 3 "~" H 6200 4800 60  0000 C CNN
	1    6200 4800
	0    -1   -1   0   
$EndComp
$Comp
L RASPI_MODEL_B_PLUS_GPIO P1
U 1 1 548F13F7
P 1850 2150
F 0 "P1" H 1850 3200 60  0000 C CNN
F 1 "RASPI_MODEL_B_PLUS_GPIO" V 1850 2150 20  0000 C CNN
F 2 "~" H 1850 2150 60  0000 C CNN
F 3 "~" H 1850 2150 60  0000 C CNN
	1    1850 2150
	1    0    0    -1  
$EndComp
Text GLabel 4700 1600 2    60   Input ~ 0
led1
Text GLabel 4700 1700 2    60   Input ~ 0
led2
Text GLabel 4700 1800 2    60   Input ~ 0
led3
Text GLabel 4700 1900 2    60   Input ~ 0
led4
Text GLabel 4700 2000 2    60   Input ~ 0
led5
Text GLabel 4700 2100 2    60   Input ~ 0
led6
Text GLabel 4700 2200 2    60   Input ~ 0
led7
Text GLabel 4700 2300 2    60   Input ~ 0
led8
Text GLabel 800  1300 0    60   Input ~ 0
col1a
Text GLabel 800  1400 0    60   Input ~ 0
col2a
Text GLabel 800  1500 0    60   Input ~ 0
col3
Text GLabel 800  2600 0    60   Input ~ 0
col4
Text GLabel 800  2700 0    60   Input ~ 0
col5
Text GLabel 2900 2400 2    60   Input ~ 0
col6
Text GLabel 2900 2300 2    60   Input ~ 0
col7
Text GLabel 800  2200 0    60   Input ~ 0
col8
Text GLabel 800  2100 0    60   Input ~ 0
col9
Text GLabel 800  2300 0    60   Input ~ 0
col10
Text GLabel 2900 2700 2    60   Input ~ 0
col11
Text GLabel 800  2800 0    60   Input ~ 0
col12
Text GLabel 2900 2900 2    60   Input ~ 0
row1
Text GLabel 800  1700 0    60   Input ~ 0
row2
Text GLabel 2900 1700 2    60   Input ~ 0
row3
Text Notes 650  800  0    31   ~ 0
Driving LEDs: a matrix of LED8 X COL12\nSensing switches: a matrix of ROW3 X COL12
Text GLabel 8900 700  2    60   Input ~ 0
led1
Text GLabel 8900 1750 2    60   Input ~ 0
led2
Text GLabel 8900 2000 2    60   Input ~ 0
led3
Text GLabel 8900 3050 2    60   Input ~ 0
led4
Text GLabel 8900 3400 2    60   Input ~ 0
led5
Text GLabel 3300 1150 0    60   Input ~ 0
col1
Text GLabel 3600 1300 0    60   Input ~ 0
col2
Text GLabel 3900 1150 0    60   Input ~ 0
col3
Text GLabel 4200 1300 0    60   Input ~ 0
col4
Text GLabel 4500 1150 0    60   Input ~ 0
col5
Text GLabel 4800 1300 0    60   Input ~ 0
col6
Text GLabel 7250 1150 0    60   Input ~ 0
col7
Text GLabel 7550 1300 0    60   Input ~ 0
col8
Text GLabel 7850 1150 0    60   Input ~ 0
col9
Text GLabel 8150 1300 0    60   Input ~ 0
col10
Text GLabel 8450 1150 0    60   Input ~ 0
col11
Text GLabel 8750 1300 0    60   Input ~ 0
col12
Text GLabel 5450 3850 0    60   Input ~ 0
col1
Text GLabel 5750 4000 0    60   Input ~ 0
col2
Text GLabel 6050 3850 0    60   Input ~ 0
col3
Text GLabel 6350 4000 0    60   Input ~ 0
col4
Text GLabel 6650 3850 0    60   Input ~ 0
col5
Text GLabel 3300 4000 0    60   Input ~ 0
col6
Text GLabel 3600 3850 0    60   Input ~ 0
col7
Text GLabel 3900 4000 0    60   Input ~ 0
col8
Text GLabel 4200 3850 0    60   Input ~ 0
col9
Text GLabel 4500 4000 0    60   Input ~ 0
col10
Text GLabel 8450 3850 0    60   Input ~ 0
col11
Text GLabel 8750 4000 0    60   Input ~ 0
col12
Text GLabel 9300 1050 1    60   Input ~ 0
led6
Text GLabel 9750 1150 1    60   Input ~ 0
col1
Text GLabel 9750 1500 1    60   Input ~ 0
col2
Text GLabel 9750 1850 1    60   Input ~ 0
col3
Text GLabel 9750 2200 1    60   Input ~ 0
col4
Text GLabel 9750 2550 1    60   Input ~ 0
col5
Text GLabel 9750 2900 1    60   Input ~ 0
col6
Text GLabel 9750 3250 1    60   Input ~ 0
col7
Text GLabel 9750 3600 1    60   Input ~ 0
col8
Text GLabel 9950 1050 1    60   Input ~ 0
led6
Text GLabel 10400 1150 1    60   Input ~ 0
col9
Text GLabel 10400 1500 1    60   Input ~ 0
col10
Text GLabel 10400 1850 1    60   Input ~ 0
col11
Text GLabel 10400 2200 1    60   Input ~ 0
col12
Text GLabel 9950 2750 1    60   Input ~ 0
led7
Text GLabel 10400 2900 1    60   Input ~ 0
col1
Text GLabel 10400 3250 1    60   Input ~ 0
col2
Text GLabel 10600 1050 1    60   Input ~ 0
led7
Text GLabel 11050 1150 1    60   Input ~ 0
col3
Text GLabel 11050 1500 1    60   Input ~ 0
col4
Text GLabel 11050 1850 1    60   Input ~ 0
col5
Text GLabel 4600 3400 2    60   Input ~ 0
led7
Text GLabel 3300 700  0    60   Input ~ 0
led8
Text GLabel 5150 2650 0    60   Input ~ 0
led8
Text GLabel 5150 3050 0    60   Input ~ 0
col7
Text GLabel 5450 1150 0    60   Input ~ 0
col1
Text GLabel 5750 1300 0    60   Input ~ 0
col2
Text GLabel 6050 1150 0    60   Input ~ 0
col3
Text GLabel 6350 1300 0    60   Input ~ 0
col4
Text GLabel 6650 1150 0    60   Input ~ 0
col5
Text GLabel 6950 1300 0    60   Input ~ 0
col6
Text GLabel 7250 2450 0    60   Input ~ 0
col7
Text GLabel 7550 2600 0    60   Input ~ 0
col8
Text GLabel 7850 2450 0    60   Input ~ 0
col9
Text GLabel 8150 2600 0    60   Input ~ 0
col10
Text GLabel 8450 2450 0    60   Input ~ 0
col11
Text GLabel 8750 2600 0    60   Input ~ 0
col12
Text GLabel 6950 2600 0    60   Input ~ 0
col6
Text GLabel 5450 2450 0    60   Input ~ 0
col1
Text GLabel 5750 2600 0    60   Input ~ 0
col2
Text GLabel 6050 2450 0    60   Input ~ 0
col3
Text GLabel 6350 2600 0    60   Input ~ 0
col4
Text GLabel 6650 2450 0    60   Input ~ 0
col5
Text GLabel 7250 3850 0    60   Input ~ 0
col7
Text GLabel 7550 4000 0    60   Input ~ 0
col8
Text GLabel 7850 3850 0    60   Input ~ 0
col9
Text GLabel 8150 4000 0    60   Input ~ 0
col10
Text GLabel 6950 4000 0    60   Input ~ 0
col6
Text GLabel 4900 5750 0    60   Input ~ 0
row1
Text GLabel 4650 7050 2    60   Input ~ 0
col1
Text GLabel 5100 7050 2    60   Input ~ 0
col2
Text GLabel 5550 7050 2    60   Input ~ 0
col3
Text GLabel 6000 7050 2    60   Input ~ 0
col4
Text GLabel 6500 7050 2    60   Input ~ 0
col5
Text GLabel 9250 7050 2    60   Input ~ 0
col11
Text GLabel 9700 7050 2    60   Input ~ 0
col12
Text GLabel 7400 7050 2    60   Input ~ 0
col7
Text GLabel 7850 7050 2    60   Input ~ 0
col8
Text GLabel 8350 7050 2    60   Input ~ 0
col9
Text GLabel 8800 7050 2    60   Input ~ 0
col10
Text GLabel 6950 7050 2    60   Input ~ 0
col6
Text GLabel 3500 5550 2    60   Input ~ 0
col1
Text GLabel 3950 5550 2    60   Input ~ 0
col2
Text GLabel 4400 5550 2    60   Input ~ 0
col3
Text GLabel 4850 5550 2    60   Input ~ 0
col4
Text GLabel 5350 5550 2    60   Input ~ 0
col5
Text GLabel 5800 5550 2    60   Input ~ 0
col6
Text GLabel 3750 4250 0    60   Input ~ 0
row2
Text GLabel 7250 4250 0    60   Input ~ 0
row3
Text GLabel 7000 5550 2    60   Input ~ 0
col1
Text GLabel 7500 5550 2    60   Input ~ 0
col2
Text GLabel 8000 5550 2    60   Input ~ 0
col3
Text GLabel 8500 5550 2    60   Input ~ 0
col4
Text GLabel 9000 5550 2    60   Input ~ 0
col5
Text GLabel 9500 5550 2    60   Input ~ 0
col6
Text GLabel 10000 5550 2    60   Input ~ 0
col7
Text GLabel 10500 5550 2    60   Input ~ 0
col8
$Comp
L DIODE D1
U 1 1 54904DF0
P 3700 5350
F 0 "D1" H 3700 5450 40  0000 C CNN
F 1 "1N4148" H 3700 5250 40  0000 C CNN
F 2 "~" H 3700 5350 60  0000 C CNN
F 3 "~" H 3700 5350 60  0000 C CNN
	1    3700 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D2
U 1 1 5490504C
P 4150 5350
F 0 "D2" H 4150 5450 40  0000 C CNN
F 1 "1N4148" H 4150 5250 40  0000 C CNN
F 2 "~" H 4150 5350 60  0000 C CNN
F 3 "~" H 4150 5350 60  0000 C CNN
	1    4150 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D3
U 1 1 54905056
P 4600 5350
F 0 "D3" H 4600 5450 40  0000 C CNN
F 1 "1N4148" H 4600 5250 40  0000 C CNN
F 2 "~" H 4600 5350 60  0000 C CNN
F 3 "~" H 4600 5350 60  0000 C CNN
	1    4600 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D4
U 1 1 5490505E
P 5050 5350
F 0 "D4" H 5050 5450 40  0000 C CNN
F 1 "1N4148" H 5050 5250 40  0000 C CNN
F 2 "~" H 5050 5350 60  0000 C CNN
F 3 "~" H 5050 5350 60  0000 C CNN
	1    5050 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D5
U 1 1 54905068
P 5550 5350
F 0 "D5" H 5550 5450 40  0000 C CNN
F 1 "1N4148" H 5550 5250 40  0000 C CNN
F 2 "~" H 5550 5350 60  0000 C CNN
F 3 "~" H 5550 5350 60  0000 C CNN
	1    5550 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D6
U 1 1 5490506E
P 6000 5350
F 0 "D6" H 6000 5450 40  0000 C CNN
F 1 "1N4148" H 6000 5250 40  0000 C CNN
F 2 "~" H 6000 5350 60  0000 C CNN
F 3 "~" H 6000 5350 60  0000 C CNN
	1    6000 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D7
U 1 1 549055F9
P 4850 6850
F 0 "D7" H 4850 6950 40  0000 C CNN
F 1 "1N4148" H 4850 6750 40  0000 C CNN
F 2 "~" H 4850 6850 60  0000 C CNN
F 3 "~" H 4850 6850 60  0000 C CNN
	1    4850 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D8
U 1 1 549055FF
P 5300 6850
F 0 "D8" H 5300 6950 40  0000 C CNN
F 1 "1N4148" H 5300 6750 40  0000 C CNN
F 2 "~" H 5300 6850 60  0000 C CNN
F 3 "~" H 5300 6850 60  0000 C CNN
	1    5300 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D9
U 1 1 54905605
P 5750 6850
F 0 "D9" H 5750 6950 40  0000 C CNN
F 1 "1N4148" H 5750 6750 40  0000 C CNN
F 2 "~" H 5750 6850 60  0000 C CNN
F 3 "~" H 5750 6850 60  0000 C CNN
	1    5750 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D10
U 1 1 5490560B
P 6200 6850
F 0 "D10" H 6200 6950 40  0000 C CNN
F 1 "1N4148" H 6200 6750 40  0000 C CNN
F 2 "~" H 6200 6850 60  0000 C CNN
F 3 "~" H 6200 6850 60  0000 C CNN
	1    6200 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D11
U 1 1 54905611
P 6700 6850
F 0 "D11" H 6700 6950 40  0000 C CNN
F 1 "1N4148" H 6700 6750 40  0000 C CNN
F 2 "~" H 6700 6850 60  0000 C CNN
F 3 "~" H 6700 6850 60  0000 C CNN
	1    6700 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D12
U 1 1 54905640
P 7150 6850
F 0 "D12" H 7150 6950 40  0000 C CNN
F 1 "1N4148" H 7150 6750 40  0000 C CNN
F 2 "~" H 7150 6850 60  0000 C CNN
F 3 "~" H 7150 6850 60  0000 C CNN
	1    7150 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D13
U 1 1 54905646
P 7600 6850
F 0 "D13" H 7600 6950 40  0000 C CNN
F 1 "1N4148" H 7600 6750 40  0000 C CNN
F 2 "~" H 7600 6850 60  0000 C CNN
F 3 "~" H 7600 6850 60  0000 C CNN
	1    7600 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D14
U 1 1 5490564C
P 8050 6850
F 0 "D14" H 8050 6950 40  0000 C CNN
F 1 "1N4148" H 8050 6750 40  0000 C CNN
F 2 "~" H 8050 6850 60  0000 C CNN
F 3 "~" H 8050 6850 60  0000 C CNN
	1    8050 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D15
U 1 1 54905652
P 8550 6850
F 0 "D15" H 8550 6950 40  0000 C CNN
F 1 "1N4148" H 8550 6750 40  0000 C CNN
F 2 "~" H 8550 6850 60  0000 C CNN
F 3 "~" H 8550 6850 60  0000 C CNN
	1    8550 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D16
U 1 1 54905658
P 9000 6850
F 0 "D16" H 9000 6950 40  0000 C CNN
F 1 "1N4148" H 9000 6750 40  0000 C CNN
F 2 "~" H 9000 6850 60  0000 C CNN
F 3 "~" H 9000 6850 60  0000 C CNN
	1    9000 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D17
U 1 1 5490565E
P 9450 6850
F 0 "D17" H 9450 6950 40  0000 C CNN
F 1 "1N4148" H 9450 6750 40  0000 C CNN
F 2 "~" H 9450 6850 60  0000 C CNN
F 3 "~" H 9450 6850 60  0000 C CNN
	1    9450 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D18
U 1 1 54905664
P 9900 6850
F 0 "D18" H 9900 6950 40  0000 C CNN
F 1 "1N4148" H 9900 6750 40  0000 C CNN
F 2 "~" H 9900 6850 60  0000 C CNN
F 3 "~" H 9900 6850 60  0000 C CNN
	1    9900 6850
	1    0    0    -1  
$EndComp
$Comp
L DIODE D19
U 1 1 549070C3
P 7200 5350
F 0 "D19" H 7200 5450 40  0000 C CNN
F 1 "1N4148" H 7200 5250 40  0000 C CNN
F 2 "~" H 7200 5350 60  0000 C CNN
F 3 "~" H 7200 5350 60  0000 C CNN
	1    7200 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D20
U 1 1 549070C9
P 7700 5350
F 0 "D20" H 7700 5450 40  0000 C CNN
F 1 "1N4148" H 7700 5250 40  0000 C CNN
F 2 "~" H 7700 5350 60  0000 C CNN
F 3 "~" H 7700 5350 60  0000 C CNN
	1    7700 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D21
U 1 1 549070CF
P 8200 5350
F 0 "D21" H 8200 5450 40  0000 C CNN
F 1 "1N4148" H 8200 5250 40  0000 C CNN
F 2 "~" H 8200 5350 60  0000 C CNN
F 3 "~" H 8200 5350 60  0000 C CNN
	1    8200 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D22
U 1 1 549070D5
P 8700 5350
F 0 "D22" H 8700 5450 40  0000 C CNN
F 1 "1N4148" H 8700 5250 40  0000 C CNN
F 2 "~" H 8700 5350 60  0000 C CNN
F 3 "~" H 8700 5350 60  0000 C CNN
	1    8700 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D23
U 1 1 549070DB
P 9200 5350
F 0 "D23" H 9200 5450 40  0000 C CNN
F 1 "1N4148" H 9200 5250 40  0000 C CNN
F 2 "~" H 9200 5350 60  0000 C CNN
F 3 "~" H 9200 5350 60  0000 C CNN
	1    9200 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D24
U 1 1 549070E1
P 9700 5350
F 0 "D24" H 9700 5450 40  0000 C CNN
F 1 "1N4148" H 9700 5250 40  0000 C CNN
F 2 "~" H 9700 5350 60  0000 C CNN
F 3 "~" H 9700 5350 60  0000 C CNN
	1    9700 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D25
U 1 1 549070E7
P 10200 5350
F 0 "D25" H 10200 5450 40  0000 C CNN
F 1 "1N4148" H 10200 5250 40  0000 C CNN
F 2 "~" H 10200 5350 60  0000 C CNN
F 3 "~" H 10200 5350 60  0000 C CNN
	1    10200 5350
	1    0    0    -1  
$EndComp
$Comp
L DIODE D26
U 1 1 549070ED
P 10700 5350
F 0 "D26" H 10700 5450 40  0000 C CNN
F 1 "1N4148" H 10700 5250 40  0000 C CNN
F 2 "~" H 10700 5350 60  0000 C CNN
F 3 "~" H 10700 5350 60  0000 C CNN
	1    10700 5350
	1    0    0    -1  
$EndComp
$Comp
L R R1
U 1 1 5490833D
P 2800 4150
F 0 "R1" V 2880 4150 40  0000 C CNN
F 1 "390" V 2807 4151 40  0000 C CNN
F 2 "~" V 2730 4150 30  0000 C CNN
F 3 "~" H 2800 4150 30  0000 C CNN
	1    2800 4150
	1    0    0    -1  
$EndComp
$Comp
L R R2
U 1 1 5490834A
P 2800 5700
F 0 "R2" V 2880 5700 40  0000 C CNN
F 1 "390" V 2807 5701 40  0000 C CNN
F 2 "~" V 2730 5700 30  0000 C CNN
F 3 "~" H 2800 5700 30  0000 C CNN
	1    2800 5700
	-1   0    0    1   
$EndComp
$Comp
L R R3
U 1 1 54908350
P 1100 1500
F 0 "R3" V 1180 1500 40  0000 C CNN
F 1 "390" V 1107 1501 40  0000 C CNN
F 2 "~" V 1030 1500 30  0000 C CNN
F 3 "~" H 1100 1500 30  0000 C CNN
	1    1100 1500
	0    -1   -1   0   
$EndComp
$Comp
L R R4
U 1 1 54908356
P 1100 2600
F 0 "R4" V 1180 2600 40  0000 C CNN
F 1 "390" V 1107 2601 40  0000 C CNN
F 2 "~" V 1030 2600 30  0000 C CNN
F 3 "~" H 1100 2600 30  0000 C CNN
	1    1100 2600
	0    -1   -1   0   
$EndComp
$Comp
L R R5
U 1 1 5490835C
P 1100 2700
F 0 "R5" V 1180 2700 40  0000 C CNN
F 1 "390" V 1107 2701 40  0000 C CNN
F 2 "~" V 1030 2700 30  0000 C CNN
F 3 "~" H 1100 2700 30  0000 C CNN
	1    1100 2700
	0    -1   -1   0   
$EndComp
$Comp
L R R6
U 1 1 54908362
P 2600 2400
F 0 "R6" V 2680 2400 40  0000 C CNN
F 1 "390" V 2607 2401 40  0000 C CNN
F 2 "~" V 2530 2400 30  0000 C CNN
F 3 "~" H 2600 2400 30  0000 C CNN
	1    2600 2400
	0    1    1    0   
$EndComp
$Comp
L R R7
U 1 1 54908368
P 2600 2300
F 0 "R7" V 2680 2300 40  0000 C CNN
F 1 "390" V 2607 2301 40  0000 C CNN
F 2 "~" V 2530 2300 30  0000 C CNN
F 3 "~" H 2600 2300 30  0000 C CNN
	1    2600 2300
	0    -1   -1   0   
$EndComp
$Comp
L R R8
U 1 1 5490836E
P 1100 2200
F 0 "R8" V 1180 2200 40  0000 C CNN
F 1 "390" V 1107 2201 40  0000 C CNN
F 2 "~" V 1030 2200 30  0000 C CNN
F 3 "~" H 1100 2200 30  0000 C CNN
	1    1100 2200
	0    1    1    0   
$EndComp
$Comp
L R R9
U 1 1 54908374
P 1100 2100
F 0 "R9" V 1180 2100 40  0000 C CNN
F 1 "390" V 1107 2101 40  0000 C CNN
F 2 "~" V 1030 2100 30  0000 C CNN
F 3 "~" H 1100 2100 30  0000 C CNN
	1    1100 2100
	0    1    1    0   
$EndComp
$Comp
L R R10
U 1 1 5490837A
P 1100 2300
F 0 "R10" V 1180 2300 40  0000 C CNN
F 1 "390" V 1107 2301 40  0000 C CNN
F 2 "~" V 1030 2300 30  0000 C CNN
F 3 "~" H 1100 2300 30  0000 C CNN
	1    1100 2300
	0    1    1    0   
$EndComp
$Comp
L R R11
U 1 1 54908380
P 2600 2700
F 0 "R11" V 2680 2700 40  0000 C CNN
F 1 "390" V 2607 2701 40  0000 C CNN
F 2 "~" V 2530 2700 30  0000 C CNN
F 3 "~" H 2600 2700 30  0000 C CNN
	1    2600 2700
	0    -1   -1   0   
$EndComp
$Comp
L R R12
U 1 1 54908386
P 1100 2800
F 0 "R12" V 1180 2800 40  0000 C CNN
F 1 "390" V 1107 2801 40  0000 C CNN
F 2 "~" V 1030 2800 30  0000 C CNN
F 3 "~" H 1100 2800 30  0000 C CNN
	1    1100 2800
	0    1    1    0   
$EndComp
$Comp
L R R_ROW1
U 1 1 5490838C
P 2600 2900
F 0 "R_ROW1" V 2680 2900 40  0000 C CNN
F 1 "1K" V 2607 2901 40  0000 C CNN
F 2 "~" V 2530 2900 30  0000 C CNN
F 3 "~" H 2600 2900 30  0000 C CNN
	1    2600 2900
	0    -1   -1   0   
$EndComp
$Comp
L R R_ROW2
U 1 1 5490839E
P 1100 1700
F 0 "R_ROW2" V 1180 1700 40  0000 C CNN
F 1 "1K" V 1107 1701 40  0000 C CNN
F 2 "~" V 1030 1700 30  0000 C CNN
F 3 "~" H 1100 1700 30  0000 C CNN
	1    1100 1700
	0    1    1    0   
$EndComp
$Comp
L R R_ROW3
U 1 1 549083A4
P 2600 1700
F 0 "R_ROW3" V 2680 1700 40  0000 C CNN
F 1 "1K" V 2607 1701 40  0000 C CNN
F 2 "~" V 2530 1700 30  0000 C CNN
F 3 "~" H 2600 1700 30  0000 C CNN
	1    2600 1700
	0    -1   -1   0   
$EndComp
$Comp
L UDN2981A P2
U 1 1 54B17386
P 4250 2000
F 0 "P2" H 4250 2550 30  0000 C CNN
F 1 "UDN2981A" H 4250 1450 30  0000 C CNN
F 2 "~" H 4250 2000 60  0000 C CNN
F 3 "~" H 4250 2000 60  0000 C CNN
	1    4250 2000
	1    0    0    -1  
$EndComp
Text GLabel 3800 1600 0    60   Input ~ 0
xled1
Text GLabel 3800 1700 0    60   Input ~ 0
xled2
Text GLabel 3800 1800 0    60   Input ~ 0
xled3
Text GLabel 3800 1900 0    60   Input ~ 0
xled4
Text GLabel 3800 2000 0    60   Input ~ 0
xled5
Text GLabel 3800 2100 0    60   Input ~ 0
xled6
Text GLabel 3800 2200 0    60   Input ~ 0
xled7
Text GLabel 3800 2300 0    60   Input ~ 0
xled8
Text GLabel 2900 3000 2    60   Input ~ 0
xled1
Text GLabel 2900 3100 2    60   Input ~ 0
xled2
Text GLabel 800  1900 0    60   Input ~ 0
xled3
Text GLabel 2900 1900 2    60   Input ~ 0
xled4
Text GLabel 2900 2000 2    60   Input ~ 0
xled5
Text GLabel 2900 2200 2    60   Input ~ 0
xled6
Text GLabel 800  3000 0    60   Input ~ 0
xled7
Text GLabel 800  1800 0    60   Input ~ 0
xled8
NoConn ~ 2250 2500
NoConn ~ 1450 2500
$Comp
L GND #PWR01
U 1 1 54B19131
P 2300 2600
F 0 "#PWR01" H 2300 2600 30  0001 C CNN
F 1 "GND" H 2300 2530 30  0001 C CNN
F 2 "" H 2300 2600 60  0000 C CNN
F 3 "" H 2300 2600 60  0000 C CNN
	1    2300 2600
	0    -1   -1   0   
$EndComp
$Comp
L GND #PWR02
U 1 1 54B1913E
P 2300 2100
F 0 "#PWR02" H 2300 2100 30  0001 C CNN
F 1 "GND" H 2300 2030 30  0001 C CNN
F 2 "" H 2300 2100 60  0000 C CNN
F 3 "" H 2300 2100 60  0000 C CNN
	1    2300 2100
	0    -1   -1   0   
$EndComp
$Comp
L GND #PWR03
U 1 1 54B19150
P 1400 1600
F 0 "#PWR03" H 1400 1600 30  0001 C CNN
F 1 "GND" H 1400 1530 30  0001 C CNN
F 2 "" H 1400 1600 60  0000 C CNN
F 3 "" H 1400 1600 60  0000 C CNN
	1    1400 1600
	0    1    1    0   
$EndComp
$Comp
L GND #PWR04
U 1 1 54B19156
P 2300 1400
F 0 "#PWR04" H 2300 1400 30  0001 C CNN
F 1 "GND" H 2300 1330 30  0001 C CNN
F 2 "" H 2300 1400 60  0000 C CNN
F 3 "" H 2300 1400 60  0000 C CNN
	1    2300 1400
	0    -1   -1   0   
$EndComp
$Comp
L GND #PWR05
U 1 1 54B19903
P 1400 3100
F 0 "#PWR05" H 1400 3100 30  0001 C CNN
F 1 "GND" H 1400 3030 30  0001 C CNN
F 2 "" H 1400 3100 60  0000 C CNN
F 3 "" H 1400 3100 60  0000 C CNN
	1    1400 3100
	0    1    1    0   
$EndComp
NoConn ~ 2250 2800
$Comp
L +3.3V #PWR06
U 1 1 54B1C371
P 1350 1100
F 0 "#PWR06" H 1350 1060 30  0001 C CNN
F 1 "+3.3V" H 1350 1210 30  0000 C CNN
F 2 "" H 1350 1100 60  0000 C CNN
F 3 "" H 1350 1100 60  0000 C CNN
	1    1350 1100
	1    0    0    -1  
$EndComp
$Comp
L GND #PWR07
U 1 1 54B1C4F8
P 4750 2550
F 0 "#PWR07" H 4750 2550 30  0001 C CNN
F 1 "GND" H 4750 2480 30  0001 C CNN
F 2 "" H 4750 2550 60  0000 C CNN
F 3 "" H 4750 2550 60  0000 C CNN
	1    4750 2550
	0    -1   -1   0   
$EndComp
NoConn ~ 4000 4300
NoConn ~ 4450 4300
NoConn ~ 4900 4300
NoConn ~ 5350 4300
NoConn ~ 5850 4300
NoConn ~ 6300 4300
NoConn ~ 7500 4300
NoConn ~ 8000 4300
NoConn ~ 8500 4300
NoConn ~ 9000 4300
NoConn ~ 9500 4300
NoConn ~ 10000 4300
NoConn ~ 10500 4300
NoConn ~ 11000 4300
NoConn ~ 10200 5800
NoConn ~ 9750 5800
NoConn ~ 9300 5800
NoConn ~ 8850 5800
NoConn ~ 8350 5800
NoConn ~ 7900 5800
NoConn ~ 7450 5800
NoConn ~ 7000 5800
NoConn ~ 6500 5800
NoConn ~ 5150 5800
NoConn ~ 5600 5800
NoConn ~ 6050 5800
$Comp
L CONN_1 M1
U 1 1 54B1CC4A
P 6150 7400
F 0 "M1" H 6230 7400 40  0000 L CNN
F 1 "M" H 6150 7455 30  0001 C CNN
F 2 "" H 6150 7400 60  0000 C CNN
F 3 "" H 6150 7400 60  0000 C CNN
	1    6150 7400
	0    -1   -1   0   
$EndComp
$Comp
L CONN_1 M2
U 1 1 54B1CC76
P 6250 7400
F 0 "M2" H 6330 7400 40  0000 L CNN
F 1 "M" H 6250 7455 30  0001 C CNN
F 2 "" H 6250 7400 60  0000 C CNN
F 3 "" H 6250 7400 60  0000 C CNN
	1    6250 7400
	0    -1   -1   0   
$EndComp
$Comp
L CONN_1 M3
U 1 1 54B1CC7C
P 6350 7400
F 0 "M3" H 6430 7400 40  0000 L CNN
F 1 "M" H 6350 7455 30  0001 C CNN
F 2 "" H 6350 7400 60  0000 C CNN
F 3 "" H 6350 7400 60  0000 C CNN
	1    6350 7400
	0    -1   -1   0   
$EndComp
$Comp
L CONN_1 M4
U 1 1 54B1CC82
P 6450 7400
F 0 "M4" H 6530 7400 40  0000 L CNN
F 1 "M" H 6450 7455 30  0001 C CNN
F 2 "" H 6450 7400 60  0000 C CNN
F 3 "" H 6450 7400 60  0000 C CNN
	1    6450 7400
	0    -1   -1   0   
$EndComp
NoConn ~ 6150 7550
NoConn ~ 6250 7550
NoConn ~ 6350 7550
NoConn ~ 6450 7550
$Comp
L +5V #PWR08
U 1 1 54BCFC39
P 2400 1100
F 0 "#PWR08" H 2400 1190 20  0001 C CNN
F 1 "+5V" H 2400 1190 30  0000 C CNN
F 2 "" H 2400 1100 60  0000 C CNN
F 3 "" H 2400 1100 60  0000 C CNN
	1    2400 1100
	1    0    0    -1  
$EndComp
Text GLabel 2750 1500 2    60   Input ~ 0
TX
Text GLabel 2750 1600 2    60   Input ~ 0
RX
Text GLabel 1350 2900 0    60   Input ~ 0
SPARE_IO
Text GLabel 2300 7600 0    60   Input ~ 0
TX
Text GLabel 2300 7500 0    60   Input ~ 0
RX
$Comp
L GND #PWR09
U 1 1 54BD292E
P 2850 7100
F 0 "#PWR09" H 2850 7100 30  0001 C CNN
F 1 "GND" H 2850 7030 30  0001 C CNN
F 2 "" H 2850 7100 60  0000 C CNN
F 3 "" H 2850 7100 60  0000 C CNN
	1    2850 7100
	-1   0    0    1   
$EndComp
NoConn ~ 1450 2400
NoConn ~ 2250 1800
$Comp
L CONN_1 M5
U 1 1 54BD36C6
P 6550 7400
F 0 "M5" H 6630 7400 40  0000 L CNN
F 1 "M" H 6550 7455 30  0001 C CNN
F 2 "" H 6550 7400 60  0000 C CNN
F 3 "" H 6550 7400 60  0000 C CNN
	1    6550 7400
	0    -1   -1   0   
$EndComp
$Comp
L CONN_1 M6
U 1 1 54BD36CC
P 6650 7400
F 0 "M6" H 6730 7400 40  0000 L CNN
F 1 "M" H 6650 7455 30  0001 C CNN
F 2 "" H 6650 7400 60  0000 C CNN
F 3 "" H 6650 7400 60  0000 C CNN
	1    6650 7400
	0    -1   -1   0   
$EndComp
NoConn ~ 6550 7550
NoConn ~ 6650 7550
$Comp
L CONN_1 M7
U 1 1 54BD36D2
P 6750 7400
F 0 "M7" H 6830 7400 40  0000 L CNN
F 1 "M" H 6750 7455 30  0001 C CNN
F 2 "" H 6750 7400 60  0000 C CNN
F 3 "" H 6750 7400 60  0000 C CNN
	1    6750 7400
	0    -1   -1   0   
$EndComp
NoConn ~ 6750 7550
$Comp
L +5V #PWR010
U 1 1 54BD75EA
P 3400 2500
F 0 "#PWR010" H 3400 2590 20  0001 C CNN
F 1 "+5V" H 3400 2590 30  0000 C CNN
F 2 "" H 3400 2500 60  0000 C CNN
F 3 "" H 3400 2500 60  0000 C CNN
	1    3400 2500
	-1   0    0    1   
$EndComp
$Comp
L DIODE DZ1
U 1 1 54BD85A3
P 3600 2400
F 0 "DZ1" H 3600 2500 40  0000 C CNN
F 1 "ZENER" H 3600 2300 40  0000 C CNN
F 2 "~" H 3600 2400 60  0000 C CNN
F 3 "~" H 3600 2400 60  0000 C CNN
	1    3600 2400
	1    0    0    -1  
$EndComp
$Comp
L CONN_20X2 P3
U 1 1 554E0D39
P 1650 5050
F 0 "P3" H 1650 6100 60  0000 C CNN
F 1 "EXPANSION_20X2" V 1650 5050 50  0000 C CNN
F 2 "" H 1650 5050 60  0000 C CNN
F 3 "" H 1650 5050 60  0000 C CNN
	1    1650 5050
	1    0    0    -1  
$EndComp
$Comp
L +5V #PWR011
U 1 1 554E0D4F
P 1100 4100
F 0 "#PWR011" H 1100 4190 20  0001 C CNN
F 1 "+5V" H 1100 4190 30  0000 C CNN
F 2 "" H 1100 4100 60  0000 C CNN
F 3 "" H 1100 4100 60  0000 C CNN
	1    1100 4100
	0    -1   -1   0   
$EndComp
NoConn ~ 1250 4200
NoConn ~ 2050 4200
$Comp
L +3.3V #PWR012
U 1 1 554E0D7A
P 1100 4300
F 0 "#PWR012" H 1100 4260 30  0001 C CNN
F 1 "+3.3V" H 1100 4410 30  0000 C CNN
F 2 "" H 1100 4300 60  0000 C CNN
F 3 "" H 1100 4300 60  0000 C CNN
	1    1100 4300
	0    -1   -1   0   
$EndComp
$Comp
L GND #PWR013
U 1 1 554E0D8A
P 1100 4400
F 0 "#PWR013" H 1100 4400 30  0001 C CNN
F 1 "GND" H 1100 4330 30  0001 C CNN
F 2 "" H 1100 4400 60  0000 C CNN
F 3 "" H 1100 4400 60  0000 C CNN
	1    1100 4400
	0    1    1    0   
$EndComp
Text GLabel 1100 4800 0    60   Input ~ 0
SPARE_IO
Text GLabel 1100 4500 0    60   Input ~ 0
led7
Text GLabel 1100 4600 0    60   Input ~ 0
led8
Text GLabel 1100 4900 0    60   Input ~ 0
col1
Text GLabel 1100 5000 0    60   Input ~ 0
col2
Text GLabel 1100 5100 0    60   Input ~ 0
col3
Text GLabel 1100 5200 0    60   Input ~ 0
col4
Text GLabel 1100 5300 0    60   Input ~ 0
col5
Text GLabel 1100 5400 0    60   Input ~ 0
col6
Text GLabel 1100 5500 0    60   Input ~ 0
col7
Text GLabel 1100 5600 0    60   Input ~ 0
col8
Text GLabel 1100 5700 0    60   Input ~ 0
col9
Text GLabel 1100 5800 0    60   Input ~ 0
col10
Text GLabel 1100 5900 0    60   Input ~ 0
col11
Text GLabel 1100 6000 0    60   Input ~ 0
col12
Text GLabel 1100 4700 0    60   Input ~ 0
row2
$Comp
L CONN_4 P5
U 1 1 554E5206
P 3250 7450
F 0 "P5" V 3200 7450 50  0000 C CNN
F 1 "SERIAL 5V TTL" V 3300 7450 50  0000 C CNN
F 2 "" H 3250 7450 60  0000 C CNN
F 3 "" H 3250 7450 60  0000 C CNN
	1    3250 7450
	1    0    0    -1  
$EndComp
$Comp
L +5V #PWR014
U 1 1 554E5213
P 2800 7400
F 0 "#PWR014" H 2800 7490 20  0001 C CNN
F 1 "+5V" H 2800 7490 30  0000 C CNN
F 2 "" H 2800 7400 60  0000 C CNN
F 3 "" H 2800 7400 60  0000 C CNN
	1    2800 7400
	0    -1   -1   0   
$EndComp
$Comp
L R R_S1
U 1 1 554E5219
P 2600 7500
F 0 "R_S1" V 2680 7500 40  0000 C CNN
F 1 "300" V 2607 7501 40  0000 C CNN
F 2 "~" V 2530 7500 30  0000 C CNN
F 3 "~" H 2600 7500 30  0000 C CNN
	1    2600 7500
	0    1    1    0   
$EndComp
$Comp
L R R_S2
U 1 1 554E5233
P 2600 7300
F 0 "R_S2" V 2680 7300 40  0000 C CNN
F 1 "620" V 2607 7301 40  0000 C CNN
F 2 "~" V 2530 7300 30  0000 C CNN
F 3 "~" H 2600 7300 30  0000 C CNN
	1    2600 7300
	0    1    1    0   
$EndComp
Text GLabel 2800 3850 1    60   Input ~ 0
col1
Text GLabel 2800 6000 3    60   Input ~ 0
col2
Text GLabel 2700 4400 1    60   Input ~ 0
col1a
Text GLabel 2700 5450 3    60   Input ~ 0
col2a
Text GLabel 2900 4400 1    60   Input ~ 0
TX
Text GLabel 2900 5450 3    60   Input ~ 0
RX
Text Notes 1100 3700 0    31   ~ 0
2 Expansion ports
Text Notes 2350 6250 1    31   ~ 0
Serial Port Option jumper.\nWarning: enabling Serial Port requires modification on Raspberry Pi.\nWarning2: circuit board traces 1-2 are added\non the PiDP circuit board to enable default option \n(no serial port, unmodified RPI). Cut traces and \njumper 2-3 to enable serial port after \nmodifying the RPi.
Text Notes 2250 6800 0    31   ~ 0
5V TTL compatible serial port (option). \nWarning: requires mod on RPi (remove R23/24)\n               & trace cut/jumper on PiDP\nWarning: do not install resistors R_S1/R_S2 until \n                this mod has been done\n
$Comp
L LED DPAUSE2
U 1 1 554E5897
P 10800 2750
F 0 "DPAUSE2" H 10800 2850 50  0000 C CNN
F 1 "LED" H 10800 2650 50  0000 C CNN
F 2 "~" H 10800 2750 60  0000 C CNN
F 3 "~" H 10800 2750 60  0000 C CNN
	1    10800 2750
	1    0    0    -1  
$EndComp
$Comp
L LED DRUN2
U 1 1 554E589D
P 10800 3100
F 0 "DRUN2" H 10800 3200 50  0000 C CNN
F 1 "LED" H 10800 3000 50  0000 C CNN
F 2 "~" H 10800 3100 60  0000 C CNN
F 3 "~" H 10800 3100 60  0000 C CNN
	1    10800 3100
	1    0    0    -1  
$EndComp
Text GLabel 10600 2600 1    60   Input ~ 0
led7
Text GLabel 11050 2750 1    60   Input ~ 0
col4
Text GLabel 11050 3100 1    60   Input ~ 0
col5
Text Notes 10550 2250 0    60   ~ 0
LEDs ONLY for\nStraight Eight:
$Comp
L CONN_3 J_COL1
U 1 1 554F46DF
P 2800 4800
F 0 "J_COL1" V 2750 4800 50  0000 C CNN
F 1 "CONN_3" V 2850 4800 40  0000 C CNN
F 2 "" H 2800 4800 60  0000 C CNN
F 3 "" H 2800 4800 60  0000 C CNN
	1    2800 4800
	0    -1   1    0   
$EndComp
$Comp
L CONN_3 J_COL2
U 1 1 554F46EE
P 2800 5050
F 0 "J_COL2" V 2750 5050 50  0000 C CNN
F 1 "CONN_3" V 2850 5050 40  0000 C CNN
F 2 "" H 2800 5050 60  0000 C CNN
F 3 "" H 2800 5050 60  0000 C CNN
	1    2800 5050
	0    -1   -1   0   
$EndComp
Wire Wire Line
	9300 1050 9300 3600
Connection ~ 9300 1150
Connection ~ 9300 1500
Connection ~ 9300 1850
Connection ~ 9300 2200
Connection ~ 9300 2550
Connection ~ 9300 2900
Connection ~ 9300 3250
Wire Wire Line
	9950 1050 9950 2200
Connection ~ 9950 1150
Connection ~ 9950 1500
Connection ~ 9950 1850
Wire Wire Line
	9950 2750 9950 3250
Connection ~ 9950 2900
Wire Wire Line
	10600 1050 10600 1850
Connection ~ 10600 1150
Connection ~ 10600 1500
Wire Wire Line
	11000 1150 11050 1150
Wire Wire Line
	11000 1500 11050 1500
Wire Wire Line
	11000 1850 11050 1850
Wire Wire Line
	10350 1150 10400 1150
Wire Wire Line
	10350 1500 10400 1500
Wire Wire Line
	10350 1850 10400 1850
Wire Wire Line
	10350 2200 10400 2200
Wire Wire Line
	9700 1150 9750 1150
Wire Wire Line
	9700 1500 9750 1500
Wire Wire Line
	9700 1850 9750 1850
Wire Wire Line
	9700 2200 9750 2200
Wire Wire Line
	9700 2550 9750 2550
Wire Wire Line
	9700 2900 9750 2900
Wire Wire Line
	9700 3250 9750 3250
Wire Wire Line
	9700 3600 9750 3600
Wire Wire Line
	5500 3050 8900 3050
Connection ~ 8800 3050
Connection ~ 8500 3050
Connection ~ 8200 3050
Connection ~ 7900 3050
Connection ~ 7600 3050
Connection ~ 7300 3050
Connection ~ 7000 3050
Connection ~ 6700 3050
Connection ~ 6400 3050
Connection ~ 6100 3050
Connection ~ 5800 3050
Wire Wire Line
	5500 2000 8900 2000
Connection ~ 5800 2000
Connection ~ 6100 2000
Connection ~ 6400 2000
Connection ~ 6700 2000
Connection ~ 7000 2000
Connection ~ 7300 2000
Connection ~ 7600 2000
Connection ~ 7900 2000
Connection ~ 8200 2000
Connection ~ 8500 2000
Connection ~ 8800 2000
Wire Wire Line
	5500 1750 8900 1750
Connection ~ 8800 1750
Connection ~ 8500 1750
Connection ~ 8200 1750
Connection ~ 7900 1750
Connection ~ 7600 1750
Connection ~ 7300 1750
Connection ~ 7000 1750
Connection ~ 6700 1750
Connection ~ 6400 1750
Connection ~ 6100 1750
Connection ~ 5800 1750
Wire Wire Line
	5500 700  8900 700 
Connection ~ 5800 700 
Connection ~ 6100 700 
Connection ~ 6400 700 
Connection ~ 6700 700 
Connection ~ 7000 700 
Connection ~ 7300 700 
Connection ~ 7600 700 
Connection ~ 7900 700 
Connection ~ 8200 700 
Connection ~ 8500 700 
Connection ~ 8800 700 
Wire Wire Line
	5500 3400 8900 3400
Connection ~ 8800 3400
Connection ~ 8500 3400
Connection ~ 8200 3400
Connection ~ 7900 3400
Connection ~ 7600 3400
Connection ~ 7300 3400
Connection ~ 7000 3400
Connection ~ 6700 3400
Connection ~ 6400 3400
Connection ~ 6100 3400
Connection ~ 5800 3400
Wire Wire Line
	6950 1300 7000 1300
Wire Wire Line
	7000 1100 7000 1350
Wire Wire Line
	7250 1150 7300 1150
Wire Wire Line
	7300 1100 7300 1350
Wire Wire Line
	7550 1300 7600 1300
Wire Wire Line
	7600 1100 7600 1350
Wire Wire Line
	7850 1150 7900 1150
Wire Wire Line
	7900 1100 7900 1350
Wire Wire Line
	8150 1300 8200 1300
Wire Wire Line
	8200 1100 8200 1350
Wire Wire Line
	8450 1150 8500 1150
Wire Wire Line
	8500 1100 8500 1350
Wire Wire Line
	8750 1300 8800 1300
Wire Wire Line
	8800 1100 8800 1350
Wire Wire Line
	10350 2900 10400 2900
Wire Wire Line
	10350 3250 10400 3250
Wire Wire Line
	5450 3850 5500 3850
Wire Wire Line
	5500 3850 5500 3800
Wire Wire Line
	5750 4000 5800 4000
Wire Wire Line
	5800 4000 5800 3800
Wire Wire Line
	6050 3850 6100 3850
Wire Wire Line
	6100 3850 6100 3800
Wire Wire Line
	6350 4000 6400 4000
Wire Wire Line
	6400 4000 6400 3800
Wire Wire Line
	6650 3850 6700 3850
Wire Wire Line
	6700 3850 6700 3800
Wire Wire Line
	8150 4000 8200 4000
Wire Wire Line
	8200 4000 8200 3800
Wire Wire Line
	8450 3850 8500 3850
Wire Wire Line
	8500 3850 8500 3800
Wire Wire Line
	8750 4000 8800 4000
Wire Wire Line
	8800 4000 8800 3800
Wire Wire Line
	3300 4000 3350 4000
Wire Wire Line
	3350 4000 3350 3800
Wire Wire Line
	3600 3850 3650 3850
Wire Wire Line
	3650 3850 3650 3800
Wire Wire Line
	3900 4000 3950 4000
Wire Wire Line
	3950 4000 3950 3800
Wire Wire Line
	4200 3850 4250 3850
Wire Wire Line
	4250 3850 4250 3800
Wire Wire Line
	4500 4000 4550 4000
Wire Wire Line
	4550 4000 4550 3800
Wire Wire Line
	3350 3400 4600 3400
Connection ~ 4550 3400
Connection ~ 4250 3400
Connection ~ 3950 3400
Connection ~ 3650 3400
Wire Wire Line
	3300 700  4850 700 
Connection ~ 3350 700 
Connection ~ 3650 700 
Connection ~ 3950 700 
Connection ~ 4250 700 
Connection ~ 4550 700 
Wire Wire Line
	3300 1150 3350 1150
Wire Wire Line
	3350 1150 3350 1100
Wire Wire Line
	3600 1300 3650 1300
Wire Wire Line
	3650 1300 3650 1100
Wire Wire Line
	3900 1150 3950 1150
Wire Wire Line
	3950 1150 3950 1100
Wire Wire Line
	4200 1300 4250 1300
Wire Wire Line
	4250 1300 4250 1100
Wire Wire Line
	4500 1150 4550 1150
Wire Wire Line
	4550 1150 4550 1100
Wire Wire Line
	4800 1300 4850 1300
Wire Wire Line
	4850 1300 4850 1100
Wire Wire Line
	5150 2650 5200 2650
Wire Wire Line
	5150 3050 5200 3050
Wire Wire Line
	5450 1150 5500 1150
Wire Wire Line
	5500 1100 5500 1350
Wire Wire Line
	5750 1300 5800 1300
Wire Wire Line
	5800 1100 5800 1350
Wire Wire Line
	6050 1150 6100 1150
Wire Wire Line
	6100 1100 6100 1350
Wire Wire Line
	6350 1300 6400 1300
Wire Wire Line
	6400 1100 6400 1350
Wire Wire Line
	6650 1150 6700 1150
Wire Wire Line
	6700 1100 6700 1350
Wire Wire Line
	5450 2450 5500 2450
Wire Wire Line
	5500 2400 5500 2650
Wire Wire Line
	5750 2600 5800 2600
Wire Wire Line
	5800 2400 5800 2650
Wire Wire Line
	6050 2450 6100 2450
Wire Wire Line
	6100 2400 6100 2650
Wire Wire Line
	6350 2600 6400 2600
Wire Wire Line
	6400 2400 6400 2650
Wire Wire Line
	6650 2450 6700 2450
Wire Wire Line
	6700 2400 6700 2650
Wire Wire Line
	6950 2600 7000 2600
Wire Wire Line
	7000 2400 7000 2650
Wire Wire Line
	7250 2450 7300 2450
Wire Wire Line
	7300 2400 7300 2650
Wire Wire Line
	7550 2600 7600 2600
Wire Wire Line
	7600 2400 7600 2650
Wire Wire Line
	7850 2450 7900 2450
Wire Wire Line
	7900 2400 7900 2650
Wire Wire Line
	8150 2600 8200 2600
Wire Wire Line
	8200 2400 8200 2650
Wire Wire Line
	8450 2450 8500 2450
Wire Wire Line
	8500 2400 8500 2650
Wire Wire Line
	8750 2600 8800 2600
Wire Wire Line
	8800 2400 8800 2650
Wire Wire Line
	6950 4000 7000 4000
Wire Wire Line
	7000 4000 7000 3800
Wire Wire Line
	7250 3850 7300 3850
Wire Wire Line
	7300 3850 7300 3800
Wire Wire Line
	7550 4000 7600 4000
Wire Wire Line
	7600 4000 7600 3800
Wire Wire Line
	7850 3850 7900 3850
Wire Wire Line
	7900 3850 7900 3800
Wire Wire Line
	3750 4250 6100 4250
Wire Wire Line
	3800 4250 3800 4300
Wire Wire Line
	4250 4250 4250 4300
Connection ~ 3800 4250
Wire Wire Line
	4700 4250 4700 4300
Connection ~ 4250 4250
Wire Wire Line
	5150 4250 5150 4300
Connection ~ 4700 4250
Wire Wire Line
	5650 4250 5650 4300
Connection ~ 5150 4250
Wire Wire Line
	6100 4250 6100 4300
Connection ~ 5650 4250
Wire Wire Line
	7250 4250 10800 4250
Wire Wire Line
	7300 4250 7300 4300
Wire Wire Line
	7800 4250 7800 4300
Connection ~ 7300 4250
Wire Wire Line
	8300 4250 8300 4300
Connection ~ 7800 4250
Wire Wire Line
	8800 4250 8800 4300
Connection ~ 8300 4250
Wire Wire Line
	9300 4250 9300 4300
Connection ~ 8800 4250
Wire Wire Line
	9800 4250 9800 4300
Connection ~ 9300 4250
Wire Wire Line
	10300 4250 10300 4300
Connection ~ 9800 4250
Wire Wire Line
	10800 4250 10800 4300
Connection ~ 10300 4250
Wire Wire Line
	4900 5750 10000 5750
Wire Wire Line
	4950 5750 4950 5800
Wire Wire Line
	5400 5750 5400 5800
Connection ~ 4950 5750
Wire Wire Line
	5850 5750 5850 5800
Connection ~ 5400 5750
Wire Wire Line
	6300 5750 6300 5800
Connection ~ 5850 5750
Wire Wire Line
	6800 5750 6800 5800
Connection ~ 6300 5750
Wire Wire Line
	7250 5750 7250 5800
Connection ~ 6800 5750
Wire Wire Line
	7700 5750 7700 5800
Connection ~ 7250 5750
Wire Wire Line
	8150 5750 8150 5800
Connection ~ 7700 5750
Wire Wire Line
	8650 5750 8650 5800
Connection ~ 8150 5750
Wire Wire Line
	9100 5750 9100 5800
Connection ~ 8650 5750
Wire Wire Line
	9550 5750 9550 5800
Connection ~ 9100 5750
Wire Wire Line
	10000 5750 10000 5800
Connection ~ 9550 5750
Wire Wire Line
	3500 5550 3500 5350
Wire Wire Line
	3950 5350 3950 5550
Wire Wire Line
	4400 5350 4400 5550
Wire Wire Line
	4850 5350 4850 5550
Wire Wire Line
	5350 5350 5350 5550
Wire Wire Line
	5800 5350 5800 5550
Wire Wire Line
	4650 7050 4650 6850
Wire Wire Line
	5100 7050 5100 6850
Wire Wire Line
	5550 7050 5550 6850
Wire Wire Line
	6000 7050 6000 6850
Wire Wire Line
	6500 7050 6500 6850
Wire Wire Line
	6950 7050 6950 6850
Wire Wire Line
	7400 7050 7400 6850
Wire Wire Line
	7850 7050 7850 6850
Wire Wire Line
	8350 7050 8350 6850
Wire Wire Line
	8800 7050 8800 6850
Wire Wire Line
	9250 7050 9250 6850
Wire Wire Line
	9700 7050 9700 6850
Wire Wire Line
	10100 6850 10100 6800
Wire Wire Line
	9650 6850 9650 6800
Wire Wire Line
	9200 6850 9200 6800
Wire Wire Line
	8750 6850 8750 6800
Wire Wire Line
	8250 6850 8250 6800
Wire Wire Line
	7800 6850 7800 6800
Wire Wire Line
	7350 6850 7350 6800
Wire Wire Line
	6900 6850 6900 6800
Wire Wire Line
	6400 6850 6400 6800
Wire Wire Line
	5950 6850 5950 6800
Wire Wire Line
	5500 6850 5500 6800
Wire Wire Line
	5050 6850 5050 6800
Wire Wire Line
	7000 5350 7000 5550
Wire Wire Line
	7500 5350 7500 5550
Wire Wire Line
	8000 5350 8000 5550
Wire Wire Line
	8500 5350 8500 5550
Wire Wire Line
	9000 5350 9000 5550
Wire Wire Line
	9500 5350 9500 5550
Wire Wire Line
	10000 5350 10000 5550
Wire Wire Line
	10500 5350 10500 5550
Wire Wire Line
	10900 5350 10900 5300
Wire Wire Line
	10400 5350 10400 5300
Wire Wire Line
	9900 5350 9900 5300
Wire Wire Line
	9400 5350 9400 5300
Wire Wire Line
	8900 5350 8900 5300
Wire Wire Line
	8400 5350 8400 5300
Wire Wire Line
	7900 5350 7900 5300
Wire Wire Line
	7400 5350 7400 5300
Wire Wire Line
	4600 1600 4700 1600
Wire Wire Line
	4600 1700 4700 1700
Wire Wire Line
	4600 1800 4700 1800
Wire Wire Line
	4600 1900 4700 1900
Wire Wire Line
	4600 2000 4700 2000
Wire Wire Line
	4600 2100 4700 2100
Wire Wire Line
	4600 2200 4700 2200
Wire Wire Line
	4600 2300 4700 2300
Wire Wire Line
	3800 1600 3900 1600
Wire Wire Line
	3800 1700 3900 1700
Wire Wire Line
	3800 1800 3900 1800
Wire Wire Line
	3800 1900 3900 1900
Wire Wire Line
	3800 2000 3900 2000
Wire Wire Line
	3800 2100 3900 2100
Wire Wire Line
	3800 2200 3900 2200
Wire Wire Line
	3800 2300 3900 2300
Wire Wire Line
	2250 1400 2300 1400
Wire Wire Line
	2250 2100 2300 2100
Wire Wire Line
	2250 2600 2300 2600
Wire Wire Line
	1450 1600 1400 1600
Wire Wire Line
	1400 3100 1450 3100
Wire Wire Line
	2850 2300 2900 2300
Wire Wire Line
	850  2200 800  2200
Wire Wire Line
	850  2100 800  2100
Wire Wire Line
	850  2300 800  2300
Wire Wire Line
	2850 2700 2900 2700
Wire Wire Line
	850  2800 800  2800
Wire Wire Line
	2850 2900 2900 2900
Wire Wire Line
	850  1700 800  1700
Wire Wire Line
	2850 1700 2900 1700
Wire Wire Line
	800  1500 850  1500
Wire Wire Line
	800  2600 850  2600
Wire Wire Line
	800  2700 850  2700
Wire Wire Line
	2900 2400 2850 2400
Wire Wire Line
	1350 1100 1350 1200
Wire Wire Line
	4750 2550 4600 2550
Wire Wire Line
	4600 2550 4600 2400
Wire Wire Line
	3900 5300 3900 5350
Wire Wire Line
	4350 5300 4350 5350
Wire Wire Line
	4800 5300 4800 5350
Wire Wire Line
	5250 5300 5250 5350
Wire Wire Line
	5750 5300 5750 5350
Wire Wire Line
	6200 5300 6200 5350
Wire Wire Line
	2250 1200 2400 1200
Wire Wire Line
	2400 1200 2400 1100
Wire Wire Line
	800  1900 1450 1900
Wire Wire Line
	800  1800 1450 1800
Wire Wire Line
	1350 1500 1450 1500
Wire Wire Line
	1350 1700 1450 1700
Wire Wire Line
	1350 2100 1450 2100
Wire Wire Line
	1350 2200 1450 2200
Wire Wire Line
	1350 2600 1450 2600
Wire Wire Line
	1350 2700 1450 2700
Wire Wire Line
	1350 2800 1450 2800
Wire Wire Line
	1350 2900 1450 2900
Wire Wire Line
	800  3000 1450 3000
Wire Wire Line
	2250 1500 2750 1500
Wire Wire Line
	2250 1600 2750 1600
Wire Wire Line
	2250 1700 2350 1700
Wire Wire Line
	2250 2200 2900 2200
Wire Wire Line
	2250 1900 2900 1900
Wire Wire Line
	2250 2000 2900 2000
Wire Wire Line
	2250 2300 2350 2300
Wire Wire Line
	2250 2700 2350 2700
Wire Wire Line
	2250 2900 2350 2900
Wire Wire Line
	2250 3000 2900 3000
Wire Wire Line
	2250 3100 2900 3100
Wire Wire Line
	1350 2300 1450 2300
Wire Wire Line
	2250 2400 2350 2400
Wire Wire Line
	2850 7100 2850 7300
Connection ~ 1350 1200
Connection ~ 2250 1200
Wire Wire Line
	2250 1200 2250 1300
Wire Wire Line
	3800 2400 3900 2400
Wire Wire Line
	3400 2500 3400 2400
Connection ~ 5500 1150
Connection ~ 5800 1300
Connection ~ 6100 1150
Connection ~ 6400 1300
Connection ~ 6700 1150
Connection ~ 7000 1300
Connection ~ 7300 1150
Connection ~ 7600 1300
Connection ~ 5500 2450
Connection ~ 6100 2450
Connection ~ 6700 2450
Connection ~ 7300 2450
Connection ~ 5800 2600
Connection ~ 6400 2600
Connection ~ 7000 2600
Connection ~ 7600 2600
Connection ~ 7900 2450
Connection ~ 8200 2600
Connection ~ 8500 2450
Connection ~ 8800 2600
Connection ~ 7900 1150
Connection ~ 8200 1300
Connection ~ 8500 1150
Connection ~ 8800 1300
Wire Wire Line
	1100 4100 2050 4100
Connection ~ 1250 4100
Wire Wire Line
	1100 4300 2050 4300
Connection ~ 1250 4300
Wire Wire Line
	1100 4400 2050 4400
Connection ~ 1250 4400
Wire Wire Line
	1100 4500 2050 4500
Connection ~ 1250 4500
Wire Wire Line
	1100 4600 2050 4600
Connection ~ 1250 4600
Wire Wire Line
	1100 4700 2050 4700
Connection ~ 1250 4700
Connection ~ 1250 4800
Wire Wire Line
	1100 4900 2050 4900
Connection ~ 1250 4900
Wire Wire Line
	1100 4800 2050 4800
Wire Wire Line
	1100 5000 2050 5000
Connection ~ 1250 5000
Wire Wire Line
	1100 5100 2050 5100
Connection ~ 1250 5100
Wire Wire Line
	1100 5200 2050 5200
Connection ~ 1250 5200
Wire Wire Line
	1100 5300 2050 5300
Connection ~ 1250 5300
Wire Wire Line
	1100 5400 2050 5400
Connection ~ 1250 5400
Wire Wire Line
	1100 5500 2050 5500
Connection ~ 1250 5500
Wire Wire Line
	1100 5600 2050 5600
Connection ~ 1250 5600
Wire Wire Line
	1100 5700 2050 5700
Connection ~ 1250 5700
Wire Wire Line
	1100 5800 2050 5800
Connection ~ 1250 5800
Wire Wire Line
	1100 5900 2050 5900
Connection ~ 1250 5900
Wire Wire Line
	1100 6000 2050 6000
Connection ~ 1250 6000
Wire Wire Line
	2300 7600 2900 7600
Wire Wire Line
	2850 7500 2900 7500
Wire Wire Line
	2800 7400 2900 7400
Wire Wire Line
	2850 7300 2900 7300
Wire Wire Line
	2350 7500 2300 7500
Wire Wire Line
	800  1400 1450 1400
Wire Wire Line
	11000 2750 11050 2750
Wire Wire Line
	11000 3100 11050 3100
Wire Wire Line
	10600 2600 10600 3100
Connection ~ 10600 2750
Wire Notes Line
	11200 2100 10500 2100
Wire Notes Line
	10500 2100 10500 3300
Wire Notes Line
	10500 3300 11200 3300
Wire Notes Line
	11200 3300 11200 2100
Wire Notes Line
	1750 6650 3600 6650
Wire Notes Line
	3600 6650 3600 7700
Wire Notes Line
	3600 7700 1800 7700
Wire Notes Line
	1800 7700 1800 6650
Wire Notes Line
	2250 6300 3000 6300
Wire Notes Line
	3000 6300 3000 3550
Wire Notes Line
	3000 3550 2250 3550
Wire Notes Line
	2250 3550 2250 6300
Wire Wire Line
	2700 5400 2700 5450
Wire Wire Line
	2800 5400 2800 5450
Wire Wire Line
	2900 5400 2900 5450
Wire Wire Line
	2800 5950 2800 6000
Wire Wire Line
	2800 3850 2800 3900
Wire Wire Line
	2700 4400 2700 4450
Wire Wire Line
	2800 4400 2800 4450
Wire Wire Line
	2900 4400 2900 4450
Wire Wire Line
	2900 7500 2900 7450
Wire Wire Line
	2900 7450 2350 7450
Wire Wire Line
	2350 7450 2350 7300
Wire Wire Line
	1450 1300 800  1300
Wire Wire Line
	1350 1200 1450 1200
NoConn ~ 1450 2000
Wire Wire Line
	2900 4450 2800 4450
Wire Wire Line
	2800 5400 2900 5400
Wire Wire Line
	3400 2400 3500 2400
Wire Wire Line
	3500 2400 3500 2600
Wire Wire Line
	3500 2600 3800 2600
Wire Wire Line
	3800 2600 3800 2400
$EndSCHEMATC
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted hardware/pdp8i/PDP8.ses.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782

(session PDP8.ses
  (base_design PDP8.dsn)
  (placement
    (resolution um 10)
    (component R3
      (place R9 579200 -1029400 back 270)
      (place R1 376000 -1029400 back 90)
      (place R2 401400 -1029400 back 90)
      (place R3 426800 -1029400 back 90)
      (place R4 452200 -1029400 back 90)
      (place R5 477600 -1029400 back 90)
      (place R6 503000 -1029400 back 90)
      (place R7 528400 -1029400 back 270)
      (place R8 553800 -1029400 back 270)
      (place R10 604600 -1029400 back 270)
      (place R11 630000 -1029400 back 270)
      (place R12 655400 -1029400 back 270)
      (place R_ROW1 789000 -1330800 front 0)
      (place R_ROW2 187500 -1295000 front 180)
      (place R_ROW3 2186000 -1330800 front 0)
      (place R_S1 187500 -1330000 front 0)
      (place R_S2 187500 -1365000 front 0)
    )
    (component "DIP-18__300"
      (place P2 2190500 -1009700 back 270)
    )
    (component 1pin
      (place M1 130000 -680000 front 0)
      (place M2 130000 -1590000 front 0)
      (place M3 2850000 -680000 front 0)
      (place M4 2860000 -1590000 front 0)
      (place M5 2080000 -680000 front 0)
      (place M6 2850000 -1320000 front 0)
      (place M7 2080000 -1320000 front 0)
    )
    (component D2
      (place D23 2490000 -1365000 front 0)
      (place D24 2590000 -1365000 front 0)
      (place D22 2390000 -1365000 front 0)
      (place D25 2690000 -1365000 front 0)
      (place D26 2790000 -1365000 front 0)
      (place D12 1390000 -1365000 front 0)
      (place D2 390000 -1365000 front 0)
      (place D3 490000 -1365000 front 0)
      (place D4 590000 -1365000 front 0)
      (place D5 690000 -1365000 front 0)
      (place D6 790000 -1365000 front 0)
      (place D7 890000 -1365000 front 0)
      (place D8 990000 -1365000 front 0)
      (place D9 1090000 -1365000 front 0)
      (place D10 1190000 -1365000 front 0)
      (place D11 1290000 -1365000 front 0)
      (place D1 290000 -1365000 front 0)
      (place D13 1490000 -1365000 front 0)
      (place D14 1590000 -1365000 front 0)
      (place D15 1690000 -1365000 front 0)
      (place D16 1790000 -1365000 front 0)
      (place D17 1890000 -1365000 front 0)
      (place D18 1990000 -1365000 front 0)
      (place D19 2090000 -1365000 front 0)
      (place D20 2190000 -1365000 front 0)
      (place D21 2290000 -1365000 front 0)
    )
    (component RASPI_BPLUS_MIRRORED
      (place P1 640000 -1240000 back 0)
    )
    (component D3
      (place DZ1 2190000 -1170000 front 0)
    )
    (component "LED-3-PDP"
      (place DMB9 1690000 -998000 front 0)
      (place DMB10 1790000 -998000 front 0)
      (place DMB11 1890000 -998000 front 0)
      (place DMB12 1990000 -998000 front 0)
      (place DAC1 890000 -1144000 front 0)
      (place DAC2 990000 -1144000 front 0)
      (place DAC3 1090000 -1144000 front 0)
      (place DAC4 1190000 -1144000 front 0)
      (place DAC5 1290000 -1144000 front 0)
      (place DAC6 1390000 -1144000 front 0)
      (place DAC7 1490000 -1144000 front 0)
      (place DAC8 1590000 -1144000 front 0)
      (place DAC9 1690000 -1144000 front 0)
      (place DAC10 1790000 -1144000 front 0)
      (place DPC1 890000 -706000 front 0)
      (place DAC12 1990000 -1144000 front 0)
      (place DMQ1 890000 -1290000 front 0)
      (place DMQ2 990000 -1290000 front 0)
      (place DMQ3 1090000 -1290000 front 0)
      (place DMQ4 1190000 -1290000 front 0)
      (place DMQ5 1290000 -1290000 front 0)
      (place DMQ6 1390000 -1290000 front 0)
      (place DMQ7 1490000 -1290000 front 0)
      (place DMQ8 1590000 -1290000 front 0)
      (place DMQ9 1690000 -1290000 front 0)
      (place DMQ10 1790000 -1290000 front 0)
      (place DMQ11 1890000 -1290000 front 0)
      (place DMQ12 1990000 -1290000 front 0)
      (place DLINK1 790000 -1144000 front 0)
      (place DSC1 290000 -1290000 front 0)
      (place DAC11 1890000 -1144000 front 0)
      (place DPC2 990000 -706000 front 0)
      (place DPC3 1090000 -706000 front 0)
      (place DPC4 1190000 -706000 front 0)
      (place DPC5 1290000 -706000 front 0)
      (place DPC6 1390000 -706000 front 0)
      (place DPC7 1490000 -706000 front 0)
      (place DPC8 1590000 -706000 front 0)
      (place DPC9 1690000 -706000 front 0)
      (place DPC10 1790000 -706000 front 0)
      (place DPC11 1890000 -706000 front 0)
      (place DPC12 1990000 -706000 front 0)
      (place DMA1 890000 -852000 front 0)
      (place DMA2 990000 -852000 front 0)
      (place DMA3 1090000 -852000 front 0)
      (place DMB8 1590000 -998000 front 0)
      (place DMA5 1290000 -852000 front 0)
      (place DMA6 1390000 -852000 front 0)
      (place DMA7 1490000 -852000 front 0)
      (place DMA8 1590000 -852000 front 0)
      (place DMA9 1690000 -852000 front 0)
      (place DMA10 1790000 -852000 front 0)
      (place DMA11 1890000 -852000 front 0)
      (place DMA12 1990000 -852000 front 0)
      (place DMB1 890000 -998000 front 0)
      (place DMB2 990000 -998000 front 0)
      (place DMB3 1090000 -998000 front 0)
      (place DMB4 1190000 -998000 front 0)
      (place DMB5 1290000 -998000 front 0)
      (place DMB6 1390000 -998000 front 0)
      (place DMB7 1490000 -998000 front 0)
      (place DMA4 1190000 -852000 front 0)
      (place DRUN1 2790000 -852000 front 0)
      (place DPAUSE1 2790000 -779000 front 0)
      (place DION1 2790000 -706000 front 0)
      (place DBREAK1 2590000 -1071000 front 0)
      (place DCURAD1 2590000 -998000 front 0)
      (place DWRDCT1 2590000 -925000 front 0)
      (place DDEFER1 2590000 -852000 front 0)
      (place DEXEC1 2590000 -779000 front 0)
      (place DFETCH1 2590000 -706000 front 0)
      (place DOPR1 2390000 -1217000 front 0)
      (place DIOT1 2390000 -1144000 front 0)
      (place DJMP1 2390000 -1071000 front 0)
      (place DJMS1 2390000 -998000 front 0)
      (place DDCA1 2390000 -925000 front 0)
      (place DSC2 390000 -1290000 front 0)
      (place DSC4 590000 -1290000 front 0)
      (place DSC5 690000 -1290000 front 0)
      (place DDF1 290000 -706000 front 0)
      (place DDF2 390000 -706000 front 0)
      (place DDF3 490000 -706000 front 0)
      (place DSC3 490000 -1290000 front 0)
      (place DTAD1 2390000 -779000 front 0)
      (place DAND1 2390000 -706000 front 0)
      (place DISZ1 2390000 -852000 front 0)
      (place DIF2 690000 -706000 front 0)
      (place DIF3 790000 -706000 front 0)
      (place DIF1 590000 -706000 front 0)
    )
    (component SW_KND2_PDP2
      (place SW6 790000 -1595000 front 0)
      (place SW5 690000 -1595000 front 0)
      (place SW4 590000 -1595000 front 0)
      (place SW3 490000 -1595000 front 0)
      (place SW2 390000 -1595000 front 0)
      (place SW1 290000 -1595000 front 0)
      (place SW18 1990000 -1595000 front 0)
      (place SW17 1890000 -1595000 front 0)
      (place SW15 1690000 -1595000 front 0)
      (place SW14 1590000 -1595000 front 0)
      (place SW13 1490000 -1595000 front 0)
      (place SW12 1390000 -1595000 front 0)
      (place SW19 2090000 -1595000 front 0)
      (place SW20 2190000 -1595000 front 0)
      (place SW16 1790000 -1595000 front 0)
      (place SW22 2390000 -1595000 front 0)
      (place SW23 2490000 -1595000 front 0)
      (place SW24 2590000 -1595000 front 0)
      (place SW25 2690000 -1595000 front 0)
      (place SW26 2790000 -1595000 front 0)
      (place SW7 890000 -1595000 front 0)
      (place SW8 990000 -1595000 front 0)
      (place SW9 1090000 -1595000 front 0)
      (place SW10 1190000 -1595000 front 0)
      (place SW11 1290000 -1595000 front 0)
      (place SW21 2290000 -1595000 front 0)
    )
    (component PIN_ARRAY_4x1
      (place P5 115000 -1360000 front 270)
    )
    (component PIN_ARRAY_20X2
      (place P3 2539000 -1300500 back 180)
    )
    (component "LED-3-StrEight"
      (place DPAUSE2 2590000 -1144000 front 0)
      (place DRUN2 2590000 -1217000 front 0)
    )
    (component PIN_ARRAY_3X1
      (place J_COL1 643000 -1118000 back 180)
      (place J_COL2 643000 -1152000 back 180)
    )
  )
  (was_is
  )
  (routes 
    (resolution um 10)
    (parser
      (host_cad "KiCad's Pcbnew")
      (host_version "(2013-07-07 BZR 4022)-stable")
    )
    (library_out 
      (padstack "Via[0-1]_889:635_um"
        (shape
          (circle F.Cu 8890 0 0)
        )
        (shape
          (circle B.Cu 8890 0 0)
        )
        (attach off)
      )
      (padstack "Via[0-1]_889:0_um"
        (shape
          (circle F.Cu 8890 0 0)
        )
        (shape
          (circle B.Cu 8890 0 0)
        )
        (attach off)
      )
    )
    (network_out 
      (net +3.3V
        (wire
          (path F.Cu 3810
            893368 -1227300
            913651 -1207017
            1290368 -1207017
            1308107 -1224756
            1308107 -1239060
            1377069 -1308022
            2011889 -1308022
            2044180 -1275731
            2336431 -1275731
            2348500 -1287800
          )
        )
        (wire
          (path F.Cu 3810
            881300 -1227300
            893368 -1227300
          )
        )
        (wire
          (path B.Cu 3810
            2348500 -1287800
            2348500 -1313200
          )
        )
      )
      (net +5V
        (wire
          (path F.Cu 3810
            2151900 -1170000
            2116585 -1205315
            1384946 -1205315
            1379892 -1200261
            886410 -1200261
            869231 -1217440
            869231 -1240631
            881300 -1252700
          )
        )
        (wire
          (path F.Cu 3810
            855900 -1252700
            761300 -1347300
            115000 -1347300
          )
        )
        (wire
          (path B.Cu 3810
            881300 -1252700
            855900 -1252700
          )
        )
        (wire
          (path F.Cu 3810
            2297700 -1287800
            2297700 -1299868
          )
        )
        (wire
          (path F.Cu 3810
            2297700 -1313200
            2297700 -1299868
          )
        )
        (wire
          (path B.Cu 3810
            2297700 -1287800
            2285632 -1287800
          )
        )
        (wire
          (path B.Cu 3810
            2285632 -1287800
            2167832 -1170000
            2151900 -1170000
          )
        )
      )
      (net GND
        (wire
          (path B.Cu 3810
            2373900 -1287800
            2298356 -1212256
            2298356 -977856
            2228600 -908100
          )
        )
        (wire
          (path B.Cu 3810
            2373900 -1313200
            2373900 -1287800
          )
        )
        (wire
          (path B.Cu 3810
            792400 -1257101
            784638 -1264863
            664863 -1264863
            652700 -1252700
          )
        )
        (wire
          (path B.Cu 3810
            792400 -1257101
            792400 -1240000
            779700 -1227300
          )
        )
        (wire
          (path B.Cu 3810
            792400 -1257101
            800256 -1264957
            818243 -1264957
            830500 -1252700
          )
        )
        (wire
          (path B.Cu 3810
            115000 -1321900
            127068 -1321900
          )
        )
        (wire
          (path B.Cu 3810
            127068 -1321900
            130612 -1318356
            154053 -1318356
            160929 -1325232
            160929 -1353471
            149400 -1365000
          )
        )
        (wire
          (path F.Cu 3810
            398700 -1227300
            411400 -1240000
            513000 -1240000
            525700 -1252700
          )
        )
        (wire
          (path F.Cu 3810
            364101 -1206624
            378024 -1206624
            398700 -1227300
          )
        )
        (wire
          (path F.Cu 3810
            652700 -1252700
            640631 -1264769
            537769 -1264769
            525700 -1252700
          )
        )
        (wire
          (path F.Cu 3810
            127068 -1321900
            139384 -1321900
            254660 -1206624
            364101 -1206624
          )
        )
        (wire
          (path F.Cu 3810
            2228600 -908100
            2216749 -919951
            1100418 -919951
            1019637 -839170
            511529 -839170
            364101 -986598
            364101 -1206624
          )
        )
        (wire
          (path F.Cu 3810
            115000 -1321900
            127068 -1321900
          )
        )
      )
      (net "N-0000023"
        (wire
          (path B.Cu 2540
            2228100 -1170000
            2228100 -1159202
          )
        )
        (wire
          (path B.Cu 2540
            2228100 -1159202
            2167001 -1098103
            2167001 -922701
            2152400 -908100
          )
        )
      )
      (net "N-0000028"
        (wire
          (path F.Cu 2540
            643000 -1118000
            631567 -1106567
            551911 -1106567
            515700 -1070356
            515700 -1064381
            502323 -1051004
            392496 -1051004
            376000 -1067500
          )
        )
      )
      (net "N-0000029"
        (wire
          (path B.Cu 2540
            643000 -1152000
            631566 -1140566
            619213 -1140566
            606166 -1127519
            606166 -1107927
            626625 -1087468
            650924 -1087468
            666200 -1072192
            666200 -1062830
            644354 -1040984
            427916 -1040984
            401400 -1067500
          )
        )
      )
      (net "N-0000035"
        (wire
          (path F.Cu 2540
            115000 -1372700
            118419 -1376119
            214481 -1376119
            225600 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            115000 -1372700
            149400 -1338300
            149400 -1330000
          )
        )
      )
      (net "N-0000039"
        (wire
          (path B.Cu 2540
            576500 -1252700
            563800 -1240000
            563800 -1223523
            503000 -1162723
            503000 -1067500
          )
        )
      )
      (net "N-0000040"
        (wire
          (path B.Cu 2540
            601900 -1227300
            542629 -1168029
            542629 -1063326
            549319 -1056636
            593736 -1056636
            604600 -1067500
          )
        )
      )
      (net "N-0000041"
        (wire
          (path B.Cu 2540
            449500 -1252700
            458311 -1252700
            490000 -1284389
            490000 -1294620
            526180 -1330800
            750900 -1330800
          )
        )
      )
      (net "N-0000042"
        (wire
          (path B.Cu 2540
            500300 -1252700
            514266 -1238734
            530434 -1238734
            537535 -1231633
            537535 -1220894
            492201 -1175560
            492201 -1062927
            503589 -1051539
            614039 -1051539
            630000 -1067500
          )
        )
      )
      (net "N-0000043"
        (wire
          (path B.Cu 2540
            601900 -1252700
            589200 -1240000
            589200 -1221790
            528400 -1160990
            528400 -1067500
          )
        )
      )
      (net "N-0000046"
        (wire
          (path F.Cu 2540
            754300 -1252700
            765788 -1241212
            860806 -1241212
            868600 -1249006
            868600 -1256571
            884342 -1272313
            977570 -1272313
            990000 -1284743
            990000 -1294994
            1008747 -1313741
            2032306 -1313741
            2062707 -1344142
            2105187 -1344142
            2118529 -1330800
            2147900 -1330800
          )
        )
      )
      (net "N-0000048"
        (wire
          (path B.Cu 2540
            655400 -1067500
            633967 -1046067
            432397 -1046067
            415681 -1062783
            415681 -1072465
            475614 -1132398
            475614 -1226586
            474900 -1227300
          )
        )
      )
      (net "N-0000049"
        (wire
          (path B.Cu 2540
            500300 -1227300
            480697 -1207697
            480697 -1112509
            441005 -1072817
            441005 -1063223
            447939 -1056289
            466389 -1056289
            477600 -1067500
          )
        )
      )
      (net "N-0000050"
        (wire
          (path B.Cu 2540
            525700 -1227300
            485781 -1187381
            485781 -1101081
            452200 -1067500
          )
        )
      )
      (net "N-0000053"
        (wire
          (path B.Cu 2540
            790000 -1539200
            790000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            790000 -1522687
            825560 -1487127
            825560 -1365000
          )
        )
      )
      (net "N-0000054"
        (wire
          (path B.Cu 2540
            627300 -1227300
            587011 -1187011
            587011 -1100711
            553800 -1067500
          )
        )
      )
      (net "N-0000055"
        (wire
          (path B.Cu 2540
            652700 -1227300
            594636 -1169236
            594636 -1082936
            579200 -1067500
          )
        )
      )
      (net "N-0000056"
        (wire
          (path F.Cu 2540
            754300 -1227300
            740334 -1241266
            698766 -1241266
            690800 -1249232
            690800 -1256341
            674806 -1272335
            248265 -1272335
            225600 -1295000
          )
        )
      )
      (net "N-0000057"
        (wire
          (path F.Cu 2540
            426800 -1067500
            426800 -1142787
            496975 -1212962
            790762 -1212962
            805100 -1227300
          )
        )
      )
      (net "N-0000059"
        (wire
          (path B.Cu 2540
            690000 -1539200
            690000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            690000 -1522687
            725560 -1487127
            725560 -1365000
          )
        )
      )
      (net "N-0000060"
        (wire
          (path B.Cu 2540
            590000 -1539200
            590000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            590000 -1522687
            625560 -1487127
            625560 -1365000
          )
        )
      )
      (net "N-0000061"
        (wire
          (path B.Cu 2540
            490000 -1539200
            490000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            490000 -1522687
            525560 -1487127
            525560 -1365000
          )
        )
      )
      (net "N-0000062"
        (wire
          (path F.Cu 2540
            390000 -1539200
            390000 -1522687
          )
        )
        (wire
          (path F.Cu 2540
            390000 -1522687
            425560 -1487127
            425560 -1365000
          )
        )
      )
      (net "N-0000063"
        (wire
          (path B.Cu 2540
            290000 -1539200
            290000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            290000 -1522687
            325560 -1487127
            325560 -1365000
          )
        )
      )
      (net "N-0000065"
        (wire
          (path B.Cu 2540
            2390000 -1539200
            2390000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            2390000 -1522687
            2425560 -1487127
            2425560 -1365000
          )
        )
      )
      (net "N-0000066"
        (wire
          (path B.Cu 2540
            2490000 -1539200
            2490000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            2490000 -1522687
            2525560 -1487127
            2525560 -1365000
          )
        )
      )
      (net "N-0000067"
        (wire
          (path B.Cu 2540
            2590000 -1539200
            2590000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            2590000 -1522687
            2625560 -1487127
            2625560 -1365000
          )
        )
      )
      (net "N-0000068"
        (wire
          (path B.Cu 2540
            2690000 -1539200
            2690000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            2690000 -1522687
            2725560 -1487127
            2725560 -1365000
          )
        )
      )
      (net "N-0000069"
        (wire
          (path F.Cu 2540
            2790000 -1539200
            2790000 -1522687
          )
        )
        (wire
          (path F.Cu 2540
            2790000 -1522687
            2825560 -1487127
            2825560 -1365000
          )
        )
      )
      (net "N-0000070"
        (wire
          (path F.Cu 2540
            2290000 -1539200
            2290000 -1522687
          )
        )
        (wire
          (path F.Cu 2540
            2290000 -1522687
            2325560 -1487127
            2325560 -1365000
          )
        )
      )
      (net "N-0000071"
        (wire
          (path B.Cu 2540
            890000 -1539200
            890000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            890000 -1522687
            925560 -1487127
            925560 -1365000
          )
        )
      )
      (net "N-0000072"
        (wire
          (path B.Cu 2540
            990000 -1539200
            990000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            990000 -1522687
            1025560 -1487127
            1025560 -1365000
          )
        )
      )
      (net "N-0000073"
        (wire
          (path B.Cu 2540
            1090000 -1539200
            1090000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            1090000 -1522687
            1125560 -1487127
            1125560 -1365000
          )
        )
      )
      (net "N-0000074"
        (wire
          (path B.Cu 2540
            1190000 -1539200
            1190000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            1190000 -1522687
            1225560 -1487127
            1225560 -1365000
          )
        )
      )
      (net "N-0000079"
        (wire
          (path B.Cu 2540
            1290000 -1522687
            1325560 -1487127
            1325560 -1375798
          )
        )
        (wire
          (path B.Cu 2540
            1325560 -1365000
            1325560 -1375798
          )
        )
        (wire
          (path B.Cu 2540
            1290000 -1539200
            1290000 -1522687
          )
        )
      )
      (net "N-0000085"
        (wire
          (path B.Cu 2540
            2090000 -1539200
            2090000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            2090000 -1522687
            2125560 -1487127
            2125560 -1365000
          )
        )
      )
      (net "N-0000086"
        (wire
          (path B.Cu 2540
            2190000 -1539200
            2190000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            2190000 -1522687
            2225560 -1487127
            2225560 -1365000
          )
        )
      )
      (net "N-0000087"
        (wire
          (path F.Cu 2540
            1390000 -1539200
            1390000 -1522687
          )
        )
        (wire
          (path F.Cu 2540
            1390000 -1522687
            1425560 -1487127
            1425560 -1365000
          )
        )
      )
      (net "N-0000088"
        (wire
          (path B.Cu 2540
            1490000 -1539200
            1490000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            1490000 -1522687
            1525560 -1487127
            1525560 -1365000
          )
        )
      )
      (net "N-0000089"
        (wire
          (path F.Cu 2540
            1590000 -1539200
            1590000 -1522687
          )
        )
        (wire
          (path F.Cu 2540
            1590000 -1522687
            1625560 -1487127
            1625560 -1365000
          )
        )
      )
      (net "N-0000090"
        (wire
          (path F.Cu 2540
            1690000 -1539200
            1690000 -1522687
          )
        )
        (wire
          (path F.Cu 2540
            1690000 -1522687
            1725560 -1487127
            1725560 -1365000
          )
        )
      )
      (net "N-0000091"
        (wire
          (path B.Cu 2540
            1790000 -1539200
            1790000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            1790000 -1522687
            1825560 -1487127
            1825560 -1365000
          )
        )
      )
      (net "N-0000092"
        (wire
          (path B.Cu 2540
            1890000 -1539200
            1890000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            1890000 -1522687
            1925560 -1487127
            1925560 -1365000
          )
        )
      )
      (net "N-0000093"
        (wire
          (path B.Cu 2540
            1990000 -1539200
            1990000 -1522687
          )
        )
        (wire
          (path B.Cu 2540
            1990000 -1522687
            2025560 -1487127
            2025560 -1365000
          )
        )
      )
      (net RX
        (wire
          (path B.Cu 2540
            668400 -1152000
            671787 -1148613
            732959 -1148613
            767000 -1182654
            767000 -1240000
            779700 -1252700
          )
        )
        (wire
          (path F.Cu 2540
            779700 -1252700
            702400 -1330000
            225600 -1330000
          )
        )
      )
      (net SPARE_IO
        (wire
          (path B.Cu 2540
            449500 -1227300
            463466 -1241266
            479661 -1241266
            487600 -1249205
            487600 -1256169
            548876 -1317445
            718670 -1317445
            721583 -1314532
            848598 -1314532
            857128 -1323062
            926456 -1323062
            982540 -1266978
            1619792 -1266978
            1622826 -1270012
          )
        )
        (wire
          (path F.Cu 2540
            2475500 -1287800
            2457712 -1270012
            1622826 -1270012
          )
        )
        (via "Via[0-1]_889:635_um" 1622826 -1270012
        )
        (wire
          (path F.Cu 2540
            2475500 -1287800
            2475500 -1313200
          )
        )
      )
      (net TX
        (wire
          (path B.Cu 2540
            668400 -1118000
            712498 -1118000
            817006 -1222508
            817006 -1240794
            805100 -1252700
          )
        )
        (wire
          (path F.Cu 2540
            805100 -1252700
            716849 -1340951
            135623 -1340951
            129910 -1335238
            110826 -1335238
            103482 -1342582
            103482 -1386582
            115000 -1398100
          )
        )
      )
      (net col1
        (wire
          (path F.Cu 2540
            902700 -1319828
            897072 -1319828
            851900 -1365000
          )
        )
        (wire
          (path F.Cu 2540
            2051900 -1365000
            2006728 -1319828
            902700 -1319828
          )
        )
        (wire
          (path F.Cu 2540
            902700 -1319828
            902700 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            2051900 -1365000
            2095110 -1365000
            2115968 -1344142
            2469958 -1344142
            2500900 -1313200
          )
        )
        (wire
          (path F.Cu 2540
            902700 -980060
            902700 -852000
          )
        )
        (wire
          (path F.Cu 2540
            902700 -998000
            902700 -980060
          )
        )
        (wire
          (path F.Cu 2540
            902700 -980060
            387240 -980060
            376000 -991300
          )
        )
        (wire
          (path B.Cu 2540
            2402700 -766805
            2397650 -766805
            2390505 -773950
            2390505 -807429
            2424985 -841909
            2424985 -910277
            2500900 -986192
            2500900 -1287800
          )
        )
        (wire
          (path B.Cu 2540
            2602700 -998000
            2590197 -1010503
            2572282 -1010503
            2450476 -888697
            2450476 -809530
            2407751 -766805
            2402700 -766805
          )
        )
        (wire
          (path B.Cu 2540
            2402700 -766805
            2402700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            2500900 -1313200
            2500900 -1287800
          )
        )
        (wire
          (path B.Cu 2540
            902700 -852000
            897645 -846945
            897645 -711055
            902700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            902700 -1144000
            902700 -998000
          )
        )
        (wire
          (path B.Cu 2540
            376000 -991300
            251900 -1115400
            251900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            302700 -706000
            302700 -918000
            376000 -991300
          )
        )
        (wire
          (path B.Cu 2540
            902700 -1290000
            897475 -1284775
            897475 -1149225
            902700 -1144000
          )
        )
      )
      (net col10
        (wire
          (path B.Cu 2540
            2602700 -779000
            2564706 -816994
            2564706 -934782
            2729500 -1099576
            2729500 -1287800
          )
        )
        (wire
          (path F.Cu 2540
            1802700 -706000
            1820450 -723750
            2119706 -723750
            2149900 -693556
            2583066 -693556
            2590000 -700490
            2590000 -766300
            2602700 -779000
          )
        )
        (wire
          (path B.Cu 2540
            1802700 -998000
            1802700 -1061727
            1707700 -1156727
            1701121 -1156727
            1690327 -1167521
            1690327 -1167769
            1621397 -1236699
            979385 -1236699
            913517 -1302567
            872621 -1302567
            860054 -1290000
            844466 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            844466 -1290000
            702700 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            844466 -1290000
            844466 -1247966
            852432 -1240000
            860267 -1240000
            867466 -1232801
            867466 -1190925
            684168 -1007627
            620927 -1007627
            604600 -991300
          )
        )
        (wire
          (path B.Cu 2540
            1802700 -852000
            1802700 -998000
          )
        )
        (wire
          (path B.Cu 2540
            2729500 -1313200
            2729500 -1287800
          )
        )
        (wire
          (path B.Cu 2540
            1802700 -1290000
            1802700 -1314200
            1751900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            1802700 -1144000
            1802700 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            1802700 -998000
            1802700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1802700 -706000
            1802700 -852000
          )
        )
      )
      (net col11
        (wire
          (path B.Cu 2540
            2754900 -1287800
            2754900 -1096506
            2590000 -931606
            2590000 -864700
            2602700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            2754900 -1313200
            2754900 -1287800
          )
        )
        (wire
          (path F.Cu 2540
            2602700 -852000
            2615335 -864635
            2615335 -929633
            2607730 -937238
            2502897 -937238
            2440222 -874563
            1925263 -874563
            1902700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            1902700 -852000
            1902700 -998000
          )
        )
        (wire
          (path B.Cu 2540
            1902700 -706000
            1902700 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1902700 -998000
            1902700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1902700 -706000
            1884949 -688249
            877805 -688249
            683427 -882627
            683427 -978664
            659879 -1002212
            640912 -1002212
            630000 -991300
          )
        )
        (wire
          (path B.Cu 2540
            1902700 -1290000
            1902700 -1314200
            1851900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            1902700 -1144000
            1902700 -1290000
          )
        )
      )
      (net col12
        (wire
          (path F.Cu 2540
            2002700 -1144000
            2002700 -1130259
            2030340 -1102619
          )
        )
        (wire
          (path B.Cu 2540
            2002700 -998000
            2002700 -1074979
            2030340 -1102619
          )
        )
        (wire
          (path B.Cu 2540
            1994465 -839286
            1972445 -839286
            1965105 -846626
            1965105 -960405
            2002700 -998000
          )
        )
        (via "Via[0-1]_889:635_um" 2030340 -1102619
        )
        (wire
          (path B.Cu 2540
            1994465 -839286
            1994465 -843765
            2002700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            1994465 -718196
            1994465 -839286
          )
        )
        (wire
          (path B.Cu 2540
            1994465 -718196
            2002700 -709961
            2002700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            655400 -991300
            655400 -902970
            875205 -683165
            1903320 -683165
            1938351 -718196
            1994465 -718196
          )
        )
        (wire
          (path B.Cu 2540
            2780300 -1287800
            2780300 -1102600
            2602700 -925000
          )
        )
        (wire
          (path B.Cu 2540
            2780300 -1313200
            2780300 -1287800
          )
        )
        (wire
          (path F.Cu 2540
            2602700 -925000
            2547039 -869339
            2020039 -869339
            2002700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            1970417 -1302410
            1970417 -1346483
            1951900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            2002700 -1144000
            1965005 -1181695
            1965005 -1296998
            1970417 -1302410
          )
        )
        (wire
          (path B.Cu 2540
            1970417 -1302410
            1990290 -1302410
            2002700 -1290000
          )
        )
      )
      (net col1a
        (wire
          (path B.Cu 2540
            855900 -1227300
            832312 -1203712
            811814 -1203712
            714668 -1106566
            637609 -1106566
            629033 -1115142
            629033 -1118000
          )
        )
        (wire
          (path B.Cu 2540
            617600 -1118000
            629033 -1118000
          )
        )
      )
      (net col2
        (wire
          (path F.Cu 2540
            2151900 -1365000
            2140935 -1375965
            1985324 -1375965
            1953253 -1343894
            973006 -1343894
            951900 -1365000
          )
        )
        (wire
          (path F.Cu 2540
            2526300 -1313200
            2487734 -1351766
            2165134 -1351766
            2151900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            2572572 -1058449
            2590149 -1058449
            2602700 -1071000
          )
        )
        (wire
          (path B.Cu 2540
            2526300 -1287800
            2526300 -1104721
            2572572 -1058449
          )
        )
        (wire
          (path B.Cu 2540
            2572572 -1058449
            2572572 -1017981
            2445392 -890801
            2445392 -821692
            2402700 -779000
          )
        )
        (wire
          (path B.Cu 2540
            401400 -991300
            264733 -1127967
            264733 -1294831
            291142 -1321240
            308140 -1321240
            351900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            402700 -706000
            402700 -990000
            401400 -991300
          )
        )
        (wire
          (path F.Cu 2540
            1002700 -1290000
            1002700 -1228440
          )
        )
        (wire
          (path B.Cu 2540
            1002700 -1228440
            1002700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1002700 -1144000
            1002700 -998000
          )
        )
        (via "Via[0-1]_889:635_um" 1002700 -1228440
        )
        (wire
          (path F.Cu 2540
            1002700 -706000
            990172 -693472
            654471 -693472
            629540 -718403
            415103 -718403
            402700 -706000
          )
        )
        (wire
          (path F.Cu 2540
            1002700 -998000
            1002700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            2526300 -1313200
            2526300 -1287800
          )
        )
        (wire
          (path B.Cu 2540
            1002700 -1290000
            1002700 -1314200
            951900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            1002700 -852000
            1002700 -706000
          )
        )
      )
      (net col2a
        (wire
          (path F.Cu 2540
            617600 -1152000
            629033 -1152000
          )
        )
        (wire
          (path F.Cu 2540
            629033 -1152000
            629033 -1154858
            680123 -1205948
            809148 -1205948
            830500 -1227300
          )
        )
      )
      (net col3
        (wire
          (path B.Cu 2540
            426800 -991300
            422334 -991300
            290000 -1123634
            290000 -1295160
            338877 -1344037
            430937 -1344037
            451900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            502700 -706000
            426800 -781900
            426800 -991300
          )
        )
        (wire
          (path F.Cu 2540
            2251900 -1365000
            2235851 -1381049
            1983220 -1381049
            1951149 -1348978
            1067922 -1348978
            1051900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            2488200 -1316770
            2488200 -985930
            2402700 -900430
            2402700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            2551700 -1313200
            2539781 -1325119
            2496549 -1325119
            2488200 -1316770
          )
        )
        (wire
          (path B.Cu 2540
            2488200 -1316770
            2468371 -1336599
            2280301 -1336599
            2251900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            2551700 -1287800
            2551700 -1313200
          )
        )
        (wire
          (path F.Cu 2540
            1102700 -1290000
            1102700 -1228440
          )
        )
        (wire
          (path B.Cu 2540
            1102700 -1144000
            1102700 -1228440
          )
        )
        (wire
          (path B.Cu 2540
            1102700 -998000
            1102700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1102700 -852000
            1102700 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1102700 -706000
            1080006 -683306
            525394 -683306
            502700 -706000
          )
        )
        (wire
          (path F.Cu 2540
            2402700 -852000
            2414956 -864256
            2582306 -864256
            2590000 -856562
            2590000 -847385
            2708089 -729296
            2779404 -729296
            2802700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1102700 -706000
            1102700 -852000
          )
        )
        (via "Via[0-1]_889:635_um" 1102700 -1228440
        )
        (wire
          (path B.Cu 2540
            1102700 -1290000
            1102700 -1314200
            1051900 -1365000
          )
        )
      )
      (net col4
        (wire
          (path F.Cu 2540
            1151900 -1365000
            1141101 -1375799
            798427 -1375799
            776829 -1354201
            562699 -1354201
            551900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            2577100 -1287800
            2577100 -1313200
          )
        )
        (wire
          (path B.Cu 2540
            2602700 -1144000
            2590000 -1156700
            2590000 -1274900
            2577100 -1287800
          )
        )
        (wire
          (path F.Cu 2540
            2584450 -1106750
            2602700 -1125000
            2602700 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            2402700 -925000
            2584450 -1106750
          )
        )
        (wire
          (path F.Cu 2540
            2584450 -1106750
            2790000 -901200
            2790000 -791700
            2802700 -779000
          )
        )
        (wire
          (path F.Cu 2540
            1202700 -852000
            1246336 -895636
            2373336 -895636
            2402700 -925000
          )
        )
        (wire
          (path B.Cu 2540
            452200 -991300
            452200 -856500
            602700 -706000
          )
        )
        (wire
          (path F.Cu 2540
            1202700 -1290000
            1202700 -1228440
          )
        )
        (wire
          (path B.Cu 2540
            1202700 -1144000
            1202700 -1228440
          )
        )
        (wire
          (path B.Cu 2540
            1202700 -1290000
            1202700 -1314200
            1151900 -1365000
          )
        )
        (wire
          (path F.Cu 2540
            1202700 -706000
            1190492 -718208
            1038889 -718208
            1009070 -688389
            620311 -688389
            602700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            2351900 -1365000
            2374911 -1341989
            2548311 -1341989
            2577100 -1313200
          )
        )
        (wire
          (path B.Cu 2540
            1202700 -998000
            1202700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1202700 -852000
            1202700 -998000
          )
        )
        (wire
          (path B.Cu 2540
            1202700 -706000
            1202700 -852000
          )
        )
        (via "Via[0-1]_889:635_um" 1202700 -1228440
        )
      )
      (net col5
        (wire
          (path F.Cu 2540
            1302700 -998000
            1352674 -948026
            2352726 -948026
            2402700 -998000
          )
        )
        (wire
          (path F.Cu 2540
            2584412 -1179711
            2402700 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1285409 -723291
            1302700 -706000
          )
        )
        (wire
          (path F.Cu 2540
            702700 -706000
            714958 -718258
            914410 -718258
            915172 -717496
            964914 -717496
            970709 -723291
            1285409 -723291
          )
        )
        (wire
          (path F.Cu 2540
            1302700 -852000
            1302700 -740582
            1285409 -723291
          )
        )
        (wire
          (path F.Cu 2540
            2602700 -1217000
            2602700 -1198000
            2584412 -1179711
          )
        )
        (wire
          (path F.Cu 2540
            2802700 -852000
            2802700 -961423
            2584412 -1179711
          )
        )
        (wire
          (path B.Cu 2540
            702700 -706000
            702700 -766200
            477600 -991300
          )
        )
        (wire
          (path B.Cu 2540
            2602500 -1287800
            2602500 -1313200
          )
        )
        (wire
          (path B.Cu 2540
            2602700 -1217000
            2602500 -1217200
            2602500 -1287800
          )
        )
        (wire
          (path F.Cu 2540
            1251900 -1365000
            1230860 -1386040
            672940 -1386040
            651900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            1302700 -1290000
            1302700 -1314200
            1251900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            1302700 -1144000
            1302700 -1224954
            1299214 -1228440
          )
        )
        (wire
          (path F.Cu 2540
            1302700 -1290000
            1299214 -1286514
            1299214 -1228440
          )
        )
        (wire
          (path B.Cu 2540
            2451900 -1365000
            2466850 -1350050
            2565650 -1350050
            2602500 -1313200
          )
        )
        (via "Via[0-1]_889:635_um" 1299214 -1228440
        )
        (wire
          (path B.Cu 2540
            1302700 -998000
            1302700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1302700 -852000
            1302700 -998000
          )
        )
      )
      (net col6
        (wire
          (path F.Cu 2540
            1402700 -998000
            1420560 -1015860
            1612551 -1015860
            1653282 -975129
            2125019 -975129
            2148688 -998798
            2235908 -998798
            2287164 -1050054
            2381754 -1050054
            2402700 -1071000
          )
        )
        (wire
          (path B.Cu 2540
            503000 -991300
            765293 -729007
            779693 -729007
            802700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            311683 -1290000
            311683 -1109141
            400177 -1020647
            473653 -1020647
            503000 -991300
          )
        )
        (wire
          (path F.Cu 2540
            1402700 -1228050
            1402700 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1402700 -1144000
            1402700 -1228050
          )
        )
        (wire
          (path B.Cu 2540
            751900 -1365000
            725853 -1338953
            360636 -1338953
            311683 -1290000
          )
        )
        (via "Via[0-1]_889:635_um" 1402700 -1228050
        )
        (wire
          (path B.Cu 2540
            1402700 -998000
            1402700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1402700 -1290000
            1402700 -1314200
            1351900 -1365000
          )
        )
        (wire
          (path F.Cu 2540
            2627900 -1287800
            2411100 -1071000
            2402700 -1071000
          )
        )
        (wire
          (path F.Cu 2540
            1351900 -1365000
            1341101 -1354201
            1194682 -1354201
            1167935 -1380948
            767848 -1380948
            751900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            311683 -1290000
            302700 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1402700 -998000
            1402700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            1402700 -706000
            1402700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            2627900 -1313200
            2576100 -1365000
            2551900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            2627900 -1287800
            2627900 -1313200
          )
        )
      )
      (net col7
        (wire
          (path B.Cu 2540
            802700 -1144000
            790503 -1156197
            771780 -1156197
            646395 -1030812
            567912 -1030812
            528400 -991300
          )
        )
        (wire
          (path B.Cu 2540
            528400 -991300
            484585 -1035115
            418307 -1035115
            387266 -1066156
            387266 -1274566
            402700 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1502700 -1290000
            1502700 -1314200
            1451900 -1365000
          )
        )
        (wire
          (path F.Cu 2540
            1580419 -1215844
            2330856 -1215844
            2402700 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1502700 -1290000
            1576856 -1215844
            1580419 -1215844
          )
        )
        (wire
          (path F.Cu 2540
            2641571 -1299529
            2641571 -1301471
            2653300 -1313200
          )
        )
        (wire
          (path F.Cu 2540
            2653300 -1287800
            2641571 -1299529
          )
        )
        (wire
          (path F.Cu 2540
            2641571 -1299529
            2623462 -1299529
            2615200 -1291267
            2615200 -1284253
            2474947 -1144000
            2402700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1502700 -1144000
            1508575 -1144000
            1580419 -1215844
          )
        )
        (wire
          (path B.Cu 2540
            1502700 -998000
            1502700 -1144000
          )
        )
        (via "Via[0-1]_889:635_um" 1580419 -1215844
        )
        (wire
          (path B.Cu 2540
            1502700 -852000
            1502700 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1502700 -1144000
            1490412 -1156288
            814988 -1156288
            802700 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            2653300 -1313200
            2653300 -1363600
            2651900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            1502700 -852000
            1502700 -706000
          )
        )
      )
      (net col8
        (wire
          (path B.Cu 2540
            1602700 -852000
            1602700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1602700 -1010468
            1572441 -1010468
            1564896 -1002923
            1564896 -889804
            1602700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            553800 -991300
            542967 -980467
            523962 -980467
            517499 -986930
            517499 -992073
            483842 -1025730
            402357 -1025730
            317164 -1110923
            317164 -1253492
            344426 -1280754
          )
        )
        (wire
          (path B.Cu 2540
            1622028 -1224390
            1602700 -1205062
            1602700 -1144000
          )
        )
        (via "Via[0-1]_889:635_um" 1622028 -1224390
        )
        (wire
          (path F.Cu 2540
            1630305 -1232667
            1602700 -1260272
            1602700 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            2402700 -1217000
            2387033 -1232667
            1630305 -1232667
          )
        )
        (wire
          (path F.Cu 2540
            1630305 -1232667
            1622028 -1224390
          )
        )
        (wire
          (path B.Cu 2540
            1602700 -1010468
            1602700 -998000
          )
        )
        (wire
          (path B.Cu 2540
            1602700 -1144000
            1602700 -1010468
          )
        )
        (wire
          (path B.Cu 2540
            502700 -1290000
            535228 -1322528
            720775 -1322528
            723687 -1319616
            833665 -1319616
            864229 -1350180
            930720 -1350180
            936932 -1356392
            936932 -1365769
            947424 -1376261
            980985 -1376261
            1047575 -1309671
            1074969 -1309671
            1090000 -1294640
            1090000 -1285169
            1103090 -1272079
            1584779 -1272079
            1602700 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            502700 -1290000
            490476 -1302224
            450282 -1302224
            425862 -1277804
            347376 -1277804
            344426 -1280754
          )
        )
        (wire
          (path B.Cu 2540
            1602700 -1290000
            1602700 -1314200
            1551900 -1365000
          )
        )
        (via "Via[0-1]_889:635_um" 344426 -1280754
        )
        (wire
          (path F.Cu 2540
            2678700 -1313200
            2667097 -1324803
            2623000 -1324803
            2613934 -1315737
            2613934 -1308466
            2604702 -1299234
            2597766 -1299234
            2589800 -1291268
            2589800 -1284209
            2570520 -1264929
            2450628 -1264929
            2450628 -1264928
            2402700 -1217000
          )
        )
        (wire
          (path F.Cu 2540
            2678700 -1287800
            2678700 -1313200
          )
        )
        (wire
          (path B.Cu 2540
            2678700 -1313200
            2716105 -1350605
            2737505 -1350605
            2751900 -1365000
          )
        )
      )
      (net col9
        (wire
          (path F.Cu 2540
            567816 -1093605
            567816 -1002684
            579200 -991300
          )
        )
        (wire
          (path B.Cu 2540
            613856 -1290000
            613856 -1223086
            567816 -1177046
            567816 -1093605
          )
        )
        (wire
          (path F.Cu 2540
            2602700 -706000
            2585172 -688472
            2125676 -688472
            2109943 -704205
            2066267 -704205
            2055364 -693302
            1715398 -693302
            1702700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            613856 -1290000
            602700 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1693295 -1261413
            977441 -1261413
            920876 -1317978
            859234 -1317978
            850612 -1309356
            719571 -1309356
            716565 -1312362
            636218 -1312362
            613856 -1290000
          )
        )
        (via "Via[0-1]_889:635_um" 567816 -1093605
        )
        (wire
          (path B.Cu 2540
            2704100 -1287800
            2704100 -1081367
            2559498 -936765
            2559498 -749202
            2602700 -706000
          )
        )
        (wire
          (path B.Cu 2540
            2704100 -1313200
            2704100 -1287800
          )
        )
        (wire
          (path B.Cu 2540
            1702700 -1290000
            1693295 -1280595
            1693295 -1261413
          )
        )
        (wire
          (path B.Cu 2540
            1708751 -1175151
            1693295 -1190607
            1693295 -1261413
          )
        )
        (via "Via[0-1]_889:635_um" 1708751 -1175151
        )
        (wire
          (path F.Cu 2540
            1702700 -1144000
            1708751 -1150051
            1708751 -1175151
          )
        )
        (wire
          (path B.Cu 2540
            1702700 -1290000
            1702700 -1314200
            1651900 -1365000
          )
        )
        (wire
          (path B.Cu 2540
            1702700 -852000
            1702700 -998000
          )
        )
        (wire
          (path B.Cu 2540
            1702700 -706000
            1702700 -852000
          )
        )
        (wire
          (path B.Cu 2540
            1702700 -1144000
            1702700 -998000
          )
        )
      )
      (net led1
        (wire
          (path B.Cu 2540
            1977300 -706000
            1989496 -693804
            2008244 -693804
            2146246 -831806
            2146246 -866766
            2225680 -946200
            2231880 -946200
            2244891 -959211
            2244891 -1095009
            2228600 -1111300
          )
        )
        (wire
          (path B.Cu 2540
            1777300 -706000
            1789699 -693601
            1864901 -693601
            1877300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1777300 -706000
            1765105 -693805
            1689495 -693805
            1677300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1677300 -706000
            1665105 -693805
            1589495 -693805
            1577300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1577300 -706000
            1565105 -693805
            1489495 -693805
            1477300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1477300 -706000
            1465105 -693805
            1389495 -693805
            1377300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1377300 -706000
            1365105 -693805
            1289495 -693805
            1277300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1277300 -706000
            1265105 -693805
            1189495 -693805
            1177300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1177300 -706000
            1165105 -693805
            1089495 -693805
            1077300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            1077300 -706000
            1065105 -693805
            989495 -693805
            977300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            977300 -706000
            965105 -693805
            889495 -693805
            877300 -706000
          )
        )
        (wire
          (path F.Cu 2540
            1977300 -706000
            1964948 -718352
            1889652 -718352
            1877300 -706000
          )
        )
      )
      (net led2
        (wire
          (path F.Cu 2540
            1277300 -852000
            1289496 -864196
            1365104 -864196
            1377300 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1177300 -852000
            1189496 -839804
            1265104 -839804
            1277300 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1977300 -852000
            1964713 -839413
            1889887 -839413
            1877300 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1877300 -852000
            1865104 -839804
            1789496 -839804
            1777300 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1777300 -852000
            1764657 -864643
            1689943 -864643
            1677300 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1677300 -852000
            1665104 -839804
            1589496 -839804
            1577300 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1577300 -852000
            1564657 -864643
            1489943 -864643
            1477300 -852000
          )
        )
        (wire
          (path F.Cu 2540
            1477300 -852000
            1465104 -839804
            1389496 -839804
            1377300 -852000
          )
        )
        (wire
          (path B.Cu 2540
            1977300 -852000
            2020025 -894725
            2154577 -894725
            2213999 -954147
            2213999 -1071299
            2228600 -1085900
          )
        )
        (wire
          (path F.Cu 2540
            1177300 -852000
            1164995 -864305
            1089605 -864305
            1077300 -852000
          )
        )
        (wire
          (path B.Cu 2540
            1077300 -852000
            1065104 -864196
            989496 -864196
            977300 -852000
          )
        )
        (wire
          (path B.Cu 2540
            877300 -852000
            889496 -864196
            965104 -864196
            977300 -852000
          )
        )
      )
      (net led3
        (wire
          (path F.Cu 2540
            1577300 -998000
            1564659 -985359
            1489941 -985359
            1477300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1477300 -998000
            1460021 -980721
            1394579 -980721
            1377300 -998000
          )
        )
        (wire
          (path B.Cu 2540
            1577300 -998000
            1589569 -985731
            1665031 -985731
            1677300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1177300 -998000
            1189496 -1010196
            1265104 -1010196
            1277300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1177300 -998000
            1165097 -1010203
            1089503 -1010203
            1077300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1377300 -998000
            1365104 -1010196
            1289496 -1010196
            1277300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1777300 -998000
            1789851 -985449
            1864749 -985449
            1877300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1677300 -998000
            1689496 -1010196
            1765104 -1010196
            1777300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            977300 -998000
            965010 -1010290
            889590 -1010290
            877300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            1977300 -998000
            2001700 -1022400
            2231272 -1022400
            2239433 -1030561
            2239433 -1049667
            2228600 -1060500
          )
        )
        (wire
          (path F.Cu 2540
            1877300 -998000
            1889730 -985570
            1964870 -985570
            1977300 -998000
          )
        )
        (wire
          (path B.Cu 2540
            1077300 -998000
            1064765 -985465
            989835 -985465
            977300 -998000
          )
        )
      )
      (net led4
        (wire
          (path F.Cu 2540
            1977300 -1144000
            1977300 -1143582
            2047067 -1073815
            2189886 -1073815
            2189886 -1073814
            2228600 -1035100
          )
        )
        (wire
          (path F.Cu 2540
            1377300 -1144000
            1365104 -1131804
            1289496 -1131804
            1277300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1477300 -1144000
            1465104 -1131804
            1389496 -1131804
            1377300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            977300 -1144000
            965104 -1131804
            889496 -1131804
            877300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1077300 -1144000
            1065104 -1131804
            989496 -1131804
            977300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1777300 -1144000
            1765036 -1131736
            1689564 -1131736
            1677300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1177300 -1144000
            1165104 -1131804
            1089496 -1131804
            1077300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1277300 -1144000
            1265104 -1131804
            1189496 -1131804
            1177300 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1877300 -1144000
            1889677 -1131623
            1964923 -1131623
            1977300 -1144000
          )
        )
        (wire
          (path B.Cu 2540
            1877300 -1144000
            1864883 -1131583
            1789717 -1131583
            1777300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1677300 -1144000
            1665078 -1156222
            1589522 -1156222
            1577300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            1577300 -1144000
            1565104 -1131804
            1489496 -1131804
            1477300 -1144000
          )
        )
      )
      (net led5
        (wire
          (path F.Cu 2540
            2117167 -1175345
            2219312 -1073200
            2231781 -1073200
            2245007 -1059974
            2245007 -1026107
            2228600 -1009700
          )
        )
        (via "Via[0-1]_889:635_um" 2117167 -1175345
        )
        (wire
          (path B.Cu 2540
            1977300 -1290000
            2091955 -1175345
            2117167 -1175345
          )
        )
        (wire
          (path F.Cu 2540
            1277300 -1290000
            1265104 -1302196
            1189496 -1302196
            1177300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            1077300 -1290000
            1089496 -1302196
            1165104 -1302196
            1177300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            1977300 -1290000
            1964997 -1302303
            1889603 -1302303
            1877300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            977300 -1290000
            965104 -1277804
            889496 -1277804
            877300 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1077300 -1290000
            1064887 -1277587
            989713 -1277587
            977300 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1377300 -1290000
            1364881 -1277581
            1289719 -1277581
            1277300 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1477300 -1290000
            1489495 -1277805
            1565105 -1277805
            1577300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            1777300 -1290000
            1765104 -1302196
            1689496 -1302196
            1677300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            1577300 -1290000
            1589496 -1302196
            1665104 -1302196
            1677300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            1877300 -1290000
            1865105 -1277805
            1789495 -1277805
            1777300 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            1477300 -1290000
            1465105 -1277805
            1389495 -1277805
            1377300 -1290000
          )
        )
      )
      (net led6
        (wire
          (path F.Cu 2540
            2377300 -998000
            2242300 -998000
            2228600 -984300
          )
        )
        (wire
          (path F.Cu 2540
            2389551 -718251
            2565049 -718251
          )
        )
        (wire
          (path F.Cu 2540
            2377300 -706000
            2389551 -718251
          )
        )
        (wire
          (path F.Cu 2540
            2377300 -779000
            2377300 -730502
            2389551 -718251
          )
        )
        (wire
          (path F.Cu 2540
            2565049 -718251
            2577300 -706000
          )
        )
        (wire
          (path F.Cu 2540
            2565049 -718251
            2565049 -766749
            2577300 -779000
          )
        )
        (wire
          (path B.Cu 2540
            2377300 -1144000
            2377300 -1217000
          )
        )
        (wire
          (path B.Cu 2540
            2377300 -1071000
            2377300 -1144000
          )
        )
        (wire
          (path F.Cu 2540
            2577300 -779000
            2577300 -852000
          )
        )
        (wire
          (path B.Cu 2540
            2577300 -852000
            2577300 -925000
          )
        )
        (wire
          (path B.Cu 2540
            2377300 -998000
            2377300 -1071000
          )
        )
        (wire
          (path B.Cu 2540
            2377300 -925000
            2377300 -998000
          )
        )
        (wire
          (path B.Cu 2540
            2377300 -852000
            2377300 -925000
          )
        )
        (wire
          (path B.Cu 2540
            2377300 -779000
            2377300 -852000
          )
        )
      )
      (net led7
        (wire
          (path F.Cu 2540
            2228600 -958900
            2355540 -958900
            2390000 -993360
            2390000 -1029700
            2577300 -1217000
          )
        )
        (wire
          (path B.Cu 2540
            2577300 -1144000
            2577300 -1217000
          )
        )
        (wire
          (path F.Cu 2540
            2777300 -852000
            2723300 -852000
            2577300 -998000
          )
        )
        (wire
          (path F.Cu 2540
            2777300 -779000
            2777300 -852000
          )
        )
        (wire
          (path B.Cu 2540
            2777300 -706000
            2777300 -779000
          )
        )
        (wire
          (path F.Cu 2540
            2577300 -1071000
            2577300 -998000
          )
        )
        (wire
          (path B.Cu 2540
            2228600 -958900
            2239609 -969909
            2239609 -1090211
            2231220 -1098600
            2225885 -1098600
            2217524 -1106961
            2217524 -1131008
            2238917 -1152401
            2238917 -1181052
          )
        )
        (wire
          (path B.Cu 2540
            2238917 -1181052
            2199421 -1181052
            2144442 -1126073
            1771310 -1126073
            1730490 -1166893
            1705331 -1166893
            1700493 -1171731
            1700493 -1171979
            1616142 -1256330
            975183 -1256330
            918681 -1312832
            861276 -1312832
            852546 -1304102
            717637 -1304102
            714460 -1307279
            694579 -1307279
            677300 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            477300 -1290000
            464551 -1302749
            390049 -1302749
            377300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            577300 -1290000
            565003 -1277703
            489597 -1277703
            477300 -1290000
          )
        )
        (wire
          (path F.Cu 2540
            677300 -1290000
            665104 -1277804
            589496 -1277804
            577300 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            2399300 -1313200
            2387380 -1325120
            2368960 -1325120
            2361200 -1317360
            2361200 -1283347
            2258905 -1181052
            2238917 -1181052
          )
        )
        (wire
          (path F.Cu 2540
            377300 -1290000
            365104 -1302196
            289496 -1302196
            277300 -1290000
          )
        )
        (wire
          (path B.Cu 2540
            2399300 -1287800
            2399300 -1313200
          )
        )
        (wire
          (path B.Cu 2540
            2577300 -1144000
            2577300 -1071000
          )
        )
      )
      (net led8
        (wire
          (path B.Cu 2540
            2217649 -897061
            2217649 -922549
            2228600 -933500
          )
        )
        (wire
          (path B.Cu 2540
            815189 -694080
            831332 -677937
            1999705 -677937
            2217649 -895881
            2217649 -897061
          )
        )
        (wire
          (path B.Cu 2540
            2424700 -1287800
            2365104 -1228204
            2365104 -1028730
            2233435 -897061
            2217649 -897061
          )
        )
        (wire
          (path B.Cu 2540
            2424700 -1313200
            2424700 -1287800
          )
        )
        (wire
          (path B.Cu 2540
            815189 -694080
            814894 -693785
            789515 -693785
            777300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            777300 -1144000
            656489 -1023189
            620804 -1023189
            593711 -996096
            593711 -944853
            815189 -723375
            815189 -694080
          )
        )
        (wire
          (path B.Cu 2540
            477300 -706000
            464624 -693324
            389976 -693324
            377300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            577300 -706000
            564624 -693324
            489976 -693324
            477300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            377300 -706000
            364624 -693324
            289976 -693324
            277300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            777300 -706000
            765104 -693804
            689496 -693804
            677300 -706000
          )
        )
        (wire
          (path B.Cu 2540
            577300 -706000
            589496 -693804
            665104 -693804
            677300 -706000
          )
        )
      )
      (net row1
        (wire
          (path B.Cu 3810
            890000 -1595000
            890000 -1577852
          )
        )
        (wire
          (path B.Cu 3810
            890000 -1577852
            836994 -1524846
            836994 -1340694
            827100 -1330800
          )
        )
        (wire
          (path F.Cu 3810
            1590000 -1595000
            1690000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1490000 -1595000
            1590000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1890000 -1595000
            1990000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1790000 -1595000
            1890000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1690000 -1595000
            1790000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1390000 -1595000
            1490000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1290000 -1595000
            1390000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1190000 -1595000
            1290000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            990000 -1595000
            890000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1090000 -1595000
            990000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            1190000 -1595000
            1090000 -1595000
          )
        )
      )
      (net row2
        (wire
          (path B.Cu 3810
            690000 -1595000
            719848 -1595000
          )
        )
        (wire
          (path B.Cu 3810
            790000 -1603574
            728422 -1603574
            719848 -1595000
          )
        )
        (wire
          (path B.Cu 3810
            790000 -1603574
            790000 -1612148
          )
        )
        (wire
          (path B.Cu 3810
            790000 -1595000
            790000 -1603574
          )
        )
        (wire
          (path B.Cu 3810
            590000 -1595000
            490000 -1595000
          )
        )
        (wire
          (path B.Cu 3810
            2450100 -1313200
            2432420 -1330880
            2250709 -1330880
            2239137 -1319308
            2139587 -1319308
            2114032 -1344863
            2025437 -1344863
            1940000 -1430300
            1940000 -1526807
            1910458 -1556349
            1490818 -1556349
            1435019 -1612148
            790000 -1612148
          )
        )
        (wire
          (path B.Cu 3810
            2450100 -1287800
            2450100 -1313200
          )
        )
        (wire
          (path B.Cu 3810
            290000 -1595000
            290000 -1577852
          )
        )
        (wire
          (path B.Cu 3810
            290000 -1577852
            245925 -1533777
            245925 -1409381
            192122 -1355578
            192122 -1337722
            149400 -1295000
          )
        )
        (wire
          (path F.Cu 3810
            290000 -1595000
            390000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            590000 -1595000
            690000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            390000 -1595000
            490000 -1595000
          )
        )
      )
      (net row3
        (wire
          (path F.Cu 3810
            2490000 -1595000
            2590000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            2390000 -1595000
            2490000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            2690000 -1595000
            2790000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            2590000 -1595000
            2690000 -1595000
          )
        )
        (wire
          (path F.Cu 3810
            2290000 -1595000
            2390000 -1595000
          )
        )
        (wire
          (path B.Cu 3810
            2239196 -1528656
            2190000 -1577852
          )
        )
        (wire
          (path B.Cu 3810
            2224100 -1330800
            2239196 -1345896
            2239196 -1528656
          )
        )
        (wire
          (path B.Cu 3810
            2290000 -1577852
            2240804 -1528656
            2239196 -1528656
          )
        )
        (wire
          (path B.Cu 3810
            2190000 -1595000
            2190000 -1577852
          )
        )
        (wire
          (path B.Cu 3810
            2290000 -1595000
            2290000 -1577852
          )
        )
        (wire
          (path F.Cu 3810
            2190000 -1595000
            2090000 -1595000
          )
        )
      )
      (net xled1
        (wire
          (path F.Cu 2540
            467355 -1171664
            498489 -1140530
            673533 -1140530
            707115 -1174112
            707115 -1176695
            731045 -1200625
            750777 -1200625
            756860 -1194542
            1632898 -1194542
            1637895 -1199539
            2053363 -1199539
            2141602 -1111300
          )
        )
        (wire
          (path B.Cu 2540
            467355 -1171664
            436800 -1202219
            436800 -1240000
            424100 -1252700
          )
        )
        (wire
          (path F.Cu 2540
            2152400 -1111300
            2141602 -1111300
          )
        )
        (via "Via[0-1]_889:635_um" 467355 -1171664
        )
      )
      (net xled2
        (wire
          (path F.Cu 2540
            467255 -1139784
            471592 -1135447
            675638 -1135447
            712198 -1172007
            712198 -1174590
            733150 -1195542
            748672 -1195542
            754755 -1189459
            1643127 -1189459
            1648008 -1194340
            2043960 -1194340
            2152400 -1085900
          )
        )
        (wire
          (path B.Cu 2540
            398700 -1252700
            411400 -1240000
            411400 -1195639
            467255 -1139784
          )
        )
        (via "Via[0-1]_889:635_um" 467255 -1139784
        )
      )
      (net xled3
        (wire
          (path F.Cu 2540
            2152400 -1060500
            2024552 -1060500
            1896176 -1188876
            1662790 -1188876
            1658133 -1184219
            746581 -1184219
            743516 -1187284
          )
        )
        (wire
          (path B.Cu 2540
            703500 -1227300
            743516 -1187284
          )
        )
        (via "Via[0-1]_889:635_um" 743516 -1187284
        )
      )
      (net xled4
        (wire
          (path F.Cu 2540
            2152400 -1035100
            2028846 -1035100
            1880154 -1183792
            1672685 -1183792
            1667756 -1178863
            735094 -1178863
          )
        )
        (wire
          (path B.Cu 2540
            703500 -1252700
            691890 -1241090
            691890 -1222067
            735094 -1178863
          )
        )
        (via "Via[0-1]_889:635_um" 735094 -1178863
        )
      )
      (net xled5
        (wire
          (path F.Cu 2540
            720456 -1171170
            721251 -1170375
            735204 -1170375
            743019 -1162560
            743019 -1161036
            777335 -1126720
            1522996 -1126720
            1669503 -980213
            2122913 -980213
            2152400 -1009700
          )
        )
        (wire
          (path B.Cu 2540
            678100 -1252700
            666329 -1240929
            666329 -1222716
            717875 -1171170
            720456 -1171170
          )
        )
        (via "Via[0-1]_889:635_um" 720456 -1171170
        )
      )
      (net xled6
        (wire
          (path B.Cu 2540
            627300 -1252700
            651061 -1276461
            681614 -1276461
            689496 -1284343
            689496 -1294386
            697306 -1302196
            709812 -1302196
            713431 -1298577
            854209 -1298577
            863283 -1307651
            916673 -1307651
            976652 -1247672
            1617612 -1247672
            1695410 -1169874
            1695410 -1169626
            1703226 -1161810
            1715043 -1161810
            1765976 -1110877
            2033834 -1110877
            2152400 -992311
            2152400 -984300
          )
        )
      )
      (net xled7
        (wire
          (path F.Cu 2540
            424100 -1227300
            415710 -1218910
            415710 -1062823
            422341 -1056192
            431391 -1056192
            439500 -1064301
            439500 -1070426
            498972 -1129898
            690864 -1129898
            726258 -1165292
            733099 -1165292
            737936 -1160455
            737936 -1158768
            789357 -1107347
            1285370 -1107347
            1389496 -1003221
            1389496 -993423
            1397115 -985804
            1409812 -985804
            1434703 -1010695
            1608205 -1010695
            1660000 -958900
            2152400 -958900
          )
        )
      )
      (net xled8
        (wire
          (path B.Cu 2540
            729678 -1157034
            751941 -1179297
            751941 -1204259
            728900 -1227300
          )
        )
        (wire
          (path F.Cu 2540
            2152400 -933500
            1102558 -933500
            1008346 -1027712
            859000 -1027712
            729678 -1157034
          )
        )
        (via "Via[0-1]_889:635_um" 729678 -1157034
        )
      )
    )
  )
)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted hardware/pdp8i/customlibraries/pdp8_library.dcm.
1
2
3
4
5
6
7
EESchema-DOCLIB  Version 2.0  Date: 19/01/2015 21:56:03
#
$CMP UDN2981A
D UDN2981A
$ENDCMP
#
#End Doc Library
<
<
<
<
<
<
<














Deleted hardware/pdp8i/customlibraries/pdp8_library.lib.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
EESchema-LIBRARY Version 2.3  Date: 19/01/2015 21:56:03
#encoding utf-8
#
# CONN_20X2
#
DEF CONN_20X2 P 0 10 Y N 1 F N
F0 "P" 0 1050 60 H V C CNN
F1 "CONN_20X2" 0 0 50 V V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -100 1000 100 -1000 0 1 0 N
X P1 1 -400 950 300 R 60 30 1 1 P I
X P2 2 400 950 300 L 60 30 1 1 P I
X P3 3 -400 850 300 R 60 30 1 1 P I
X P4 4 400 850 300 L 60 30 1 1 P I
X P5 5 -400 750 300 R 60 30 1 1 P I
X P6 6 400 750 300 L 60 30 1 1 P I
X P7 7 -400 650 300 R 60 30 1 1 P I
X P8 8 400 650 300 L 60 30 1 1 P I
X P9 9 -400 550 300 R 60 30 1 1 P I
X P10 10 400 550 300 L 60 30 1 1 P I
X P20 20 400 50 300 L 60 30 1 1 P I
X P30 30 400 -450 300 L 60 30 1 1 P I
X P40 40 400 -950 300 L 60 30 1 1 P I
X P11 11 -400 450 300 R 60 30 1 1 P I
X P21 21 -400 -50 300 R 60 30 1 1 P I
X P31 31 -400 -550 300 R 60 30 1 1 P I
X P12 12 400 450 300 L 60 30 1 1 P I
X P22 22 400 -50 300 L 60 30 1 1 P I
X P32 32 400 -550 300 L 60 30 1 1 P I
X P13 13 -400 350 300 R 60 30 1 1 P I
X P23 23 -400 -150 300 R 60 30 1 1 P I
X P33 33 -400 -650 300 R 60 30 1 1 P I
X P14 14 400 350 300 L 60 30 1 1 P I
X P24 24 400 -150 300 L 60 30 1 1 P I
X P34 34 400 -650 300 L 60 30 1 1 P I
X P15 15 -400 250 300 R 60 30 1 1 P I
X ~ 25 -400 -250 300 R 60 30 1 1 P I
X P35 35 -400 -750 300 R 60 30 1 1 P I
X P16 16 400 250 300 L 60 30 1 1 P I
X P26 26 400 -250 300 L 60 30 1 1 P I
X P36 36 400 -750 300 L 60 30 1 1 P I
X P17 17 -400 150 300 R 60 30 1 1 P I
X P27 27 -400 -350 300 R 60 30 1 1 P I
X P37 37 -400 -850 300 R 60 30 1 1 P I
X P18 18 400 150 300 L 60 30 1 1 P I
X P28 28 400 -350 300 L 60 30 1 1 P I
X P38 38 400 -850 300 L 60 30 1 1 P I
X P19 19 -400 50 300 R 60 30 1 1 P I
X P29 29 -400 -450 300 R 60 30 1 1 P I
X P39 39 -400 -950 300 R 60 30 1 1 P I
ENDDRAW
ENDDEF
#
# RASPI_MODEL_B_PLUS_GPIO
#
DEF RASPI_MODEL_B_PLUS_GPIO P 0 10 Y Y 1 F N
F0 "P" 0 1050 60 H V C CNN
F1 "RASPI_MODEL_B_PLUS_GPIO" 0 0 20 V V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -100 1000 100 -1000 0 1 0 N
X 3.3v 1 -400 950 300 R 60 30 1 1 w I
X 5v 2 400 950 300 L 60 30 1 1 w I
X g2 3 -400 850 300 R 60 30 1 1 P I
X 5v 4 400 850 300 L 60 30 1 1 P I
X g3 5 -400 750 300 R 60 30 1 1 P I
X GND 6 400 750 300 L 60 30 1 1 w I
X g4 7 -400 650 300 R 60 30 1 1 P I
X g14 8 400 650 300 L 60 30 1 1 P I
X GND 9 -400 550 300 R 60 30 1 1 P I
X g15 10 400 550 300 L 60 30 1 1 P I
X GND 20 400 50 300 L 60 30 1 1 P I
X GND 30 400 -450 300 L 60 30 1 1 P I
X g21 40 400 -950 300 L 60 30 1 1 P I
X g17 11 -400 450 300 R 60 30 1 1 P I
X g9 21 -400 -50 300 R 60 30 1 1 P I
X g6 31 -400 -550 300 R 60 30 1 1 P I
X g18 12 400 450 300 L 60 30 1 1 P I
X g25 22 400 -50 300 L 60 30 1 1 P I
X g12 32 400 -550 300 L 60 30 1 1 P I
X g27 13 -400 350 300 R 60 30 1 1 P I
X g11 23 -400 -150 300 R 60 30 1 1 P I
X g13 33 -400 -650 300 R 60 30 1 1 P I
X GND 14 400 350 300 L 60 30 1 1 P I
X g8 24 400 -150 300 L 60 30 1 1 P I
X GND 34 400 -650 300 L 60 30 1 1 P I
X g22 15 -400 250 300 R 60 30 1 1 P I
X GND 25 -400 -250 300 R 60 30 1 1 P I
X g19 35 -400 -750 300 R 60 30 1 1 P I
X g23 16 400 250 300 L 60 30 1 1 P I
X g7 26 400 -250 300 L 60 30 1 1 P I
X g16 36 400 -750 300 L 60 30 1 1 P I
X 3.3v 17 -400 150 300 R 60 30 1 1 P I
X n/c 27 -400 -350 300 R 60 30 1 1 P I
X g26 37 -400 -850 300 R 60 30 1 1 P I
X g24 18 400 150 300 L 60 30 1 1 P I
X n/c 28 400 -350 300 L 60 30 1 1 P I
X g20 38 400 -850 300 L 60 30 1 1 P I
X g10 19 -400 50 300 R 60 30 1 1 P I
X g5 29 -400 -450 300 R 60 30 1 1 P I
X GND 39 -400 -950 300 R 60 30 1 1 P I
ENDDRAW
ENDDEF
#
# UDN2981A
#
DEF UDN2981A P 0 40 Y Y 1 F N
F0 "P" 0 550 30 H V C CNN
F1 "UDN2981A" 0 -550 30 H V C CNN
F2 "~" 0 0 60 H V C CNN
F3 "~" 0 0 60 H V C CNN
DRAW
S -150 500 150 -500 0 1 0 N
X IN1 1 -350 400 200 R 40 20 1 1 I I
X IN2 2 -350 300 200 R 40 20 1 1 I I
X IN3 3 -350 200 200 R 40 20 1 1 I I
X IN4 4 -350 100 200 R 40 20 1 1 I I
X IN5 5 -350 0 200 R 40 20 1 1 I I
X IN6 6 -350 -100 200 R 40 20 1 1 I I
X IN7 7 -350 -200 200 R 40 20 1 1 I I
X IN8 8 -350 -300 200 R 40 20 1 1 I I
X Vs 9 -350 -400 200 R 40 20 1 1 P I
X GND 10 350 -400 200 L 40 20 1 1 P I
X OUT8 11 350 -300 200 L 40 20 1 1 O I
X OUT7 12 350 -200 200 L 40 20 1 1 O I
X OUT6 13 350 -100 200 L 40 20 1 1 O I
X OUT5 14 350 0 200 L 40 20 1 1 O I
X OUT4 15 350 100 200 L 40 20 1 1 O I
X OUT3 16 350 200 200 L 40 20 1 1 O I
X OUT2 17 350 300 200 L 40 20 1 1 O I
X OUT1 18 350 400 200 L 40 20 1 1 O I
ENDDRAW
ENDDEF
#
#End Library
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































Deleted hardware/pdp8i/customlibraries/pdp8footprintlib2.mod.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
PCBNEW-LibModule-V1  09/05/2015 20:49:52
# encoding utf-8
Units mm
$INDEX
D2
LED-3-PDP
LED-3-StrEight
RASPI_BPLUS
RASPI_BPLUS_MIRRORED
SIL-3PDP
SIL-5PDP
SW_KND2
SW_KND2_PDP
SW_KND2_PDP2
$EndINDEX
$MODULE D2
Po 0 0 0 15 54B29F05 00000000 ~~
Li D2
Cd Diode 3 pas
Kw DIODE DEV
Sc 0
AR 
Op 0 0 0
T0 0 -0.508 0.25 0.25 0 0.05 N V 21 N "D2"
T1 -0.508 0.508 0.381 0.381 0 0.0762 N I 21 N "D***"
DS -2.032 1.016 2.032 1.016 0.3048 21
DS -2.032 -1.016 2.032 -1.016 0.3048 21
DS 2.794 0 2.032 0 0.3048 21
DS 2.032 0 2.032 -1.016 0.3048 21
DS -2.032 -1.016 -2.032 0 0.3048 21
DS -2.032 0 -2.794 0 0.3048 21
DS -2.032 0 -2.032 1.016 0.3048 21
DS 2.032 1.016 2.032 0 0.3048 21
DS 1.524 -1.016 1.524 1.016 0.3048 21
DS 1.27 1.016 1.27 -1.016 0.3048 21
$PAD
Sh "2" R 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 3.556 0
$EndPAD
$PAD
Sh "1" C 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -3.81 0
$EndPAD
$SHAPE3D
Na "discret/diode.wrl"
Sc 0.3 0.3 0.3
Of 0 0 0
Ro 0 0 0
$EndSHAPE3D
$EndMODULE D2
$MODULE LED-3-PDP
Po 0 0 0 15 54BD7621 00000000 ~~
Li LED-3-PDP
Cd LED 3mm - Lead pitch 100mil (2,54mm)
Kw LED led 3mm 3MM 100mil 2,54mm
Sc 0
AR /548EF4B8
Op 0 0 0
T0 0 -5.5372 0.7 0.7 0 0.025 N V 21 N "DMA12"
T1 0 2.54 0.762 0.762 0 0.0889 N I 21 N "LED"
DS -2.4 1.5 -2.4 -1.5 0.15 21
DS 1.5 2.4 -1.5 2.4 0.15 21
DS 2.4 -1.5 2.4 1.5 0.15 21
DS -1.5 -2.4 1.5 -2.4 0.15 21
DA -1.5 1.5 -1.5 2.4 900 0.15 21
DA 1.5 1.5 2.4 1.5 900 0.15 21
DA -1.5 -1.5 -2.4 -1.5 900 0.15 21
DA 1.5 -1.5 1.5 -2.4 900 0.15 21
$PAD
Sh "1" C 1.6764 1.6764 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 2 "led2"
Po -1.27 0
$EndPAD
$PAD
Sh "2" C 1.6764 1.6764 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 1 "N-000004"
Po 1.27 0
$EndPAD
$SHAPE3D
Na "discret/leds/led3_vertical_verde.wrl"
Sc 1 1 1
Of 0 0 0
Ro 0 0 0
$EndSHAPE3D
$EndMODULE LED-3-PDP
$MODULE LED-3-StrEight
Po 0 0 0 15 554E561D 00000000 ~~
Li LED-3-StrEight
Cd LED
Kw LED
Sc 0
AR /548EF4B8
Op 0 0 0
T0 0 -5.5372 0.7 0.7 0 0.025 N I 21 N "Str8"
T1 0 2.54 0.762 0.762 0 0.0889 N I 21 N "LED"
$PAD
Sh "1" C 1.6764 1.6764 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 2 "led2"
Po -1.27 0
$EndPAD
$PAD
Sh "2" C 1.6764 1.6764 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 1 "N-000004"
Po 1.27 0
$EndPAD
$SHAPE3D
Na "discret/leds/led3_vertical_verde.wrl"
Sc 1 1 1
Of 0 0 0
Ro 0 0 0
$EndSHAPE3D
$EndMODULE LED-3-StrEight
$MODULE RASPI_BPLUS
Po 0 0 0 15 54B191EE 00000000 ~~
Li RASPI_BPLUS
Cd Double rangee de contacts 2 x 12 pins
Kw CONN
Sc 0
AR 
Op 0 0 0
T0 0 -3.81 1.016 1.016 0 0.27432 N V 21 N "REF*"
T1 0 3.81 1.016 1.016 0 0.2032 N V 21 N "PIN_ARRAY_20X2"
T2 8 26.5 1 1 0 0.15 N V 21 N "GPIO and mount holes exact, port placement approx."
T2 6 20.5 1 1 0 0.15 N V 21 N "COMPONENT SIDE (TOP)"
T2 -19 48 1 1 0 0.15 N V 21 N "microUSB"
DS -22 52.5 -22 49 0.15 21
DS -22 49 -16 52.5 0.15 21
DS -16 52.5 -16 49 0.15 21
DS -16 49 -22 52.5 0.15 21
T2 0 49 1 1 0 0.15 N V 21 N "HDMI"
DS -7 52.5 -7 48.5 0.15 21
DS -7 48.5 6 52.5 0.15 21
DS 6 52.5 6 48.5 0.15 21
DS 6 48.5 -7 52.5 0.15 21
T2 50.5 24 1 1 900 0.15 N V 21 N "USB"
T2 50.5 7 1 1 900 0.15 N V 21 N "USB"
DS 50.5 18.5 55 18.5 0.15 21
DS 55 18.5 55 29.5 0.15 21
DS 55 29.5 51 29.5 0.15 21
DS 50.5 1.5 55 1.5 0.15 21
DS 55 1.5 55 13 0.15 21
DS 55 13 50.5 13 0.15 21
DS -32.5 -3.5 52.5 -3.5 0.15 21
DS 52.5 -3.5 52.5 52.5 0.15 21
DS 52.5 52.5 32 52.5 0.15 21
DS -32.5 -3.5 -32.5 52.5 0.15 21
DS -32.5 52.5 32.5 52.5 0.15 21
DS 25.4 2.54 -25.4 2.54 0.3048 21
DS 25.4 -2.54 -25.4 -2.54 0.3048 21
DS 25.4 -2.54 25.4 2.54 0.3048 21
DS -25.4 -2.54 -25.4 2.54 0.3048 21
$PAD
Sh "1" R 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -24.13 1.27
$EndPAD
$PAD
Sh "2" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 1 "GND"
Po -24.13 -1.27
$EndPAD
$PAD
Sh "11" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 18 "PA8_1"
Po -11.43 1.27
$EndPAD
$PAD
Sh "4" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 11 "PA1_1"
Po -21.59 -1.27
$EndPAD
$PAD
Sh "13" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 5 "PA10_1"
Po -8.89 1.27
$EndPAD
$PAD
Sh "6" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 13 "PA3_1"
Po -19.05 -1.27
$EndPAD
$PAD
Sh "15" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 7 "PA12_1"
Po -6.35 1.27
$EndPAD
$PAD
Sh "8" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 15 "PA5_1"
Po -16.51 -1.27
$EndPAD
$PAD
Sh "17" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 9 "PA14_1"
Po -3.81 1.27
$EndPAD
$PAD
Sh "10" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 17 "PA7_1"
Po -13.97 -1.27
$EndPAD
$PAD
Sh "19" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -1.27 1.27
$EndPAD
$PAD
Sh "12" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 19 "PA9_1"
Po -11.43 -1.27
$EndPAD
$PAD
Sh "21" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 1.27 1.27
$EndPAD
$PAD
Sh "14" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 6 "PA11_1"
Po -8.89 -1.27
$EndPAD
$PAD
Sh "23" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "INT1_1"
Po 3.81 1.27
$EndPAD
$PAD
Sh "16" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 8 "PA13_1"
Po -6.35 -1.27
$EndPAD
$PAD
Sh "25" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 6.35 1.27
$EndPAD
$PAD
Sh "18" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 10 "PA15_1"
Po -3.81 -1.27
$EndPAD
$PAD
Sh "27" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 8.89 1.27
$EndPAD
$PAD
Sh "20" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -1.27 -1.27
$EndPAD
$PAD
Sh "29" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 22 "VCC"
Po 11.43 1.27
$EndPAD
$PAD
Sh "22" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 1.27 -1.27
$EndPAD
$PAD
Sh "31" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 22 "VCC"
Po 13.97 1.27
$EndPAD
$PAD
Sh "24" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 3 "INT2_1"
Po 3.81 -1.27
$EndPAD
$PAD
Sh "26" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 6.35 -1.27
$EndPAD
$PAD
Sh "33" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 21 "Tin1_cold_1"
Po 16.51 1.27
$EndPAD
$PAD
Sh "28" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 10 "PA15_1"
Po 8.89 -1.27
$EndPAD
$PAD
Sh "32" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 1 "GND"
Po 13.97 -1.27
$EndPAD
$PAD
Sh "34" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 16.51 -1.27
$EndPAD
$PAD
Sh "36" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 19.05 -1.27
$EndPAD
$PAD
Sh "38" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 21.59 -1.27
$EndPAD
$PAD
Sh "35" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 19.05 1.27
$EndPAD
$PAD
Sh "37" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 20 "PB4_1"
Po 21.59 1.27
$EndPAD
$PAD
Sh "3" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 4 "PA0_1"
Po -21.59 1.27
$EndPAD
$PAD
Sh "5" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 12 "PA2_1"
Po -19.05 1.27
$EndPAD
$PAD
Sh "7" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 14 "PA4_1"
Po -16.51 1.27
$EndPAD
$PAD
Sh "9" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 16 "PA6_1"
Po -13.97 1.27
$EndPAD
$PAD
Sh "39" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 24.13 1.27
$EndPAD
$PAD
Sh "40" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 24.13 -1.27
$EndPAD
$PAD
Sh "30" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 1 "GND"
Po 11.43 -1.27
$EndPAD
$PAD
Sh "2" C 6.2 6.2 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -29 0
$EndPAD
$PAD
Sh "3" C 6.2 6.2 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 29 0
$EndPAD
$PAD
Sh "4" C 6.2 6.2 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -29 49
$EndPAD
$PAD
Sh "5" C 6.2 6.2 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 29 49
$EndPAD
$SHAPE3D
Na "pin_array/pins_array_20x2.wrl"
Sc 1 1 1
Of 0 0 0
Ro 0 0 0
$EndSHAPE3D
$EndMODULE RASPI_BPLUS
$MODULE RASPI_BPLUS_MIRRORED
Po 0 0 0 15 54B2FF09 00000000 ~~
Li RASPI_BPLUS_MIRRORED
Cd Double rangee de contacts 2 x 12 pins
Kw CONN
Sc 0
AR /548F13F7
Op 0 0 0
T0 0 -3.81 1.016 1.016 0 0.27432 N V 21 N "P1"
T1 0 3.81 1.016 1.016 0 0.2032 N V 21 N "RASPI_MODEL_B_PLUS_GPIO"
T2 49.53 -43.18 1 1 900 0.15 N V 21 N "ETH"
DS 48.768 -49.022 53.594 -49.022 0.15 21
DS 53.594 -49.022 53.594 -38.354 0.15 21
DS 53.594 -38.354 49.784 -38.354 0.15 21
T2 7.5 -18 1 1 0 0.15 N V 21 N "GPIO and mount holes exact, port placement approx."
T2 0 -24.5 1 1 0 0.15 N V 21 N "RASPI B PLUS (MIRROR IMAGE)"
T2 -19 -47 1 1 0 0.15 N V 21 N "microUSB"
DS -22 -49.008 -22 -52.508 0.15 21
DS -16 -49.008 -16 -52.508 0.15 21
T2 0 -47 1 1 0 0.15 N V 21 N "HDMI"
DS -7 -48.5 -7 -52.5 0.15 21
DS 6 -48.5 6 -52.5 0.15 21
T2 49.5 -3.5 1 1 900 0.15 N V 21 N "USB"
T2 49.5 -20.5 1 1 900 0.15 N V 21 N "USB"
DS 49.5 -11.032 54 -11.032 0.15 21
DS 54 -11.032 54 -0.032 0.15 21
DS 54 -0.032 50 -0.032 0.15 21
DS 49.5 -28.032 54 -28.032 0.15 21
DS 54 -28.032 54 -16.532 0.15 21
DS 54 -16.532 49.5 -16.532 0.15 21
DS -32.5 3.5 52.5 3.5 0.15 21
DS 52.5 -52.5 52.5 3.5 0.15 21
DS 52.5 -52.5 32 -52.5 0.15 21
DS -32.5 -52.5 -32.5 3.5 0.15 21
DS -32.5 -52.5 32.5 -52.5 0.15 21
DS 25.4 2.54 -25.4 2.54 0.3048 21
DS 25.4 -2.54 -25.4 -2.54 0.3048 21
DS 25.4 -2.54 25.4 2.54 0.3048 21
DS -25.4 -2.54 -25.4 2.54 0.3048 21
$PAD
Sh "1" R 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 1 "+3.3V"
Po -24.13 -1.27
$EndPAD
$PAD
Sh "2" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -24.13 1.27
$EndPAD
$PAD
Sh "11" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 21 "xled4"
Po -11.43 -1.27
$EndPAD
$PAD
Sh "4" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -21.59 1.27
$EndPAD
$PAD
Sh "13" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 22 "xled5"
Po -8.89 -1.27
$EndPAD
$PAD
Sh "6" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "GND"
Po -19.05 1.27
$EndPAD
$PAD
Sh "15" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 23 "xled6"
Po -6.35 -1.27
$EndPAD
$PAD
Sh "8" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 7 "N-0000031"
Po -16.51 1.27
$EndPAD
$PAD
Sh "17" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -3.81 -1.27
$EndPAD
$PAD
Sh "10" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 8 "N-0000032"
Po -13.97 1.27
$EndPAD
$PAD
Sh "19" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 24 "xled7"
Po -1.27 -1.27
$EndPAD
$PAD
Sh "12" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 9 "N-0000033"
Po -11.43 1.27
$EndPAD
$PAD
Sh "21" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 25 "xled8"
Po 1.27 -1.27
$EndPAD
$PAD
Sh "14" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "GND"
Po -8.89 1.27
$EndPAD
$PAD
Sh "23" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 17 "N-0000092"
Po 3.81 -1.27
$EndPAD
$PAD
Sh "16" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 10 "N-0000034"
Po -6.35 1.27
$EndPAD
$PAD
Sh "25" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "GND"
Po 6.35 -1.27
$EndPAD
$PAD
Sh "18" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 3 "N-0000027"
Po -3.81 1.27
$EndPAD
$PAD
Sh "27" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 8.89 -1.27
$EndPAD
$PAD
Sh "20" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "GND"
Po -1.27 1.27
$EndPAD
$PAD
Sh "29" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 15 "N-0000090"
Po 11.43 -1.27
$EndPAD
$PAD
Sh "22" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 11 "N-0000035"
Po 1.27 1.27
$EndPAD
$PAD
Sh "31" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 16 "N-0000091"
Po 13.97 -1.27
$EndPAD
$PAD
Sh "24" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 12 "N-0000036"
Po 3.81 1.27
$EndPAD
$PAD
Sh "26" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 13 "N-0000037"
Po 6.35 1.27
$EndPAD
$PAD
Sh "33" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 4 "N-0000028"
Po 16.51 -1.27
$EndPAD
$PAD
Sh "28" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 8.89 1.27
$EndPAD
$PAD
Sh "32" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 14 "N-0000038"
Po 13.97 1.27
$EndPAD
$PAD
Sh "34" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 16.51 1.27
$EndPAD
$PAD
Sh "36" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 19.05 1.27
$EndPAD
$PAD
Sh "38" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 21.59 1.27
$EndPAD
$PAD
Sh "35" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 5 "N-0000029"
Po 19.05 -1.27
$EndPAD
$PAD
Sh "37" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 6 "N-0000030"
Po 21.59 -1.27
$EndPAD
$PAD
Sh "3" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 18 "xled1"
Po -21.59 -1.27
$EndPAD
$PAD
Sh "5" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 19 "xled2"
Po -19.05 -1.27
$EndPAD
$PAD
Sh "7" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 20 "xled3"
Po -16.51 -1.27
$EndPAD
$PAD
Sh "9" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "GND"
Po -13.97 -1.27
$EndPAD
$PAD
Sh "39" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "GND"
Po 24.13 -1.27
$EndPAD
$PAD
Sh "40" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 24.13 1.27
$EndPAD
$PAD
Sh "30" C 1.524 1.524 0 0 0
Dr 1.016 0 0
At STD N 00E0FFFF
Ne 2 "GND"
Po 11.43 1.27
$EndPAD
$PAD
Sh "H2" C 5.7 5.7 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -29 0
$EndPAD
$PAD
Sh "H3" C 5.7 5.7 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 29 0
$EndPAD
$PAD
Sh "H4" C 5.7 5.7 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 29 -49
$EndPAD
$PAD
Sh "H1" C 5.7 5.7 0 0 0
Dr 2.75 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -29 -49
$EndPAD
$SHAPE3D
Na "pin_array/pins_array_20x2.wrl"
Sc 1 1 1
Of 0 0 0
Ro 0 0 0
$EndSHAPE3D
$EndMODULE RASPI_BPLUS_MIRRORED
$MODULE SIL-3PDP
Po 0 0 0 15 54BD2D6F 00000000 ~~
Li SIL-3PDP
Cd Connecteur 3 pins
Kw CONN DEV
Sc 0
AR /54BD28E4
Op 0 0 0
T0 3.175 -2.54 0.5 0.5 0 0.125 N V 21 N "P3"
T1 -2.286 -2.54 0.5 0.5 0 0.125 N I 21 N "SERIAL3V"
T2 2.54 -1.778 0.5 0.5 0 0.1 N V 21 N "TX"
T2 0 -1.778 0.5 0.5 0 0.1 N V 21 N "RX"
T2 -2.54 -1.778 0.5 0.5 0 0.1 N V 21 N "GND"
DS -3.81 1.27 -3.81 -1.27 0.3048 21
DS -3.81 -1.27 3.81 -1.27 0.3048 21
DS 3.81 -1.27 3.81 1.27 0.3048 21
DS 3.81 1.27 -3.81 1.27 0.3048 21
DS -1.27 -1.27 -1.27 1.27 0.3048 21
$PAD
Sh "1" R 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 1 "GND"
Po -2.54 0
$EndPAD
$PAD
Sh "2" C 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 2 "RX"
Po 0 0
$EndPAD
$PAD
Sh "3" C 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 3 "TX"
Po 2.54 0
$EndPAD
$EndMODULE SIL-3PDP
$MODULE SIL-5PDP
Po 0 0 0 15 54BD2E53 00000000 ~~
Li SIL-5PDP
Cd Connecteur 5 pins
Kw CONN DEV
Sc 0
AR /54BD2904
Op 0 0 0
T0 4.699 -2.54 0.5 0.5 0 0.125 N V 21 N "P4"
T1 -5.715 -2.54 0.5 0.5 0 0.125 N I 21 N "EXPANSION"
T2 3.81 -1.778 0.5 0.5 0 0.1 N V 21 N "GPIO"
T2 1.27 -1.778 0.5 0.5 0 0.1 N V 21 N "GND"
T2 -1.27 -1.778 0.5 0.5 0 0.1 N V 21 N "5V"
T2 -3.81 -1.778 0.5 0.5 0 0.1 N V 21 N "N/C"
T2 -6.223 -1.778 0.5 0.5 0 0.1 N V 21 N "3.3V"
DS -7.62 1.27 -7.62 -1.27 0.3048 21
DS -7.62 -1.27 5.08 -1.27 0.3048 21
DS 5.08 -1.27 5.08 1.27 0.3048 21
DS 5.08 1.27 -7.62 1.27 0.3048 21
DS -5.08 1.27 -5.08 -1.27 0.3048 21
$PAD
Sh "1" R 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 1 "+3.3V"
Po -6.35 0
$EndPAD
$PAD
Sh "2" C 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -3.81 0
$EndPAD
$PAD
Sh "3" C 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 2 "+5V"
Po -1.27 0
$EndPAD
$PAD
Sh "4" C 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 3 "GND"
Po 1.27 0
$EndPAD
$PAD
Sh "5" C 1.397 1.397 0 0 0
Dr 0.8128 0 0
At STD N 00E0FFFF
Ne 4 "SPARE_IO"
Po 3.81 0
$EndPAD
$EndMODULE SIL-5PDP
$MODULE SW_KND2
Po 0 0 0 15 548F15A7 00000000 ~~
Li SW_KND2
Cd Switch inverseur
Kw SWITCH DEV
Sc 0
AR 
Op 0 0 0
T0 3.5 7.9 1.016 1.016 900 0.2032 N V 21 N "SW_KND2_1x2"
T1 -0.05 -20.3 1.016 1.016 0 0.2032 N V 21 N "SW*"
DS -4.75 -18.9 -4.75 18.9 0.15 21
DS -4.75 18.9 4.75 18.9 0.15 21
DS 4.75 18.9 4.75 -18.9 0.15 21
DS 4.75 -18.9 -4.75 -18.9 0.15 21
DS -4.75 -10.3 -4.75 10.3 0.15 21
DS -4.75 10.3 4.75 10.3 0.15 21
DS 4.75 10.3 4.75 -10.3 0.15 21
DS 4.75 -10.3 -4.75 -10.3 0.15 21
$PAD
Sh "2" O 3.81 2.54 0 0 0
Dr 2.5 0 0 O 2.5 0.8
At STD N 00E0FFFF
Ne 0 ""
Po 0 0
$EndPAD
$PAD
Sh "1" O 3.81 2.54 0 0 0
Dr 2.5 0 0 O 2.5 0.8
At STD N 00E0FFFF
Ne 0 ""
Po 0 -5.58
$EndPAD
$PAD
Sh "3" O 3.81 2.54 0 0 0
Dr 2.5 0 0 O 2.5 0.8
At STD N 00E0FFFF
Ne 0 ""
Po 0 5.58
$EndPAD
$PAD
Sh "H1" C 4 4 0 0 0
Dr 3 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 -15
$EndPAD
$PAD
Sh "H2" C 4 4 0 0 0
Dr 3 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 15
$EndPAD
$EndMODULE SW_KND2
$MODULE SW_KND2_PDP
Po 0 0 0 15 54B2AA91 00000000 ~~
Li SW_KND2_PDP
Cd Switch inverseur
Kw SWITCH DEV
Sc 0
AR 
Op 0 0 0
T0 4 0 0.3 0.3 900 0.05 N I 21 N "SW_KND2_1x2_PDP"
T1 -0.05 -20.3 1.2 1.2 0 0.2032 N V 21 N "SW*"
DS -4.75 7.8 -4.75 -10.3 0.15 21
DS -4.75 7.8 4.75 7.8 0.15 21
DS 4.75 7.8 4.75 -10.3 0.15 21
DS -4.75 -10.3 -4.75 -18.9 0.15 21
DS 4.75 -10.3 4.75 -18.9 0.15 21
DS 4.75 -18.9 -4.75 -18.9 0.15 21
DS 4.75 -10.3 -4.75 -10.3 0.15 21
$PAD
Sh "1" O 3.81 2.54 0 0 0
Dr 2.5 0 0 O 2.5 0.8
At STD N 00E0FFFF
Ne 0 ""
Po 0 0
$EndPAD
$PAD
Sh "2" O 3.81 2.54 0 0 0
Dr 2.5 0 0 O 2.5 0.8
At STD N 00E0FFFF
Ne 0 ""
Po 0 -5.58
$EndPAD
$PAD
Sh "3" O 3.81 2.54 0 0 0
Dr 2.5 0 0 O 2.5 0.8
At STD N 00E0FFFF
Ne 0 ""
Po 0 5.58
$EndPAD
$PAD
Sh "H1" C 4 4 0 0 0
Dr 3 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 -15
$EndPAD
$EndMODULE SW_KND2_PDP
$MODULE SW_KND2_PDP2
Po 0 0 0 15 554E2AD7 00000000 ~~
Li SW_KND2_PDP2
Cd Switch inverseur
Kw SWITCH DEV
Sc 0
AR 
Op 0 0 0
T0 3.429 -3.683 0.3 0.3 900 0.05 N I 21 N "SW_KND2_1x2_PDP"
T1 -0.05 -20.3 1.2 1.2 0 0.2032 N V 21 N "SW*"
DS -4.75 1.95 -4.75 -10.35 0.15 21
DS 4.75 -10.3 4.75 1.95 0.15 21
DS -4.75 1.958 4.75 1.958 0.15 21
DS -4.75 -10.3 -4.75 -18.9 0.15 21
DS 4.75 -10.3 4.75 -18.9 0.15 21
DS 4.75 -18.9 -4.75 -18.9 0.15 21
DS 4.75 -10.3 -4.75 -10.3 0.15 21
$PAD
Sh "1" O 5.08 2.54 0 0 0
Dr 3.45 0 0 O 3.45 1.18
At STD N 00E0FFFF
Ne 0 ""
Po 0 0
$EndPAD
$PAD
Sh "2" O 5.08 2.54 0 0 0
Dr 3.45 0 0 O 3.45 1.15
At STD N 00E0FFFF
Ne 0 ""
Po 0 -5.58
$EndPAD
$PAD
Sh "3" C 4 4 0 0 0
Dr 3 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 -15
$EndPAD
$EndMODULE SW_KND2_PDP2
$EndLIBRARY
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted hardware/pdp8i/schematic.pdf.

cannot compute difference between binary files

Deleted hardware/power-switch.gsch.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
v 20130925 2
C 39600 60100 1 0 0 5V-plus-1.sym
{
T 39600 60100 5 10 1 1 0 0 1
pinnumber=1
}
C 39700 58200 1 0 0 gnd-1.sym
{
T 39600 58400 5 10 1 1 0 0 1
pinnumber=7
}
C 40100 58200 1 0 0 gnd-1.sym
{
T 40000 58400 5 10 1 1 0 0 1
pinnumber=8
}
C 40000 60100 1 0 0 5V-plus-1.sym
{
T 40000 60100 5 10 1 1 0 0 1
pinnumber=2
}
C 38500 60600 1 270 0 switch-spst-1.sym
{
T 39200 60200 5 10 0 0 270 0 1
device=SPST
T 38800 60400 5 10 1 1 270 0 1
refdes=Switch
}
N 40200 59300 40200 60100 4
N 39800 58500 39800 58700 4
N 40200 58500 40200 59000 4
C 37900 60300 1 0 0 BNC-1.sym
{
T 38250 60950 5 10 0 0 0 0 1
device=BNC
T 37900 61000 5 10 1 1 0 0 1
refdes=DC Jack
}
B 39400 57800 1200 3000 3 0 0 0 -1 -1 0 -1 -1 -1 -1 -1
{
T 40700 60100 5 10 1 1 270 0 1
name=Expansion Port Pins
}
N 38000 60300 38000 58700 4
N 38000 58700 39800 58700 4
N 38000 59000 40200 59000 4
N 39800 60100 39800 59600 4
N 38500 59600 39800 59600 4
N 38500 59300 38500 59800 4
N 40200 59300 38500 59300 4
N 38400 60800 38500 60800 4
N 38500 60800 38500 60600 4
T 37800 56300 9 10 1 0 0 0 5
Copyright © 2016 by Warren Young

This file is licensed under the terms of
the SIMH license, a copy of which is in
../SIMH-LICENSE.md.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































Deleted labels/README.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# USB Stick Labels

## What It Is

This directory contains an Inkscape document (`*.svg`) containing the
DECtape logo and USB stick labels with graphics based on that label.
There are three example labels in the document:

*   **BIN Loader** for `media/copytoUSBsticks/binloader.pt`
*   **FOCAL-69** for `media/copytoUSBsticks/focal.pt`
*   **ADD.PA** for `examples/add.pt`

These labels use the "DECtape" graphics even though they're paper tapes,
primarily because it's a nice graphic and I haven't bothered to draw
something appropriate to paper tapes yet.

The labels print out at approximately 30×16mm each, which fits the USB
sticks I have here, but you may need to scale the printout for your
particular USB sticks.


## Affixing the Labels

This document is not designed with any particular self-adhesive label
stock in mind. Instead, I simply use rubber cement as a contact adhesive
to affix these labels to the USB stick.

Simply cut the label(s) you want to use out with scissors, paint both
the back of the label and the top of the USB stick with rubber cement,
and let it dry for a minute or so. When the glue is dry-looking,
carefully place the label where you want it on the USB stick. You won't
have much of a chance to move the label around after the two dried glue
patches touch, so be careful with your placement.

Press the label firmly against the stick, pressing repeatedly to cover
the entire surface, then rub around the label gently to brush away any
excess cement.

Protip: Use the part of the page you cut the labels out of as a
protective mat to work on. It will let you apply cement to the label
fully edge-to-edge without messing up your work surface. The labels will
be much more durable if there is no unglued bit near the edge for
fingernails and such to snag on. You were going to throw this excess
material away, so you might as well get one final use out of it, yes?


## Fonts

This SVG file uses a non-free font called [Dottie][font] for the faux
dot matrix text. There are [free alternatives][alt], but none of the
ones I liked allow redistribution, so I couldn't include one of them in
this repository.

[font]: https://www.fonts.com/font/ingrimayne-type/dottie/regular
[alt]:  http://www.1001fonts.com/digital+dot-matrix-fonts.html


## PDF Version

If you don't want to use one of those alternative fonts or simply like
the look of Dottie and don't need custom labels, this directory also
includes a PDF of the same design with the necessary subset of Dottie
embedded, so that you can print it out.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































Deleted labels/dectape-usb-key.pdf.

cannot compute difference between binary files

Deleted labels/dectape-usb-key.svg.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   id="svg2"
   version="1.1"
   inkscape:version="0.91 r13725"
   xml:space="preserve"
   width="765"
   height="990"
   viewBox="0 0 765 990"
   sodipodi:docname="dectape-usb-key.svg"><title
     id="title4244">PiDP-8/I USB key labels</title><metadata
     id="metadata8"><rdf:RDF><cc:Work
         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title>PiDP-8/I USB key labels</dc:title><dc:date>December 2016</dc:date><dc:creator><cc:Agent><dc:title>Warren Young</dc:title></cc:Agent></dc:creator><dc:rights><cc:Agent><dc:title>see license</dc:title></cc:Agent></dc:rights><dc:language>English</dc:language><dc:subject><rdf:Bag><rdf:li>label</rdf:li><rdf:li>USB</rdf:li><rdf:li>DEC</rdf:li><rdf:li>PDP-8</rdf:li><rdf:li>dot matrix</rdf:li><rdf:li>DECtape</rdf:li></rdf:Bag></dc:subject><dc:description>Graphical labels for use on USB sticks containing binary media images suitable for use with the PiDP-8/I's USB stick auto-attaching feature.</dc:description><cc:license
           rdf:resource="https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md" /></cc:Work></rdf:RDF></metadata><defs
     id="defs6"><clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath18"><path
         d="M 0,0 612,0 612,792 0,792 0,0 Z"
         id="path20"
         inkscape:connector-curvature="0" /></clipPath><filter
       inkscape:label="Opacity"
       style="color-interpolation-filters:sRGB;"
       id="filter3471"><feColorMatrix
         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 -0 "
         result="colormatrix"
         id="feColorMatrix3473" /><feComposite
         in2="colormatrix"
         operator="arithmetic"
         k2="0.343085"
         result="composite"
         id="feComposite3475" /></filter></defs><sodipodi:namedview
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1"
     objecttolerance="10"
     gridtolerance="10"
     guidetolerance="10"
     inkscape:pageopacity="0"
     inkscape:pageshadow="2"
     inkscape:window-width="2560"
     inkscape:window-height="1391"
     id="namedview4"
     showgrid="false"
     inkscape:zoom="3.17"
     inkscape:cx="117.85871"
     inkscape:cy="792.26542"
     inkscape:window-x="0"
     inkscape:window-y="1"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer2"
     showguides="true"
     inkscape:guide-bbox="true"><sodipodi:guide
       position="278.68734,454.12002"
       orientation="0,1"
       id="guide3550" /><sodipodi:guide
       position="294.28136,404.66471"
       orientation="0,1"
       id="guide3552" /></sodipodi:namedview><g
     id="g10"
     inkscape:groupmode="layer"
     inkscape:label="reference"
     transform="matrix(1.25,0,0,-1.25,0,990)"
     style="display:inline"><g
       id="g12" /></g><g
     inkscape:groupmode="layer"
     id="layer1"
     inkscape:label="inner elements"
     style="display:inline" /><g
     inkscape:groupmode="layer"
     id="layer2"
     inkscape:label="ring"
     style="display:inline"><g
       id="g4253"
       transform="translate(-3.4700316,-242.58675)"><ellipse
         ry="37.22398"
         rx="39.077209"
         style="display:inline;fill:none;fill-opacity:1;stroke:none;stroke-width:0.99528235;stroke-opacity:1"
         id="circle4384"
         cx="88.770988"
         cy="306.1496" /><g
         inkscape:label="#g3477"
         style="display:inline;fill:#1e97ec;fill-opacity:1;stroke:none"
         id="digital-logo"
         transform="matrix(0.05536257,0,0,-0.05536257,75.852793,325.57701)"><g
           style="fill:#1e97ec;fill-opacity:1;stroke:none"
           id="g3479"
           clip-path="url(#clipPath18)"><path
             d="m 101.3,107.13 c 0.02,-2.96 -3.43,-7.55 -7.63,-7.56 -4.48,0.02 -8.87,4.08 -8.87,12.2 0,8.24 4.38,12.48 8.73,12.5 4.34,-0.02 7.79,-4.67 7.77,-8.2 l 0,-8.94 z m 0.23,22.74 0,18.13 8.9,0 0,-56.4 -9.2,0 0,2.6 c -0.75,-0.76 -3.92,-4.07 -9.33,-4.07 -5.64,-0.01 -15.73,4.69 -15.73,21.64 0,14.37 7.54,21.8 16.5,21.8 3.32,0 6.58,-1.18 8.86,-3.7 z M 72,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m 7,0 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 61.18,-20.72 c 0,3.59 -4.04,7.3 -7.78,7.3 -3.22,0 -8.2,-2.05 -8.2,-11.24 0,-9.79 6.12,-11.22 8.15,-11.22 4.03,0 7.83,2.77 7.83,7.05 l 0,8.11 z M 171,172 l 42.5,0 0,-100 -42.5,0 0,100 z m 28.52,-43.91 c -0.93,1.33 -3.98,4.35 -8.34,4.35 -6.77,-0.01 -16.21,-3.92 -16.21,-20.89 0.01,-13.38 10.7,-17.87 15.09,-17.87 4.74,-0.01 8.26,2.75 9.22,3.79 l 0,-4.21 c 0,-3.11 -3.19,-6.15 -8.53,-6.15 -4.6,0.01 -5.08,2.96 -5.08,4.42 l -9.4,0 c 0,-4.67 3.01,-11.49 13.91,-11.5 9.76,0 12.98,3.73 14.37,5.13 1.17,1.18 2.92,4.42 2.92,7.01 l 0,39.83 -7.94,0 -0.01,-3.91 z M 220.5,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 56.03,9.75 -8.23,0 0,-14.54 -4.31,0 0,-6.75 4.31,0 0,-25.44 c 0,-4.85 2.49,-8.66 9.43,-8.65 3.25,0 3.12,-0.02 5.94,0.47 l 0,8.4 c -1.84,-0.32 -2.41,-0.45 -3.31,-0.42 -1.73,0.05 -3.83,0.66 -3.83,3.74 l 0,21.89 6.52,0 0,6.76 -6.52,0 0,14.54 z M 312.5,72 270,72 l 0,100 42.5,0 0,-100 z m 49.5,0 -42.5,0 0,100 42.5,0 0,-100 z m -42.5,0 z m 6.99,47.28 7.71,0 c 0,4.1 2.12,6.25 6.16,6.25 6.44,0.01 6.23,-2.86 6.22,-6.45 -3.98,-1.55 -3.61,-1.51 -9.68,-2.89 -7.71,-1.78 -12.43,-5.08 -12.44,-13.07 0.01,-7.81 5.57,-11.98 11.84,-11.97 6.28,-0.01 7.58,2.02 10.18,3.75 l 0,-3.12 9.84,0 c -2.32,3.74 -1.71,4.47 -1.73,7.28 0.01,2.2 0,23.74 0,23.74 0.01,4.27 -2.21,6.88 -3.66,7.75 -3.62,2.16 -8.09,2.42 -10.57,2.43 -8.81,-0.02 -13.88,-4.45 -13.87,-13.7 z m 20.09,-7.82 0,-5.45 c 0,-2.49 -3.03,-7.31 -8.98,-7.32 -2.9,-0.01 -4.52,2.14 -4.53,4.93 0.01,2.8 2.38,4.95 4.39,5.35 2.09,0.42 6.9,1.65 9.12,2.49 z M 369,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,56.9 9,0 0,-56.9 z"
             style="fill:#1e97ec;fill-opacity:1;fill-rule:nonzero;stroke:none"
             id="path3481"
             inkscape:connector-curvature="0" /></g></g><g
         transform="matrix(0.140057,0,0,0.140057,28.143932,232.97391)"
         inkscape:label="#g4177"
         id="text"
         style="display:inline"><text
           xml:space="preserve"
           style="font-style:normal;font-weight:normal;font-size:32px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#1e97ec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           x="234.70551"
           y="-270.57205"
           id="text3511"
           sodipodi:linespacing="125%"
           transform="matrix(1.25,0,0,1.25,0,990)"><tspan
             sodipodi:role="line"
             id="tspan3513"
             x="234.70551"
             y="-270.57205"
             style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:13px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold';fill:#1e97ec;fill-opacity:1;stroke:none">DIGITAL EQUIPMENT CORPORATION</tspan></text>
<text
           transform="matrix(1.25,0,0,1.25,0,990)"
           sodipodi:linespacing="125%"
           id="text3515"
           y="-258.09683"
           x="252.52724"
           style="font-style:normal;font-weight:normal;font-size:32px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#1e97ec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           xml:space="preserve"><tspan
             style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:11px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold';fill:#1e97ec;fill-opacity:1;stroke:none"
             y="-258.09683"
             x="252.52724"
             id="tspan3517"
             sodipodi:role="line">MAYNARD, MASSACHUSETTS, 01754</tspan></text>
<text
           transform="matrix(1.25,0,0,1.25,0,990)"
           sodipodi:linespacing="125%"
           id="text3519"
           y="-237.42363"
           x="236.84412"
           style="font-style:normal;font-weight:normal;font-size:32px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#1e97ec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           xml:space="preserve"><tspan
             style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:15px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold';letter-spacing:0.80000001px;fill:#1e97ec;fill-opacity:1;stroke:none"
             y="-237.42363"
             x="236.84412"
             id="tspan3521"
             sodipodi:role="line">REEL NO.</tspan></text>
<text
           xml:space="preserve"
           style="font-style:normal;font-weight:normal;font-size:32px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#1e97ec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           x="422.72479"
           y="-237.42363"
           id="text3523"
           sodipodi:linespacing="125%"
           transform="matrix(1.25,0,0,1.25,0,990)"><tspan
             sodipodi:role="line"
             id="tspan3525"
             x="422.72479"
             y="-237.42363"
             style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:15px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold';letter-spacing:0.80000001px;fill:#1e97ec;fill-opacity:1;stroke:none">DATE</tspan></text>
</g><path
         inkscape:connector-curvature="0"
         d="m 72.199362,308.19926 0,6.84856 1.404033,-0.0156 c 0,0 4.448809,0.2496 4.461705,-3.60369 0.01175,-3.51016 -4.430504,-3.27607 -4.430504,-3.27607 z m 1.326032,1.31043 0,4.1965 0.686416,0 c 0,0 2.523387,0.12492 2.542859,-2.30886 0.0156,-1.95004 -2.402456,-1.91884 -2.402456,-1.91884 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         id="path3539" /><path
         inkscape:connector-curvature="0"
         id="path3554"
         d="m 78.252303,308.02765 0,6.92656 3.588086,0 0,-1.29483 -2.106051,0 0,-1.54443 2.028048,0 0,-1.31043 -2.074848,0 0,-1.41964 2.059249,0 0,-1.35723 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         inkscape:connector-curvature="0"
         id="path3556"
         d="m 87.48772,310.0089 1.450835,0 c 0,0 -0.702017,-2.23085 -3.416481,-2.23085 -2.714464,0 -3.572483,2.38685 -3.572483,3.74408 0,1.35724 1.294829,3.43208 3.775287,3.43208 2.480459,0 3.229277,-2.04364 3.229277,-2.04364 l -1.466435,0 c 0,0 -0.358807,0.71761 -1.747241,0.71761 -1.388432,0 -2.402456,-0.99842 -2.402456,-2.23085 0,-1.23243 0.951623,-2.16845 2.230851,-2.16845 1.279232,0 1.918846,0.78002 1.918846,0.78002 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         inkscape:connector-curvature="0"
         id="path3558"
         d="m 89.219362,308.02765 0,6.92656 1.669238,0 0,-5.46012 -1.201229,0 0,-1.46644 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         inkscape:connector-curvature="0"
         id="path3560"
         d="m 92.152229,314.95421 0,-5.47572 1.29483,0 0.0312,-1.45084 3.697286,0 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         inkscape:connector-curvature="0"
         id="path3562"
         d="m 93.868269,314.95421 1.357232,-1.90324 1.560036,0 0,1.90324 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         sodipodi:nodetypes="cccc"
         inkscape:connector-curvature="0"
         id="path3564"
         d="m 96.052321,311.84974 0.748816,-1.06082 0,1.04522 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         inkscape:connector-curvature="0"
         id="path3566"
         d="m 98.080369,308.02765 0,6.92656 0.530412,0 0,-6.92656 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         inkscape:connector-curvature="0"
         id="path3568"
         d="m 99.87441,309.32248 0,1.79404 0.67082,0.0156 c 0,0 0.99842,-0.1248 0.99842,-0.92042 0,-0.79562 -1.02962,-0.85802 -1.02962,-0.85802 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
         inkscape:connector-curvature="0"
         id="path3570"
         d="m 99.936811,312.28655 0,2.66766 3.057669,0 0,-6.92656 -1.84084,0 c 0,0 1.56004,0.35881 1.56004,2.32446 0,1.96564 -1.90325,1.95004 -1.90325,1.95004 z"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><g
         transform="matrix(0.140057,0,0,0.140057,28.143932,232.97391)"
         inkscape:label="#g4171"
         id="dectape-graphics"
         style="display:inline"><path
           transform="matrix(1.25,0,0,-1.25,0,990)"
           style="fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 139.98514,433.20896 410.6593,-5.07131 c 0,0 -5.97508,23.16953 -13.43181,38.13146 -167.11395,1.42458 -326.54993,2.93466 -382.95298,3.28558 -9.80882,-18.26995 -14.27451,-36.34573 -14.27451,-36.34573 z"
           id="path3574"
           inkscape:connector-curvature="0"
           sodipodi:nodetypes="ccccc" /><path
           transform="matrix(1.25,0,0,-1.25,0,990)"
           style="fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 163.42461,486.64088 c 0,0 17.16387,25.4632 30.545,37.27097 14.36613,-10e-6 304.87219,-2.95063 304.87219,-2.95063 0,0 18.39873,-19.40688 28.73226,-37.55356 -41.33413,-0.25205 -364.14945,3.23322 -364.14945,3.23322 z"
           id="path3576"
           inkscape:connector-curvature="0"
           sodipodi:nodetypes="ccccc" /><path
           transform="matrix(1.25,0,0,-1.25,0,990)"
           style="fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 208.21343,538.27798 277.34946,-3.48528 c 0,0 -34.54921,30.89095 -64.85267,39.09636 -20.66706,0.50408 -148.33167,1.15579 -148.33167,1.15579 0,0 -35.4761,-11.99339 -64.16512,-36.76687 z"
           id="path3578"
           inkscape:connector-curvature="0"
           sodipodi:nodetypes="ccccc" /><path
           transform="matrix(1.25,0,0,-1.25,0,990)"
           style="fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 446.79083,363.29602 0,-7.57424 -11.58413,0 0,-9.53463 11.49503,0 0,-6.23761 -11.76235,0 0,-9.62373 11.85145,0 0,-6.59404 56.4949,0 c 0,0 38.49493,6.86137 38.49493,45.35631 0,38.49494 -42.59393,44.82166 -42.59393,44.82166 l -363.02869,3.74256 c 0,0 -5.43563,-22.45538 -5.43563,-40.00979 15.77223,0 363.1178,-2.67326 363.1178,-2.67326 0,0 6.86137,0.35644 6.86137,-6.1485 0,-6.50493 -6.23761,-5.52473 -6.23761,-5.52473 z"
           id="path3572"
           inkscape:connector-curvature="0"
           sodipodi:nodetypes="cccccccccccsccccscc" /></g><path
         inkscape:label="#circle4400"
         inkscape:connector-curvature="0"
         id="ring"
         d="M 88.506113,265.74856 A 40.577442,40.577442 0 0 0 47.928702,306.32597 40.577442,40.577442 0 0 0 88.506113,346.90365 40.577442,40.577442 0 0 0 129.0838,306.32597 40.577442,40.577442 0 0 0 88.506113,265.74856 Z m 0,2.02535 A 38.375756,38.552254 0 0 1 126.88201,306.32597 38.375756,38.552254 0 0 1 88.506113,344.8783 38.375756,38.552254 0 0 1 50.130497,306.32597 38.375756,38.552254 0 0 1 88.506113,267.77391 Z"
         style="display:inline;fill:#53a6c2;fill-opacity:1;stroke:none;stroke-width:1.16711712;stroke-opacity:1" /></g><text
       xml:space="preserve"
       style="font-style:normal;font-weight:normal;font-size:5.5970993px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       x="3.6412585"
       y="379.60495"
       id="text4175"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         id="tspan4177"
         x="3.6412585"
         y="379.60495" /></text>
<text
       xml:space="preserve"
       style="font-style:normal;font-weight:normal;font-size:10.07446671px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       x="48.558857"
       y="344.43402"
       id="text4177"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         x="48.558857"
         y="344.43402"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:6.29654121px;font-family:Dottie;-inkscape-font-specification:Dottie"
         id="tspan4185" /></text>
<text
       sodipodi:linespacing="125%"
       id="text4251"
       y="445.44971"
       x="3.6412585"
       style="font-style:normal;font-weight:normal;font-size:5.5970993px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       xml:space="preserve"><tspan
         y="445.44971"
         x="3.6412585"
         id="tspan4253"
         sodipodi:role="line" /></text>
<ellipse
       ry="37.22398"
       rx="39.077209"
       style="display:inline;fill:none;fill-opacity:1;stroke:none;stroke-width:0.99528235;stroke-opacity:1"
       id="ellipse4269"
       cx="188.95584"
       cy="309.14252" /><g
       id="g4403"
       transform="translate(-3.4700316,-242.58675)"><rect
         style="fill:none;fill-opacity:1;stroke:#dcdcdc;stroke-width:0.33938482;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
         id="rect4249"
         width="98.517426"
         height="51.003555"
         x="42.359982"
         y="431.91147" /><text
         xml:space="preserve"
         style="font-style:normal;font-weight:normal;font-size:12.70192051px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         x="46.723854"
         y="443.1936"
         id="text4255"
         sodipodi:linespacing="125%"><tspan
           sodipodi:role="line"
           id="tspan4257"
           x="46.723854"
           y="443.1936"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie">BIN LOADER</tspan><tspan
           id="tspan4425"
           sodipodi:role="line"
           x="46.723854"
           y="453.11697"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie">DEC-08-LBAA-PM</tspan><tspan
           sodipodi:role="line"
           x="46.723854"
           y="463.04034"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie"
           id="tspan4261">5/10/67  SA:7777</tspan><tspan
           sodipodi:role="line"
           x="46.723854"
           y="472.96371"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie"
           id="tspan4263" /></text>
<g
         id="g4393"
         transform="translate(-0.5513317,64.832146)"><g
           transform="matrix(0.03699838,0,0,-0.03699838,88.960048,419.11479)"
           id="g4395"
           style="display:inline;fill:#1e97ec;fill-opacity:1;stroke:none"
           inkscape:label="#g3477"><g
             clip-path="url(#clipPath18)"
             id="g4397"
             style="fill:#1e97ec;fill-opacity:1;stroke:none"><path
               inkscape:connector-curvature="0"
               id="path4399"
               style="fill:#1e97ec;fill-opacity:1;fill-rule:nonzero;stroke:none"
               d="m 101.3,107.13 c 0.02,-2.96 -3.43,-7.55 -7.63,-7.56 -4.48,0.02 -8.87,4.08 -8.87,12.2 0,8.24 4.38,12.48 8.73,12.5 4.34,-0.02 7.79,-4.67 7.77,-8.2 l 0,-8.94 z m 0.23,22.74 0,18.13 8.9,0 0,-56.4 -9.2,0 0,2.6 c -0.75,-0.76 -3.92,-4.07 -9.33,-4.07 -5.64,-0.01 -15.73,4.69 -15.73,21.64 0,14.37 7.54,21.8 16.5,21.8 3.32,0 6.58,-1.18 8.86,-3.7 z M 72,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m 7,0 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 61.18,-20.72 c 0,3.59 -4.04,7.3 -7.78,7.3 -3.22,0 -8.2,-2.05 -8.2,-11.24 0,-9.79 6.12,-11.22 8.15,-11.22 4.03,0 7.83,2.77 7.83,7.05 l 0,8.11 z M 171,172 l 42.5,0 0,-100 -42.5,0 0,100 z m 28.52,-43.91 c -0.93,1.33 -3.98,4.35 -8.34,4.35 -6.77,-0.01 -16.21,-3.92 -16.21,-20.89 0.01,-13.38 10.7,-17.87 15.09,-17.87 4.74,-0.01 8.26,2.75 9.22,3.79 l 0,-4.21 c 0,-3.11 -3.19,-6.15 -8.53,-6.15 -4.6,0.01 -5.08,2.96 -5.08,4.42 l -9.4,0 c 0,-4.67 3.01,-11.49 13.91,-11.5 9.76,0 12.98,3.73 14.37,5.13 1.17,1.18 2.92,4.42 2.92,7.01 l 0,39.83 -7.94,0 -0.01,-3.91 z M 220.5,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 56.03,9.75 -8.23,0 0,-14.54 -4.31,0 0,-6.75 4.31,0 0,-25.44 c 0,-4.85 2.49,-8.66 9.43,-8.65 3.25,0 3.12,-0.02 5.94,0.47 l 0,8.4 c -1.84,-0.32 -2.41,-0.45 -3.31,-0.42 -1.73,0.05 -3.83,0.66 -3.83,3.74 l 0,21.89 6.52,0 0,6.76 -6.52,0 0,14.54 z M 312.5,72 270,72 l 0,100 42.5,0 0,-100 z m 49.5,0 -42.5,0 0,100 42.5,0 0,-100 z m -42.5,0 z m 6.99,47.28 7.71,0 c 0,4.1 2.12,6.25 6.16,6.25 6.44,0.01 6.23,-2.86 6.22,-6.45 -3.98,-1.55 -3.61,-1.51 -9.68,-2.89 -7.71,-1.78 -12.43,-5.08 -12.44,-13.07 0.01,-7.81 5.57,-11.98 11.84,-11.97 6.28,-0.01 7.58,2.02 10.18,3.75 l 0,-3.12 9.84,0 c -2.32,3.74 -1.71,4.47 -1.73,7.28 0.01,2.2 0,23.74 0,23.74 0.01,4.27 -2.21,6.88 -3.66,7.75 -3.62,2.16 -8.09,2.42 -10.57,2.43 -8.81,-0.02 -13.88,-4.45 -13.87,-13.7 z m 20.09,-7.82 0,-5.45 c 0,-2.49 -3.03,-7.31 -8.98,-7.32 -2.9,-0.01 -4.52,2.14 -4.53,4.93 0.01,2.8 2.38,4.95 4.39,5.35 2.09,0.42 6.9,1.65 9.12,2.49 z M 369,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,56.9 9,0 0,-56.9 z" /></g></g><path
           id="path4401"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 106.30956,411.81751 0,4.57684 0.9383,-0.0104 c 0,0 2.97311,0.1668 2.98173,-2.40832 0.008,-2.34582 -2.96088,-2.18938 -2.96088,-2.18938 z m 0.88618,0.87575 0,2.80449 0.45873,0 c 0,0 1.68636,0.0835 1.69937,-1.54299 0.0104,-1.3032 -1.60555,-1.28235 -1.60555,-1.28235 z"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 110.35469,411.70282 0,4.62897 2.3979,0 0,-0.86532 -1.40746,0 0,-1.03213 1.35532,0 0,-0.87575 -1.3866,0 0,-0.94874 1.37618,0 0,-0.90703 z"
           id="path4403"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 116.52666,413.02688 0.96958,0 c 0,0 -0.46915,-1.49086 -2.28321,-1.49086 -1.81406,0 -2.38747,1.59511 -2.38747,2.50214 0,0.90703 0.86533,2.29363 2.523,2.29363 1.65767,0 2.1581,-1.36575 2.1581,-1.36575 l -0.98,0 c 0,0 -0.23979,0.47958 -1.16767,0.47958 -0.92789,0 -1.60555,-0.66724 -1.60555,-1.49086 0,-0.82363 0.63596,-1.44916 1.49086,-1.44916 0.8549,0 1.28236,0.52128 1.28236,0.52128 z"
           id="path4405"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 117.6839,411.70282 0,4.62897 1.11554,0 0,-3.64895 -0.80277,0 0,-0.98002 z"
           id="path4407"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 119.64391,416.33179 0,-3.65938 0.86533,0 0.0208,-0.96959 2.47087,0 z"
           id="path4409"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 120.79073,416.33179 0.90703,-1.27192 1.04255,0 0,1.27192 z"
           id="path4411"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 122.25032,414.2571 0.50043,-0.70894 0,0.69851 z"
           id="path4413"
           inkscape:connector-curvature="0"
           sodipodi:nodetypes="cccc" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 123.60565,411.70282 0,4.62897 0.35447,0 0,-4.62897 z"
           id="path4415"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 124.80459,412.56815 0,1.19894 0.4483,0.0104 c 0,0 0.66724,-0.0834 0.66724,-0.61511 0,-0.53171 -0.68809,-0.57341 -0.68809,-0.57341 z"
           id="path4417"
           inkscape:connector-curvature="0" /><path
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 124.84629,414.54901 0,1.78278 2.04342,0 0,-4.62897 -1.23022,0 c 0,0 1.04256,0.23979 1.04256,1.55342 0,1.31363 -1.27192,1.3032 -1.27192,1.3032 z"
           id="path4419"
           inkscape:connector-curvature="0" /><path
           style="fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           d="m 129.14164,411.70282 0,0.88618 -1.35533,0 0,1.11554 1.34491,0 0,0.7298 -1.37619,0 0,1.12596 1.38661,0 0,0.77149 6.60983,0 c 0,0 4.50387,-0.80276 4.50387,-5.30663 0,-4.50386 -4.98345,-5.24408 -4.98345,-5.24408 l -90.87296,-0.43787 c 0,0 -0.04525,2.62725 -0.04525,4.68109 1.845329,0 90.29268,0.31277 90.29268,0.31277 0,0 0.80277,-0.0417 0.80277,0.71937 0,0.76107 -0.72979,0.64638 -0.72979,0.64638 z"
           id="path4421"
           inkscape:connector-curvature="0"
           sodipodi:nodetypes="cccccccccccsccccscc" /></g></g><g
       id="g4381"
       transform="translate(-3.4700316,-242.58675)"><rect
         y="366.06671"
         x="42.359982"
         height="51.003555"
         width="98.517426"
         id="rect4187"
         style="fill:none;fill-opacity:1;stroke:#dcdcdc;stroke-width:0.33938482;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /><g
         transform="translate(-0.5513317,-0.5513317)"
         id="g4377"><g
           inkscape:label="#g3477"
           style="display:inline;fill:#1e97ec;fill-opacity:1;stroke:none"
           id="g4271"
           transform="matrix(0.03699838,0,0,-0.03699838,88.960048,419.11479)"><g
             style="fill:#1e97ec;fill-opacity:1;stroke:none"
             id="g4273"
             clip-path="url(#clipPath18)"><path
               d="m 101.3,107.13 c 0.02,-2.96 -3.43,-7.55 -7.63,-7.56 -4.48,0.02 -8.87,4.08 -8.87,12.2 0,8.24 4.38,12.48 8.73,12.5 4.34,-0.02 7.79,-4.67 7.77,-8.2 l 0,-8.94 z m 0.23,22.74 0,18.13 8.9,0 0,-56.4 -9.2,0 0,2.6 c -0.75,-0.76 -3.92,-4.07 -9.33,-4.07 -5.64,-0.01 -15.73,4.69 -15.73,21.64 0,14.37 7.54,21.8 16.5,21.8 3.32,0 6.58,-1.18 8.86,-3.7 z M 72,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m 7,0 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 61.18,-20.72 c 0,3.59 -4.04,7.3 -7.78,7.3 -3.22,0 -8.2,-2.05 -8.2,-11.24 0,-9.79 6.12,-11.22 8.15,-11.22 4.03,0 7.83,2.77 7.83,7.05 l 0,8.11 z M 171,172 l 42.5,0 0,-100 -42.5,0 0,100 z m 28.52,-43.91 c -0.93,1.33 -3.98,4.35 -8.34,4.35 -6.77,-0.01 -16.21,-3.92 -16.21,-20.89 0.01,-13.38 10.7,-17.87 15.09,-17.87 4.74,-0.01 8.26,2.75 9.22,3.79 l 0,-4.21 c 0,-3.11 -3.19,-6.15 -8.53,-6.15 -4.6,0.01 -5.08,2.96 -5.08,4.42 l -9.4,0 c 0,-4.67 3.01,-11.49 13.91,-11.5 9.76,0 12.98,3.73 14.37,5.13 1.17,1.18 2.92,4.42 2.92,7.01 l 0,39.83 -7.94,0 -0.01,-3.91 z M 220.5,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 56.03,9.75 -8.23,0 0,-14.54 -4.31,0 0,-6.75 4.31,0 0,-25.44 c 0,-4.85 2.49,-8.66 9.43,-8.65 3.25,0 3.12,-0.02 5.94,0.47 l 0,8.4 c -1.84,-0.32 -2.41,-0.45 -3.31,-0.42 -1.73,0.05 -3.83,0.66 -3.83,3.74 l 0,21.89 6.52,0 0,6.76 -6.52,0 0,14.54 z M 312.5,72 270,72 l 0,100 42.5,0 0,-100 z m 49.5,0 -42.5,0 0,100 42.5,0 0,-100 z m -42.5,0 z m 6.99,47.28 7.71,0 c 0,4.1 2.12,6.25 6.16,6.25 6.44,0.01 6.23,-2.86 6.22,-6.45 -3.98,-1.55 -3.61,-1.51 -9.68,-2.89 -7.71,-1.78 -12.43,-5.08 -12.44,-13.07 0.01,-7.81 5.57,-11.98 11.84,-11.97 6.28,-0.01 7.58,2.02 10.18,3.75 l 0,-3.12 9.84,0 c -2.32,3.74 -1.71,4.47 -1.73,7.28 0.01,2.2 0,23.74 0,23.74 0.01,4.27 -2.21,6.88 -3.66,7.75 -3.62,2.16 -8.09,2.42 -10.57,2.43 -8.81,-0.02 -13.88,-4.45 -13.87,-13.7 z m 20.09,-7.82 0,-5.45 c 0,-2.49 -3.03,-7.31 -8.98,-7.32 -2.9,-0.01 -4.52,2.14 -4.53,4.93 0.01,2.8 2.38,4.95 4.39,5.35 2.09,0.42 6.9,1.65 9.12,2.49 z M 369,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,56.9 9,0 0,-56.9 z"
               style="fill:#1e97ec;fill-opacity:1;fill-rule:nonzero;stroke:none"
               id="path4275"
               inkscape:connector-curvature="0" /></g></g><path
           inkscape:connector-curvature="0"
           d="m 106.30956,411.81751 0,4.57684 0.9383,-0.0104 c 0,0 2.97311,0.1668 2.98173,-2.40832 0.008,-2.34582 -2.96088,-2.18938 -2.96088,-2.18938 z m 0.88618,0.87575 0,2.80449 0.45873,0 c 0,0 1.68636,0.0835 1.69937,-1.54299 0.0104,-1.3032 -1.60555,-1.28235 -1.60555,-1.28235 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
           id="path4295" /><path
           inkscape:connector-curvature="0"
           id="path4297"
           d="m 110.35469,411.70282 0,4.62897 2.3979,0 0,-0.86532 -1.40746,0 0,-1.03213 1.35532,0 0,-0.87575 -1.3866,0 0,-0.94874 1.37618,0 0,-0.90703 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           inkscape:connector-curvature="0"
           id="path4299"
           d="m 116.52666,413.02688 0.96958,0 c 0,0 -0.46915,-1.49086 -2.28321,-1.49086 -1.81406,0 -2.38747,1.59511 -2.38747,2.50214 0,0.90703 0.86533,2.29363 2.523,2.29363 1.65767,0 2.1581,-1.36575 2.1581,-1.36575 l -0.98,0 c 0,0 -0.23979,0.47958 -1.16767,0.47958 -0.92789,0 -1.60555,-0.66724 -1.60555,-1.49086 0,-0.82363 0.63596,-1.44916 1.49086,-1.44916 0.8549,0 1.28236,0.52128 1.28236,0.52128 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           inkscape:connector-curvature="0"
           id="path4301"
           d="m 117.6839,411.70282 0,4.62897 1.11554,0 0,-3.64895 -0.80277,0 0,-0.98002 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           inkscape:connector-curvature="0"
           id="path4303"
           d="m 119.64391,416.33179 0,-3.65938 0.86533,0 0.0208,-0.96959 2.47087,0 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           inkscape:connector-curvature="0"
           id="path4305"
           d="m 120.79073,416.33179 0.90703,-1.27192 1.04255,0 0,1.27192 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           sodipodi:nodetypes="cccc"
           inkscape:connector-curvature="0"
           id="path4307"
           d="m 122.25032,414.2571 0.50043,-0.70894 0,0.69851 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           inkscape:connector-curvature="0"
           id="path4309"
           d="m 123.60565,411.70282 0,4.62897 0.35447,0 0,-4.62897 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           inkscape:connector-curvature="0"
           id="path4311"
           d="m 124.80459,412.56815 0,1.19894 0.4483,0.0104 c 0,0 0.66724,-0.0834 0.66724,-0.61511 0,-0.53171 -0.68809,-0.57341 -0.68809,-0.57341 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           inkscape:connector-curvature="0"
           id="path4313"
           d="m 124.84629,414.54901 0,1.78278 2.04342,0 0,-4.62897 -1.23022,0 c 0,0 1.04256,0.23979 1.04256,1.55342 0,1.31363 -1.27192,1.3032 -1.27192,1.3032 z"
           style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /><path
           sodipodi:nodetypes="cccccccccccsccccscc"
           inkscape:connector-curvature="0"
           id="path4323"
           d="m 129.14164,411.70282 0,0.88618 -1.35533,0 0,1.11554 1.34491,0 0,0.7298 -1.37619,0 0,1.12596 1.38661,0 0,0.77149 6.60983,0 c 0,0 4.50387,-0.80276 4.50387,-5.30663 0,-4.50386 -4.98345,-5.24408 -4.98345,-5.24408 l -90.87296,-0.43787 c 0,0 -0.04525,2.62725 -0.04525,4.68109 1.845329,0 90.29268,0.31277 90.29268,0.31277 0,0 0.80277,-0.0417 0.80277,0.71937 0,0.76107 -0.72979,0.64638 -0.72979,0.64638 z"
           style="fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /></g><text
         sodipodi:linespacing="125%"
         id="text4427"
         y="378.7012"
         x="46.723854"
         style="font-style:normal;font-weight:normal;font-size:12.70192051px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         xml:space="preserve"><tspan
           id="tspan4455"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie"
           y="378.7012"
           x="46.723854"
           sodipodi:role="line">FOCAL-69</tspan><tspan
           id="tspan4459"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie"
           y="388.62457"
           x="46.723854"
           sodipodi:role="line">DEC-08-AJAB-PB</tspan><tspan
           id="tspan4465"
           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie"
           y="398.54794"
           x="46.723854"
           sodipodi:role="line">4/29/68  SA:0200</tspan></text>
</g><rect
       style="fill:none;fill-opacity:1;stroke:#dcdcdc;stroke-width:0.33938482;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4428"
       width="98.517426"
       height="51.003555"
       x="38.88995"
       y="254.30894" /><text
       xml:space="preserve"
       style="font-style:normal;font-weight:normal;font-size:12.70192051px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       x="43.253822"
       y="265.59109"
       id="text4430"
       sodipodi:linespacing="125%"><tspan
         sodipodi:role="line"
         id="tspan4432"
         x="43.253822"
         y="265.59109"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie">ADD.PA</tspan><tspan
         id="tspan4434"
         sodipodi:role="line"
         x="43.253822"
         y="275.51447"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie">PIDP-8/I Example</tspan><tspan
         sodipodi:role="line"
         x="43.253822"
         y="285.43784"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie"
         id="tspan4436">11/27/16 SA:0200</tspan><tspan
         sodipodi:role="line"
         x="43.253822"
         y="295.36121"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.93869972px;font-family:Dottie;-inkscape-font-specification:Dottie"
         id="tspan4438" /></text>
<g
       id="g4440"
       transform="translate(-4.0213633,-112.77037)"><g
         transform="matrix(0.03699838,0,0,-0.03699838,88.960048,419.11479)"
         id="g4442"
         style="display:inline;fill:#1e97ec;fill-opacity:1;stroke:none"
         inkscape:label="#g3477"><g
           clip-path="url(#clipPath18)"
           id="g4444"
           style="fill:#1e97ec;fill-opacity:1;stroke:none"><path
             inkscape:connector-curvature="0"
             id="path4446"
             style="fill:#1e97ec;fill-opacity:1;fill-rule:nonzero;stroke:none"
             d="m 101.3,107.13 c 0.02,-2.96 -3.43,-7.55 -7.63,-7.56 -4.48,0.02 -8.87,4.08 -8.87,12.2 0,8.24 4.38,12.48 8.73,12.5 4.34,-0.02 7.79,-4.67 7.77,-8.2 l 0,-8.94 z m 0.23,22.74 0,18.13 8.9,0 0,-56.4 -9.2,0 0,2.6 c -0.75,-0.76 -3.92,-4.07 -9.33,-4.07 -5.64,-0.01 -15.73,4.69 -15.73,21.64 0,14.37 7.54,21.8 16.5,21.8 3.32,0 6.58,-1.18 8.86,-3.7 z M 72,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m 7,0 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 61.18,-20.72 c 0,3.59 -4.04,7.3 -7.78,7.3 -3.22,0 -8.2,-2.05 -8.2,-11.24 0,-9.79 6.12,-11.22 8.15,-11.22 4.03,0 7.83,2.77 7.83,7.05 l 0,8.11 z M 171,172 l 42.5,0 0,-100 -42.5,0 0,100 z m 28.52,-43.91 c -0.93,1.33 -3.98,4.35 -8.34,4.35 -6.77,-0.01 -16.21,-3.92 -16.21,-20.89 0.01,-13.38 10.7,-17.87 15.09,-17.87 4.74,-0.01 8.26,2.75 9.22,3.79 l 0,-4.21 c 0,-3.11 -3.19,-6.15 -8.53,-6.15 -4.6,0.01 -5.08,2.96 -5.08,4.42 l -9.4,0 c 0,-4.67 3.01,-11.49 13.91,-11.5 9.76,0 12.98,3.73 14.37,5.13 1.17,1.18 2.92,4.42 2.92,7.01 l 0,39.83 -7.94,0 -0.01,-3.91 z M 220.5,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,40.4 9,0 0,-40.4 z m -9,0 z m 9,45.9 -9,0 0,10 9,0 0,-10 z m -9,0 z m 56.03,9.75 -8.23,0 0,-14.54 -4.31,0 0,-6.75 4.31,0 0,-25.44 c 0,-4.85 2.49,-8.66 9.43,-8.65 3.25,0 3.12,-0.02 5.94,0.47 l 0,8.4 c -1.84,-0.32 -2.41,-0.45 -3.31,-0.42 -1.73,0.05 -3.83,0.66 -3.83,3.74 l 0,21.89 6.52,0 0,6.76 -6.52,0 0,14.54 z M 312.5,72 270,72 l 0,100 42.5,0 0,-100 z m 49.5,0 -42.5,0 0,100 42.5,0 0,-100 z m -42.5,0 z m 6.99,47.28 7.71,0 c 0,4.1 2.12,6.25 6.16,6.25 6.44,0.01 6.23,-2.86 6.22,-6.45 -3.98,-1.55 -3.61,-1.51 -9.68,-2.89 -7.71,-1.78 -12.43,-5.08 -12.44,-13.07 0.01,-7.81 5.57,-11.98 11.84,-11.97 6.28,-0.01 7.58,2.02 10.18,3.75 l 0,-3.12 9.84,0 c -2.32,3.74 -1.71,4.47 -1.73,7.28 0.01,2.2 0,23.74 0,23.74 0.01,4.27 -2.21,6.88 -3.66,7.75 -3.62,2.16 -8.09,2.42 -10.57,2.43 -8.81,-0.02 -13.88,-4.45 -13.87,-13.7 z m 20.09,-7.82 0,-5.45 c 0,-2.49 -3.03,-7.31 -8.98,-7.32 -2.9,-0.01 -4.52,2.14 -4.53,4.93 0.01,2.8 2.38,4.95 4.39,5.35 2.09,0.42 6.9,1.65 9.12,2.49 z M 369,72 l 42.5,0 0,100 -42.5,0 0,-100 z m 42.5,0 z m -16.75,19.6 -9,0 0,56.9 9,0 0,-56.9 z" /></g></g><path
         id="path4448"
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 106.30956,411.81751 0,4.57684 0.9383,-0.0104 c 0,0 2.97311,0.1668 2.98173,-2.40832 0.008,-2.34582 -2.96088,-2.18938 -2.96088,-2.18938 z m 0.88618,0.87575 0,2.80449 0.45873,0 c 0,0 1.68636,0.0835 1.69937,-1.54299 0.0104,-1.3032 -1.60555,-1.28235 -1.60555,-1.28235 z"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 110.35469,411.70282 0,4.62897 2.3979,0 0,-0.86532 -1.40746,0 0,-1.03213 1.35532,0 0,-0.87575 -1.3866,0 0,-0.94874 1.37618,0 0,-0.90703 z"
         id="path4450"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 116.52666,413.02688 0.96958,0 c 0,0 -0.46915,-1.49086 -2.28321,-1.49086 -1.81406,0 -2.38747,1.59511 -2.38747,2.50214 0,0.90703 0.86533,2.29363 2.523,2.29363 1.65767,0 2.1581,-1.36575 2.1581,-1.36575 l -0.98,0 c 0,0 -0.23979,0.47958 -1.16767,0.47958 -0.92789,0 -1.60555,-0.66724 -1.60555,-1.49086 0,-0.82363 0.63596,-1.44916 1.49086,-1.44916 0.8549,0 1.28236,0.52128 1.28236,0.52128 z"
         id="path4452"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 117.6839,411.70282 0,4.62897 1.11554,0 0,-3.64895 -0.80277,0 0,-0.98002 z"
         id="path4454"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 119.64391,416.33179 0,-3.65938 0.86533,0 0.0208,-0.96959 2.47087,0 z"
         id="path4456"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 120.79073,416.33179 0.90703,-1.27192 1.04255,0 0,1.27192 z"
         id="path4458"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 122.25032,414.2571 0.50043,-0.70894 0,0.69851 z"
         id="path4460"
         inkscape:connector-curvature="0"
         sodipodi:nodetypes="cccc" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 123.60565,411.70282 0,4.62897 0.35447,0 0,-4.62897 z"
         id="path4462"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 124.80459,412.56815 0,1.19894 0.4483,0.0104 c 0,0 0.66724,-0.0834 0.66724,-0.61511 0,-0.53171 -0.68809,-0.57341 -0.68809,-0.57341 z"
         id="path4464"
         inkscape:connector-curvature="0" /><path
         style="display:inline;fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 124.84629,414.54901 0,1.78278 2.04342,0 0,-4.62897 -1.23022,0 c 0,0 1.04256,0.23979 1.04256,1.55342 0,1.31363 -1.27192,1.3032 -1.27192,1.3032 z"
         id="path4466"
         inkscape:connector-curvature="0" /><path
         style="fill:#1e97ec;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.80000001px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
         d="m 129.14164,411.70282 0,0.88618 -1.35533,0 0,1.11554 1.34491,0 0,0.7298 -1.37619,0 0,1.12596 1.38661,0 0,0.77149 6.60983,0 c 0,0 4.50387,-0.80276 4.50387,-5.30663 0,-4.50386 -4.98345,-5.24408 -4.98345,-5.24408 l -90.87296,-0.43787 c 0,0 -0.04525,2.62725 -0.04525,4.68109 1.845329,0 90.29268,0.31277 90.29268,0.31277 0,0 0.80277,-0.0417 0.80277,0.71937 0,0.76107 -0.72979,0.64638 -0.72979,0.64638 z"
         id="path4468"
         inkscape:connector-curvature="0"
         sodipodi:nodetypes="cccccccccccsccccscc" /></g></g></svg>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted media/copytoUSBsticks/binloader.pt.

cannot compute difference between binary files

Deleted media/copytoUSBsticks/focal69.pt.

cannot compute difference between binary files

Deleted media/copytoUSBsticks/readme.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
The PiDP is typically used with a USB hub as its 'PiDP Universal Storage Device'.

Image files (disk images, paper tape images, DECtape images) are then stored on a USB stick,
and when inserted to the USB hub the first image file can be mounted into the emulated device.

The image files in this directory are typical candidates to put on USB sticks.

Mounting works as follows:

1. Select the device you want to mount on by setting the Data Field switches

   Switch Settings                                                   File Extension
   --------------------------------------------------------------------------------
        000 - mount USB paper tape on the high-speed paper tape reader   .pt
        001 - mount USB paper tape on the paper tape punch               .pt
        010 - mount DECtape on DT0 (TU55)                                .dt
        011 - mount DECtape on DT1 (TU55)                                .dt
        100 - mount 8" floppy disk on RX0 (RX01/02)                      .rx
        101 - mount 8" floppy disk on RX1 (RX01/02)                      .rx
        110 - mount 10MB removable disk cartridge on RL0 (RL8A)          .rl
        111 - mount 10MB removable disk cartridge on RL1 (RL8A)          .rl

2. Toggle Sing_Step and Sing_Inst switches together

3. The PiDP will scan all inserted USB sticks and mount the first unmounted image file for that device.
   Scanning requires the image file to have the extension as per the above table.
   This is equivalent to using the attach command from the simh command line.

Notes:

- Multiple image files can reside on one USB stick, as long as they do not have the same extension 
  (and your USB stick is large enough).

- You can put any other files on the sticks too, the PiDP will just ignore them.

- You can, of course, also just use the simh attach command to mount any image files on the SD card,
  and ignore the "PiDP Universal USB Storage Device" altogether.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































Deleted media/etos/etos.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
At main console:
----------------
To run ETOS: R ETOS to start the operating system. Hit return at the option prompt.

To login enter LOGIN and then hit return which should then give the login prompt.  No prompt will be displayed for entering the login command. At the prompt enter account number such as 0,3 and hit return. Then enter the password at the password prompt. On the distribution ETOS pack the following users exist:

At terminal (telnet localhost 4000):
-----------

LOGIN;0,4 USER1 <CTRL-M>


Users:
------
Account Password
0,4     USER1
0,5     USER2

Shutdown:
---------
You can To shutdown enter
. ^VS      (^V is control-V)
!PRIV 4040
!SHUTUP 

See:
----
http://www.pdp8.net/os/etos/ (introduction)
http://highgate.comm.sfu.ca/pdp8/index.html (manuals, search page for ETOS)
ftp://ftp.pdp8online.com/images/etos/ (disk images)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































Deleted media/etos/etosv5b-demo.rk05.
Deleted media/os8/LICENSE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# Digital License Agreement

This document is your Proof of License and the legal agreement governing
your use of the OS/8 software.


## 1 DEFINITION

SOFTWARE TECHNOLOGY shall mean the sources and binaries to the OS/8, an
operating system that runs on PDP-8 computers.

DIGITAL’S INTELLECTUAL PROPERTY RIGHTS shall mean DIGITAL’s patent,
copyright and trade secret rights in its SOFTWARE TECHNOLOGY.


## 2 LICENSE GRANT

Digital grants to Customer a worldwide, non-exclusive, royalty-free
license under DIGITAL’s INTELLECTUAL PROPERTY RIGHTS to reproduce,
modify, use and distribute the SOFTWARE TECHNOLOGY solely for
non-commercial uses.


## 3 TECHNOLOGY TRANSFER AND ACCEPTANCE

3.1 CUSTOMER acknowledges that it accepts the SOFTWARE TECHNOLOGY "AS
IS".

3.2 DIGITAL is under no obligation to supply error corrections or
updates to the SOFTWARE TECHNOLOGY as they become available, or to
provide training, support or consulting for the SOFTWARE TECHNOLOGY.


## 4 WARRANTY DISCLAIMER/LIMITATION OF LIABILITY

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO ANY SOFTWARE TECHNOLOGY
LICENSED TO CUSTOMER HEREUNDER, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL DIGITAL BE LIABLE FOR
ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
CONTRACT, NEGLIGENCE, INTELLECTUAL PROPERTY INFRINGEMENT OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF ANY SOFTWARE TECHNOLOGY LICENSE HEREUNDER.


## 5 INDEMNITY

CUSTOMER will hold DIGITAL harmless against all liabilities, demands,
damages, expenses, or losses arising out of use by CUSTOMER of SOFTWARE
TECHNOLOGY or information furnished under this Agreement.


## 6 TERM AND TERMINATION

6.1 This Agreement shall be effective until otherwise terminated.
Either party may terminate this Agreement at any time upon 30 days
written notice.

6.2 If CUSTOMER shall fail to perform or observe any of the terms and
conditions to be performed or observed by it under this Agreement,
DIGITAL may in its sole discretion thereafter elect to terminate this
Agreement, and this Agreement and all the obligations owed and rights
granted herein to CUSTOMER shall immediately terminate.

6.3 The parties agree that the termination of this Agreement shall not
release either party from any other liability which shall have accrued
to the other party at the time such termination becomes effective, nor
affect in any manner the survival of any right, duty or obligation of
either party.

6.4 In the event of any termination of this Agreement for any reason,
CUSTOMER shall delete all original and all whole or partial copies and
derivatives of the SOFTWARE TECHNOLOGY provided to CUSTOMER under this
Agreement.  CUSTOMER further shall cease to use and distribute the
SOFTWARE TECHNOLOGY in all forms immediately upon the date of
termination.


## 7 GENERAL TERMS

7.1 This Agreement shall be governed by the laws of the Commonwealth of
Massachusetts.

7.2 This Agreement imposes personal obligations on CUSTOMER.  CUSTOMER
shall not assign any rights under this Agreement not specifically
transferable by its terms without the written consent of DIGITAL.

7.3 The SOFTWARE TECHNOLOGY obtained under this Agreement may be subject
to US and other government export control regulations.  CUSTOMER assures
that it will comply with these regulations whenever it exports or
re-exports a controlled product or technical data obtained from DIGITAL
or any product produced directly from the SOFTWARE TECHNOLOGY.

7.4 The waiver of a breach hereunder may be effected only by a writing
signed by the waiving party and shall not constitute a waiver of any
other breach.

7.5 CUSTOMER acknowledges that he has read this Agreement, understands
it and agrees to be bound by its term and further agrees that it is the
complete and exclusive statement of the Agreement between the parties
which supersedes all communications and understanding between the
parties relating to the subject matter of this Agreement.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































Deleted media/os8/os8.rk05.

cannot compute difference between binary files

Deleted media/os8/os8.tu56.

cannot compute difference between binary files

Deleted media/spacewar/spacewar.bin.

cannot compute difference between binary files

Deleted media/tss8/tss8_init.bin.

cannot compute difference between binary files

Deleted media/tss8/tss8_rf.dsk.

cannot compute difference between binary files

Deleted palbart/LICENSE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# palbart License

The following was extracted from the top of [`palbart.c`][1] in this
directory:

---------

This is free software.  There is no fee for using it.  You may make any
changes that you wish and also give it away.  If you can make commercial
product out of it, fine, but do not put any limits on the purchaser's
right to do the same.  If you improve it or fix any bugs, it would be
nice if you told me and offered me a copy of the new version.

---------

[1]: https://tangentsoft.com/pidp8i/doc/trunk/palbart/palbart.c
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































Deleted palbart/palbart.1.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
.\"                                      Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH PALBART 1 "January 16, 2000"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh        disable hyphenation
.\" .hy        enable hyphenation
.\" .ad l      left justify
.\" .ad b      justify to both left and right margins
.\" .nf        disable filling
.\" .fi        enable filling
.\" .br        insert line break
.\" .sp <n>    insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
palbart \- BART enhanced PDP8 crossassembler
.SH SYNOPSIS
.B palbart
.RI [options] inputfile
.br
.SH DESCRIPTION
This manual page documents briefly the
.B palbart
command.
It is a cross-assembler to for PDP/8 assembly language programs.
It will produce an output file in bin format, rim format, and using the
appropriate pseudo-ops, a combination of rim and bin formats.
A listing file is always produced and with an optional symbol table
and/or a symbol cross-reference (concordance).  The permanent symbol
table can be output in a form that may be read back in so a customized
permanent symbol table can be produced.  Any detected errors are output
to a separate file giving the filename in which they were detected
along with the line number, column number and error message as well as
marking the error in the listing file.
.PP
The following file name extensions are used:
.PP
 .pal    source code (input)
.PP
 .lst    assembly listing (output)
.PP
 .bin    assembly output in DEC's bin format (output)
.PP
 .rim    assembly output in DEC's rim format (output)
.PP
 .err    assembly errors detected (if any) (output)
.PP
 .prm    permanent symbol table in form suitable for reading after the EXPUNGE pseudo-op.

.PP
.SH OPTIONS
A summary of options is included below.
.TP
.B \-d
Show symbol table at end of assembly
.TP
.B \-h
Display help.
.TP
.B \-l
Allow generation of literals (default is no literal generation)
Show version of program.
.TP
.B \-p
Generate a file with the permanent symbols in it.
(To get the current symbol table, assemble a file than has only
a $ in it.)
.TP
.B \-r
Produce output in rim format (default is bin format)
.TP
.B \-v
Display version information.
.TP
.B \-x
Generate a cross-reference (concordance) of user symbols.

.SH  DIAGNOSTICS
Assembler error diagnostics are output to an error file and inserted
in the listing file.  Each line in the error file has the form
.PP
<filename>(<line>:<col>) : error:  <message> at Loc = <loc>
.PP
An example error message is:
.br
bintst.pal(17:9) : error:  undefined symbol "UNDEF" at Loc = 07616
.PP
The error diagnostics put in the listing start with a two character
error code (if appropriate) and a short message.  A carat '^' is
placed under the item in error if appropriate.
An example error message is:
.PP
      17 07616 3000          DCA     UNDEF
.br
   UD undefined                      ^
.br
      18 07617 1777          TAD  I  DUMMY
.PP
When an indirect is generated, an at character '@' is placed after the
the instruction value in the listing as an indicator as follows:
.PP
      14 03716 1777@         TAD     OFFPAG
.PP
Undefined symbols are marked in the symbol table listing by prepending
a '?' to the symbol.  Redefined symbols are marked in the symbol table
listing by prepending a '#' to the symbol.  Examples are:
.PP
   #REDEF   04567
.br
    SWITCH  07612
.br
   ?UNDEF   00000
.PP
Refer to the code for the diagnostic messages generated.

.SH BUGS
Only a minimal effort has been made to keep the listing format
anything like the PAL-8 listing format.
The operation of the conditional assembly pseudo-ops may not function
exactly as the DEC versions.  I did not have any examples of these so
the implementation is my interpretation of how they should work.
.PP
The RIMPUNch and BINPUNch pseudo-ops do not change the binary output
file type that was specified on startup.  This was intentional and
and allows rim formatted data to be output prior to the actual binary
formatted data.  On UN*X style systems, the same effect can be achieved
ing the "cat" command, but on DOS/Windows systems, doing this was
a major chore.
.PP
The floating point input does not generate values exactly as the DEC
compiler does.  I worked out several examples by hand and believe that
this implementation is slightly more accurate.  If I am mistaken,
let me know and, if possible, a better method of generating the values.
.br

.SH HISTORICAL NOTE
This assembler was written to support the fleet of PDP-8 systems
used by the Bay Area Rapid Transit System.  As of early 1997,
this includes about 40 PDP-8/E systems driving the train destination
signs in passenger stations.

.SH REFERENCES
This assembler is based on the pal assember by:
.br
Douglas Jones <jones@cs.uiowa.edu> and
.br
Rich Coon <coon@convexw.convex.com>

.SH DISCLAIMER
See the symbol table for the set of pseudo-ops supported.
.PP
See the code for pseudo-ops that are not standard for PDP/8 assembly.
.PP
Refer to DEC's "Programming Languages (for the PDP/8)" for complete
documentation of pseudo-ops.
.PP
Refer to DEC's "Introduction to Programming (for the PDP/8)" or a
lower level introduction to the assembly language.

.SH WARRANTY
If you don't like it the way it works or if it doesn't work, that's
tough.  You're welcome to fix it yourself.  That's what you get for
using free software.

.SH COPYRIGHT NOTICE
This is free software.  There is no fee for using it.  You may make
any changes that you wish and also give it away.  If you can make
a commercial product out of it, fine, but do not put any limits on
the purchaser's right to do the same.  If you improve it or fix any
bugs, it would be nice if you told me and offered me a copy of the
new version.
Gary Messenbrink <gam@rahul.net>

.SH VERSIONS
 Version  Date    by   Comments
.br
   v1.0  12Apr96  GAM  Original
.br
   v1.1  18Nov96  GAM  Permanent symbol table initialization error.
.br
   v1.2  20Nov96  GAM  Added BINPUNch and RIMPUNch pseudo-operators.
.br
   v1.3  24Nov96  GAM  Added DUBL pseudo-op (24 bit integer constants).
.br
   v1.4  29Nov96  GAM  Fixed bug in checksum generation.
.br
   v2.1  08Dec96  GAM  Added concordance processing (cross reference).
.br
   v2.2  10Dec96  GAM  Added FLTG psuedo-op (floating point constants).
.br
   v2.3   2Feb97  GAM  Fixed paging problem in cross reference output.
.br
   v2.4  11Apr97  GAM  Fixed problem with some labels being put in cross reference multiple times.

.SH AUTHOR
This manual page was written by Vince Mulhollon <vlm@execpc.com>,
for the Debian GNU/Linux system (but may be used by others).
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































































































































































































Deleted palbart/palbart.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
/******************************************************************************/
/*                                                                            */
/* Program:  PAL (BART version)                                               */
/* File:     pal.c                                                            */
/* Author:   Gary A. Messenbrink                                              */
/*           gam@rahul.net                                                    */
/*                                                                            */
/* Purpose:  A 2 pass PDP-8 pal-like assembler.                               */
/*                                                                            */
/* PAL(1)                                                                     */
/*                                                                            */
/* NAME                                                                       */
/*    pal - a PDP/8 pal-like assembler.                                       */
/*                                                                            */
/* SYNOPSIS:                                                                  */
/*    pal [ -$ -d -h -e -l -p -r -t -v -x ] inputfile                         */
/*                                                                            */
/* DESCRIPTION                                                                */
/*    This is a cross-assembler to for PDP/8 assembly language programs.      */
/*    It will produce an output file in bin format, rim format, and using the */
/*    appropriate pseudo-ops, a combination of rim and bin formats.           */
/*    A listing file is always produced and with an optional symbol table     */
/*    and/or a symbol cross-reference (concordance).  The permanent symbol    */
/*    table can be output in a form that may be read back in so a customized  */
/*    permanent symbol table can be produced.  Any detected errors are output */
/*    to a separate file giving the filename in which they were detected      */
/*    along with the line number, column number and error message as well as  */
/*    marking the error in the listing file.                                  */
/*    The following file name extensions are used:                            */
/*       .pal    source code (input)                                          */
/*       .lst    assembly listing (output)                                    */
/*       .bin    assembly output in DEC's bin format (output)                 */
/*       .rim    assembly output in DEC's rim format (output)                 */
/*       .err    assembly errors detected (if any) (output)                   */
/*       .prm    permanent symbol table in form suitable for reading after    */
/*               the EXPUNGE pseudo-op.                                       */
/*                                                                            */
/* OPTIONS                                                                    */
/*    -$   Allow files to not end with $                                      */
/*    -d   Dump the symbol table at end of assembly                           */
/*    -h   Show help                                                          */
/*    -e   Don't allow generation of links                                    */
/*    -l   Allow generation of links (default is link generation)             */
/*    -n   No redefinition of permanent symbols with labels                   */
/*    -p   Generate a file with the permanent symbols in it.                  */
/*         (To get the current symbol table, assemble a file than has only    */
/*          a $ in it.)                                                       */
/*    -r   Produce output in rim format (default is bin format)               */
/*    -tN  Set tab stops to N spaces (default is 8)                           */
/*    -v   Display program version.                                           */
/*    -x   Generate a cross-reference (concordance) of user symbols.          */
/*                                                                            */
/* DIAGNOSTICS                                                                */
/*    Assembler error diagnostics are output to an error file and inserted    */
/*    in the listing file.  Each line in the error file has the form          */
/*                                                                            */
/*       <filename>(<line>:<col>) : error:  <message> at Loc = <loc>          */
/*                                                                            */
/*    An example error message is:                                            */
/*                                                                            */
/*       bintst.pal(17:9) : error:  undefined symbol "UNDEF" at Loc = 07616   */
/*                                                                            */
/*    The error diagnostics put in the listing start with a two character     */
/*    error code (if appropriate) and a short message.  A carat '^' is        */
/*    placed under the item in error if appropriate.                          */
/*    An example error message is:                                            */
/*                                                                            */
/*          17 07616 3000          DCA     UNDEF                              */
/*       UD undefined                      ^                                  */
/*          18 07617 1777          TAD  I  DUMMY                              */
/*                                                                            */
/*    When an indirect is generated, an at character '@' is placed after the  */
/*    the instruction value in the listing as an indicator as follows:        */
/*                                                                            */
/*          14 03716 1777@         TAD     OFFPAG                             */
/*                                                                            */
/*    Undefined symbols are marked in the symbol table listing by prepending  */
/*    a '?' to the symbol.  Redefined symbols are marked in the symbol table  */
/*    listing by prepending a '#' to the symbol.  Examples are:               */
/*                                                                            */
/*       #REDEF   04567                                                       */
/*        SWITCH  07612                                                       */
/*       ?UNDEF   00000                                                       */
/*                                                                            */
/*    Refer to the code for the diagnostic messages generated.                */
/*                                                                            */
/* BUGS                                                                       */
/*    This program will accept source that real PAL will not. To ensure       */
/*    valid source assemble on real or simulated PDP-8.                       */
/*    Different PAL versions have different permanent symbols defined. This   */
/*    program define more than and PAL version. By default redefining them    */
/*    as a label is not an error. It is for normal PAL. The -n flag will      */
/*    make redefining an error.                                               */
/*                                                                            */
/*    Only a minimal effort has been made to keep the listing format          */
/*    anything like the PAL-8 listing format.                                 */
/*    The operation of the conditional assembly pseudo-ops may not function   */
/*    exactly as the DEC versions.  I did not have any examples of these so   */
/*    the implementation is my interpretation of how they should work.        */
/*                                                                            */
/*    The RIMPUNch and BINPUNch pseudo-ops do not change the binary output    */
/*    file type that was specified on startup.  This was intentional and      */
/*    and allows rim formatted data to be output prior to the actual binary   */
/*    formatted data.  On UN*X style systems, the same effect can be achieved */
/*    by using the "cat" command, but on DOS/Windows systems, doing this was  */
/*    a major chore.                                                          */
/*                                                                            */
/*    The floating point input does not generate values exactly as the DEC    */
/*    compiler does.  I worked out several examples by hand and believe that  */
/*    this implementation is slightly more accurate.  If I am mistaken,       */
/*    let me know and, if possible, a better method of generating the values. */
/*                                                                            */
/*    CDF .-.                                                                 */
/*       Generates 2201 when assembled at 5000. This looks like a bug in OS/8 */
/*       PAL                                                                  */
/*                                                                            */
/* BUILD and INSTALLATION                                                     */
/*    The current version has only been built under Linux.                    */
/*    Earlier versions have been built and successfully executed on:          */
/*      a.  Linux (80486 CPU)using gcc                                        */
/*      b.  RS/6000 (AIX 3.2.5)                                               */
/*      c.  Borland C++ version 3.1  (large memory model)                     */
/*      d.  Borland C++ version 4.52 (large memory model)                     */
/*    with no modifications to the source code.                               */
/*                                                                            */
/*    On UNIX type systems, store the the program as the pal command          */
/*    and on PC type systems, store it as pal.exe                             */
/*                                                                            */
/* HISTORICAL NOTE:                                                           */
/*    This assembler was written to support the fleet of PDP-8 systems        */
/*    used by the Bay Area Rapid Transit System.  As of early 1997,           */
/*    this includes about 40 PDP-8/E systems driving the train destination    */
/*    signs in passenger stations.                                            */
/*                                                                            */
/* REFERENCES:                                                                */
/*    This assembler is based on the pal assembler by:                         */
/*       Douglas Jones <jones@cs.uiowa.edu> and                               */
/*       Rich Coon <coon@convexw.convex.com>                                  */
/*                                                                            */
/* DISCLAIMER:                                                                */
/*    See the symbol table for the set of pseudo-ops supported.               */
/*    See the code for pseudo-ops that are not standard for PDP/8 assembly.   */
/*    Refer to DEC's "Programming Languages (for the PDP/8)" for complete     */
/*    documentation of pseudo-ops.                                            */
/*    Refer to DEC's "Introduction to Programming (for the PDP/8)" or a       */
/*    lower level introduction to the assembly language.                      */
/*                                                                            */
/* WARRANTY:                                                                  */
/*    If you don't like it the way it works or if it doesn't work, that's     */
/*    tough.  You're welcome to fix it yourself.  That's what you get for     */
/*    using free software.                                                    */
/*                                                                            */
/* COPYRIGHT NOTICE:                                                          */
/*    This is free software.  There is no fee for using it.  You may make     */
/*    any changes that you wish and also give it away.  If you can make       */
/*    a commercial product out of it, fine, but do not put any limits on      */
/*    the purchaser's right to do the same.  If you improve it or fix any     */
/*    bugs, it would be nice if you told me and offered me a copy of the      */
/*    new version.                                                            */
/*                                                                            */
/*                                                                            */
/* Amendments Record:                                                         */
/*  Version  Date    by   Comments                                            */
/*  ------- -------  ---  --------------------------------------------------- */
/*    v1.0  12Apr96  GAM  Original                                            */
/*    v1.1  18Nov96  GAM  Permanent symbol table initialization error.        */
/*    v1.2  20Nov96  GAM  Added BINPUNch and RIMPUNch pseudo-operators.       */
/*    v1.3  24Nov96  GAM  Added DUBL pseudo-op (24 bit integer constants).    */
/*    v1.4  29Nov96  GAM  Fixed bug in checksum generation.                   */
/*    v2.1  08Dec96  GAM  Added concordance processing (cross reference).     */
/*    v2.2  10Dec96  GAM  Added FLTG psuedo-op (floating point constants).    */
/*    v2.3   2Feb97  GAM  Fixed paging problem in cross reference output.     */
/* DJG: I started with the 2.5 RK version but found when looking on the net   */
/* later that multiple diverging version existed. I have tried to combine     */
/* the fixed into one version. I took the version info below from the versions*/
/* I pulled from.                                                             */
/* http://dustyoldcomputers.com/pdp-common/reference/host/index.html          */
/* http://www.dunnington.u-net.com/public/PDP-8/palbart.c                     */
/* http://sourcecodebrowser.com/palbart/2.4/palbart-2_84_8c_source.html       */
/* http://packages.qa.debian.org/p/palbart.html                               */
/*    v2.4  11Apr97  GAM  Fixed problem with some labels being put in cross   */
/*                        reference multiple times.                           */
/*                        Started with RK version, Attempted to merge         */
/*                        GAM V2.4 and PNT change DJG                         */
/*    v2.4  29Oct07  RK   Added 4 character tabstop; IOTs for TA8/E.          */
/*    v2.4  19Jan03  PNT  Added ASCII pseudo-op, like TEXT but not packed.    */
/*    v2.5  03Nov07  RK   Fixed buffer overflow problem in readLine and       */
/*                        increased symbol table size                         */
/*    v2.6  14Jul03  PNT  Added missing TTY symbols, and "1st TTY" symbols.   */
/*    v2.7  14Jun13  DJG  David Gesswein djg@pdp8online.com                   */
/*                        Merged other changes found online giving duplicate  */
/*                         Versions in the history                            */
/*                         Didn't copy over deleting -l literal flag          */
/*                        All fixes to make it match OS/8 PAL8 better         */
/*                        Fixed handling of IFDEF type conditionals           */
/*                        Fixed excessive redefined symbol errors             */
/*                         PAL8 uses 12 bit symbols and this program label    */
/*                         symbols are 15 bit.                                */
/*                        Added FILENAME and DEVNAME psuedo ops               */
/*                        Added OPR and KCF instructions. Fixed RMF           */
/*                        Allowed space after =                               */
/*                        Prevented I and D from being deleted by EXPUNGE     */
/*                        Allowed permanent symbols to be redefined with error*/
/*                         PAL8 updates without message. Error is just warning*/
/*                        Fixed certain cases of memory reference generation  */
/*                        Allowed unary +                                     */
/*                        Fixed " character literal at end of line            */
/*                        Fixed errors in reloc handling                      */
/*                        Fixed [CDF CIF type expressions                     */
/*                        Made title default to first line                    */
/*                        Fixed checksum when nopunch used                    */
/*                        Fixed FIXTAB                                        */
/*                        Probably added more subtle bugs                     */
/*    v2.8  15Jun13  DJG  Merged versions found on net. See above             */
/*                        Added * to RELOC addresses in listing               */
/*                        Changed default to literal/links on. Added -e to    */
/*                         turn off                                           */
/*                        Fixed PAGE when RELOC used                          */
/*                        Changed SPF to TFL and SPI to TSK                   */
/*                        Make error when changing permanent symbol to label  */
/*                         if -e flag is used                                 */
/*                        Allow space oring in IFZERO etc                     */
/*                        Fixed handling of page zero overflow                */
/*    v2.9  23Jun13  DJG  Fixed properly all pages literal handling           */
/*                         changing page doesn't cause loss of last literal   */
/*                         location used.                                     */
/*                        Fixed bin generation if no origin set               */
/*    v2.9a 01Jul13  DJG  Fixed Comment. Binaries not updated                 */
/*    v2.10 08Feb14  DJG  Changed trailer to 8 bytes since pip didn't like    */
/*                        trailer of one 0x80                                 */
/*    v2.11 19Apr15  DPI  Fixed incorrect link generation with impled 0200    */
/*                        starting address. Patch from Doug Ingrams           */
/*    v2.12 28Apr15  DJG  Fixed incorrect handling of reloc, expressions with */
/*                        undefined symbols. Fixed conditional assembly with  */
/*                        undefined symbols. Added new flag to allow file to  */
/*                        not end with $                                      */
/*    v2.13 02May15  DPI  Fixed bug in readLine when removing \r from a blank */
/*                        line.  Changed -s to -$ in -h display.  Corrected   */
/*                        version comment.                                    */
/*    v2.13 03May15  DJG  Moved TITLE, BANK to new additional option.         */
/* Change release variable below when you update. Send changes back to        */
/*   David Gesswein, djg@pdp8online.com.                                      */
/******************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

char *release = "pal-2.13, 03 May 2015";

/* Set to 1 and use -e flag to make ( and [ literals errors */
#define LITERAL_ERROR        0

#define LINELEN              132
#define LIST_LINES_PER_PAGE  55         /* Includes 5 line page header.       */
#define NAMELEN             128
#define SYMBOL_COLUMNS        5
#define SYMLEN                7
#define SYMBOL_TABLE_SIZE  4096
#define TITLELEN             63
#define XREF_COLUMNS          8

#define ADDRESS_FIELD  00177
#define FIELD_FIELD   070000
#define INDIRECT_BIT   00400
#define LAST_PAGE_LOC  00177
#define OP_CODE        07000
#define PAGE_BIT       00200

#ifdef  PAGE_SIZE
#undef  PAGE_SIZE
#endif
#define PAGE_SIZE      00200

#define PAGE_FIELD     07600
#define PAGE_ZERO_END  00200

/* Macro to get the number of elements in an array.                           */
#define DIM(a) (sizeof(a)/sizeof(a[0]))

/* Macro to get the address plus one of the end of an array.                  */
#define BEYOND(a) ((a) + DIM(A))

#define is_blank(c) ((c==' ') || (c=='\t') || (c=='\f') || (c=='>'))
#define isend(c)   ((c=='\0')|| (c=='\n'))
#define isdone(c)  ((c=='/') || (isend(c)) || (c==';'))

/* Macros for testing symbol attributes.  Each macro evaluates to non-zero    */
/* (true) if the stated condition is met.                                      */
/* Use these to test attributes.  The proper bits are extracted and then      */
/* tested.                                                                    */
#define M_CONDITIONAL(s) ((s & CONDITION) == CONDITION)
#define M_DEFINED(s)     ((s & DEFINED) == DEFINED)
#define M_DUPLICATE(s)   ((s & DUPLICATE) == DUPLICATE)
#define M_FIXED(s)       ((s & FIXED) == FIXED)
#define M_LABEL(s)       ((s & LABEL) == LABEL)
#define M_MRI(s)         ((s & MRI) == MRI)
#define M_MRIFIX(s)      ((s & MRIFIX) == MRIFIX)
#define M_PSEUDO(s)      ((s & PSEUDO) == PSEUDO)
#define M_REDEFINED(s)   ((s & REDEFINED) == REDEFINED)
#define M_UNDEFINED(s)   (!M_DEFINED(s))
#define M_PERM_REDEFINED(s)   ((s & PERM_REDEFINED) == PERM_REDEFINED)

/* This macro is used to test symbols by the conditional assembly pseudo-ops. */
#define M_DEF(s) (M_DEFINED(s))
#define M_COND(s) (M_CONDITIONAL(s))
#define M_DEFINED_CONDITIONALLY(t) (M_DEF(t) && ((pass==1) ||!M_COND(t)))

typedef unsigned char BOOL;
typedef unsigned char BYTE;
typedef short    int  WORD16;
typedef long     int  WORD32;

#ifndef FALSE
  #define FALSE 0
  #define TRUE (!FALSE)
#endif

/* Line listing styles.  Used to control listing of lines.                    */
enum linestyle_t
{
  LINE, LINE_VAL, LINE_LOC_VAL, LOC_VAL
};
typedef enum linestyle_t LINESTYLE_T;

/* Symbol Types.                                                              */  
/* Note that the names that have FIX as the suffix contain the FIXED bit      */
/* included in the value.                                                     */
/*                                                                            */
/* The CONDITION bit is used when processing the conditional assembly PSEUDO- */
/* OPs (e.g., IFDEF).  During pass 1 of the assembly, the symbol is either    */
/* defined or undefined.  The condition bit is set when the symbol is defined */
/* during pass 1 and reset on pass 2 at the location the symbol was defined   */
/* during pass 1.  When processing conditionals during pass 2, if the symbol  */
/* is defined and the condition bit is set, the symbol is treated as if it    */
/* were undefined.  This gives consistent behavior of the conditional         */
/* pseudo-ops during both pass 1 and pass 2.                                  */
enum symtyp
{
  UNDEFINED = 0000,
  DEFINED   = 0001,
  FIXED     = 0002,
  MRI       = 0004    | DEFINED,
  LABEL     = 0010    | DEFINED,
  REDEFINED = 0020    | DEFINED,
  DUPLICATE = 0040    | DEFINED,
  PSEUDO    = 0100    | FIXED | DEFINED,
  CONDITION = 0200    | DEFINED,
  PERM_REDEFINED = 0400,
  MRIFIX    = MRI     | FIXED | DEFINED,
  DEFFIX    = DEFINED | FIXED
};
typedef enum symtyp SYMTYP;

enum pseudo_t
{
  BANK,    BINPUNCH, DECIMAL, DUBL,    EJECT,    ENPUNCH, EXPUNGE, FIELD,
  FIXMRI,  FIXTAB,   FLTG,    IFDEF,   IFNDEF,   IFNZERO, IFZERO,  NOPUNCH,
  OCTAL,   PAGE,     PAUSE,   RELOC,   RIMPUNCH, SEGMNT,  TEXT,    TITLE,
  XLIST,   ZBLOCK, FILENAME, DEVICE, ASCII
};
typedef enum pseudo_t PSEUDO_T;

struct sym_t
{
  SYMTYP  type;
  char    name[SYMLEN];
  WORD16  val;
  int     xref_index;
  int     xref_count;
};
typedef struct sym_t SYM_T;

struct lpool_t
{
  WORD16  loc;
  WORD16  last_punched;
  WORD16  pool[PAGE_SIZE];
};
typedef struct lpool_t LPOOL_T;

struct emsg_t
{
  char  *list;
  char  *file;
};
typedef struct emsg_t EMSG_T;

struct errsave_t
{
  char  *mesg;
  int    col;
};
typedef struct errsave_t ERRSAVE_T;

struct fltg_
{
  WORD16 exponent;
  WORD32 mantissa;
};
typedef struct fltg_ FLTG_T;

/*----------------------------------------------------------------------------*/

/* Function Prototypes                                                        */

int     binarySearch( char *name, int start, int symbol_count );
int     compareSymbols( const void *a, const void *b );
void    conditionFalse( void );
void    conditionTrue( void );
SYM_T  *defineLexeme( int start, int term, WORD16 val, SYMTYP type );
SYM_T  *defineSymbol( char *name, WORD16 val, SYMTYP type, WORD16 start);
void    endOfBinary( void );
void    errorLexeme( EMSG_T *mesg, int col );
void    errorMessage( EMSG_T *mesg, int col );
void    errorSymbol( EMSG_T *mesg, char *name, int col );
SYM_T  *eval( void );
WORD32  evalDubl( WORD32 initial_value );
FLTG_T *evalFltg( void );
SYM_T  *evalSymbol( void );
void    getArgs( int argc, char *argv[] );
WORD32  getDublExpr( void );
WORD32  getDublExprs( void );
FLTG_T *getFltgExpr( void );
FLTG_T *getFltgExprs( void );
SYM_T  *getExpr( void );
WORD16  getExprs( void );
WORD16  incrementClc( void );
void    inputDubl( void );
void    inputFltg( void );
WORD16  insertLiteral( LPOOL_T *pool, WORD16 value, int fieldpage_index );
char   *lexemeToName( char *name, int from, int term );
void    listLine( void );
SYM_T  *lookup( char *name );
void    moveToEndOfLine( void );
void    nextLexBlank( void );
void    nextLexeme( void );
void    normalizeFltg( FLTG_T *fltg );
void    onePass( void );
void    printCrossReference( void );
void    printErrorMessages( void );
void    printLine(char *line, WORD16 loc, WORD16 val, LINESTYLE_T linestyle);
void    printPageBreak( void );
void    printPermanentSymbolTable( void );
void    printSymbolTable( void );
BOOL    pseudoOperators( PSEUDO_T val );
void    punchChecksum( void );
void    punchLocObject( WORD16 loc, WORD16 val );
void    punchLiteralPool( LPOOL_T *p, BOOL punch_page0 );
void    punchOutObject( WORD16 loc, WORD16 val );
void    punchLeader( int count );
void    punchObject( WORD16 val );
void    punchOrigin( WORD16 loc );
void    readLine( void );
void    saveError( char *mesg, int cc );
BOOL    testForLiteralCollision( WORD16 loc );
void    topOfForm( char *title, char *sub_title );

/*----------------------------------------------------------------------------*/

/* Table of pseudo-ops (directives) which are used to setup the symbol        */
/* table on startup and when the EXPUNGE pseudo-op is executed.               */
SYM_T pseudo[] =
{
  { PSEUDO, "ASCII",  ASCII   },    /* Put 8-bit ASCII into memory (see TEXT) */
  { PSEUDO, "BINPUN", BINPUNCH },   /* Output in Binary Loader format.        */
  { PSEUDO, "DECIMA", DECIMAL },    /* Read literal constants in base 10.     */
  { PSEUDO, "DEVICE", DEVICE },     /* Pack 6 bit device name into memory     */
  { PSEUDO, "DUBL",   DUBL    },    /* Ignored (unsupported).                 */
  { PSEUDO, "EJECT",  EJECT   },    /* Eject a page in the listing.           */
  { PSEUDO, "ENPUNC", ENPUNCH },    /* Turn on object code generation.        */
  { PSEUDO, "EXPUNG", EXPUNGE },    /* Remove all symbols from symbol table.  */
  { PSEUDO, "FIELD",  FIELD   },    /* Set origin to memory field.            */
  { PSEUDO, "FILENA", FILENAME },   /* Pack 6 bit filename into memory.       */
  { PSEUDO, "FIXMRI", FIXMRI  },    /* Like =, but creates mem ref instruction*/
  { PSEUDO, "FIXTAB", FIXTAB  },    /* Mark current symbols as permanent.     */
  { PSEUDO, "FLTG",   FLTG    },    /* Ignored (unsupported).                 */
  { PSEUDO, "IFDEF",  IFDEF   },    /* Assemble if symbol is defined.         */
  { PSEUDO, "IFNDEF", IFNDEF  },    /* Assemble if symbol is not defined.     */
  { PSEUDO, "IFNZER", IFNZERO },    /* Assemble if symbol value is not 0.     */
  { PSEUDO, "IFNZRO", IFNZERO },    /* Assemble if symbol value is not 0.     */
  { PSEUDO, "IFZERO", IFZERO  },    /* Assemble if symbol value is 0.         */
  { PSEUDO, "NOPUNC", NOPUNCH },    /* Turn off object code generation.       */
  { PSEUDO, "OCTAL",  OCTAL   },    /* Read literal constants in base 8.      */
  { PSEUDO, "PAGE",   PAGE    },    /* Set orign to page +1 or page n (0..37).*/
  { PSEUDO, "PAUSE",  PAUSE   },    /* Ignored                                */
  { PSEUDO, "RELOC",  RELOC   },    /* Assemble to run at a different address.*/
  { PSEUDO, "RIMPUN", RIMPUNCH },   /* Output in Read In Mode format.         */
  { PSEUDO, "SEGMNT", SEGMNT  },    /* Like page, but with page size=1K words.*/
  { PSEUDO, "TEXT",   TEXT    },    /* Pack 6 bit trimmed ASCII into memory.  */
  { PSEUDO, "XLIST",  XLIST   },    /* Toggle listing generation.             */
  { PSEUDO, "ZBLOCK", ZBLOCK  },    /* Zero a block of memory.                */
  { PSEUDO, "TITLE",  TITLE   },    /* Use the text string as a listing title.*/
  { PSEUDO, "BANK",   BANK    }     /* Like field, select some 32K out of 128K*/
};
/* Number o extended pseudo operators to ignore unless command option specified
 * to enable */
#define NUMBER_ADDITIONAL_PSEUDO 2

/* Symbol Table                                                               */
/* The table is put in lexical order on startup, so symbols can be            */
/* inserted as desired into the initial table.                                */
/* really_permanent_symbols aren't removed by EXPUNGE                         */
SYM_T really_permanent_symbols[] =
{
  { MRIFIX, "I",      00400   },    /* INDIRECT ADDRESSING                    */
  { MRIFIX, "Z",      00000   }     /* PAGE ZERO ADDRESS                      */
};

SYM_T permanent_symbols[] =
{
  /* Memory Reference Instructions                                            */
  { MRIFIX, "AND",    00000   },    /* LOGICAL AND                            */
  { MRIFIX, "TAD",    01000   },    /* TWO'S COMPLEMENT ADD                   */
  { MRIFIX, "ISZ",    02000   },    /* INCREMENT AND SKIP IF ZERO             */
  { MRIFIX, "DCA",    03000   },    /* DEPOSIT AND CLEAR ACC                  */
  { MRIFIX, "JMP",    05000   },    /* JUMP                                   */
  { MRIFIX, "JMS",    04000   },    /* JUMP TO SUBROUTINE                     */
  /* Floating Point Interpreter Instructions                                  */
  { MRIFIX, "FEXT",   00000   },    /* FLOATING EXIT                          */
  { MRIFIX, "FADD",   01000   },    /* FLOATING ADD                           */
  { MRIFIX, "FSUB",   02000   },    /* FLOATING SUBTRACT                      */
  { MRIFIX, "FMPY",   03000   },    /* FLOATING MULTIPLY                      */
  { MRIFIX, "FDIV",   04000   },    /* FLOATING DIVIDE                        */
  { MRIFIX, "FGET",   05000   },    /* FLOATING GET                           */
  { MRIFIX, "FPUT",   06000   },    /* FLOATING PUT                           */
  { FIXED,  "FNOR",   07000   },    /* FLOATING NORMALIZE                     */
  { FIXED,  "FEXT",   00000   },    /* EXIT FROM FLOATING POINT INTERPRETER   */
  { FIXED,  "SQUARE", 00001   },    /* SQUARE C(FAC)                          */
  { FIXED,  "SQROOT", 00002   },    /* TAKE SQUARE ROOT OF C(FAC)             */
  /* Group 1 Operate Microinstrcutions                                        */
  { FIXED,  "OPR",    07000   },    /* NO OPERATION                           */
  { FIXED,  "NOP",    07000   },    /* NO OPERATION                           */
  { FIXED,  "IAC",    07001   },    /* INCREMENT AC                           */
  { FIXED,  "RAL",    07004   },    /* ROTATE AC AND LINK LEFT ONE            */
  { FIXED,  "RTL",    07006   },    /* ROTATE AC AND LINK LEFT TWO            */
  { FIXED,  "RAR",    07010   },    /* ROTATE AC AND LINK RIGHT ONE           */
  { FIXED,  "RTR",    07012   },    /* ROTATE AC AND LINK RIGHT TWO           */
  { FIXED,  "CML",    07020   },    /* COMPLEMENT LINK                        */
  { FIXED,  "CMA",    07040   },    /* COMPLEMEMNT AC                         */
  { FIXED,  "CLL",    07100   },    /* CLEAR LINK                             */
  { FIXED,  "CLA",    07200   },    /* CLEAR AC                               */
  /* Group 2 Operate Microinstructions                                        */
  { FIXED,  "BSW",    07002   },    /* Swap bytes in AC (PDP/8e)              */
  { FIXED,  "HLT",    07402   },    /* HALT THE COMPUTER                      */
  { FIXED,  "OSR",    07404   },    /* INCLUSIVE OR SR WITH AC                */
  { FIXED,  "SKP",    07410   },    /* SKIP UNCONDITIONALLY                   */
  { FIXED,  "SNL",    07420   },    /* SKIP ON NON-ZERO LINK                  */
  { FIXED,  "SZL",    07430   },    /* SKIP ON ZERO LINK                      */
  { FIXED,  "SZA",    07440   },    /* SKIP ON ZERO AC                        */
  { FIXED,  "SNA",    07450   },    /* SKIP ON NON=ZERO AC                    */
  { FIXED,  "SMA",    07500   },    /* SKIP MINUS AC                          */
  { FIXED,  "SPA",    07510   },    /* SKIP ON POSITIVE AC (ZERO IS POSITIVE) */
  /* Combined Operate Microinstructions                                       */
  { FIXED,  "CIA",    07041   },    /* COMPLEMENT AND INCREMENT AC            */
  { FIXED,  "STL",    07120   },    /* SET LINK TO 1                          */
  { FIXED,  "GLK",    07204   },    /* GET LINK (PUT LINK IN AC BIT 11)       */
  { FIXED,  "STA",    07240   },    /* SET AC TO -1                           */
  { FIXED,  "LAS",    07604   },    /* LOAD ACC WITH SR                       */
  /* MQ Instructions (PDP/8e)                                                 */
  { FIXED,  "MQL",    07421   },    /* Load MQ from AC, then clear AC.        */
  { FIXED,  "MQA",    07501   },    /* Inclusive OR MQ with AC                */
  { FIXED,  "SWP",    07521   },    /* Swap AC and MQ                         */
  { FIXED,  "ACL",    07701   },    /* Load MQ into AC                        */
  /* Program Interrupt                                                        */
  { FIXED,  "IOT",    06000   },
  { FIXED,  "ION",    06001   },    /* TURN INTERRUPT PROCESSOR ON            */
  { FIXED,  "IOF",    06002   },    /* TURN INTERRUPT PROCESSOR OFF           */
  /* Program Interrupt, PDP-8/e                                               */
  { FIXED,  "SKON",   06000   },    /* Skip if interrupt on and turn int off. */
  { FIXED,  "SRQ",    06003   },    /* Skip on interrupt request.             */
  { FIXED,  "GTF",    06004   },    /* Get interrupt flags.                   */
  { FIXED,  "RTF",    06005   },    /* Restore interrupt flags.               */
  { FIXED,  "SGT",    06006   },    /* Skip on greater than flag.             */
  { FIXED,  "CAF",    06007   },    /* Clear all flags.                       */
  /* Keyboard/Reader                                                          */
  { FIXED,  "KCF",    06030   },    /* CLEAR KEYBOAR FLAG                     */
  { FIXED,  "KSF",    06031   },    /* SKIP ON KEYBOARD FLAG                  */
  { FIXED,  "KCC",    06032   },    /* CLEAR KEYBOARD FLAG & READ CHAR        */
  { FIXED,  "KRS",    06034   },    /* READ KEYBOARD BUFFER (STATIC)          */
  { FIXED,  "KIE",    06035   },    /* AC11 TO KEYBD/RDR INT ENABLE F/F       */
  { FIXED,  "KRB",    06036   },    /* READ KEYBOARD BUFFER & CLEAR FLAG      */
  /* Teleprinter/Punch                                                        */
  { FIXED,  "TFL",    06040   },    /* SET TELEPRINTER/PUNCH FLAG             */
  { FIXED,  "TSF",    06041   },    /* SKIP ON TELEPRINTER FLAG               */
  { FIXED,  "TCF",    06042   },    /* CLEAR TELEPRINTER FLAG                 */
  { FIXED,  "TPC",    06044   },    /* LOAD TELEPRINTER & PRINT               */
  { FIXED,  "TSK",    06045   },    /* SKIP IF TELETYPE INTERRUPT             */
  { FIXED,  "TLS",    06046   },    /* LOAD TELPRINTER & CLEAR FLAG           */
  /* High Speed Paper Tape Reader                                             */
  { FIXED,  "RSF",    06011   },    /* SKIP ON READER FLAG                    */
  { FIXED,  "RRB",    06012   },    /* READ READER BUFFER AND CLEAR FLAG      */
  { FIXED,  "RFC",    06014   },    /* READER FETCH CHARACTER                 */
  /* PC8-E High Speed Paper Tape Reader & Punch                               */
  { FIXED,  "RPE",    06010   },    /* Set interrupt enable for reader/punch  */
  { FIXED,  "PCE",    06020   },    /* Clear interrupt enable for rdr/punch   */
  { FIXED,  "RCC",    06016   },    /* Read reader buffer, clear flags & buf, */
                                    /* and fetch character.                   */
  /* High Speed Paper Tape Punch                                              */
  { FIXED,  "PSF",    06021   },    /* SKIP ON PUNCH FLAG                     */
  { FIXED,  "PCF",    06022   },    /* CLEAR ON PUNCH FLAG                    */
  { FIXED,  "PPC",    06024   },    /* LOAD PUNCH BUFFER AND PUNCH CHARACTER* */
  { FIXED,  "PLS",    06026   },    /* LOAD PUNCH BUFFER AND CLEAR FLAG       */

  /* DECassette TU60 (RK 20071008)                                            */
  { FIXED,  "KCLR",   06700   },    /* Clear all (clear A and B)              */
  { FIXED,  "KSDR",   06701   },    /* Skip if data flag set                  */
  { FIXED,  "KSEN",   06702   },    /* Skip if EOT/BOT, not ready, or empty   */
  { FIXED,  "KSBF",   06703   },    /* Skip if ready flag set                 */
  { FIXED,  "KLSA",   06704   },    /* AC4-11 -> A, clear A, -(AC4-11) -> A   */
  { FIXED,  "KSAF",   06705   },    /* Skip on any flag or error              */
  { FIXED,  "KGOA",   06706   },    /* Assert status A and transfer data to AC*/
  { FIXED,  "KRSB",   06707   },    /* Transfer B -> AC4-11                   */

  /* DECtape Transport Type TU55 and DECtape Control Type TC01                */
  { FIXED,  "DTRA",   06761   },    /* Contents of status register is ORed    */
                                    /* into AC bits 0-9                       */
  { FIXED,  "DTCA",   06762   },    /* Clear status register A, all flags     */
                                    /* undisturbed                            */
  { FIXED,  "DTXA",   06764   },    /* Status register A loaded by exclusive  */
                                    /* OR from AC.  If AC bit 10=0, clear     */
                                    /* error flags; if AC bit 11=0, DECtape   */
                                    /* control flag is cleared.               */
  { FIXED,  "DTLA",   06766   },    /* Combination of DTCA and DTXA           */
  { FIXED,  "DTSF",   06771   },    /* Skip if error flag is 1 or if DECtape  */
                                    /* control flag is 1                      */
  { FIXED,  "DTRB",   06772   },    /* Contents of status register B is       */
                                    /* ORed into AC                           */
  { FIXED,  "DTLB",   06774   },    /* Memory field portion of status         */
                                    /* register B loaded from AC bits 6-8     */
  /* Disk File and Control, Type DF32                                         */
  { FIXED,  "DCMA",   06601   },    /* CLEAR DISK MEMORY REQUEST AND          */
                                    /* INTERRUPT FLAGS                        */
  { FIXED,  "DMAR",   06603   },    /* LOAD DISK FROM AC, CLEAR AC READ       */
                                    /* INTO CORE, CLEAR INTERRUPT FLAG        */
  { FIXED,  "DMAW",   06605   },    /* LOAD DISK FROM AC, WRITE ONTO DISK     */
                                    /* FROM CORE, CLEAR INTERRUPT FLAG        */
  { FIXED,  "DCEA",   06611   },    /* CLEAR DISK EXTENDED ADDRESS AND        */
  { FIXED,  "DSAC",   06612   },    /* SKIP IF ADDRESS CONFIRMED FLAG = 1     */
                                    /* MEMORY ADDRESS EXTENSION REGISTER      */
  { FIXED,  "DEAL",   06615   },    /* CLEAR DISK EXTENDED ADDRESS AND        */
                                    /* MEMORY ADDRESS EXTENSION REGISTER      */
                                    /* AND LOAD SAME FROM AC                  */
  { FIXED,  "DEAC",   06616   },    /* CLEAR AC, LOAD AC FROM DISK EXTENDED   */
                                    /* ADDRESS REGISTER, SKIP IF ADDRESS      */
                                    /* CONFIRMED FLAG = 1                     */
  { FIXED,  "DFSE",   06621   },    /* SKIP IF PARITY ERROR, DATA REQUEST     */
                                    /* LATE, OR WRITE LOCK SWITCH FLAG = 0    */
                                    /* (NO ERROR)                             */
  { FIXED,  "DFSC",   06622   },    /* SKIP IF COMPLETION FLAG = 1 (DATA      */
                                    /* TRANSFER COMPLETE)                     */
  { FIXED,  "DMAC",   06626   },    /* CLEAR AC, LOAD AC FROM DISK MEMORY     */
                                    /* ADDRESS REGISTER                       */
  /* Disk File and Control, Type RF08                                         */
  { FIXED,  "DCIM",   06611   },
  { FIXED,  "DIML",   06615   },
  { FIXED,  "DIMA",   06616   },
  { FIXED,  "DISK",   06623   },
  { FIXED,  "DCXA",   06641   },
  { FIXED,  "DXAL",   06643   },
  { FIXED,  "DXAC",   06645   },
  { FIXED,  "DMMT",   06646   },
  /* Memory Extension Control, Type 183                                       */
  { FIXED,  "CDF",    06201   },    /* CHANGE DATA FIELD                      */
  { FIXED,  "CIF",    06202   },    /* CHANGE INSTRUCTION FIELD               */
  { FIXED,  "CDI",    06203   },    /* Change data & instrution field.        */
  { FIXED,  "RDF",    06214   },    /* READ DATA FIELD                        */
  { FIXED,  "RIF",    06224   },    /* READ INSTRUCTION FIELD                 */
  { FIXED,  "RIB",    06234   },    /* READ INTERRUPT BUFFER                  */
  { FIXED,  "RMF",    06244   },    /* RESTORE MEMORY FIELD                   */
  /* Memory Parity, Type MP8/I (MP8/L)                                        */
  { FIXED,  "SMP",    06101   },    /* SKIP IF MEMORY PARITY FLAG = 0         */
  { FIXED,  "CMP",    06104   },    /* CLEAR MEMORY PAIRTY FLAG               */
  /* Memory Parity, Type MP8-E (PDP8/e)                                       */
  { FIXED,  "DPI",    06100   },    /* Disable parity interrupt.              */
  { FIXED,  "SNP",    06101   },    /* Skip if no parity error.               */
  { FIXED,  "EPI",    06103   },    /* Enable parity interrupt.               */
  { FIXED,  "CNP",    06104   },    /* Clear parity error flag.               */
  { FIXED,  "CEP",    06106   },    /* Check for even parity.                 */
  { FIXED,  "SPO",    06107   },    /* Skip on parity option.                 */
  /* Data Communications Systems, Type 680I                                   */
  { FIXED,  "TTINCR", 06401   },    /* The content of the line select         */
                                    /* register is incremented by one.        */
  { FIXED,  "TTI",    06402   },    /* The line status word is read and       */
                                    /* sampled.  If the line is active for    */
                                    /* the fourth time, the line bit is       */
                                    /* shifted into the character assembly    */
                                    /* word.  If the line bit is active for   */
                                    /* a number of times less than four,      */
                                    /* the count is incremented.  If the      */
                                    /* line is not active, the active/inac-   */
                                    /* tive status of the line is recorded    */
  { FIXED,  "TTO",    06404   },    /* The character in the AC is shifted     */
                                    /* right one position, zeros are shifted  */
                                    /* into vacated positions, and the orig-  */
                                    /* inal content of AC11 is transferred    */
                                    /* out of the computer on the TTY line.   */
  { FIXED,  "TTCL",   06411   },    /* The line select register is cleared.   */
  { FIXED,  "TTSL",   06412   },    /* The line select register is loaded by  */
                                    /* an OR transfer from the content of     */
                                    /* of AC5-11, the the AC is cleared.      */
  { FIXED,  "TTRL",   06414   },    /* The content of the line select regis-  */
                                    /* ter is read into AC5-11 by an OR       */
                                    /* transfer.                              */
  { FIXED,  "TTSKP",  06421   },    /* Skip if clock flag is a 1.             */
  { FIXED,  "TTXON",  06424   },    /* Clock 1 is enabled to request a prog-  */
                                    /* ram interrupt and clock 1 flag is      */
                                    /* cleared.                               */
  { FIXED,  "TTXOF",  06422   },    /* Clock 1 is disabled from causing a     */
                                    /* program interrupt and clock 1 flag     */
                                    /* is cleared.                            */
};      /* End-of-Symbols for Permanent Symbol Table                          */

/* Global variables                                                           */
SYM_T *symtab;                  /* Symbol Table                               */
int    symbol_top;              /* Number of entries in symbol table.         */

SYM_T *fixed_symbols;           /* Start of the fixed symbol table entries.   */
int    number_of_fixed_symbols;

/*----------------------------------------------------------------------------*/

WORD16 *xreftab;                /* Start of the concordance table.            */

ERRSAVE_T error_list[20];
int     save_error_count;

#define GET_PAGE_INDEX(x) (((x) & 07600) >> 7)
#define MAX_PAGES 32
LPOOL_T cp[MAX_PAGES];             /* Storage for page constants.       */
int     max_page_used[MAX_PAGES];

char   s_detected[] = "detected";
char   s_error[]    = "error";
char   s_errors[]   = "errors";
char   s_no[]       = "No";
char   s_page[]     = "Page";
char   s_symtable[] = "Symbol Table";
char   s_xref[]     = "Cross Reference";
char   s_generated[] = "generated";
char   s_link[]    = "link";
char   s_links[]   = "links";

/* Assembler diagnostic messages.                                             */
/* Some attempt has been made to keep continuity with the PAL-III and         */
/* MACRO-8 diagnostic messages.  If a diagnostic indicator, (e.g., IC)        */
/* exists, then the indicator is put in the listing as the first two          */
/* characters of the diagnostic message.  The PAL-III indicators where used   */
/* when there was a choice between using MACRO-8 and PAL-III indicators.      */
/* The character pairs and their meanings are:                                */
/*      DT  Duplicate Tag (symbol)                                            */
/*      IC  Illegal Character                                                 */
/*      ID  Illegal Redefinition of a symbol.  An attempt was made to give    */
/*          a symbol a new value not via =.                                   */
/*      IE  Illegal Equals  An equal sign was used in the wrong context,      */
/*          (e.g., A+B=C, or TAD A+=B)                                        */
/*      II  Illegal Indirect  An off page reference was made, but a literal   */
/*          could not be generated because the indirect bit was already set.  */
/*      IR  Illegal Reference (address is not on current page or page zero)   */
/*      ND  No $ (the program terminator) at end of file.                     */
/*      PE  Current, Non-Zero Page Exceeded (literal table flowed into code)  */
/*      RD  ReDefintion of a symbol                                           */
/*      ST  Symbol Table full                                                 */
/*      UA  Undefined Address (undefined symbol)                              */
/*      ZE  Zero Page Exceeded (see above, or out of space)                   */
EMSG_T  duplicate_label     = { "DT duplicate",  "duplicate label" };
EMSG_T  illegal_blank       = { "IC illegal blank", "illegal blank" };
EMSG_T  illegal_character   = { "IC illegal char",  "illegal character" };
EMSG_T  illegal_expression  = { "IC in expression", "illegal expression" };
EMSG_T  label_syntax        = { "IC label syntax",  "label syntax" };
EMSG_T  not_a_number        = { "IC numeric syntax", "numeric syntax of" };
EMSG_T  number_not_radix    = { "IC radix", "number not in current radix"};
EMSG_T  symbol_syntax       = { "IC symbol syntax", "symbol syntax" };
EMSG_T  illegal_equals      = { "IE illegal =",  "illegal equals" };
EMSG_T  illegal_indirect    = { "II off page",   "illegal indirect" };
EMSG_T  illegal_reference   = { "IR off page",   "illegal reference" };
EMSG_T  undefined_symbol    = { "UD undefined",  "undefined symbol" };
EMSG_T  redefined_symbol    = { "RD redefined",  "redefined symbol" };
EMSG_T  illegal_redefine    = { "ID redefined",  "Illegal redefine of symbol" };
EMSG_T  literal_overflow    = { "PE page exceeded",
                                   "current page literal capacity exceeded" };
EMSG_T  pz_literal_overflow = { "ZE page exceeded",
                                   "page zero capacity exceeded" };
EMSG_T  dubl_overflow       = { "dubl overflow",  "DUBL value overflow" };
EMSG_T  fltg_overflow       = { "fltg overflow",  "FLTG value overflow" };
EMSG_T  zblock_too_small    = { "expr too small", "ZBLOCK value too small" };
EMSG_T  zblock_too_large    = { "expr too large", "ZBLOCK value too large" };
EMSG_T  end_of_file         = { "ND no $ at EOF", "No $ at End-of-File" };
EMSG_T  no_pseudo_op        = { "not implemented",
                                   "not implemented pseudo-op" };
EMSG_T  illegal_field_value = { "expr out of range",
                                   "field value not in range of 0 through 7" };
EMSG_T  literal_gen_off     = { "literals off",
                                                "literal generation is off" };
EMSG_T  no_literal_value    = { "no value",  "no literal value" };
EMSG_T  text_string         = { "no delimiter",
                                    "text string delimiters not matched" };
EMSG_T  in_rim_mode         = { "not OK in rim mode"
                                    "FIELD pseudo-op not valid in RIM mode" };
EMSG_T  lt_expected         = { "'<' expected",  "'<' expected" };
EMSG_T  symbol_table_full   = { "ST Symbol Tbl Full",
                                                    "Symbol Table Full" };
/*----------------------------------------------------------------------------*/

FILE   *errorfile;
FILE   *infile;
FILE   *listfile;
FILE   *listsave;
FILE   *objectfile;
FILE   *objectsave;

char    errorpathname[NAMELEN];
char    filename[NAMELEN];
char    listpathname[NAMELEN];
char    objectpathname[NAMELEN];
char   *pathname;
char    permpathname[NAMELEN];

int     tabstops;               /* number of characters to expand a tab to   */
int     list_lineno;
int     list_pageno;
char    list_title[LINELEN];
BOOL    list_title_set;         /* Set if TITLE pseudo-op used.               */
char    line[LINELEN];          /* Input line.                                */
int     lineno;                 /* Current line number.                       */
int     page_lineno;            /* print line number on current page.         */
BOOL    listed;                 /* Listed flag.                               */
BOOL    listedsave;

int     cc;                     /* Column Counter (char position in line).    */
WORD16  checksum;               /* Generated checksum                         */
BOOL    binary_data_output;     /* Set true when data has been output.        */
WORD16  clc;                    /* Location counter                           */
WORD16  cplc;                   /* Current page literal counter.              */
char    delimiter;              /* Character immediately after eval'd term.   */
int     errors;                 /* Number of errors found so far.             */
int     links;                  /* Number of links generated so far.          */
BOOL    error_in_line;          /* TRUE if error on current line.             */
int     errors_pass_1;          /* Number of errors on pass 1.                */
WORD16  field;                  /* Current field                              */
WORD16  fieldlc;                /* location counter without field portion.    */
BOOL    fltg_input;             /* TRUE when doing floating point input.      */
BOOL    indirect_generated;     /* TRUE if an off page address generated.     */
int     last_xref_lexstart;     /* Column where last xref symbol was located. */
int     last_xref_lineno;       /* Line where last xref symbol was located.   */
int     lexstartprev;           /* Where previous lexeme started.             */
int     lextermprev;            /* Where previous lexeme ended.               */
int     lexstart;               /* Index of current lexeme on line.           */
int     lexterm;                /* Index of character after current lexeme.   */
BOOL    literals_ok;            /* Generate literals, ignore ID redefine err  */
BOOL    perm_redef_error;       /* Make redefining perm sym with labels error */
int     maxcc;                  /* Current line length.                       */
BOOL    overflow;               /* Overflow flag for math routines.           */
int     pass;                   /* Number of current pass.                    */
BOOL    print_permanent_symbols;
WORD16  pzlc;                   /* Page Zero literal counter.                 */
WORD16  radix;                  /* Default number radix.                      */
WORD16  reloc;                  /* The relocation distance.                   */
BOOL    rim_mode;               /* Generate rim format, defaults to bin       */
BOOL    dollar_not_required;    /* $ not required at end of file              */
BOOL    additional_enabled;     /* True if extended functions over PAL8       */
                                /* enabled                                    */
BOOL    symtab_print;           /* Print symbol table flag                    */
BOOL    xref;

FLTG_T  fltg_ac;                /* Value holder for evalFltg()                */
SYM_T   sym_eval = { DEFINED, "", 0 };       /* Value holder for eval()       */
SYM_T   sym_getexpr = { DEFINED, "", 0 };    /* Value holder for getexpr()    */
SYM_T   sym_undefined = { UNDEFINED, "", 0 };/* Symbol Table Terminator       */


/******************************************************************************/
/*                                                                            */
/*  Function:  main                                                           */
/*                                                                            */
/*  Synopsis:  Starting point.  Controls order of assembly.                   */
/*                                                                            */
/******************************************************************************/
int main( int argc, char *argv[] )
{
  int     ix;
  int     space;

  /* Set the default values for global symbols.                               */
  binary_data_output = FALSE;
  fltg_input = FALSE;
  literals_ok = TRUE;
  perm_redef_error = FALSE;
  print_permanent_symbols = FALSE;
  rim_mode = FALSE;
  dollar_not_required = FALSE;
  additional_enabled = FALSE;
  symtab_print = FALSE;
  xref = FALSE;
  pathname = NULL;

  /* Get the options and pathnames                                            */
  getArgs( argc, argv );

  /* Setup the error file in case symbol table overflows while installing the */
  /* permanent symbols.                                                       */
  errorfile = fopen( errorpathname, "w" );
  if (errorfile == NULL) {
    fprintf( stderr, "Could not open error file %s: %s\n", errorpathname, strerror(errno));
    exit( -1 );

  }
  errors = 0;
  save_error_count = 0;
  pass = 0;             /* This is required for symbol table initialization.  */
  symtab = (SYM_T *) malloc( sizeof( SYM_T ) * SYMBOL_TABLE_SIZE );

  if( symtab == NULL )
  {
    fprintf( stderr, "Could not allocate memory for symbol table.\n");
    exit( -1 );
  }

  /* Place end marker in symbol table.                                        */
  symtab[0] = sym_undefined;
  symbol_top = 0;
  number_of_fixed_symbols = symbol_top;
  fixed_symbols = &symtab[symbol_top - 1];

  /* Enter the pseudo-ops into the symbol table                               */
  for( ix = 0; ix < DIM( pseudo ) - 
        (additional_enabled ? 0 : NUMBER_ADDITIONAL_PSEUDO) ; ix++ )
  {
    defineSymbol( pseudo[ix].name, pseudo[ix].val, pseudo[ix].type, 0 );
  }

  /* Enter the predefined symbols into the table.                             */
  /* Also make them part of the permanent symbol table.                       */
  for( ix = 0; ix < DIM( really_permanent_symbols ); ix++ )
  {
    defineSymbol( really_permanent_symbols[ix].name,
                  really_permanent_symbols[ix].val,
                  really_permanent_symbols[ix].type | DEFFIX , 0 );
  }

  /* Enter the predefined symbols into the table.                             */
  /* Also make them part of the permanent symbol table.                       */
  for( ix = 0; ix < DIM( permanent_symbols ); ix++ )
  {
    defineSymbol( permanent_symbols[ix].name,
                  permanent_symbols[ix].val,
                  permanent_symbols[ix].type | DEFFIX , 0 );
  }

  number_of_fixed_symbols = symbol_top;
  fixed_symbols = &symtab[symbol_top - 1];

  /* Do pass one of the assembly                                              */
  checksum = 0;
  pass = 1;
  page_lineno = LIST_LINES_PER_PAGE;
  onePass();
  errors_pass_1 = errors;

  /* Set up for pass two                                                      */
  rewind( infile );
  /*Opened in main errorfile = fopen( errorpathname, "w" );*/
  objectfile = fopen( objectpathname, "wb" );
  if (objectfile == NULL) {
    fprintf( stderr, "Could not open object file %s: %s\n", objectpathname, strerror(errno));
    exit( -1 );

  }
  objectsave = objectfile;

  listfile = fopen( listpathname, "w" );
  if (listfile == NULL) {
    fprintf( stderr, "Could not open list file %s: %s\n", listpathname, strerror(errno));
    exit( -1 );

  }
  listsave = NULL;

  punchLeader( 0 );
  checksum = 0;

  /* Do pass two of the assembly                                              */
  errors = 0;
  save_error_count = 0;
  page_lineno = LIST_LINES_PER_PAGE;

  if( xref )
  {
    /* Get the amount of space that will be required for the concordance.     */
    for( space = 0, ix = 0; ix < symbol_top; ix++ )
    {
      symtab[ix].xref_index = space;    /* Index into concordance table.      */
      space += symtab[ix].xref_count + 1;
      symtab[ix].xref_count = 0;        /* Clear the count for pass 2.        */

    }
    /* Allocate the necessary space.                                          */
    xreftab = (WORD16 *) malloc( sizeof( WORD16 ) * space );

    /* Clear the cross reference space.                                       */
    for( ix = 0; ix < space; ix++ )
    {
      xreftab[ix] = 0;
    }
  }
  pass = 2;
  onePass();

  /* Undo effects of NOPUNCH for any following checksum                       */
  objectfile = objectsave;
  punchChecksum();

  /* Works great for trailer.                                                 */
  punchLeader( 8 );

  /* undo effects of XLIST for any following output to listing file.          */
  if( listfile == NULL )
  {
    listfile = listsave;
  }

  /* Display value of error counter.                                          */
  if( errors == 0 )
  {
    fprintf( listfile, "\n      %s %s %s\n", s_no, s_detected, s_errors );
  }
  else
  {
    fprintf( errorfile, "\n      %d %s %s\n", errors, s_detected,
                                        ( errors == 1 ? s_error : s_errors ));
    fprintf( listfile, "\n      %d %s %s\n", errors, s_detected,
                                        ( errors == 1 ? s_error : s_errors ));
    fprintf( stderr,   "      %d %s %s\n", errors, s_detected,
                                        ( errors == 1 ? s_error : s_errors ));
  }
  /* Display value of link counter.                                          */
  if( links == 0 )
  {
    fprintf( listfile, "      %s %s %s\n", s_no, s_links, s_generated );
  }
  else
  {
    fprintf( errorfile, "      %d %s %s\n", links, 
                                        ( links == 1 ? s_link : s_links ), 
                                        s_generated);
    fprintf( listfile, "      %d %s %s\n", links, 
                                        ( links == 1 ? s_link : s_links ), 
                                        s_generated);
    fprintf( stderr, "      %d %s %s\n", links, 
                                        ( links == 1 ? s_link : s_links ), 
                                        s_generated);
  }

  if( symtab_print )
  {
    printSymbolTable();
  }

  if( print_permanent_symbols )
  {
    printPermanentSymbolTable();
  }

  if( xref )
  {
    printCrossReference();
  }

  fclose( objectfile );
  fclose( listfile );
  fclose( errorfile );
  if( errors == 0 && errors_pass_1 == 0 )
  {
    remove( errorpathname );
  }

  return( errors != 0 );
} /* main()                                                                   */

/******************************************************************************/
/*                                                                            */
/*  Function:  getArgs                                                        */
/*                                                                            */
/*  Synopsis:  Parse command line, set flags accordingly and setup input and  */
/*             output files.                                                  */
/*                                                                            */
/******************************************************************************/
void getArgs( int argc, char *argv[] )
{
  int  len;
  int  ix, jx;

  /* Set the defaults                                                         */
  errorfile = NULL;
  infile = NULL;
  listfile = NULL;
  listsave = NULL;
  objectfile = NULL;
  objectsave = NULL;
  tabstops = 8;

  for( ix = 1; ix < argc; ix++ )
  {
    if( argv[ix][0] == '-' )
    {
      for( jx = 1; argv[ix][jx] != 0; jx++ )
      {
        switch( argv[ix][jx] )
        {
        case '$':
          dollar_not_required = TRUE;
          break;

        case 'd':
          symtab_print = TRUE;
          break;

        case 'a':
          additional_enabled = TRUE;
          break;

        case 'r':
          rim_mode = TRUE;
          break;

        case 'e':
          literals_ok = FALSE;
          break;

        case 'l':
          literals_ok = TRUE;
          break;

        case 'n':
          perm_redef_error = TRUE;
          break;

        case 'p':
          print_permanent_symbols = TRUE;
          break;

        /* Added -tN; RK 20071029 */
        /* Damn, this is ugly, we should use getopt() */
        case 't':
          if (argv [ix][jx + 1]) {
            tabstops = atoi (argv [ix] + (jx + 1));
            /* advance past numbers */
            for (jx++; argv [ix][jx]; jx++) ;
            jx--;
          } else {
            ix++;
            if (ix >= argc) {
              fprintf( stderr, "%s: missing argument for -t, expected number of tabsopts\n", argv[0] );
              exit( -1 );
            }
            for (jx = 0; argv [ix][jx]; jx++) ;
            jx--;
            tabstops = atoi (argv [ix]);
          }
          break;

        case 'x':
          xref = TRUE;
          break;

        case 'v':
          fprintf( stderr, "%s\n", release );
          fflush( stderr );
          exit( -1 );
          break;

        default:
          fprintf( stderr, "%s: unknown flag: %s\n", argv[0], argv[ix] );
        case 'h':
          fprintf( stderr, " -$ -- allow file to not end with $\n" );
          fprintf( stderr, " -a -- enable additional function not in PAL8\n" );
          fprintf( stderr, " -d -- dump symbol table\n" );
          fprintf( stderr, " -e -- error if link generated\n" );
          fprintf( stderr, " -h -- show this help\n" );
          fprintf( stderr, " -l -- generate literal/link (default)\n" );
          fprintf( stderr, " -n -- no redefining with label permanent symbols\n" );
          fprintf( stderr, " -p -- output permanent symbols to file\n" );
          fprintf( stderr, " -r -- output rim format file\n" );
          fprintf( stderr, " -t N -- set tab stops to N\n" );
          fprintf( stderr, " -v -- display version\n" );
          fprintf( stderr, " -x -- output cross reference to file\n" );
          fflush( stderr );
          exit( -1 );
        } /* end switch                                                       */
      } /* end for                                                            */
    }
    else
    {
      if( pathname != NULL )
      {
        fprintf( stderr, "%s: too many input files\n", argv[0] );
        exit( -1 );
      }
      pathname = &argv[ix][0];
    }
  } /* end for                                                                */

  if( pathname == NULL )
  {
    fprintf( stderr, "%s:  no input file specified\n", argv[0] );
    exit( -1 );
  }

  len = strlen( pathname );
  if( len > NAMELEN - 5 )
  {
    fprintf( stderr, "%s: pathname \"%s\" too long\n", argv[0], pathname );
    exit( -1 );
  }

  /* Now open the input file.                                                 */
  if(( infile = fopen( pathname, "r" )) == NULL )
  {
    fprintf( stderr, "%s: cannot open \"%s\": %s\n", argv[0], pathname, strerror(errno) );
    exit( -1 );
  }

  /* Now make the pathnames                                                   */
  /* Find last '.', if it exists.                                             */
  jx = len - 1;
  while( pathname[jx] != '.'  && pathname[jx] != '/'
      && pathname[jx] != '\\' && jx >= 0 )
  {
    jx--;
  }

  switch( pathname[jx] )
  {
  case '.':
    break;

  case '/':
  case '\\':
    jx = len;
    break;

  default:
    break;
  }

  /* Add the pathname extensions.                                             */
  strncpy( objectpathname, pathname, jx );
  objectpathname[jx] = '\0';
  strcat( objectpathname, rim_mode ? ".rim" : ".bin" );

  strncpy( listpathname, pathname, jx );
  listpathname[jx] = '\0';
  strcat( listpathname, ".lst" );

  strncpy( errorpathname, pathname, jx );
  errorpathname[jx] = '\0';
  strcat( errorpathname, ".err" );

  strncpy( permpathname, pathname, jx );
  permpathname[jx] = '\0';
  strcat( permpathname, ".prm" );

  /* Extract the filename from the path.                                      */
  if( isalpha( pathname[0] ) && pathname[1] == ':' && pathname[2] != '\\' )
  {
    pathname[1] = '\\';         /* MS-DOS style pathname                      */
  }

  jx = len - 1;
  while( pathname[jx] != '/' && pathname[jx] != '\\' && jx >= 0 )
  {
    jx--;
  }
  strcpy( filename, &pathname[jx + 1] );

} /* getArgs()                                                                */

/******************************************************************************/
/*                                                                            */
/*  Function:  clearLiteralTable                                              */
/*                                                                            */
/*  Synopsis:  Clear the cp and max_page_used data storing literal            */
/*             information.                                                   */
/*                                                                            */
/******************************************************************************/
void clearLiteralTable()
{
  int i;

  for (i = 0; i < DIM(cp); i++)
  {
    cp[i].loc = 0200;             /* Points to end of page for [] operands.  */
    cp[i].last_punched = 0200;    /* Points to end of page for [] operands.  */
  }
  memset(max_page_used, 0, sizeof(max_page_used));
}

/******************************************************************************/
/*                                                                            */
/*  Function:  onePass                                                        */
/*                                                                            */
/*  Synopsis:  Do one assembly pass.                                          */
/*                                                                            */
/******************************************************************************/
void onePass()
{
  char    name[SYMLEN];
  WORD16  newclc;
  BOOL    scanning_line;
  int     start;
  SYM_T  *sym;
  int     term;
  WORD16  val;

  clc = 0200;                   /* Default starting address is 200 octal.     */
  field = 0;
  fieldlc = clc & 07777;
  reloc = 0;
  clearLiteralTable();
  listed = TRUE;
  lineno = 0;
  list_pageno = 0;
  list_lineno = 0;
  last_xref_lexstart = 0;
  last_xref_lineno = 0;
  list_title_set = FALSE;
  radix = 8;                    /* Initial radix is octal (base 8).           */

  if( !rim_mode )
  {
    /* Put out initial origin if not in rim mode.                             */
    punchOrigin( clc );
  }

  while( TRUE )
  {
    readLine();
    nextLexeme();

    scanning_line = TRUE;
    while( scanning_line )
    {
      if( isend( line[lexstart] ))
      {
        scanning_line = FALSE;
      }
      else
      {
        switch( line[lexstart] )
        {
        case '/':
          scanning_line = FALSE;
          break;

        case ';':
          nextLexeme();
          break;

        case '$':
          endOfBinary();
          return;

        case '*':
          nextLexeme();             /* Skip '*', (set origin symbol)          */
          newclc = ((getExpr())->val & 07777 ) | field;
          /* Do not change Current Location Counter if an error occurred.     */
          if( !error_in_line )
          {
            if(( newclc & 07600 ) != ( clc & 07600 ) ) 
            {
              /* Current page has changed.                                    */
              punchLiteralPool( cp, 0 );
            }
            clc = newclc - reloc;
            fieldlc = clc & 07777;

            if( !rim_mode )
            {
              /* Not rim mode, put out origin.                                */
              punchOrigin( clc );
            }
            printLine( line, 0, fieldlc, LINE_VAL );
          }
          break;

        default:
          switch( line[lexterm] )
          {
          case ',':
            if( isalpha( line[lexstart] ))
            {
              /* Use lookup so symbol will not be counted as reference.       */
              sym = lookup( lexemeToName( name, lexstart, lexterm ));
              if( M_DEFINED( sym->type ))
              {
                if( (sym->val & 07777) != ( ( clc+reloc ) & 07777) && pass == 2 )
                {
                  errorSymbol( &duplicate_label, sym->name, lexstart );
                }
                sym->type = sym->type | DUPLICATE;
              }
              /* Must call define on pass 2 to generate concordance.          */
              defineLexeme( lexstart, lexterm, ( clc + reloc ), LABEL );
            }
            else
            {
              errorLexeme( &label_syntax, lexstart );
            }
            nextLexeme();           /* skip label                             */
            nextLexeme();           /* skip comma                             */
            break;

          case '=':
            if( isalpha( line[lexstart] ))
            {
              start = lexstart;
              term = lexterm;
              delimiter = line[lexterm];
              nextLexBlank();       /* skip symbol                            */
              nextLexeme();         /* skip trailing =, allow blank           */
              delimiter = line[lexterm];
              val = getExprs();
              defineLexeme( start, term, val, DEFINED );
              printLine( line, 0, val, LINE_VAL );
            }
            else
            {
              errorLexeme( &symbol_syntax, lexstartprev );
              nextLexeme();         /* skip symbol                            */
              nextLexeme();         /* skip trailing =                        */
              getExprs();           /* skip expression                        */
            }
            break;

          default:
            if( isalpha( line[lexstart] ))
            {
              sym = evalSymbol();
              val = sym->val;
              if( M_PSEUDO( sym->type ))
              {
                nextLexeme();         /* Skip symbol                          */
                scanning_line = pseudoOperators( (PSEUDO_T)val & 07777 );
              }
              else
              {
                /* Identifier is not a pseudo-op, interpret as load value     */
                punchOutObject( clc, getExprs() & 07777 );
                incrementClc();
              }
            }
            else
            {
              /* Identifier is a value, interpret as load value               */
              punchOutObject( clc, getExprs() & 07777 );
              incrementClc();
            }
            break;
          } /* end switch                                                     */
          break;
        } /* end switch                                                       */
      } /* end if                                                             */
    } /* end while( scanning_line )                                           */
  } /* end while( TRUE )                                                      */
} /* onePass()                                                                */


/******************************************************************************/
/*                                                                            */
/*  Function:  fixMRIInstruction                                              */
/*                                                                            */
/*  Synopsis:  Now that we have the final value figure out if page 0, current */
/*             page, or indirect needed and max final instruction             */
/*                                                                            */
/******************************************************************************/
WORD16 fixMRIInstruction(WORD16 instruction, WORD16 value)
{
        /* Now have the address part of the MRI instruction.                  */
        if( value < 00200 )
        {
          instruction |= value;        /* Page zero MRI.                             */
        }
        else if( (( fieldlc + reloc ) & 07600 ) <= value
             && value <= ((( fieldlc + reloc ) & 07600) | 0177 ))
        {
          instruction |= ( PAGE_BIT | (value & ADDRESS_FIELD )); /* Current page MRI */
        }
        else
        {
          if(( instruction & INDIRECT_BIT ) == INDIRECT_BIT )
          {
            /* Already indirect, can't generate                               */
            errorSymbol( &illegal_indirect, NULL, lexstartprev );
          }
          else
          {
            if( literals_ok )
            {
              /* Now fix off page reference.                                  */
              /* Search current page literal pool for needed instruction.           */
              /* Set Indirect Current Page                                    */
              instruction |= ( 00600 | insertLiteral( cp, value, GET_PAGE_INDEX(clc) ));
              indirect_generated = TRUE;
              if (pass == 2)
              {
                links++;
              }
            }
            else
            {
              errorSymbol( &illegal_reference, NULL, lexstartprev );
              instruction |= ( value & 0177 );
            }
          }
        }
   return instruction;
}
/******************************************************************************/
/*                                                                            */
/*  Function:  getExprs                                                       */
/*                                                                            */
/*  Synopsis:  Or together a list of blank separated expressions, from the    */
/*             current lexeme onward.  Leave the current lexeme as            */
/*             the last one in the list.                                      */
/*                                                                            */
/******************************************************************************/
WORD16 getExprs()
{
  SYM_T  *symv;
  SYM_T  *symt;
  WORD16  temp;
  SYMTYP  temp_type;
  WORD16  value;
  SYMTYP  value_type;
  BOOL    MRI_held = FALSE;
  WORD16  held_value = 0;

  symv = getExpr();
  value = symv->val;
  value_type = symv->type;

  while( TRUE )
  {
    if( isdone( line[lexstart] ))
    {
      if (MRI_held)
      {
        value = fixMRIInstruction(value, held_value);
      }
      return( value );
    }
    switch( line[lexstart] )
    {
    case ')':
    case ']':
    case '<':
      if (MRI_held)
      {
        value = fixMRIInstruction(value, held_value);
      }
      return( value );

    default:
      break;
    }

    /* Interpret space as logical or                                          */
    symt = getExpr();
    temp = symt->val & 07777;
    temp_type = symt->type;

    switch( value_type & (MRI | MRIFIX))
    {
    case MRI:
    case MRIFIX:
      /* Previous symbol was a Memory Reference Instruction.                  */
      switch( temp_type & (MRI | MRIFIX) )
      {
      case MRI:
      case MRIFIX:
        /* If we have held value don't or in more MRI's to instuction, they */
        /* are now instuction value */
        if (MRI_held)
        {
          held_value |= temp;
        }
        else
        { 
          /* Current symbol is also a Memory Reference Instruction.           */
          value |= temp;          /* Just OR the MRI instructions.            */
        }
        break;

      default:
        held_value |= temp;
        MRI_held = TRUE;
        break;
      }
      break;

    default:
        if (value_type == UNDEFINED || temp_type == UNDEFINED) {
            value = 0;
        } else {
            value |= temp;          /* Normal 12 bit value.                       */
         }
        break;
    }
  } /* end while                                                              */
} /* getExprs()                                                               */


/******************************************************************************/
/*                                                                            */
/*  Function:  getExpr                                                        */
/*                                                                            */
/*  Synopsis:  Get an expression, from the current lexeme onward, leave the   */
/*             current lexeme as the one after the expression.  Expressions   */
/*             contain terminal symbols (identifiers) separated by operators. */
/*                                                                            */
/******************************************************************************/
SYM_T *getExpr()
{
  SYM_T *sym;
  delimiter = line[lexterm];


  if( line[lexstart] == '-' )
  {
    nextLexBlank();
    sym_getexpr = *(eval());
    sym_getexpr.val = ( - sym_getexpr.val ) & 07777;
  }
  else
  {
    if( line[lexstart] == '+' )
    {
      nextLexBlank();
    }
    sym_getexpr = *(eval());
    sym_getexpr.val = sym_getexpr.val & 07777;
  }

  if( is_blank( delimiter ))
  {
    return( &sym_getexpr );
  }

  /* Here we assume the current lexeme is the operator separating the         */
  /* previous operator from the next, if any.                                 */
  while( TRUE )
  {
    /* assert line[lexstart] == delimiter                                     */
    if( is_blank( delimiter ))
    {
      return( &sym_getexpr );
    }

    switch( line[lexstart] )
    {
    case '+':                   /* add                                        */
      nextLexBlank();           /* skip over the operator                     */
      sym = eval();
      sym_getexpr.val += sym->val;
      if (sym_getexpr.type == UNDEFINED || sym->type == UNDEFINED) {
         sym_getexpr.val = 0;
         sym_getexpr.type = UNDEFINED;
      }
      break;

    case '-':                   /* subtract                                   */
      nextLexBlank();           /* skip over the operator                     */
      sym = eval();
      sym_getexpr.val -= sym->val;
      if (sym_getexpr.type == UNDEFINED || sym->type == UNDEFINED) {
         sym_getexpr.val = 0;
         sym_getexpr.type = UNDEFINED;
      }
      break;

    case '^':                   /* multiply                                   */
      nextLexBlank();           /* skip over the operator                     */
      sym = eval();
      sym_getexpr.val *= sym->val;
      if (sym_getexpr.type == UNDEFINED || sym->type == UNDEFINED) {
         sym_getexpr.val = 0;
         sym_getexpr.type = UNDEFINED;
      }
      break;

    case '%':                   /* divide                                     */
      nextLexBlank();           /* skip over the operator                     */
      sym = eval();
      sym_getexpr.val /= sym->val;
      if (sym_getexpr.type == UNDEFINED || sym->type == UNDEFINED) {
         sym_getexpr.val = 0;
         sym_getexpr.type = UNDEFINED;
      }
      break;

    case '&':                   /* and                                        */
      nextLexBlank();           /* skip over the operator                     */
      sym = eval();
      sym_getexpr.val &= sym->val;
      if (sym_getexpr.type == UNDEFINED || sym->type == UNDEFINED) {
         sym_getexpr.val = 0;
         sym_getexpr.type = UNDEFINED;
      }
      break;

    case '!':                   /* or                                         */
      nextLexBlank();           /* skip over the operator                     */
      sym = eval();
      sym_getexpr.val |= sym->val;
      if (sym_getexpr.type == UNDEFINED || sym->type == UNDEFINED) {
         sym_getexpr.val = 0;
         sym_getexpr.type = UNDEFINED;
      }
      break;

    default:
      if( isend( line[lexstart] ))
      {
        return( &sym_getexpr );
      }

      switch( line[lexstart] )
      {
      case '/':
      case ';':
      case ')':
      case ']':
      case '<':
        break;

      case '=':
        errorMessage( &illegal_equals, lexstart );
        moveToEndOfLine();
        sym_getexpr.val = 0;
        break;

      default:
        errorMessage( &illegal_expression, lexstart );
        moveToEndOfLine();
        sym_getexpr.val = 0;
        break;
      }
      return( &sym_getexpr );
    }
  } /* end while                                                              */
} /* getExpr()                                                                */


/******************************************************************************/
/*                                                                            */
/*  Function:  eval                                                           */
/*                                                                            */
/*  Synopsis:  Get the value of the current lexeme, set delimiter and advance.*/
/*                                                                            */
/******************************************************************************/
SYM_T *eval()
{
  WORD16  digit;
  int     from;
  WORD16  loc;
  SYM_T  *sym;
  WORD16  val;

  val = 0;

  delimiter = line[lexterm];
  if( isalpha( line[lexstart] ))
  {
    sym = evalSymbol();
    if( M_UNDEFINED( sym->type ) && pass == 2 )
    {
      errorSymbol( &undefined_symbol, sym->name, lexstart );
      nextLexeme();
      return( sym );
    }
    else
    {
      nextLexeme();
      return( sym );
    }
  }
  else if( isdigit( line[lexstart] ))
  {
    from = lexstart;
    val = 0;
    while( from < lexterm )
    {
      if( isdigit( line[from] ))
      {
        digit = (WORD16) line[from++] - (WORD16) '0';
        if( digit < radix )
        {
          val = val * radix + digit;
        }
        else
        {
          errorLexeme( &number_not_radix, from - 1 );
          val = 0;
          from = lexterm;
        }
      }
      else
      {
        errorLexeme( &not_a_number, lexstart );
        val = 0;
        from = lexterm;
      }
    }
    nextLexeme();
    sym_eval.val = val;
    return( &sym_eval );
  }
  else
  {
    switch( line[lexstart] )
    {
    case '"':                   /* Character literal                          */
      if( cc + 1 <= maxcc )
      {
        val = line[lexstart + 1] | 0200;
        delimiter = line[lexstart + 2];
        cc = lexstart + 2;
      }
      else
      {
        errorMessage( &no_literal_value, lexstart );
      }
      nextLexeme();
      break;

    case '.':                   /* Value of Current Location Counter          */
      val = (clc & 07777) + reloc;
      nextLexeme();
      break;

    case '[':                   /* Generate literal on page zero.             */
      if( !literals_ok && LITERAL_ERROR)
      {
        errorMessage( &literal_gen_off, lexstart );
      }
      nextLexBlank();           /* Skip bracket                               */
      val = getExprs() & 07777;

      if( line[lexstart] == ']' )
      {
        nextLexBlank();         /* Skip end bracket                           */
      }

      sym_eval.val = (literals_ok || !LITERAL_ERROR) ? insertLiteral( cp , val,
        GET_PAGE_INDEX(field)) : 0;
      return( &sym_eval );

    case '(':                   /* Generate literal on current page.          */
      if( !literals_ok && LITERAL_ERROR)
      {
        errorMessage( &literal_gen_off, lexstart );
      }

      nextLexBlank();           /* Skip paren                                 */
      val = getExprs() & 07777;

      if( line[lexstart] == ')' )
      {
        nextLexBlank();         /* Skip end paren                             */
      }

      loc = (literals_ok || !LITERAL_ERROR) ? insertLiteral( cp, val, GET_PAGE_INDEX(clc) ) : 0;
      sym_eval.val = loc + (( clc + reloc ) & 077600 );
      return( &sym_eval );

    default:
      switch( line[lexstart] )
      {
      case '=':
        errorMessage( &illegal_equals, lexstart );
        moveToEndOfLine();
        break;

      default:
        errorMessage( &illegal_character, lexstart );
        break;
      }
      val = 0;                  /* On error, set value to zero.               */
      nextLexBlank();           /* Go past illegal character.                 */
    }
  }
  sym_eval.val = val;
  return( &sym_eval );
} /* eval()                                                                   */


/******************************************************************************/
/*                                                                            */
/*  Function:  inputDubl                                                      */
/*                                                                            */
/*  Synopsis:  Get the value of the current lexeme as a double word.          */
/*                                                                            */
/******************************************************************************/
void inputDubl()
{
  WORD32 dublvalue;
  BOOL   scanning_line;

  scanning_line = TRUE;
  do
  {
    while( scanning_line )
    {
      if( isend( line[lexstart] ))
      {
        scanning_line = FALSE;
      }
      else
      {
        switch( line[lexstart] )
        {
        case '/':
          scanning_line = FALSE;
          break;

        case ';':
          nextLexeme();
          break;

        case '+':
          delimiter = line[lexterm];
          nextLexBlank();
        case '-':
        default:
          if( isdigit( line[lexstart] ) || line[lexstart] == '-' )
          {
            dublvalue = getDublExprs();
            punchOutObject( clc, (WORD16)(( dublvalue >> 12 ) & 07777 ));
            incrementClc();
            punchOutObject( clc, (WORD16)( dublvalue & 07777 ));
            incrementClc();
          }
          else
          {
            return;             /* Non-numeric input, back to assembly.       */
          }
          break;
        } /* end switch                                                       */
      } /* end if                                                             */

      if( error_in_line )
      {
        return;                 /* Error occurred, exit DUBL input mode.      */
      }
    } /* end while( scanning_line )                                           */
    readLine();
    nextLexeme();
    scanning_line = TRUE;
  }
  while( TRUE );
} /* inputDubl()                                                              */


/******************************************************************************/
/*                                                                            */
/*  Function:  getDublExprs                                                   */
/*                                                                            */
/*  Synopsis:  Get a DUBL expression.                                         */
/*                                                                            */
/******************************************************************************/
WORD32 getDublExprs()
{
  WORD32 dublvalue;

  dublvalue = getDublExpr();

  while( TRUE )
  {
    if( isdone( line[lexstart] ))
    {
      return( dublvalue );
    }
    else
    {
      errorMessage( &illegal_expression, lexstart - 1 );
      return( 0 );
    }
  } /* end while                                                              */
} /* getDublExprs()                                                           */


/******************************************************************************/
/*                                                                            */
/*  Function:  getDublExpr                                                    */
/*                                                                            */
/*  Synopsis:  Get the value of the current lexeme as a double word.  The     */
/*             number is always considered to have a decimal radix.           */
/*                                                                            */
/******************************************************************************/
WORD32 getDublExpr()
{
  WORD32 dublvalue;

  delimiter = line[lexterm];
  if( line[lexstart] == '-' )
  {
    nextLexBlank();
    dublvalue = evalDubl( 0 );
    nextLexeme();
    /* Test for any value greater than 23 bits in length.                     */
    if( (unsigned long int)dublvalue > 040000000L )
    {
      errorMessage( &dubl_overflow, lexstart );
      dublvalue = 0;
    }
    dublvalue = -dublvalue;
  }
  else
  {
    dublvalue = evalDubl( 0 );
    nextLexeme();
    /* Test for any value greater than 23 bits in length.                     */
    if( (unsigned long int)dublvalue > 037777777L )
    {
      errorMessage( &dubl_overflow, lexstart );
      dublvalue = 0;
    }
  }

  if( is_blank( delimiter ))
  {
    return( dublvalue );
  }

  /* Here we assume the current lexeme is the operator separating the         */
  /* previous operator from the next, if any.                                 */
  while( TRUE )
  {
    /* assert line[lexstart] == delimiter                                     */
    if( is_blank( delimiter ))
    {
      errorMessage( &illegal_expression, lexstart );
      moveToEndOfLine();
      dublvalue = 0;
      return( dublvalue );
    }

    switch( line[lexstart] )
    {
    case '+':                   /* add                                        */
    case '-':                   /* subtract                                   */
    case '^':                   /* multiply                                   */
    case '%':                   /* divide                                     */
    case '&':                   /* and                                        */
    case '!':                   /* or                                         */
      errorMessage( &illegal_expression, lexstart );
      moveToEndOfLine();
      dublvalue = 0;
      break;

    default:
      if( isend( line[lexstart] ))
      {
        return( dublvalue );
      }

      switch( line[lexstart] )
      {
      case '/':
      case ';':
        break;

      default:
        errorMessage( &illegal_expression, lexstart );
        moveToEndOfLine();
        dublvalue = 0;
        break;
      }
      return( dublvalue );
    }
  } /* end while                                                              */
} /* getDublExpr()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  evalDubl                                                       */
/*                                                                            */
/*  Synopsis:  Get the value of the current lexeme as a double word.  The     */
/*             number is always considered to have a decimal radix.           */
/*                                                                            */
/******************************************************************************/
WORD32 evalDubl( WORD32 initial_value )
{
  WORD32  digit;
  int     from;
  WORD32  dublvalue;
  WORD32  olddublvalue;

  overflow = FALSE;
  delimiter = line[lexterm];
  from = lexstart;
  dublvalue = initial_value;

  while( from < lexterm )
  {
    if( isdigit( line[from] ))
    {
      olddublvalue = dublvalue;
      digit = (WORD32)( line[from++] - '0' );
      dublvalue = dublvalue * 10 + digit;
      if( dublvalue < olddublvalue )
      {
        overflow = TRUE;
      }
    }
    else
    {
      errorLexeme( &not_a_number, from );
      dublvalue = 0;
      from = lexterm;
    }
  }
  return( dublvalue );
} /* evalDubl()                                                               */


/******************************************************************************/
/*                                                                            */
/*  Function:  inputFltg                                                      */
/*                                                                            */
/*  Synopsis:  Get the value of the current lexeme as a Floating Point const. */
/*                                                                            */
/******************************************************************************/
void inputFltg()
{
  FLTG_T *fltg;
  BOOL    scanning_line;

  fltg_input = TRUE;            /* Set lexeme scanner for floating point.     */
  scanning_line = TRUE;
  while( TRUE )
  {
    while( scanning_line )
    {
      if( isend( line[lexstart] ))
      {
        scanning_line = FALSE;
      }
      else
      {
        switch( line[lexstart] )
        {
        case '/':
          scanning_line = FALSE;
          break;

        case ';':
          nextLexeme();
          break;

        case '+':
          delimiter = line[lexterm];
          nextLexBlank();
        case '-':
        default:
          if( isdigit( line[lexstart] ) || line[lexstart] == '-' )
          {
            fltg = getFltgExprs();
            punchOutObject( clc, ( fltg->exponent & 07777 ));
            incrementClc();
            punchOutObject( clc, (WORD16)(( fltg->mantissa >> 12 ) & 07777 ));
            incrementClc();
            punchOutObject( clc, (WORD16)( fltg->mantissa & 07777 ));
            incrementClc();
          }
          else
          {
            fltg_input = FALSE; /* Reset lexeme scanner.                      */
            return;             /* Non-numeric input, back to assembly.       */
          }
          break;
        } /* end switch                                                       */
      } /* end if                                                             */

      if( error_in_line )
      {
        fltg_input = FALSE;     /* Reset lexeme scanner.                      */
        return;                 /* Error occurred, exit FLTG input mode.      */
      }
    } /* end while( scanning_line )                                           */
    readLine();
    nextLexeme();
    scanning_line = TRUE;
  }
} /* inputFltg()                                                              */


/******************************************************************************/
/*                                                                            */
/*  Function:  getFltgExprs                                                   */
/*                                                                            */
/*  Synopsis:  Get a FLTG expression.                                         */
/*                                                                            */
/******************************************************************************/
FLTG_T *getFltgExprs()
{
  FLTG_T *fltg;

  fltg = getFltgExpr();

  while( TRUE )
  {
    if( isdone( line[lexstart] ))
    {
      return( fltg );
    }
    else
    {
      errorMessage( &illegal_expression, lexstart - 1 );
      return( 0 );
    }
  } /* end while                                                              */
} /* getFltgExprs()                                                           */


/******************************************************************************/
/*                                                                            */
/*  Function:  getFltgExpr                                                    */
/*                                                                            */
/*  Synopsis:  Get the value of the current lexeme as a double word.  The     */
/*             number is always considered to have a decimal radix.           */
/*                                                                            */
/******************************************************************************/
FLTG_T *getFltgExpr()
{
  FLTG_T *fltg;

  delimiter = line[lexterm];
  fltg = evalFltg();
  /* Test for any value greater than 23 bits in length.                     */
  if( (unsigned long int)fltg->mantissa> 077777777L )
  {
    errorMessage( &fltg_overflow, lexstart );
  }

  if( is_blank( delimiter ))
  {
    return( fltg );
  }

  /* Here we assume the current lexeme is the operator separating the         */
  /* previous operator from the next, if any.                                 */
  while( TRUE )
  {
    /* assert line[lexstart] == delimiter                                     */
    if( is_blank( delimiter ))
    {
      errorMessage( &illegal_expression, lexstart );
      moveToEndOfLine();
      fltg = 0;
      return( fltg );
    }

    switch( line[lexstart] )
    {
    case '+':                   /* add                                        */
    case '-':                   /* subtract                                   */
    case '^':                   /* multiply                                   */
    case '%':                   /* divide                                     */
    case '&':                   /* and                                        */
    case '!':                   /* or                                         */
      errorMessage( &illegal_expression, lexstart );
      moveToEndOfLine();
      fltg = NULL;
      break;

    default:
      if( isend( line[lexstart] ))
      {
        return( fltg );
      }

      switch( line[lexstart] )
      {
      case '/':
      case ';':
        break;

      default:
        errorMessage( &illegal_expression, lexstart );
        moveToEndOfLine();
        fltg = NULL;
        break;
      }
      return( fltg );
    }
  } /* end while                                                              */
} /* getFltgExpr()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  evalFltg                                                       */
/*                                                                            */
/*  Synopsis:  Get the value of the current lexeme as a floating point value. */
/*             Floating point input is alwasy considered decimal.             */
/*             The general format of a floating point number is:              */
/*                +-ddd.dddE+-dd  where each d is a decimal digit.            */
/*                                                                            */
/******************************************************************************/
FLTG_T *evalFltg()
{
  int      current_state;
  int      current_col;
  WORD16   exponent;
  FLTG_T  *fltg;
  WORD32   input_value;
  BOOL     negate;
  BOOL     negate_exponent;
  int      next_state;
  int      right_digits;

  /* This uses a lexical analyzer to parse the floating point format.         */
  static BYTE state_table[][10] =
  {
    /*  0   1   2   3   4   5   6  Oolumn index                               */
    /*  +   -   d   .   E  sp   p      State  Comment                         */
     {  2,  1,  3,  4, 10, 10, 10  },  /*  0  Initial state.                  */
     { 11, 11,  3,  4, 11, 11, 11  },  /*  1  -                               */
     { 11, 11,  3,  4, 11, 11, 11  },  /*  2  +                               */
     { 10, 10, 10,  4,  6, 10, 10  },  /*  3  # (+-ddd)                       */
     { 11, 11,  5, 11, 11, 10, 10  },  /*  4  . (+-ddd.)                      */
     { 11, 11, 11, 11,  6, 10, 11  },  /*  5  # (+-ddd.ddd)                   */
     {  8,  7,  9, 11, 11, 11, 11  },  /*  6  E (+-ddd.dddE)                  */
     { 11, 11,  9, 11, 11, 11, 11  },  /*  7  - (+-ddd.dddE-                  */
     { 11, 11,  9, 11, 11, 11, 11  },  /*  8  + (+-ddd.dddE+                  */
     { 11, 11, 11, 11, 11, 10, 11  }   /*  9  # (+-ddd.dddE+-dd               */
                                       /* 10  Completion state                */
                                       /* 11  Error state.                    */
  };

  delimiter = line[lexterm];
  fltg = &fltg_ac;
  fltg->exponent = 0;
  fltg->mantissa = 0;
  input_value = 0;
  negate = FALSE;
  negate_exponent = FALSE;
  next_state = 0;
  exponent = 0;
  right_digits = 0;
  current_state = 0;

  while( TRUE )
  {
    /* Classify character.  This is the column index.                         */
    switch( line[lexstart] )
    {
    case '+':
      current_col = 0;
      break;

    case '-':
      current_col = 1;
      break;

    case '.':
      current_col = 3;
      break;

    case 'E':  case 'e':
      current_col = 4;
      break;

    default:
      if( isdigit( line[lexstart] ))
      {
        current_col = 2;
      }
      else if( isdone( line[lexstart] ))
      {
        current_col = 5;
      }
      else
      {
        current_col = 6;
      }
      break;
    }

    next_state = state_table[current_state][current_col];

    switch( next_state )
    {
    case 1:                             /*  -                                 */
      negate = TRUE;
    case 2:                             /*  +                                 */
      delimiter = line[lexterm];        /* Move past the + or - character.    */
      nextLexBlank();
      break;

    case 3:                             /* Number  (+-ddd)                    */
      input_value = evalDubl( 0 );      /* Integer part of the number.        */
      nextLexeme();                     /* Move past previous lexeme.         */
      break;

    case 4:
      delimiter = line[lexterm];
      nextLexBlank();                   /* Move past the . character.         */
      break;

    case 5:                             /* .  (+-ddd.ddd)                     */
                                        /* Fractional part of the number.     */
      input_value = evalDubl( input_value );
      right_digits = lexterm - lexstart;/* Digit count to right of decimal.   */
      nextLexeme();                     /* Move past previous lexeme.         */
      break;

    case 6:                             /* E  (+-ddd.dddE)                    */
      delimiter = line[lexterm];        /* Move past the E.                   */
      nextLexBlank();
      break;

    case 7:                             /* -  (+-ddd.dddE-)                   */
      negate_exponent = TRUE;
    case 8:                             /* +  (+-ddd.dddE+)                   */
      delimiter = line[lexterm];        /* Move past the + or - character.    */
      nextLexBlank();
      break;

    case 9:                             /* #  (+-ddd.dddE+-dd)                */
      exponent = (int)evalDubl( 0 );    /* Exponent of floating point number. */
      if( negate_exponent ) { exponent = - exponent; }
      nextLexeme();                     /* Move past previous lexeme.         */
      break;

    case 10:                            /* Floating number parsed, convert    */
                                        /* the number.                        */
      /* Get the exponent for the number as input.                            */
      exponent -= right_digits;

      /* Remove trailing zeros and adjust the exponent accordingly.           */
      while(( input_value % 10 ) == 0 )
      {
        input_value /= 10;
        exponent++;
      }

      /* Convert the number to floating point.  The number is calculated with */
      /* a 27 bit mantissa to improve precision.  The extra 3 bits are        */
      /* discarded after the result has been calculated.                      */
      fltg->exponent = 26;
      fltg->mantissa = input_value << 3;
      normalizeFltg( fltg );


      while( exponent != 0 )
      {
        if( exponent < 0 )
        {
          /* Decimal point is to the left. */
          fltg->mantissa /= 10;
          normalizeFltg( fltg );
          exponent++;
        }
        else if( exponent > 0 )
        {
          /* Decimal point is to the right. */
          fltg->mantissa *= 10;
          normalizeFltg( fltg );
          exponent--;
        }
      }

      /* Discard the extra precsion used for calculating the number.          */
      fltg->mantissa >>= 3;
      fltg->exponent -= 3;
      if( negate )
      {
        fltg->mantissa = (- fltg->mantissa ) & 077777777L;
      }
      return( fltg );

    case 11:                            /* Error in format.                   */
      /* Not a properly constructued floating point number.                   */
      return( fltg );
    default:
      break;
    }
    /* Set state for next pass through the loop.                              */
    current_state = next_state;
  }
} /* evalFltg()                                                               */



/******************************************************************************/
/*                                                                            */
/*  Function:  normalizeFltg                                                  */
/*                                                                            */
/*  Synopsis:  Normalize a PDP-8 double precision floating point number.      */
/*                                                                            */
/******************************************************************************/
void normalizeFltg( FLTG_T *fltg )
{
  /* Normalize the floating point number.                                     */
  if( fltg->mantissa != 0 )
  {
    if(( fltg->mantissa & ~0x3FFFFFFL ) == 0 )
    {
      while(( fltg->mantissa & ~0x1FFFFFFL ) == 0 )

      {
        fltg->mantissa <<= 1;
        fltg->exponent--;
      }
    }
    else
    {
      while(( fltg->mantissa & ~0x3FFFFFFL ) != 0 )
      {
        fltg->mantissa >>= 1;
        fltg->exponent++;
      }
    }
  }
  else
  {
    fltg->exponent = 0;
  }
  return;
}


/******************************************************************************/
/*                                                                            */
/*  Function:  incrementClc                                                   */
/*                                                                            */
/*  Synopsis:  Set the next assembly location.  Test for collision with       */
/*             the literal tables.                                            */
/*                                                                            */
/******************************************************************************/
WORD16 incrementClc()
{
  testForLiteralCollision( clc );

  /* Incrementing the location counter is not to change field setting.        */
  clc = ( clc & 070000 ) + (( clc + 1 ) & 07777 );
  fieldlc = clc & 07777;
  return( clc );
} /* incrementClc()                                                           */


/******************************************************************************/
/*                                                                            */
/*  Function:  testForLiteralCollision                                        */
/*                                                                            */
/*  Synopsis:  Test the given location for collision with the literal tables. */
/*                                                                            */
/******************************************************************************/
BOOL testForLiteralCollision( WORD16 loc )
{
  WORD16  pagelc;
  BOOL    result = FALSE;
  WORD16  tmppage;
  int     tmpfield;

  tmpfield = GET_PAGE_INDEX(loc);
  tmppage = loc & 07600;
  pagelc  = loc & 00177;

  if ( pagelc > max_page_used[tmpfield] ) 
  {
     max_page_used[tmpfield] = pagelc;
  }
  if ( pagelc >= cp[tmpfield].loc )
  {
    if ( tmppage == 0 )
    {
      errorMessage( &pz_literal_overflow, -1 );
    }
    else
    {
      errorMessage( &literal_overflow, -1 );
    }
    result = TRUE;
  }

  return( result );
} /* testForLiteralCollision()                                                */


/******************************************************************************/
/*                                                                            */
/*  Function:  readLine                                                       */
/*                                                                            */
/*  Synopsis:  Get next line of input.  Print previous line if needed.        */
/*                                                                            */
/******************************************************************************/
void readLine()
{
  WORD16  ix;
  WORD16  iy;
  char   inpline[LINELEN];

  listLine();                   /* List previous line if needed.              */
  lineno++;                     /* Count lines read.                          */
  indirect_generated = FALSE;   /* Mark no indirect address generated.        */
  listed = FALSE;               /* Mark as not listed.                        */
  cc = 0;                       /* Initialize column counter.                 */
  lexstartprev = 0;

  error_in_line = FALSE;
  if(( fgets( inpline, LINELEN - 1, infile )) == NULL )
  {
    inpline[0] = '$';
    inpline[1] = '\n';
    inpline[2] = '\0';
    if (!dollar_not_required) {
       error_in_line = TRUE;
    }
  }

  /* Remove any tabs from the input line by inserting the required number     */
  /* of spaces to simulate N character tab stops, where N defaults to 8 and   */
  /* is set by the command line option -t. (RK 20071029)                      */
  /* Ignore \r if there is one.  (DPI 20150501)                               */
  for( ix = 0, iy = 0; inpline[ix] != '\0' && iy < (LINELEN - 2); ix++ )
  {
    switch( inpline[ix] )
    {
    case '\t':
      do
      {
        line[iy] = ' ';
        iy++;
      }
      while(( iy % tabstops ) != 0 && iy < (LINELEN - 2));
      break;

    case '\r':        /* dont copy the carriage return */
       break;

    default:
      line[iy] = inpline[ix];
      iy++;
      break;
    }
  }
  if (iy >= (LINELEN - 2)) {
  	line [iy] = '\n';
  	iy++;
  } 
  line[iy] = '\0';

  maxcc = iy;                   /* Save the current line length.              */
  /* Save the first line for possible use as the listing title.               */
  if( lineno == 1 )
  {
    strcpy( list_title, line );
  }
} /* readLine()                                                               */


/******************************************************************************/
/*                                                                            */
/*  Function:  listLine                                                       */
/*                                                                            */
/*  Synopsis:  Output a line to the listing file.                             */
/*                                                                            */
/******************************************************************************/
void listLine()
/* generate a line of listing if not already done!                            */
{
  if( listfile != NULL && listed == FALSE )
  {
    printLine( line, 0, 0, LINE );
  }
} /* listLine()                                                               */


/******************************************************************************/
/*                                                                            */
/*  Function:  printPageBreak                                                 */
/*                                                                            */
/*  Synopsis:  Output a Top of Form and listing header if new page necessary. */
/*                                                                            */
/******************************************************************************/
void printPageBreak()
{
  if( page_lineno >= LIST_LINES_PER_PAGE )
         /*  ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */
  {
    if( !list_title_set )
    {
      /* strcpy( list_title, line ); */
      if( list_title[strlen(list_title) - 1] == '\n' )
      {
        list_title[strlen(list_title) - 1] = '\0';
      }
      if( strlen( list_title ) > TITLELEN )
      {
        list_title[TITLELEN] = '\0';
      }
      list_title_set = TRUE;
    }
    topOfForm( list_title, NULL );

  }
} /* printPageBreak()                                                         */


/******************************************************************************/
/*                                                                            */
/*  Function:  printLine                                                      */
/*                                                                            */
/*  Synopsis:  Output a line to the listing file with new page if necessary.  */
/*                                                                            */
/******************************************************************************/
void printLine( char *line, WORD16 loc, WORD16 val, LINESTYLE_T linestyle )
{
  char rlc;

  if( listfile == NULL )
  {
    save_error_count = 0;
    return;
  }

  printPageBreak();

  list_lineno++;
  page_lineno++;

  if (reloc == 0)
  {
    rlc = ' ';
  }
  else
  {
    rlc = '*';
  }

  switch( linestyle )
  {
  default:
  case LINE:
    fprintf(listfile, "%5d              ", lineno );
    fputs( line, listfile );
    listed = TRUE;
    break;

  case LINE_VAL:
    fprintf(listfile, "%5d        %4.4o  ", lineno, val );
    fputs( line, listfile );
    listed = TRUE;
    break;

  case LINE_LOC_VAL:
    if( !listed )
    {
      if( indirect_generated )
      {
        fprintf( listfile, "%5d %5.5o%c %4.4o@ ", lineno, loc, rlc, val );
      }
      else
      {
        fprintf( listfile, "%5d %5.5o%c %4.4o  ", lineno, loc, rlc, val );
      }
      fputs( line, listfile );
      listed = TRUE;
    }
    else
    {
      fprintf( listfile, "      %5.5o%c %4.4o\n", loc, rlc, val );
    }
    break;

  case LOC_VAL:
    fprintf( listfile, "      %5.5o%c %4.4o\n", loc, rlc, val );
    break;
  }
  printErrorMessages();
} /* printLine()                                                              */


/******************************************************************************/
/*                                                                            */
/*  Function:  printErrorMessages                                             */
/*                                                                            */
/*  Synopsis:  Output any error messages from the current list of errors.     */
/*                                                                            */
/******************************************************************************/
void printErrorMessages()
{
  WORD16  ix;
  WORD16  iy;

  if( listfile != NULL )
  {
    /* If any errors, display them now.                                       */
    for( iy = 0; iy < save_error_count; iy++ )
    {
      printPageBreak();
      fprintf( listfile, "%-18.18s", error_list[iy].mesg );
      if( error_list[iy].col >= 0 )
      {
        for( ix = 0; ix < error_list[iy].col; ix++ )
        {
          if( line[ix] == '\t' )
          {
            putc( '\t', listfile );
          }
          else
          {
            putc( ' ', listfile );
          }
        }
        fputs( "^", listfile );
        list_lineno++;
        page_lineno++;
      }
      fputs( "\n", listfile );
    }
  }
  save_error_count = 0;
} /* printErrorMessages()                                                     */


/******************************************************************************/
/*                                                                            */
/*  Function:  endOfBinary                                                    */
/*                                                                            */
/*  Synopsis:  Outputs both literal tables at the end of a binary segment.    */
/*                                                                            */
/******************************************************************************/
void endOfBinary()
{
  /* Punch page 0 also.                                   */
  punchLiteralPool( cp, 1 );
  if( error_in_line )
  {
    listed = TRUE;
    clc = ( clc & 070000 ) + (( clc - 1 ) & 07777 );
    errorMessage( &end_of_file, -1 );
    clc = ( clc & 070000 ) + (( clc + 1 ) & 07777 );
  }
  else
  {
    listLine();             /* List line if not done yet.                     */
  }
  return;
} /* endOfBinary()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  punchChecksum                                                  */
/*                                                                            */
/*  Synopsis:  Output a checksum if the current mode requires it and an       */
/*             object file exists.                                            */
/*                                                                            */
/******************************************************************************/
void punchChecksum()
{
  /* If the assembler has output any BIN data output the checksum.            */
  if( binary_data_output && !rim_mode )
  {
    punchLocObject( 0, checksum );
  }
  binary_data_output = FALSE;
  checksum = 0;
} /* punchChecksum()                                                          */


/******************************************************************************/
/*                                                                            */
/*  Function:  punchLeader                                                    */
/*                                                                            */
/*  Synopsis:  Generate 2 feet of leader on object file, as per DEC           */
/*             documentation.  Paper tape has 10 punches per inch.            */
/*                                                                            */
/******************************************************************************/
void punchLeader( int count )
{
  int ix;

  /* If value is zero, set to the default of 2 feet of leader.                */
  count = ( count == 0 ) ? 240 : count;

  if( objectfile != NULL )
  {
    for( ix = 0; ix < count; ix++ )
    {
      fputc( 0200, objectfile );
    }
  }
} /* punchLeader()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  punchOrigin                                                    */
/*                                                                            */
/*  Synopsis:  Output an origin to the object file.                           */
/*                                                                            */
/******************************************************************************/
void punchOrigin( WORD16 loc )
{
  punchObject((( loc >> 6 ) & 0077 ) | 0100 );
  punchObject( loc & 0077 );
} /* punchOrigin()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  punchObject                                                    */
/*                                                                            */
/*  Synopsis:  Put one character to object file and include it in checksum.   */
/*                                                                            */
/******************************************************************************/
void punchObject( WORD16 val )
{
  val &= 0377;
  if( objectfile != NULL )
  {
    fputc( val, objectfile );
    checksum += val;
  }
  binary_data_output = TRUE;
} /* punchObject()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  punchOutObject                                                 */
/*                                                                            */
/*  Synopsis:  Output the current line and then then punch value to the       */
/*             object file.                                                   */
/*                                                                            */
/******************************************************************************/
void punchOutObject( WORD16 loc, WORD16 val )
{
  /* Adding reloc makes printout agree with PAL8 where is prints the */
  /* relocated address, not the address in the BIN file */
  printLine( line,( ( field | loc ) + reloc ), val, LINE_LOC_VAL );
  punchLocObject( loc, val );
} /* punchOutObject()                                                         */

/******************************************************************************/
/*                                                                            */
/*  Function:  punchLocObject                                                 */
/*                                                                            */
/*  Synopsis:  Output the word (with origin if rim format) to the object file.*/
/*                                                                            */
/******************************************************************************/
void punchLocObject( WORD16 loc, WORD16 val )
{
  if( rim_mode )
  {
    punchOrigin( loc );
  }
  punchObject(( val >> 6 ) & 0077 );
  punchObject( val & 0077 );
} /* punchLocObject()                                                         */


/******************************************************************************/
/*                                                                            */
/*  Function:  punchLiteralPool                                               */
/*                                                                            */
/*  Synopsis:  Output the current page data.                                  */
/*                                                                            */
/******************************************************************************/
void punchLiteralPool( LPOOL_T *p, BOOL punch_page0 )
{
  WORD16  loc;
  WORD16  tmplc;
  int lpool_page = 0; /* Silence false uninitialized error from GCC */
  int i;

  for (i = MAX_PAGES-1; i >= 0;  i--) {
    lpool_page = (i << 7) & 07600;

    if ( p[i].loc != p[i].last_punched && (punch_page0 || lpool_page != 0) )
    {
      if( !rim_mode )
      {
        /* Put out origin if not in rim mode.                                 */
        punchOrigin( p[i].loc | lpool_page );
      }
      /* Put the literals in the object file.                                 */
      for( loc = p[i].loc; loc < p[i].last_punched; loc++ )
      {
        tmplc = loc + lpool_page;
        printLine( line, (field | tmplc), p[i].pool[loc], LOC_VAL );
        punchLocObject( tmplc, p[i].pool[loc] );
      }
      p[i].last_punched = p[i].loc;
    }
  }
} /* punchLiteralPool()                                                       */


/******************************************************************************/
/*                                                                            */
/*  Function:  insertLiteral                                                  */
/*                                                                            */
/*  Synopsis:  Add a value to the given literal pool if not already in pool.  */
/*             Return the location of the value in the pool.                  */
/*                                                                            */
/******************************************************************************/
WORD16 insertLiteral( LPOOL_T *pool, WORD16 value, int fieldpage_index )
{
  WORD16  ix;
  LPOOL_T *p;

  p = &pool[fieldpage_index];

  /* Search the literal pool for any occurence of the needed value.           */
  ix = PAGE_SIZE - 1;
  while( ix >= p->loc && p->pool[ix] != value )
  {
    ix--;
  }

  /* Check if value found in literal pool. If not, then insert value.         */
  if( ix < p->loc )
  {
    (p->loc)--;
    p->pool[p->loc] = value;
    ix = p->loc;
    if( max_page_used[fieldpage_index] >= p->loc ) {
      if ( (fieldpage_index & 017) == 0 )
      {
        errorMessage( &pz_literal_overflow, -1 );
      }
      else
      {
        errorMessage( &literal_overflow, -1 );
      }
    }
  }
  return( ix );
} /* insertLiteral()                                                          */


/******************************************************************************/
/*                                                                            */
/*  Function:  printSymbolTable                                               */
/*                                                                            */
/*  Synopsis:  Output the symbol table.                                       */
/*                                                                            */
/******************************************************************************/
void printSymbolTable()
{
  int    col;
  int    cx;
  char  *fmt;
  int    ix;
  char   mark;
  int    page;
  int    row;
  int    symbol_base;
  int    symbol_lines;

  symbol_base = number_of_fixed_symbols;

  for( page=0, list_lineno=0, col=0, ix=symbol_base; ix < symbol_top; page++ )
  {
    topOfForm( list_title, s_symtable );
    symbol_lines = LIST_LINES_PER_PAGE - page_lineno;

    for( row = 0; page_lineno < LIST_LINES_PER_PAGE && ix < symbol_top; row++)
    {
      list_lineno++;
      page_lineno++;
      fprintf( listfile, "%5d", list_lineno );

      for( col = 0; col < SYMBOL_COLUMNS && ix < symbol_top; col++ )
      {
        /* Get index of symbol for the current line and column                         */
        cx = symbol_lines * ( SYMBOL_COLUMNS * page + col ) + row;
        cx += symbol_base;

        /* Make sure that there is a symbol to be printed.                    */
        if( number_of_fixed_symbols <= cx && cx < symbol_top )
        {
          switch( symtab[cx].type & LABEL )
          {
          case LABEL:
            fmt = " %c%-6.6s %5.5o ";
            break;

          default:
            fmt = " %c%-6.6s  %4.4o ";
            break;
          }

          switch( symtab[cx].type & ( DEFINED | REDEFINED ))
          {
          case UNDEFINED:
            mark = '?';
            break;

          case REDEFINED:
            mark = '#';
            break;

          default:
            mark = ' ';
            break;
          }
          fprintf( listfile, fmt, mark, symtab[cx].name, symtab[cx].val );
          ix++;
        }
      }
      fprintf( listfile, "\n" );
    }
  }
} /* printSymbolTable()                                                       */


/******************************************************************************/
/*                                                                            */
/*  Function:  printPermanentSymbolTable                                      */
/*                                                                            */
/*  Synopsis:  Output the permanent symbol table to a file suitable for       */
/*             being input after the EXPUNGE pseudo-op.                       */
/*                                                                            */
/******************************************************************************/
void printPermanentSymbolTable()
{
  int     ix;
  FILE   *permfile;
  char  *s_type;

  if(( permfile = fopen( permpathname, "w" )) == NULL )
  {
    exit( 2 );
  }

  fprintf( permfile, "/ PERMANENT SYMBOL TABLE\n/\n" );
  fprintf( permfile, "        EXPUNGE\n/\n" );
  /* Print the memory reference instructions first.                           */
  s_type = "FIXMRI";
  for( ix = 0; ix < symbol_top; ix++ )
  {
    if( M_MRI( symtab[ix].type ))
    {
      fprintf( permfile, "%-7s %s=%4.4o\n",
                                    s_type, symtab[ix].name, symtab[ix].val );
    }
  }

  s_type = " ";
  for( ix = 0; ix < symbol_top; ix++ )
  {
    if( M_FIXED( symtab[ix].type ))
    {
      if( !M_MRI( symtab[ix].type ) && !M_PSEUDO( symtab[ix].type ))
      {
        fprintf( permfile, "%-7s %s=%4.4o\n",
                                    s_type, symtab[ix].name, symtab[ix].val );
      }
    }
  }
  fprintf( permfile, "/\n        FIXTAB\n" );
  fclose( permfile );
} /* printPermanentSymbolTable()                                              */


/******************************************************************************/
/*                                                                            */
/*  Function:  printCrossReference                                            */
/*                                                                            */
/*  Synopsis:  Output a cross reference (concordance) for the file being      */
/*             assembled.                                                     */
/*                                                                            */
/******************************************************************************/
void printCrossReference()
{
  int    ix;
  int    symbol_base;
  int    xc;
  int    xc_index;
  int    xc_refcount;
  int    xc_cols;

  /* Force top of form for first page.                                        */
  page_lineno = LIST_LINES_PER_PAGE;

  list_lineno = 0;
  symbol_base = number_of_fixed_symbols;

  for( ix = symbol_base; ix < symbol_top; ix++ )
  {
    list_lineno++;
    page_lineno++;
    if( page_lineno >= LIST_LINES_PER_PAGE )
    {
      topOfForm( list_title, s_xref );
    }

    fprintf( listfile, "%5d", list_lineno );

    /* Get reference count & index into concordance table for this symbol.    */
    xc_refcount = symtab[ix].xref_count;
    xc_index = symtab[ix].xref_index;
    /* Determine how to label symbol on concordance.                          */
    switch( symtab[ix].type & ( DEFINED | REDEFINED ))
    {
    case UNDEFINED:
      fprintf( listfile, " U         ");
      break;

    case REDEFINED:
      fprintf( listfile, " M  %5d  ", xreftab[xc_index] );
      break;

    default:
      fprintf( listfile, " A  %5d  ", xreftab[xc_index] );
      break;
    }
    fprintf( listfile, "%-6.6s  ", symtab[ix].name );

    /* Output the references, 8 numbers per line after symbol name.           */
    for( xc_cols = 0, xc = 1; xc < xc_refcount + 1; xc++, xc_cols++ )
    {
      if( xc_cols >= XREF_COLUMNS )
      {
        xc_cols = 0;
        page_lineno++;
        if( page_lineno >= LIST_LINES_PER_PAGE )
        {
          topOfForm( list_title, s_xref);
        }
        list_lineno++;
        fprintf( listfile, "\n%5d%-19s", list_lineno, " " );
      }
      fprintf( listfile, "  %5d", xreftab[xc_index + xc] );
    }
    fprintf( listfile, "\n" );
  }
} /* printCrossReference()                                                    */


/******************************************************************************/
/*                                                                            */
/*  Function:  topOfForm                                                      */
/*                                                                            */
/*  Synopsis:  Prints title and sub-title on top of next page of listing.     */
/*                                                                            */
/******************************************************************************/
void topOfForm( char *title, char *sub_title )
{
  char temp[10];

  list_pageno++;
  strcpy( temp, s_page );
  sprintf( temp, "%s %d", s_page, list_pageno );

  /* Output a top of form if not the first page of the listing.               */
  if( list_pageno > 1 )
  {
    fprintf( listfile, "\f" );
  }
  fprintf( listfile, "\n\n\n      %-63s %10s\n", title, temp );

  /* Reset the current page line counter.                                     */
  page_lineno = 3;
  if( sub_title != NULL )
  {
    fprintf( listfile, "%80s\n", sub_title );
    page_lineno++;
  }
  else
  {
    fprintf( listfile, "\n" );
    page_lineno++;
  }
  fprintf( listfile, "\n" );
  page_lineno++;
} /* topOfForm()                                                              */


/******************************************************************************/
/*                                                                            */
/*  Function:  lexemeToName                                                   */
/*                                                                            */
/*  Synopsis:  Convert the current lexeme into a string.                      */
/*                                                                            */
/******************************************************************************/
char *lexemeToName( char *name, int from, int term )
{
  int  to;

  to = 0;

  while( from < term && to < ( SYMLEN - 1 ))
  {
    name[to++] = toupper( line[from++] );
  }

  while( to < SYMLEN )
  {
    name[to++] = '\0';
  }
  return( name );
} /* lexemeToName()                                                           */

/******************************************************************************/
/*                                                                            */
/*  Function:  defineLexeme                                                   */
/*                                                                            */
/*  Synopsis:  Put lexeme into symbol table with a value.                     */
/*                                                                            */
/******************************************************************************/
SYM_T *defineLexeme( int     start,     /* start of lexeme being defined.     */
                     int     term,      /* end+1 of lexeme being defined.     */
                     WORD16  val,       /* value of lexeme being defined.     */
                     SYMTYP  type )     /* how symbol is being defined.       */
{
  char  name[SYMLEN];

  lexemeToName( name, start, term);
  return( defineSymbol( name, val, type, start ));
} /* defineLexeme()                                                           */


/******************************************************************************/
/*                                                                            */
/*  Function:  defineSymbol                                                   */
/*                                                                            */
/*  Synopsis:  Define a symbol in the symbol table, enter symbol name if not  */
/*             not already in table.                                          */
/*                                                                            */
/******************************************************************************/
SYM_T *defineSymbol( char *name, WORD16 val, SYMTYP type, WORD16 start )
{
  SYM_T  *sym;
  int     xref_count;

  if( strlen( name ) < 1 )
  {
    return( &sym_undefined );   /* Protect against non-existent names.        */
  }
  sym = lookup( name );
  /* OS/8 PAL8 seems to allow permanent symbold to be redefined without error */
  if( ( M_FIXED( sym->type ) && pass == 1 && perm_redef_error ) || 
     (M_PERM_REDEFINED( sym->type ) && (sym->val != val)) )
  {
     type |= PERM_REDEFINED;
  }

  xref_count = 0;               /* Set concordance for normal defintion.      */

  if( M_DEFINED( sym->type ))
  {
    if( pass == 2 && ( (sym->val & 07777) != (val & 07777) || M_PERM_REDEFINED(sym->type)) )
    {
      /* Generate diagnostic if redefining a symbol.                          */
      if( M_PERM_REDEFINED( sym->type ) && (M_LABEL(sym->type) || M_LABEL(type)) )
      {
        errorSymbol( &illegal_redefine, sym->name, start );
      } else 
      {
        /* Generate diagnostic if redefining a symbol.                          */
        if( M_REDEFINED( sym->type ) && (M_LABEL(sym->type) || M_LABEL(type)) )
        {
          errorSymbol( &redefined_symbol, sym->name, start );
        }
      }
      type = type | REDEFINED;
      sym->xref_count++;      /* Referenced suymbol, count it.                */
      xref_count = sym->xref_count;
    }
  }

  if( pass == 2 && xref )
  {
    /* Put the definition line number in the concordance table.               */
    /* Defined symbols are not counted as references.                         */
    xreftab[sym->xref_index] = lineno;
    /* Put the line number in the concordance table.                          */
    xreftab[sym->xref_index + xref_count] = lineno;
  }

  /* Now set the value and the type.                                          */
  sym->val = ( M_LABEL(type) ) ? val : val & 07777;
  sym->type = ( pass == 1 ) ? ( type | CONDITION ) : type;
  return( sym );
} /* defineSymbol()                                                           */


/******************************************************************************/
/*                                                                            */
/*  Function:  lookup                                                         */
/*                                                                            */
/*  Synopsis:  Find a symbol in table.  If not in table, enter symbol in      */
/*             table as undefined.  Return address of symbol in table.        */
/*                                                                            */
/******************************************************************************/
SYM_T *lookup( char *name )
{
  int     ix;                   /* Insertion index                            */
  int     lx;                   /* Left index                                 */
  int     rx;                   /* Right index                                */

  /* First search the permanent symbols.                                      */
  lx = 0;
  ix = binarySearch( name, lx, number_of_fixed_symbols );

  /* If symbol not in permanent symbol table.                                 */
  if( ix < 0 )
  {
    /* Now try the user symbol table.                                         */
    ix = binarySearch( name, number_of_fixed_symbols, symbol_top );

    /* If symbol not in user symbol table.                                    */
    if( ix < 0 )
    {
      /* Must put symbol in table if index is negative.                       */
      ix = ~ix;
      if( symbol_top + 1 >= SYMBOL_TABLE_SIZE )
      {
        errorSymbol( &symbol_table_full, name, lexstart );
        exit( 1 );
      }

      for( rx = symbol_top; rx >= ix; rx-- )
      {
        symtab[rx + 1] = symtab[rx];
      }
      symbol_top++;

      /* Enter the symbol as UNDEFINED with a value of zero.                  */
      strcpy( symtab[ix].name, name );
      symtab[ix].type = UNDEFINED;
      symtab[ix].val  = 0;
      symtab[ix].xref_count = 0;
      if( xref && pass == 2 )
      {
        xreftab[symtab[ix].xref_index] = 0;
      }
    }
  }

  return( &symtab[ix] );        /* Return the location of the symbol.         */
} /* lookup()                                                                 */


/******************************************************************************/
/*                                                                            */
/*  Function:  binarySearch                                                   */
/*                                                                            */
/*  Synopsis:  Searches the symbol table within the limits given.  If the     */
/*             symbol is not in the table, it returns the insertion point.    */
/*                                                                            */
/******************************************************************************/
int binarySearch( char *name, int start, int symbol_count )
{
  int     lx;                   /* Left index                                 */
  int     mx;                   /* Middle index                               */
  int     rx;                   /* Right index                                */
  int     compare;              /* Results of comparison                      */

  lx = start;
  rx = symbol_count - 1;
  while( lx <= rx )
  {
    mx = ( lx + rx ) / 2;   /* Find center of search area.                    */

    compare = strcmp( name, symtab[mx].name );

    if( compare < 0 )
    {
      rx = mx - 1;
    }
    else if( compare > 0 )
    {
      lx = mx + 1;
    }
    else
    {
      return( mx );         /* Found a match in symbol table.                 */
    }
  } /* end while                                                              */
  return( ~lx );            /* Return insertion point.                        */
} /* binarySearch()                                                           */


/******************************************************************************/
/*                                                                            */
/*  Function:  compareSymbols                                                 */
/*                                                                            */
/*  Synopsis:  Used to presort the symbol table when starting assembler.      */
/*                                                                            */
/******************************************************************************/
int compareSymbols( const void *a, const void *b )
{
  return( strcmp( ((SYM_T *) a)->name, ((SYM_T *) b)->name ));
} /* compareSymbols()                                                         */


/******************************************************************************/
/*                                                                            */
/*  Function:  evalSymbol                                                     */
/*                                                                            */
/*  Synopsis:  Get the pointer for the symbol table entry if exists.          */
/*             If symbol doesn't exist, return a pointer to the undefined sym */
/*                                                                            */
/******************************************************************************/
SYM_T *evalSymbol()
{
  char   name[SYMLEN];
  SYM_T *sym;

  sym = lookup( lexemeToName( name, lexstart, lexterm ));

  /* The symbol goes in the concordance iff it is in a different position in  */
  /* the assembler source file.                                               */
  if( lexstart != last_xref_lexstart ||  lineno != last_xref_lineno )
  {
    sym->xref_count++;          /* Count the number of references to symbol.  */
    last_xref_lexstart = lexstart;
    last_xref_lineno = lineno;

    /* Put the line number in the concordance table.                          */
    if( xref && pass == 2 )
    {
      xreftab[sym->xref_index + sym->xref_count] = lineno;
    }
  }

  return( sym );
} /* evalSymbol()                                                             */


/******************************************************************************/
/*                                                                            */
/*  Function:  moveToEndOfLine                                                */
/*                                                                            */
/*  Synopsis:  Move the parser input to the end of the current input line.    */
/*                                                                            */
/******************************************************************************/
void moveToEndOfLine()
{
  while( !isend( line[cc] )) cc++;
  lexstart = cc;
  lexterm = cc;
  lexstartprev = lexstart;
} /* moveToEndOfLine()                                                        */

/******************************************************************************/
/*                                                                            */
/*  Function:  nextLexeme                                                     */
/*                                                                            */
/*  Synopsis:  Get the next lexical element from input line.                  */
/*                                                                            */
/******************************************************************************/
void nextLexeme()
{
  /* Save start column of previous lexeme for diagnostic messages.            */
  lexstartprev = lexstart;
  lextermprev = lexterm;

  while( is_blank( line[cc] )) { cc++; }
  lexstart = cc;

  if( isalnum( line[cc] ))
  {
    while( isalnum( line[cc] )) { cc++; }
  }
  else if( isend( line[cc] ))
  {
    /* End-of-Line, don't advance cc!                                         */
  }
  else
  {
    switch( line[cc] )
    {
    case '"':     /* Quoted letter                                            */
      if( cc + 2 < maxcc )
      {
        cc++;
        cc++;
      }
      else
      {
        errorMessage( &no_literal_value, lexstart );
        cc++;
      }
      break;

    case '/':     /* Comment, don't advance cc!                               */
      break;

    default:      /* All other punctuation.                                   */
      cc++;
      break;
    }
  }
  lexterm = cc;
} /* nextLexeme()                                                             */


/******************************************************************************/
/*                                                                            */
/*  Function:  nextLexBlank                                                   */
/*                                                                            */
/*  Synopsis:  Used to prevent illegal blanks in expressions.                 */
/*                                                                            */
/******************************************************************************/
void nextLexBlank()
{
  nextLexeme();
  if( is_blank( delimiter ))
  {
    errorMessage( &illegal_blank, lexstart - 1 );
  }
  delimiter = line[lexterm];
} /* nextLexBlank()                                                           */


/******************************************************************************/
/*                                                                            */
/*  Function:  pseudoOperators                                                */
/*                                                                            */
/*  Synopsis:  Process pseudo-ops (directives).                               */
/*                                                                            */
/******************************************************************************/
BOOL pseudoOperators( PSEUDO_T val )
{
  int     count, count2;
  int     delim;
  int     index;
  int     ix;
  int     lexstartsave;
  WORD16  newfield;
  WORD16  oldclc;
  int     pack;
  BOOL    status;
  SYM_T  *sym;
  FILE   *temp;
  int     term;
  WORD16  value;
  char os8_name[8];
  int     reloc_clc;

  status = TRUE;
  switch( (PSEUDO_T) val )
  {
  case ASCII:
    /* added 18-Jan-2003 PNT  -- derived from TEXT */
    delim = line[lexstart];
    index = lexstart + 1;
    while( line[index] != delim && !isend( line[index] ))
    {
      punchOutObject( clc, (line[index] & 127) | 128 );
      incrementClc();
      index++;
    }
    if( isend( line[index] ))
    {
      cc = index;
      lexterm = cc;
      errorMessage( &text_string, cc );
    }
    else
    {
      cc = index + 1;
      lexterm = cc;
    }
    nextLexeme();
    break;
  
  case BANK:
    errorSymbol( &no_pseudo_op, "BANK", lexstartprev );
    /* should select a different 32K out of 128K                              */
    break;

  case BINPUNCH:
    /* If there has been data output and this is a mode switch, set up to     */
    /* output data in BIN mode.                                               */
    if( binary_data_output && rim_mode )
    {
      clearLiteralTable();
      punchLeader( 8 );         /* Generate a short leader/trailer.           */
      checksum = 0;
      binary_data_output = FALSE;
    }
    rim_mode = FALSE;
    break;

  case DECIMAL:
    radix = 10;
    break;

  case DUBL:
    inputDubl();
    break;

  case EJECT:
    page_lineno = LIST_LINES_PER_PAGE;  /* This will force a page break.      */
    status = FALSE;             /* This will force reading of next line       */
    break;

  case ENPUNCH:
    if( pass == 2 )
    {
      objectfile = objectsave;
    }
    break;

  case EXPUNGE:                 /* Erase symbol table                         */
    if( pass == 1 )
    {
      symtab[0] = sym_undefined;
      symbol_top = 0;
      number_of_fixed_symbols = symbol_top;
      fixed_symbols = &symtab[symbol_top - 1];

      /* Enter the pseudo-ops into the symbol table.                          */
      for( ix = 0; ix < DIM( pseudo ); ix++ )
      {
        defineSymbol( pseudo[ix].name, pseudo[ix].val, pseudo[ix].type, 0 );
      }
      /* Enter the really permanent symbols into the table.                   */
      /* Also make them part of the permanent symbol table.                   */
      for( ix = 0; ix < DIM( really_permanent_symbols ); ix++ )
      {
        defineSymbol( really_permanent_symbols[ix].name,
                      really_permanent_symbols[ix].val,
                      really_permanent_symbols[ix].type | DEFFIX , 0 );
      }
      number_of_fixed_symbols = symbol_top;
      fixed_symbols = &symtab[symbol_top - 1];

    }
    break;

  case FIELD:
    /* Punch page 0 also */
    punchLiteralPool( cp, 1 );
    newfield = field >> 12;
    lexstartsave = lexstartprev;
    if( isdone( line[lexstart] ))
    {
      newfield += 1;            /* Blank FIELD directive.                     */
    }
    else
    {
      newfield = (getExpr())->val;      /* FIELD with argument.               */
    }

    if( rim_mode )
    {
      errorMessage( &in_rim_mode, lexstartsave ); /* Can't change fields.     */
    }
    else if( newfield > 7 || newfield < 0 )
    {
      errorMessage( &illegal_field_value, lexstartprev );
    }
    else
    {
      value = (( newfield & 0007 ) << 3 ) | 00300;
      punchObject( value );
      if( objectfile != NULL )    /* Only fix checksum if punching */
      {
        checksum -= value;        /* Field punches are not added to checksum.   */
      }
      field = newfield << 12;
    }

    clc = 0200 | field;
    fieldlc = clc & 07777;

    if( !rim_mode )
    {
      punchOrigin( clc );
    }

    clearLiteralTable();

    break;

  case FIXMRI:
    if( line[lexterm] == '=' && isalpha( line[lexstart] ))
    {
      lexstartsave = lexstart;
      term = lexterm;
      nextLexeme();           /* Skip symbol.                                 */
      nextLexeme();           /* Skip trailing =                              */
      defineLexeme( lexstartsave, term, getExprs(), MRI );
    }
    else
    {
      errorLexeme( &symbol_syntax, lexstart );
      nextLexeme();           /* Skip symbol.                                 */
      nextLexeme();           /* Skip trailing =                              */
      (void) getExprs();      /* Skip expression.                             */
    }
    break;

  case FIXTAB:
    if (pass == 1) /* Only fix on first pass, on second all are defined */
    {
      /* Mark all current symbols as permanent symbols.                         */
      for( ix = 0; ix < symbol_top; ix++ )
      {
        symtab[ix].type = symtab[ix].type | FIXED;
      }
      number_of_fixed_symbols = symbol_top;
      fixed_symbols = &symtab[symbol_top - 1];

      /* Re-sort the symbol table                                               */
      qsort( symtab, symbol_top, sizeof(symtab[0]), compareSymbols );
    }
    break;

  case FLTG:
    inputFltg();
    /* errorSymbol( &no_pseudo_op, "FLTG", lexstartprev ); */
    break;

  case IFDEF:
    if( isalpha( line[lexstart] ))
    {
      sym = evalSymbol();
      nextLexeme();
      if( M_DEFINED_CONDITIONALLY( sym->type ))
      {
        conditionTrue();
      }
      else
      {
        conditionFalse();
      }
    }
    else
    {
      errorLexeme( &label_syntax, lexstart );
    }
    break;

  case IFNDEF:
    if( isalpha( line[lexstart] ))
    {
      sym = evalSymbol();
      nextLexeme();
      if( M_DEFINED_CONDITIONALLY( sym->type ))
      {
        conditionFalse();
      }
      else
      {
        conditionTrue();
      }
    }
    else
    {
      errorLexeme( &label_syntax, lexstart );
    }
    break;

  case IFNZERO:
    if( getExprs() == 0 )
    {
      conditionFalse();
    }
    else
    {
      conditionTrue();
    }
    break;

  case IFZERO:
    if( getExprs() == 0 )
    {
      conditionTrue();
    }
    else
    {
      conditionFalse();
    }
    break;

  case NOPUNCH:
    if( pass == 2 )
    {
      objectfile = NULL;
    }
    break;

  case OCTAL:
    radix = 8;
    break;

  case PAGE:
    reloc_clc = clc + reloc;
    punchLiteralPool( cp, 0 );
    oldclc = clc;
    if( isdone( line[lexstart] ))
    {
      clc = (( reloc_clc + 0177 ) & 077600) - reloc;  /* No argumnet.               */
      fieldlc = clc & 07777;
    }
    else
    {
      value = (getExpr())->val;
      clc = field + (( value & 037 ) << 7 ) - reloc;
      fieldlc = clc & 07777;
    }
    testForLiteralCollision( clc + reloc );

    if( !rim_mode && clc != oldclc )
    {
      punchOrigin( clc );
    }
    break;

  case PAUSE:
    break;

  case RELOC:
    if( isdone( line[lexstart] ))
    {
       reloc = 0;               /* Blank RELOC directive.                     */
    }
    else
    {
      value = (getExpr())->val; /* RELOC with argument.                       */
      reloc = (value & 07777) - ( clc  & 07777);
    }
    break;

  case RIMPUNCH:
    /* If the assembler has output any BIN data, output the literal tables    */
    /* and the checksum for what has been assembled and setup for RIM mode.   */
    if( binary_data_output && !rim_mode )
    {
      endOfBinary();
      clearLiteralTable();
      punchChecksum();
      punchLeader( 8 );         /* Generate a short leader/trailer.           */
    }
    rim_mode = TRUE;
    break;

  case SEGMNT:
    punchLiteralPool( cp, 0 );
    if( isdone( line[lexstart] ))
    {                           /* No argument.                               */
      clc = ( clc & 06000 ) + 02000;
      fieldlc = clc & 07777;
    }
    else
    {
      getExpr();
      clc = ( val & 003 ) << 10;
      fieldlc = clc & 07777;
    }
    if( !rim_mode )
    {
      punchOrigin( clc );
    }
    testForLiteralCollision( clc );
    break;

  case TEXT:
    delim = line[lexstart];
    pack = 0;
    count = 0;
    index = lexstart + 1;
    while( line[index] != delim && !isend( line[index] ))
    {
      pack = ( pack << 6 ) | ( line[index] & 077 );
      count++;
      if( count > 1 )
      {
        punchOutObject( clc, pack );
        incrementClc();
        count = 0;
        pack = 0;
      }
      index++;
    }

    if( count != 0 )
    {
      punchOutObject( clc, pack << 6 );
      incrementClc();
    }
    else
    {
      punchOutObject( clc, 0 );
      incrementClc();
    }

    if( isend( line[index] ))
    {
      cc = index;
      lexterm = cc;
      errorMessage( &text_string, cc );
    }
    else
    {
      cc = index + 1;
      lexterm = cc;
    }
    nextLexeme();
    break;

  case FILENAME:
    memset(os8_name, 0, sizeof(os8_name));
    delimiter=line[lexstart];
    if (delimiter != '.')
    {
      for (index = lexstart, count = 0; index < lexterm && count < 6; index++)
      {
        os8_name[count++] = line[index];
      }
      delimiter=line[lexterm];
      if (delimiter == '.')
      {
         nextLexeme();     /* Skip . */
      }
    }
    nextLexeme();
    if (delimiter == '.')
    {
      for (index = lexstart, count = 6; index < lexterm && count < 8; index++)
      {
        os8_name[count++] = line[index];
      }
    }

    pack = 0;
    count = 0;
    for (count2 = 0; count2 < 8; count2++) 
    {
      pack = ( pack << 6 ) | ( os8_name[count2] & 077 );
      count++;
      if( count > 1 )
      {
        punchOutObject( clc, pack );
        incrementClc();
        count = 0;
        pack = 0;
      }
    }
    nextLexeme();
    break;

  case DEVICE:
    memset(os8_name, 0, sizeof(os8_name));
    for (index = lexstart, count = 0; index < lexterm && count < 4; index++)
    {
      os8_name[count++] = line[index];
    }

    pack = 0;
    count = 0;
    for (count2 = 0; count2 < 4; count2++) 
    {
      pack = ( pack << 6 ) | ( os8_name[count2] & 077 );
      count++;
      if( count > 1 )
      {
        punchOutObject( clc, pack );
        incrementClc();
        count = 0;
        pack = 0;
      }
    }

    nextLexeme();
    break;

  case TITLE:
    delim = line[lexstart];
    ix = lexstart + 1;
    /* Find string delimiter.                                                 */
    do
    {
      if( list_title[ix] == delim && list_title[ix + 1] == delim )
      {
        ix++;
      }
      ix++;
    } while( line[ix] != delim && !isend(line[ix]) );

    if( line[ix] == delim )
    {
      count = 0;
      ix = lexstart + 1;
      do
      {
        if( list_title[ix] == delim && list_title[ix + 1] == delim )
        {
          ix++;
        }
        list_title[count] = line[ix];
        count++;
        ix++;
        list_title[count] = '\0';
      } while( line[ix] != delim && !isend(line[ix]) );

      if( strlen( list_title ) > TITLELEN )
      {
        list_title[TITLELEN] = '\0';
      }

      cc = ix + 1;
      lexterm = cc;
      page_lineno = LIST_LINES_PER_PAGE;/* Force top of page for new titles.  */
      list_title_set = TRUE;
    }
    else
    {
      cc = ix;
      lexterm = cc;
      errorMessage( &text_string, cc );
    }

    nextLexeme();
    break;

  case XLIST:
    if( isdone( line[lexstart] ))
    {
      temp = listfile;          /* Blank XLIST directive.                     */
      listfile = listsave;
      listsave = temp;
    }
    else
    {
      if( (getExpr())->val == 0 )
      {
        if( listfile == NULL )
        {
          listfile = listsave;
          listsave = NULL;
        }
      }
      else
      {
        if( listfile != NULL )
        {
          listsave = listfile;
          listfile = NULL;
        }
      }
    }
    break;

  case ZBLOCK:
    value = (getExpr())->val;
    if( value < 0 )
    {
      errorMessage( &zblock_too_small, lexstartprev );
    }
    else if( value + ( clc & 07777 ) - 1 > 07777 )
    {
      errorMessage( &zblock_too_large, lexstartprev );
    }
    else
    {
      for( ; value > 0; value-- )
      {
        punchOutObject( clc, 0 );
        incrementClc();
      }
    }

    break;

  default:
    break;
  } /* end switch for pseudo-ops                                              */
  return( status );
} /* pseudoOperators()                                                        */


/******************************************************************************/
/*                                                                            */
/*  Function:  conditionFalse                                                 */
/*                                                                            */
/*  Synopsis:  Called when a false conditional has been evaluated.            */
/*             Lex should be the opening <; ignore all text until             */
/*             the closing >.                                                 */
/*                                                                            */
/******************************************************************************/
void conditionFalse()
{
  int     level;

  if( line[lexstart] == '<' )
  {
    /* Invariant: line[cc] is the next unexamined character.                  */
    level = 1;
    while( level > 0 )
    {
      if( isend( line[cc] ))
      {
        readLine();
      }
      else
      {
        switch( line[cc] )
        {
        case '>':
          level--;
          cc++;
          break;

        case '<':
          level++;
          cc++;
          break;

        case '$':
          level = 0;
          cc++;
          break;

        default:
          cc++;
          break;
        } /* end switch                                                       */
      } /* end if                                                             */
    } /* end while                                                            */
    nextLexeme();
  }
  else
  {
    errorMessage( &lt_expected, lexstart );
  }
} /* conditionFalse()                                                         */

/******************************************************************************/
/*                                                                            */
/*  Function:  conditionTrue                                                  */
/*                                                                            */
/*  Synopsis:  Called when a true conditional has been evaluated.             */
/*             Lex should be the opening <; skip it and setup for             */
/*             normal assembly.                                               */
/*                                                                            */
/******************************************************************************/
void conditionTrue()
{
  if( line[lexstart] == '<' )
  {
    nextLexeme();               /* Skip the opening '<'                       */
  }
  else
  {
    errorMessage( &lt_expected, lexstart );
  }
} /* conditionTrue()                                                          */


/******************************************************************************/
/*                                                                            */
/*  Function:  errorLexeme                                                    */
/*                                                                            */
/*  Synopsis:  Display an error message using the current lexical element.    */
/*                                                                            */
/******************************************************************************/
void errorLexeme( EMSG_T *mesg, int col )
{
  char   name[SYMLEN];

  errorSymbol( mesg, lexemeToName( name, lexstart, lexterm ), col );
} /* errorLexeme()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  errorSymbol                                                    */
/*                                                                            */
/*  Synopsis:  Display an error message with a given string.                  */
/*                                                                            */
/******************************************************************************/
void errorSymbol( EMSG_T *mesg, char *name, int col )
{
  char   linecol[12];
  char  *s;

  if( pass == 2 )
  {
    s = ( name == NULL ) ? "" : name ;
    errors++;
    sprintf( linecol, "(%d:%d)", lineno, col + 1 );
    fprintf( errorfile, "%s%-9s : error:  %s \"%s\" at Loc = %5.5o\n",
                                      filename, linecol, mesg->file, s, clc );
    saveError( mesg->list, col );
  }
  error_in_line = TRUE;
} /* errorSymbol()                                                            */


/******************************************************************************/
/*                                                                            */
/*  Function:  errorMessage                                                   */
/*                                                                            */
/*  Synopsis:  Display an error message without a name argument.              */
/*                                                                            */
/******************************************************************************/
void errorMessage( EMSG_T *mesg, int col )
{
  char   linecol[12];

  if( pass == 2 )
  {
    errors++;
    sprintf( linecol, "(%d:%d)", lineno, col + 1 );
    fprintf( errorfile, "%s%-9s : error:  %s at Loc = %5.5o\n",
                                         filename, linecol, mesg->file, clc );
    saveError( mesg->list, col );
  }
  error_in_line = TRUE;
} /* errorMessage()                                                           */

/******************************************************************************/
/*                                                                            */
/*  Function:  saveError                                                      */
/*                                                                            */
/*  Synopsis:  Save the current error in a list so it may displayed after the */
/*             the current line is printed.                                   */
/*                                                                            */
/******************************************************************************/
void saveError( char *mesg, int col )
{
  if( save_error_count < DIM( error_list ))
  {
    error_list[save_error_count].mesg = mesg;
    error_list[save_error_count].col = col;
    save_error_count++;
  }
  error_in_line = TRUE;

  if( listed )
  {
    printErrorMessages();
  }
} /* saveError()                                                              */
/* End-of-File                                                                */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted pics/schofield-brtval.R.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# schofield-brtval.R: Generate SVG graph of the brightness curves
#    produced by Ian Schofield's ILS patch.
#
# The schofield-brtval.svg file checked into Fossil is modified from the
# version output by this program:
#
# 1. The colors are modified to match the scheme on tangentsoft.com/pidp8i
#
# 2. The data line thickness was increased
#
# 3. The data lines were smoothed by Inkscape's "simplify" function
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above shall
# not be used in advertising or otherwise to promote the sale, use or other
# dealings in this Software without prior written authorization from those
# authors.
#

min = 0
max = 32
a = min
b = max

rising  = c(min);
falling = c(max);

for (i in 1:400) {
  a = a + (max - a) * 0.01
  b = b + (min - b) * 0.01
  
  rising[i]  = a
  falling[i] = b
  
  if (a > 31 || b < 1) break
}

data = data.frame(Rising = rising, Falling = falling)
dts = ts(data)
svg("schofield-brtval.svg", width=8, height=6)
plot.ts(dts, plot.type='single', ylab='Brightness',
        yaxp=c(min, max, 8))
dev.off()
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































Deleted pics/schofield-brtval.svg.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="576pt"
   height="396.73468pt"
   viewBox="0 0 576 396.73468"
   version="1.1"
   id="svg4276"
   inkscape:version="0.91 r13725"
   sodipodi:docname="schofield-brtval.svg">
  <title
     id="title4481">Schofield ILS Brightness Curves</title>
  <metadata
     id="metadata267">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title>Schofield ILS Brightness Curves</dc:title>
        <cc:license
           rdf:resource="https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md" />
        <dc:date>2017-02-02</dc:date>
        <dc:creator>
          <cc:Agent>
            <dc:title>Warren Young</dc:title>
          </cc:Agent>
        </dc:creator>
        <dc:language>English</dc:language>
        <dc:description>Curves showing the brightness levels of an LED driven from 0 to full brightness and from full brightness back to 0 under Ian Schofield's indandescent lamp simulator for the PiDP-8/I.</dc:description>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <sodipodi:namedview
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1"
     objecttolerance="10"
     gridtolerance="10"
     guidetolerance="10"
     inkscape:pageopacity="0"
     inkscape:pageshadow="2"
     inkscape:window-width="2560"
     inkscape:window-height="1391"
     id="namedview4548"
     showgrid="false"
     inkscape:zoom="1.6333333"
     inkscape:cx="360"
     inkscape:cy="253.95917"
     inkscape:window-x="0"
     inkscape:window-y="1"
     inkscape:window-maximized="1"
     inkscape:current-layer="svg4276"
     fit-margin-top="0"
     fit-margin-left="0"
     fit-margin-right="0"
     fit-margin-bottom="0" />
  <defs
     id="defs4278">
    <g
       id="g4280">
      <symbol
         overflow="visible"
         id="glyph0-0"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 0.390625,0 0,-8.609375 6.828125,0 0,8.609375 z m 5.75,-1.078125 0,-6.453125 -4.671875,0 0,6.453125 z"
           id="path4283"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-1"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 7.171875,-8.609375 0,1.03125 -2.890625,0 0,7.578125 -1.1875,0 0,-7.578125 -2.90625,0 0,-1.03125 z"
           id="path4286"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-2"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 0.78125,-6.25 1.0625,0 0,6.25 -1.0625,0 z m 0,-2.359375 1.0625,0 0,1.203125 -1.0625,0 z"
           id="path4289"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-3"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 0.78125,-6.28125 1.03125,0 0,0.890625 C 2.0625,-5.691406 2.289062,-5.914062 2.5,-6.0625 c 0.34375,-0.238281 0.738281,-0.359375 1.1875,-0.359375 0.5,0 0.898438,0.125 1.203125,0.375 0.164063,0.136719 0.320313,0.34375 0.46875,0.625 0.226563,-0.34375 0.5,-0.59375 0.8125,-0.75 0.320313,-0.164063 0.679687,-0.25 1.078125,-0.25 0.84375,0 1.414062,0.308594 1.71875,0.921875 0.164062,0.324219 0.25,0.765625 0.25,1.328125 L 9.21875,0 8.125,0 l 0,-4.359375 C 8.125,-4.773438 8.019531,-5.0625 7.8125,-5.21875 7.601562,-5.375 7.347656,-5.453125 7.046875,-5.453125 c -0.417969,0 -0.777344,0.140625 -1.078125,0.421875 -0.292969,0.273438 -0.4375,0.730469 -0.4375,1.375 l 0,3.65625 -1.078125,0 0,-4.09375 c 0,-0.425781 -0.054687,-0.738281 -0.15625,-0.9375 C 4.140625,-5.320312 3.84375,-5.46875 3.40625,-5.46875 3.007812,-5.46875 2.644531,-5.3125 2.3125,-5 1.988281,-4.695312 1.828125,-4.140625 1.828125,-3.328125 L 1.828125,0 0.78125,0 Z"
           id="path4292"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-4"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 3.390625,-6.421875 c 0.445313,0 0.878906,0.105469 1.296875,0.3125 0.414062,0.210937 0.734375,0.480469 0.953125,0.8125 0.207031,0.324219 0.347656,0.695313 0.421875,1.109375 0.0625,0.292969 0.09375,0.757812 0.09375,1.390625 l -4.609375,0 C 1.566406,-2.160156 1.71875,-1.648438 2,-1.265625 2.28125,-0.878906 2.71875,-0.6875 3.3125,-0.6875 c 0.550781,0 0.988281,-0.179688 1.3125,-0.546875 C 4.8125,-1.441406 4.945312,-1.6875 5.03125,-1.96875 l 1.03125,0 C 6.039062,-1.738281 5.953125,-1.484375 5.796875,-1.203125 5.640625,-0.921875 5.46875,-0.6875 5.28125,-0.5 4.957031,-0.1875 4.554688,0.0195312 4.078125,0.125 3.828125,0.1875 3.539062,0.21875 3.21875,0.21875 2.4375,0.21875 1.773438,-0.0625 1.234375,-0.625 c -0.542969,-0.570312 -0.8125,-1.367188 -0.8125,-2.390625 0,-1.007813 0.269531,-1.828125 0.8125,-2.453125 0.550781,-0.632812 1.269531,-0.953125 2.15625,-0.953125 z M 5.0625,-3.640625 C 5.019531,-4.097656 4.921875,-4.460938 4.765625,-4.734375 4.484375,-5.242188 4.003906,-5.5 3.328125,-5.5 2.835938,-5.5 2.425781,-5.320312 2.09375,-4.96875 1.769531,-4.625 1.597656,-4.179688 1.578125,-3.640625 Z m -1.78125,-2.78125 z"
           id="path4295"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-5"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 3.25,-8.390625 c 1.082031,0 1.867188,0.449219 2.359375,1.34375 0.375,0.6875 0.5625,1.636719 0.5625,2.84375 C 6.171875,-3.066406 6,-2.125 5.65625,-1.375 5.164062,-0.300781 4.359375,0.234375 3.234375,0.234375 c -1,0 -1.75,-0.4375 -2.25,-1.3125 C 0.578125,-1.816406 0.375,-2.800781 0.375,-4.03125 c 0,-0.945312 0.125,-1.765625 0.375,-2.453125 0.457031,-1.269531 1.289062,-1.90625 2.5,-1.90625 z m -0.015625,7.65625 c 0.550781,0 0.988281,-0.238281 1.3125,-0.71875 0.320313,-0.488281 0.484375,-1.394531 0.484375,-2.71875 0,-0.945313 -0.121094,-1.726563 -0.359375,-2.34375 C 4.441406,-7.128906 3.988281,-7.4375 3.3125,-7.4375 c -0.625,0 -1.085938,0.292969 -1.375,0.875 -0.28125,0.585938 -0.421875,1.445312 -0.421875,2.578125 0,0.855469 0.09375,1.542969 0.28125,2.0625 0.28125,0.792969 0.757813,1.1875 1.4375,1.1875 z"
           id="path4298"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-6"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 1.484375,-2.140625 c 0.070313,0.605469 0.351563,1.023437 0.84375,1.25 0.25,0.117187 0.535156,0.171875 0.859375,0.171875 0.625,0 1.085938,-0.195312 1.390625,-0.59375 C 4.878906,-1.707031 5.03125,-2.148438 5.03125,-2.640625 5.03125,-3.222656 4.847656,-3.675781 4.484375,-4 4.128906,-4.320312 3.703125,-4.484375 3.203125,-4.484375 c -0.367187,0 -0.679687,0.074219 -0.9375,0.21875 C 2.003906,-4.128906 1.785156,-3.9375 1.609375,-3.6875 L 0.6875,-3.734375 1.328125,-8.25 l 4.359375,0 0,1.015625 -3.5625,0 -0.359375,2.328125 c 0.195313,-0.144531 0.382813,-0.253906 0.5625,-0.328125 0.3125,-0.125 0.671875,-0.1875 1.078125,-0.1875 0.769531,0 1.421875,0.25 1.953125,0.75 0.539063,0.492187 0.8125,1.117187 0.8125,1.875 0,0.792969 -0.25,1.496094 -0.75,2.109375 -0.492187,0.6054688 -1.273437,0.90625 -2.34375,0.90625 -0.679687,0 -1.28125,-0.1953125 -1.8125,-0.578125 -0.523437,-0.382813 -0.8125,-0.976563 -0.875,-1.78125 z"
           id="path4301"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-7"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 1.15625,-5.9375 0,-0.8125 c 0.757812,-0.070312 1.285156,-0.195312 1.578125,-0.375 0.300781,-0.175781 0.53125,-0.585938 0.6875,-1.234375 l 0.828125,0 L 4.25,0 3.125,0 l 0,-5.9375 z"
           id="path4304"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-8"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="M 0.375,0 C 0.414062,-0.71875 0.566406,-1.34375 0.828125,-1.875 1.085938,-2.414062 1.59375,-2.90625 2.34375,-3.34375 L 3.46875,-4 c 0.5,-0.289062 0.851562,-0.539062 1.0625,-0.75 0.320312,-0.320312 0.484375,-0.691406 0.484375,-1.109375 0,-0.488281 -0.152344,-0.875 -0.453125,-1.15625 -0.292969,-0.289063 -0.679688,-0.4375 -1.15625,-0.4375 -0.730469,0 -1.230469,0.273437 -1.5,0.8125 -0.15625,0.304687 -0.242188,0.710937 -0.25,1.21875 l -1.078125,0 c 0.007813,-0.726563 0.144531,-1.320313 0.40625,-1.78125 0.457031,-0.8125 1.265625,-1.21875 2.421875,-1.21875 0.957031,0 1.65625,0.261719 2.09375,0.78125 0.445312,0.523437 0.671875,1.101563 0.671875,1.734375 0,0.667969 -0.234375,1.242188 -0.703125,1.71875 C 5.195312,-3.90625 4.707031,-3.566406 4,-3.171875 l -0.8125,0.4375 C 2.8125,-2.523438 2.515625,-2.320312 2.296875,-2.125 1.898438,-1.789062 1.648438,-1.414062 1.546875,-1 l 4.59375,0 0,1 z"
           id="path4307"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph0-9"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 3.125,0.234375 c -1,0 -1.726562,-0.2695312 -2.171875,-0.8125 -0.449219,-0.550781 -0.671875,-1.21875 -0.671875,-2 l 1.109375,0 c 0.039063,0.542969 0.140625,0.9375 0.296875,1.1875 0.28125,0.4375 0.773438,0.65625 1.484375,0.65625 0.5625,0 1.007813,-0.144531 1.34375,-0.4375 0.332031,-0.300781 0.5,-0.6875 0.5,-1.15625 0,-0.570313 -0.179687,-0.972656 -0.53125,-1.203125 -0.355469,-0.238281 -0.84375,-0.359375 -1.46875,-0.359375 -0.074219,0 -0.148437,0.00781 -0.21875,0.015625 -0.074219,0 -0.148437,0 -0.21875,0 l 0,-0.9375 c 0.113281,0.023438 0.207031,0.03125 0.28125,0.03125 0.070313,0 0.148437,0 0.234375,0 0.394531,0 0.71875,-0.0625 0.96875,-0.1875 C 4.507812,-5.1875 4.734375,-5.578125 4.734375,-6.140625 4.734375,-6.554688 4.582031,-6.875 4.28125,-7.09375 3.988281,-7.320312 3.644531,-7.4375 3.25,-7.4375 c -0.699219,0 -1.183594,0.234375 -1.453125,0.703125 -0.148437,0.25 -0.230469,0.617187 -0.25,1.09375 l -1.046875,0 c 0,-0.625 0.125,-1.15625 0.375,-1.59375 0.425781,-0.78125 1.179688,-1.171875 2.265625,-1.171875 0.851563,0 1.515625,0.195312 1.984375,0.578125 0.46875,0.375 0.703125,0.929687 0.703125,1.65625 0,0.511719 -0.136719,0.929687 -0.40625,1.25 -0.179687,0.199219 -0.402344,0.355469 -0.671875,0.46875 0.4375,0.125 0.78125,0.359375 1.03125,0.703125 0.25,0.34375 0.375,0.765625 0.375,1.265625 0,0.804687 -0.265625,1.460937 -0.796875,1.96875 -0.523437,0.5 -1.265625,0.75 -2.234375,0.75 z"
           id="path4310"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-0"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 0,-0.390625 -8.609375,0 0,-6.828125 8.609375,0 z m -1.078125,-5.75 -6.453125,0 0,4.671875 6.453125,0 z"
           id="path4313"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-1"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -4.96875,-4.15625 c 0,-0.488281 -0.066406,-0.867188 -0.203125,-1.140625 -0.21875,-0.425781 -0.601563,-0.640625 -1.15625,-0.640625 -0.5625,0 -0.941406,0.230469 -1.140625,0.6875 -0.113281,0.25 -0.171875,0.632812 -0.171875,1.140625 l 0,2.078125 2.671875,0 z M -1,-4.546875 c 0,-0.707031 -0.207031,-1.21875 -0.625,-1.53125 -0.257812,-0.1875 -0.570312,-0.28125 -0.9375,-0.28125 -0.625,0 -1.050781,0.28125 -1.28125,0.84375 -0.125,0.292969 -0.1875,0.683594 -0.1875,1.171875 l 0,2.3125 3.03125,0 z m -7.609375,3.65625 0,-3.6875 c 0,-1.007813 0.304687,-1.726563 0.90625,-2.15625 0.355469,-0.25 0.765625,-0.375 1.234375,-0.375 0.542969,0 0.984375,0.15625 1.328125,0.46875 0.1875,0.15625 0.355469,0.386719 0.5,0.6875 0.167969,-0.4375 0.359375,-0.765625 0.578125,-0.984375 0.375,-0.394531 0.890625,-0.59375 1.546875,-0.59375 0.554687,0 1.054687,0.179688 1.5,0.53125 C -0.335938,-6.476562 0,-5.65625 0,-4.53125 l 0,3.640625 z"
           id="path4316"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-2"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -6.28125,-0.796875 0,-1.015625 1.09375,0 c -0.21875,-0.070312 -0.476562,-0.269531 -0.78125,-0.59375 -0.300781,-0.320312 -0.453125,-0.691406 -0.453125,-1.109375 0,-0.019531 0.00781,-0.050781 0.015625,-0.09375 0,-0.050781 0.00781,-0.132813 0.015625,-0.25 l 1.109375,0 c -0.00781,0.0625 -0.015625,0.121094 -0.015625,0.171875 0,0.054688 0,0.109375 0,0.171875 0,0.53125 0.171875,0.945313 0.515625,1.234375 0.335938,0.28125 0.726562,0.421875 1.171875,0.421875 l 3.609375,0 0,1.0625 z"
           id="path4319"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-3"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -6.25,-0.78125 0,-1.0625 6.25,0 0,1.0625 z m -2.359375,0 0,-1.0625 1.203125,0 0,1.0625 z"
           id="path4322"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-4"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -6.390625,-2.984375 c 0,-0.5 0.121094,-0.929687 0.359375,-1.296875 0.148438,-0.195312 0.351562,-0.398438 0.609375,-0.609375 l -0.796875,0 0,-0.96875 5.703125,0 c 0.800781,0 1.429687,0.117187 1.890625,0.34375 0.851562,0.4375 1.28125,1.265625 1.28125,2.484375 0,0.679688 -0.152344,1.246094 -0.453125,1.703125 -0.304687,0.460937 -0.777344,0.71875 -1.421875,0.78125 l 0,-1.078125 c 0.28125,-0.050781 0.5,-0.148438 0.65625,-0.296875 0.226562,-0.238281 0.34375,-0.613281 0.34375,-1.125 0,-0.8125 -0.289062,-1.34375 -0.859375,-1.59375 C 0.585938,-4.785156 -0.0078125,-4.851562 -0.875,-4.84375 c 0.324219,0.210938 0.5625,0.464844 0.71875,0.765625 0.15625,0.292969 0.234375,0.683594 0.234375,1.171875 0,0.679688 -0.238281,1.273438 -0.71875,1.78125 -0.488281,0.511719 -1.289063,0.765625 -2.40625,0.765625 -1.050781,0 -1.867187,-0.253906 -2.453125,-0.765625 -0.59375,-0.519531 -0.890625,-1.140625 -0.890625,-1.859375 z m 3.21875,-1.90625 c -0.769531,0 -1.34375,0.164063 -1.71875,0.484375 -0.375,0.324219 -0.5625,0.730469 -0.5625,1.21875 0,0.75 0.351563,1.261719 1.046875,1.53125 0.367188,0.148438 0.851562,0.21875 1.453125,0.21875 0.710937,0 1.25,-0.140625 1.625,-0.421875 0.367187,-0.289063 0.546875,-0.679687 0.546875,-1.171875 0,-0.757812 -0.34375,-1.289062 -1.03125,-1.59375 -0.382812,-0.175781 -0.835938,-0.265625 -1.359375,-0.265625 z m -3.25,1.78125 z"
           id="path4325"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-5"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -8.640625,-0.78125 0,-1.046875 3.21875,0 C -5.742188,-2.078125 -5.96875,-2.300781 -6.09375,-2.5 -6.3125,-2.84375 -6.421875,-3.269531 -6.421875,-3.78125 c 0,-0.90625 0.320313,-1.519531 0.953125,-1.84375 0.34375,-0.175781 0.824219,-0.265625 1.4375,-0.265625 l 4.03125,0 0,1.078125 -3.953125,0 c -0.457031,0 -0.796875,0.0625 -1.015625,0.1875 -0.34375,0.1875 -0.515625,0.546875 -0.515625,1.078125 0,0.4375 0.152344,0.835937 0.453125,1.1875 0.304688,0.355469 0.871094,0.53125 1.703125,0.53125 l 3.328125,0 0,1.046875 z"
           id="path4328"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-6"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -8.03125,-0.984375 0,-1.0625 1.75,0 0,-1 0.859375,0 0,1 4.109375,0 c 0.21875,0 0.367188,-0.078125 0.4375,-0.234375 0.042969,-0.070312 0.0625,-0.207031 0.0625,-0.40625 0,-0.050781 0,-0.101562 0,-0.15625 -0.007812,-0.0625 -0.015625,-0.128906 -0.015625,-0.203125 l 0.828125,0 c 0.03125,0.117187 0.0507812,0.242187 0.0625,0.375 0.0195312,0.125 0.03125,0.265625 0.03125,0.421875 0,0.492188 -0.125,0.824219 -0.375,1 -0.25,0.179688 -0.578125,0.265625 -0.984375,0.265625 l -4.15625,0 0,0.84375 -0.859375,0 0,-0.84375 z"
           id="path4331"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-7"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -6.28125,-0.78125 0,-1 0.890625,0 c -0.363281,-0.289062 -0.625,-0.601562 -0.78125,-0.9375 -0.164063,-0.332031 -0.25,-0.703125 -0.25,-1.109375 0,-0.882813 0.3125,-1.484375 0.9375,-1.796875 0.34375,-0.175781 0.828125,-0.265625 1.453125,-0.265625 l 4.03125,0 0,1.078125 -3.953125,0 c -0.382813,0 -0.691406,0.058594 -0.921875,0.171875 -0.394531,0.1875 -0.59375,0.527344 -0.59375,1.015625 0,0.25 0.027344,0.453125 0.078125,0.609375 0.085937,0.292969 0.257813,0.546875 0.515625,0.765625 0.210938,0.179688 0.421875,0.292969 0.640625,0.34375 0.21875,0.054688 0.539063,0.078125 0.953125,0.078125 l 3.28125,0 0,1.046875 z M -6.421875,-3.25 Z"
           id="path4334"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-8"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -6.421875,-3.390625 c 0,-0.445313 0.105469,-0.878906 0.3125,-1.296875 0.210937,-0.414062 0.480469,-0.734375 0.8125,-0.953125 0.324219,-0.207031 0.695313,-0.347656 1.109375,-0.421875 0.292969,-0.0625 0.757812,-0.09375 1.390625,-0.09375 l 0,4.609375 C -2.160156,-1.566406 -1.648438,-1.71875 -1.265625,-2 -0.878906,-2.28125 -0.6875,-2.71875 -0.6875,-3.3125 c 0,-0.550781 -0.179688,-0.988281 -0.546875,-1.3125 C -1.441406,-4.8125 -1.6875,-4.945312 -1.96875,-5.03125 l 0,-1.03125 c 0.230469,0.023438 0.484375,0.109375 0.765625,0.265625 0.28125,0.15625 0.515625,0.328125 0.703125,0.515625 0.3125,0.324219 0.5195312,0.726562 0.625,1.203125 0.0625,0.25 0.09375,0.539063 0.09375,0.859375 0,0.78125 -0.28125,1.445312 -0.84375,1.984375 -0.570312,0.542969 -1.367188,0.8125 -2.390625,0.8125 -1.007813,0 -1.828125,-0.269531 -2.453125,-0.8125 -0.632812,-0.550781 -0.953125,-1.269531 -0.953125,-2.15625 z m 2.78125,-1.671875 c -0.457031,0.042969 -0.820313,0.140625 -1.09375,0.296875 -0.507813,0.28125 -0.765625,0.761719 -0.765625,1.4375 0,0.492187 0.179688,0.902344 0.53125,1.234375 0.34375,0.324219 0.789062,0.496094 1.328125,0.515625 z m -2.78125,1.78125 z"
           id="path4337"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-9"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -1.96875,-1.40625 c 0.355469,-0.03125 0.625,-0.117188 0.8125,-0.265625 0.335938,-0.257813 0.5,-0.71875 0.5,-1.375 0,-0.394531 -0.082031,-0.738281 -0.25,-1.03125 -0.164062,-0.300781 -0.425781,-0.453125 -0.78125,-0.453125 -0.269531,0 -0.476562,0.121094 -0.625,0.359375 -0.082031,0.15625 -0.179688,0.460937 -0.296875,0.90625 L -2.8125,-2.421875 C -2.945312,-1.890625 -3.097656,-1.5 -3.265625,-1.25 c -0.28125,0.460938 -0.675781,0.6875 -1.1875,0.6875 -0.59375,0 -1.070313,-0.210938 -1.4375,-0.640625 C -6.253906,-1.628906 -6.4375,-2.207031 -6.4375,-2.9375 c 0,-0.9375 0.277344,-1.613281 0.828125,-2.03125 0.355469,-0.269531 0.734375,-0.398438 1.140625,-0.390625 l 0,1 c -0.238281,0.023437 -0.457031,0.105469 -0.65625,0.25 -0.269531,0.242187 -0.40625,0.664063 -0.40625,1.265625 0,0.398438 0.078125,0.699219 0.234375,0.90625 0.148437,0.199219 0.34375,0.296875 0.59375,0.296875 0.273437,0 0.492187,-0.132813 0.65625,-0.40625 0.09375,-0.15625 0.179687,-0.382813 0.25,-0.6875 l 0.171875,-0.6875 c 0.1875,-0.757813 0.367188,-1.269531 0.53125,-1.53125 0.273438,-0.40625 0.699219,-0.609375 1.28125,-0.609375 0.554688,0 1.03125,0.214844 1.4375,0.640625 0.40625,0.417969 0.609375,1.058594 0.609375,1.921875 0,0.9375 -0.2109375,1.605469 -0.625,2 -0.425781,0.386719 -0.953125,0.589844 -1.578125,0.609375 z m -4.453125,-1.546875 z"
           id="path4340"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-10"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -8.390625,-3.25 c 0,-1.082031 0.449219,-1.867188 1.34375,-2.359375 0.6875,-0.375 1.636719,-0.5625 2.84375,-0.5625 1.136719,0 2.078125,0.171875 2.828125,0.515625 1.074219,0.492188 1.609375,1.296875 1.609375,2.421875 0,1 -0.4375,1.75 -1.3125,2.25 -0.738281,0.40625 -1.722656,0.609375 -2.953125,0.609375 -0.945312,0 -1.765625,-0.125 -2.453125,-0.375 -1.269531,-0.457031 -1.90625,-1.289062 -1.90625,-2.5 z m 7.65625,0.015625 c 0,-0.550781 -0.238281,-0.988281 -0.71875,-1.3125 -0.488281,-0.320313 -1.394531,-0.484375 -2.71875,-0.484375 -0.945313,0 -1.726563,0.121094 -2.34375,0.359375 -0.613281,0.230469 -0.921875,0.683594 -0.921875,1.359375 0,0.625 0.292969,1.085938 0.875,1.375 0.585938,0.28125 1.445312,0.421875 2.578125,0.421875 0.855469,0 1.542969,-0.09375 2.0625,-0.28125 0.792969,-0.28125 1.1875,-0.757813 1.1875,-1.4375 z"
           id="path4343"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-11"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -2.96875,-3.96875 -3.8125,0 3.8125,2.6875 z M 0,-3.984375 l -2.046875,0 0,3.671875 -1.03125,0 -5.34375,-3.84375 0,-0.890625 5.453125,0 0,-1.234375 0.921875,0 0,1.234375 2.046875,0 z"
           id="path4346"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-12"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -4.875,-3.265625 c 0,-0.46875 -0.128906,-0.832031 -0.390625,-1.09375 C -5.523438,-4.617188 -5.832031,-4.75 -6.1875,-4.75 c -0.3125,0 -0.597656,0.125 -0.859375,0.375 -0.269531,0.25 -0.40625,0.632812 -0.40625,1.140625 0,0.511719 0.136719,0.882813 0.40625,1.109375 0.261719,0.230469 0.5625,0.34375 0.90625,0.34375 0.398437,0 0.710937,-0.144531 0.9375,-0.4375 0.21875,-0.300781 0.328125,-0.648438 0.328125,-1.046875 z m 4.15625,-0.0625 c 0,-0.488281 -0.128906,-0.894531 -0.390625,-1.21875 -0.269531,-0.320313 -0.664063,-0.484375 -1.1875,-0.484375 -0.539063,0 -0.953125,0.167969 -1.234375,0.5 -0.28125,0.335938 -0.421875,0.761719 -0.421875,1.28125 0,0.5 0.148437,0.914062 0.4375,1.234375 0.28125,0.3125 0.679687,0.46875 1.1875,0.46875 0.4375,0 0.820313,-0.144531 1.140625,-0.4375 0.3125,-0.289063 0.46875,-0.738281 0.46875,-1.34375 z m -3.75,1.5 c -0.125,0.292969 -0.269531,0.523437 -0.4375,0.6875 -0.3125,0.304687 -0.71875,0.453125 -1.21875,0.453125 -0.625,0 -1.160156,-0.222656 -1.609375,-0.671875 -0.457031,-0.457031 -0.6875,-1.097656 -0.6875,-1.921875 0,-0.8125 0.214844,-1.441406 0.640625,-1.890625 0.429688,-0.457031 0.921875,-0.6875 1.484375,-0.6875 0.523437,0 0.949219,0.132813 1.28125,0.390625 0.179687,0.148438 0.355469,0.375 0.53125,0.6875 0.15625,-0.34375 0.339844,-0.613281 0.546875,-0.8125 0.398438,-0.375 0.90625,-0.5625 1.53125,-0.5625 0.742188,0 1.367188,0.25 1.875,0.75 0.5117188,0.492188 0.765625,1.1875 0.765625,2.09375 0,0.824219 -0.21875,1.515625 -0.65625,2.078125 -0.445313,0.5625 -1.09375,0.84375 -1.9375,0.84375 -0.488281,0 -0.914063,-0.117187 -1.28125,-0.359375 -0.363281,-0.238281 -0.640625,-0.597656 -0.828125,-1.078125 z"
           id="path4349"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-13"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -5.9375,-1.15625 -0.8125,0 c -0.070312,-0.757812 -0.195312,-1.285156 -0.375,-1.578125 -0.175781,-0.300781 -0.585938,-0.53125 -1.234375,-0.6875 l 0,-0.828125 8.359375,0 0,1.125 -5.9375,0 z"
           id="path4352"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-14"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="M 0,-0.375 C -0.71875,-0.414062 -1.34375,-0.566406 -1.875,-0.828125 -2.414062,-1.085938 -2.90625,-1.59375 -3.34375,-2.34375 L -4,-3.46875 c -0.289062,-0.5 -0.539062,-0.851562 -0.75,-1.0625 -0.320312,-0.320312 -0.691406,-0.484375 -1.109375,-0.484375 -0.488281,0 -0.875,0.152344 -1.15625,0.453125 -0.289063,0.292969 -0.4375,0.679688 -0.4375,1.15625 0,0.730469 0.273437,1.230469 0.8125,1.5 0.304687,0.15625 0.710937,0.242188 1.21875,0.25 l 0,1.078125 c -0.726563,-0.007813 -1.320313,-0.144531 -1.78125,-0.40625 -0.8125,-0.457031 -1.21875,-1.265625 -1.21875,-2.421875 0,-0.957031 0.261719,-1.65625 0.78125,-2.09375 0.523437,-0.445312 1.101563,-0.671875 1.734375,-0.671875 0.667969,0 1.242188,0.234375 1.71875,0.703125 0.28125,0.273438 0.621094,0.761719 1.015625,1.46875 l 0.4375,0.8125 c 0.210937,0.375 0.414063,0.671875 0.609375,0.890625 0.335938,0.398437 0.710938,0.648437 1.125,0.75 l 0,-4.59375 1,0 z"
           id="path4355"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-15"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m -8.421875,-3.515625 c 0,-0.9375 0.246094,-1.585937 0.734375,-1.953125 0.480469,-0.375 0.980469,-0.5625 1.5,-0.5625 l 0,1.046875 c -0.332031,0.0625 -0.59375,0.164063 -0.78125,0.296875 C -7.320312,-4.425781 -7.5,-4.039062 -7.5,-3.53125 c 0,0.59375 0.277344,1.070312 0.828125,1.421875 0.542969,0.34375 1.320313,0.53125 2.328125,0.5625 -0.351562,-0.238281 -0.617188,-0.539063 -0.796875,-0.90625 -0.15625,-0.332031 -0.234375,-0.707031 -0.234375,-1.125 0,-0.707031 0.226562,-1.320313 0.671875,-1.84375 0.449219,-0.519531 1.121094,-0.78125 2.015625,-0.78125 0.761719,0 1.4375,0.25 2.03125,0.75 0.5859375,0.492187 0.875,1.195313 0.875,2.109375 0,0.792969 -0.296875,1.476562 -0.890625,2.046875 -0.601563,0.5625 -1.609375,0.84375 -3.015625,0.84375 -1.039062,0 -1.925781,-0.125 -2.65625,-0.375 -1.382812,-0.488281 -2.078125,-1.382813 -2.078125,-2.6875 z M -0.71875,-3.4375 c 0,-0.550781 -0.1875,-0.960938 -0.5625,-1.234375 -0.375,-0.28125 -0.816406,-0.421875 -1.328125,-0.421875 -0.425781,0 -0.832031,0.125 -1.21875,0.375 -0.382813,0.242188 -0.578125,0.6875 -0.578125,1.34375 0,0.449219 0.152344,0.84375 0.453125,1.1875 0.292969,0.34375 0.742187,0.515625 1.34375,0.515625 0.53125,0 0.980469,-0.15625 1.34375,-0.46875 0.367187,-0.3125 0.546875,-0.742187 0.546875,-1.296875 z"
           id="path4358"
           inkscape:connector-curvature="0" />
      </symbol>
      <symbol
         overflow="visible"
         id="glyph1-16"
         style="overflow:visible">
        <path
           style="stroke:none"
           d="m 0.234375,-3.125 c 0,1 -0.2695312,1.726562 -0.8125,2.171875 -0.550781,0.449219 -1.21875,0.671875 -2,0.671875 l 0,-1.109375 c 0.542969,-0.039063 0.9375,-0.140625 1.1875,-0.296875 0.4375,-0.28125 0.65625,-0.773438 0.65625,-1.484375 0,-0.5625 -0.144531,-1.007813 -0.4375,-1.34375 -0.300781,-0.332031 -0.6875,-0.5 -1.15625,-0.5 -0.570313,0 -0.972656,0.179687 -1.203125,0.53125 -0.238281,0.355469 -0.359375,0.84375 -0.359375,1.46875 0,0.074219 0.00781,0.148437 0.015625,0.21875 0,0.074219 0,0.148437 0,0.21875 l -0.9375,0 c 0.023438,-0.113281 0.03125,-0.207031 0.03125,-0.28125 0,-0.070313 0,-0.148437 0,-0.234375 0,-0.394531 -0.0625,-0.71875 -0.1875,-0.96875 -0.21875,-0.445312 -0.609375,-0.671875 -1.171875,-0.671875 -0.414063,0 -0.734375,0.152344 -0.953125,0.453125 -0.226562,0.292969 -0.34375,0.636719 -0.34375,1.03125 0,0.699219 0.234375,1.183594 0.703125,1.453125 0.25,0.148437 0.617187,0.230469 1.09375,0.25 l 0,1.046875 c -0.625,0 -1.15625,-0.125 -1.59375,-0.375 -0.78125,-0.425781 -1.171875,-1.179688 -1.171875,-2.265625 0,-0.851563 0.195312,-1.515625 0.578125,-1.984375 0.375,-0.46875 0.929687,-0.703125 1.65625,-0.703125 0.511719,0 0.929687,0.136719 1.25,0.40625 0.199219,0.179687 0.355469,0.402344 0.46875,0.671875 0.125,-0.4375 0.359375,-0.78125 0.703125,-1.03125 0.34375,-0.25 0.765625,-0.375 1.265625,-0.375 0.804687,0 1.460937,0.265625 1.96875,0.796875 0.5,0.523437 0.75,1.265625 0.75,2.234375 z"
           id="path4361"
           inkscape:connector-curvature="0" />
      </symbol>
    </g>
  </defs>
  <rect
     id="rect4364"
     style="fill:#fff3df;fill-opacity:1;stroke:none"
     height="396.73468"
     width="576"
     y="0"
     x="0" />
  <path
     style="fill:none;stroke:#45873b;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
     d="M 88.266406,310.63218 C 122.02676,237.79712 168.07359,167.7088 234.99687,121.36656 298.00502,77.074005 374.52101,57.963738 449.84844,47.956407 c 29.57913,-3.956704 59.3163,-6.634684 89.08593,-8.656254"
     id="path4366"
     inkscape:connector-curvature="0" />
  <path
     style="fill:none;stroke:#95473f;stroke-width:1.60000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
     d="M 88.266406,33.300157 C 122.02506,106.13557 168.07177,176.22644 234.99687,222.56578 c 63.74354,44.80848 141.26877,63.83721 217.47266,73.75781 28.71422,3.77216 57.57485,6.34594 86.46484,8.31216"
     id="path4368"
     inkscape:connector-curvature="0" />
  <g
     id="g4370"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-41.632655)">
    <use
       height="100%"
       width="100%"
       id="use4372"
       y="413.28125"
       x="289.06641"
       xlink:href="#glyph0-1"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4374"
       y="413.28125"
       x="296.39648"
       xlink:href="#glyph0-2"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4376"
       y="413.28125"
       x="299.0625"
       xlink:href="#glyph0-3"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4378"
       y="413.28125"
       x="309.05859"
       xlink:href="#glyph0-4"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4380"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4382"
       y="237.14844"
       x="12.960938"
       xlink:href="#glyph1-1"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4384"
       y="229.14453"
       x="12.960938"
       xlink:href="#glyph1-2"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4386"
       y="225.14844"
       x="12.960938"
       xlink:href="#glyph1-3"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4388"
       y="222.48242"
       x="12.960938"
       xlink:href="#glyph1-4"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4390"
       y="215.80859"
       x="12.960938"
       xlink:href="#glyph1-5"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4392"
       y="209.13477"
       x="12.960938"
       xlink:href="#glyph1-6"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4394"
       y="205.80078"
       x="12.960938"
       xlink:href="#glyph1-7"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4396"
       y="199.12695"
       x="12.960938"
       xlink:href="#glyph1-8"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4398"
       y="192.45312"
       x="12.960938"
       xlink:href="#glyph1-9"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4400"
       y="186.45312"
       x="12.960938"
       xlink:href="#glyph1-9"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <path
     inkscape:connector-curvature="0"
     id="path4402"
     d="m 86.957812,321.72593 458.527348,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4404"
     d="m 86.957812,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4406"
     d="m 152.46172,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4408"
     d="m 217.96562,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4410"
     d="m 283.46953,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4412"
     d="m 348.97344,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4414"
     d="m 414.47734,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4416"
     d="m 479.98125,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4418"
     d="m 545.48516,321.72593 0,7.20313"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <g
     id="g4420"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4422"
       y="384.48047"
       x="72.421875"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4424"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4426"
       y="384.48047"
       x="134.58984"
       xlink:href="#glyph0-6"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4428"
       y="384.48047"
       x="141.26367"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4430"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4432"
       y="384.48047"
       x="196.75391"
       xlink:href="#glyph0-7"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4434"
       y="384.48047"
       x="203.42773"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4436"
       y="384.48047"
       x="210.10156"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4438"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4440"
       y="384.48047"
       x="262.25781"
       xlink:href="#glyph0-7"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4442"
       y="384.48047"
       x="268.93164"
       xlink:href="#glyph0-6"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4444"
       y="384.48047"
       x="275.60547"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4446"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4448"
       y="384.48047"
       x="327.76172"
       xlink:href="#glyph0-8"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4450"
       y="384.48047"
       x="334.43555"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4452"
       y="384.48047"
       x="341.10938"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4454"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4456"
       y="384.48047"
       x="393.26562"
       xlink:href="#glyph0-8"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4458"
       y="384.48047"
       x="399.93945"
       xlink:href="#glyph0-6"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4460"
       y="384.48047"
       x="406.61328"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4462"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4464"
       y="384.48047"
       x="458.76953"
       xlink:href="#glyph0-9"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4466"
       y="384.48047"
       x="465.44336"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4468"
       y="384.48047"
       x="472.11719"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4470"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4472"
       y="384.48047"
       x="524.27344"
       xlink:href="#glyph0-9"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4474"
       y="384.48047"
       x="530.94727"
       xlink:href="#glyph0-6"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4476"
       y="384.48047"
       x="537.62109"
       xlink:href="#glyph0-5"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <path
     inkscape:connector-curvature="0"
     id="path4478"
     d="m 70.239062,313.46421 0,-282.992177"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4480"
     d="m 70.239062,313.46421 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4482"
     d="m 70.239062,278.08921 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4484"
     d="m 70.239062,242.71421 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4486"
     d="m 70.239062,207.34312 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4488"
     d="m 70.239062,171.96812 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4490"
     d="m 70.239062,136.59312 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4492"
     d="m 70.239062,101.21812 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4494"
     d="m 70.239062,65.843125 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <path
     inkscape:connector-curvature="0"
     id="path4496"
     d="m 70.239062,30.472033 -7.199218,0"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
  <g
     id="g4498"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4500"
       y="353.63281"
       x="41.761719"
       xlink:href="#glyph1-10"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4502"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4504"
       y="318.25781"
       x="41.761719"
       xlink:href="#glyph1-11"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4506"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4508"
       y="282.88281"
       x="41.761719"
       xlink:href="#glyph1-12"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4510"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4512"
       y="250.84766"
       x="41.761719"
       xlink:href="#glyph1-13"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4514"
       y="244.17383"
       x="41.761719"
       xlink:href="#glyph1-14"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4516"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4518"
       y="215.47266"
       x="41.761719"
       xlink:href="#glyph1-13"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4520"
       y="208.79883"
       x="41.761719"
       xlink:href="#glyph1-15"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4522"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4524"
       y="180.09766"
       x="41.761719"
       xlink:href="#glyph1-14"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4526"
       y="173.42383"
       x="41.761719"
       xlink:href="#glyph1-10"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4528"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4530"
       y="144.72266"
       x="41.761719"
       xlink:href="#glyph1-14"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4532"
       y="138.04883"
       x="41.761719"
       xlink:href="#glyph1-11"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4534"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4536"
       y="109.34766"
       x="41.761719"
       xlink:href="#glyph1-14"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4538"
       y="102.67383"
       x="41.761719"
       xlink:href="#glyph1-12"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <g
     id="g4540"
     style="fill:#5d4734;fill-opacity:1"
     transform="translate(11.2,-36.832655)">
    <use
       height="100%"
       width="100%"
       id="use4542"
       y="73.976562"
       x="41.761719"
       xlink:href="#glyph1-16"
       style="fill:#5d4734;fill-opacity:1" />
    <use
       height="100%"
       width="100%"
       id="use4544"
       y="67.302734"
       x="41.761719"
       xlink:href="#glyph1-14"
       style="fill:#5d4734;fill-opacity:1" />
  </g>
  <path
     inkscape:connector-curvature="0"
     id="path4546"
     d="m 70.239062,321.72593 486.722658,0 0,-299.519523 -486.722658,0 0,299.519523"
     style="fill:none;stroke:#5d4734;stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
</svg>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted pics/wy/back.jpg.

cannot compute difference between binary files

Deleted pics/wy/front.jpg.

cannot compute difference between binary files

Deleted pics/wy/power-switch.png.

cannot compute difference between binary files

Deleted pics/wy/serial-db9.jpg.

cannot compute difference between binary files

Deleted pics/wy/serial-kk.jpg.

cannot compute difference between binary files

Deleted pics/wy/system.jpg.

cannot compute difference between binary files

Deleted src/Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
########################################################################
# Makefile.in - Processed by autosetup's configure script to generate
#    an intermediate GNU make(1) file for building the PiDP-8/I software
#    from within its src/ subdirectory.
#
# The resulting Makefile will redirect simple "make" calls to the top
# level as well as the major top-level targets (e.g. "make clean") but
# purposefully will not redirect anything like an installation or "run
# the system" type target.  Its only purpose is to help out those who
# are working on the PiDP-8/I project's C source code from within this
# directory.  If you need to work on the wider system, do it from the
# project's top level.
#
# If you are seeing this at the top of a file called Makefile and you
# intend to make edits, do that in Makefile.in.  Saying "make" will then
# re-build Makefile from that modified Makefile.in before proceeding to
# do the "make" operation.
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

all clean ctags distclean tags reconfig:
	cd @builddir@; make $@
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































Deleted src/PDP8/Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
########################################################################
# Makefile.in - Processed by autosetup's configure script to generate
#    an intermediate GNU make(1) file for building the PiDP-8/I software
#    from within its src/PDP8 subdirectory.
#
# The resulting Makefile will redirect simple "make" calls to the top
# level as well as the major top-level targets (e.g. "make clean") but
# purposefully will not redirect anything like an installation or "run
# the system" type target.  Its only purpose is to help out those who
# are working on the PiDP-8/I project's C source code from within this
# directory.  If you need to work on the wider system, do it from the
# project's top level.
#
# If you are seeing this at the top of a file called Makefile and you
# intend to make edits, do that in Makefile.in.  Saying "make" will then
# re-build Makefile from that modified Makefile.in before proceeding to
# do the "make" operation.
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

all clean ctags distclean tags reconfig:
	cd @builddir@; make $@
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































Deleted src/PDP8/pdp8_clk.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* pdp8_clk.c: PDP-8 real-time clock simulator

   Copyright (c) 1993-2012, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   clk          real time clock

   18-Apr-12    RMS     Added clock coscheduling
   18-Jun-07    RMS     Added UNIT_IDLE flag
   01-Mar-03    RMS     Aded SET/SHOW CLK FREQ support
   04-Oct-02    RMS     Added DIB, device number support
   30-Dec-01    RMS     Removed for generalized timers
   05-Sep-01    RMS     Added terminal multiplexor support
   17-Jul-01    RMS     Moved function prototype
   05-Mar-01    RMS     Added clock calibration support

   Note: includes the IOT's for both the PDP-8/E and PDP-8/A clocks
*/

#include "pdp8_defs.h"

extern int32 int_req, int_enable, dev_done, stop_inst;

int32 clk_tps = 60;                                     /* ticks/second */
int32 tmxr_poll = 16000;                                /* term mux poll */

int32 clk (int32 IR, int32 AC);
t_stat clk_svc (UNIT *uptr);
t_stat clk_reset (DEVICE *dptr);
t_stat clk_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc);

/* CLK data structures

   clk_dev      CLK device descriptor
   clk_unit     CLK unit descriptor
   clk_reg      CLK register list
*/

DIB clk_dib = { DEV_CLK, 1, { &clk } };

UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), 16000 };

REG clk_reg[] = {
    { FLDATAD (DONE, dev_done, INT_V_CLK, "device done flag") },
    { FLDATAD (ENABLE, int_enable, INT_V_CLK, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_CLK, "interrupt pending flag") },
    { DRDATAD (TIME, clk_unit.wait, 24, "clock interval"), REG_NZ + PV_LEFT },
    { DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO },
    { NULL }
    };

MTAB clk_mod[] = {
    { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ",
      &clk_set_freq, NULL, NULL },
    { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ",
      &clk_set_freq, NULL, NULL },
    { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,
      NULL, &clk_show_freq, NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
    { 0 }
    };

DEVICE clk_dev = {
    "CLK", &clk_unit, clk_reg, clk_mod,
    1, 0, 0, 0, 0, 0,
    NULL, NULL, &clk_reset,
    NULL, NULL, NULL,
    &clk_dib, 0
    };

/* IOT routine

   IOT's 6131-6133 are the PDP-8/E clock
   IOT's 6135-6137 are the PDP-8/A clock
*/

int32 clk (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 1:                                             /* CLEI */
        int_enable = int_enable | INT_CLK;              /* enable clk ints */
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 2:                                             /* CLDI */
        int_enable = int_enable & ~INT_CLK;             /* disable clk ints */
        int_req = int_req & ~INT_CLK;                   /* update interrupts */
        return AC;

    case 3:                                             /* CLSC */
        if (dev_done & INT_CLK) {                       /* flag set? */
            dev_done = dev_done & ~INT_CLK;             /* clear flag */
            int_req = int_req & ~INT_CLK;               /* clear int req */
            return IOT_SKP + AC;
            }
        return AC;

    case 5:                                             /* CLLE */
        if (AC & 1)                                     /* test AC<11> */
            int_enable = int_enable | INT_CLK;
        else int_enable = int_enable & ~INT_CLK;
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 6:                                             /* CLCL */
        dev_done = dev_done & ~INT_CLK;                 /* clear flag */
        int_req = int_req & ~INT_CLK;                   /* clear int req */
        return AC;

    case 7:                                             /* CLSK */
        return (dev_done & INT_CLK)? IOT_SKP + AC: AC;

    default:
        return (stop_inst << IOT_V_REASON) + AC;
        }                                               /* end switch */
}

/* Unit service */

t_stat clk_svc (UNIT *uptr)
{
dev_done = dev_done | INT_CLK;                          /* set done */
int_req = INT_UPDATE;                                   /* update interrupts */
tmxr_poll = sim_rtcn_calb (clk_tps, TMR_CLK);           /* calibrate clock */
sim_activate_after (uptr, 1000000/clk_tps);             /* reactivate unit */
return SCPE_OK;
}

/* Reset routine */

t_stat clk_reset (DEVICE *dptr)
{
dev_done = dev_done & ~INT_CLK;                         /* clear done, int */
int_req = int_req & ~INT_CLK;
int_enable = int_enable & ~INT_CLK;                     /* clear enable */
if (!sim_is_running) {                                  /* RESET (not CAF)? */
    tmxr_poll = sim_rtcn_init_unit (&clk_unit, clk_unit.wait, TMR_CLK);/* init 100Hz timer */
    sim_activate_after (&clk_unit, 1000000/clk_tps);        /* activate 100Hz unit */
    }
return SCPE_OK;
}

/* Set frequency */

t_stat clk_set_freq (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (cptr)
    return SCPE_ARG;
if ((val != 50) && (val != 60))
    return SCPE_IERR;
clk_tps = val;
return SCPE_OK;
}

/* Show frequency */

t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
fprintf (st, (clk_tps == 50)? "50Hz": "60Hz");
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































Deleted src/PDP8/pdp8_cpu.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
/* pdp8_cpu.c: PDP-8 CPU simulator

   Copyright (c) 1993-2017, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   ----------------------------------------------------------------------------

   Portions copyright (c) 2015-2017, Oscar Vermeulen and Warren Young

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the names of the authors above shall
   not be used in advertising or otherwise to promote the sale, use or other
   dealings in this Software without prior written authorization from those
   authors.

   ----------------------------------------------------------------------------

   cpu          central processor

   09-Mar-17    RMS     Fixed PCQ_ENTRY for interrupts (COVERITY)
   13-Feb-17    RMS     RESET clear L'AC, per schematics
   28-Jan-17    RMS     Renamed switch register variable to SR, per request
   18-Sep-16    RMS     Added alternate dispatch table for non-contiguous devices
   17-Sep-13    RMS     Fixed boot in wrong field problem (Dave Gesswein)
   28-Apr-07    RMS     Removed clock initialization
   30-Oct-06    RMS     Added idle and infinite loop detection
   30-Sep-06    RMS     Fixed SC value after DVI overflow (Don North)
   22-Sep-05    RMS     Fixed declarations (Sterling Garwood)
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   06-Nov-04    RMS     Added =n to SHOW HISTORY
   31-Dec-03    RMS     Fixed bug in set_cpu_hist
   13-Oct-03    RMS     Added instruction history
                        Added TSC8-75 support (Bernhard Baehr)
   12-Mar-03    RMS     Added logical name support
   04-Oct-02    RMS     Revamped device dispatching, added device number support
   06-Jan-02    RMS     Added device enable/disable routines
   30-Dec-01    RMS     Added old PC queue
   16-Dec-01    RMS     Fixed bugs in EAE
   07-Dec-01    RMS     Revised to use new breakpoint package
   30-Nov-01    RMS     Added RL8A, extended SET/SHOW support
   16-Sep-01    RMS     Fixed bug in reset routine, added KL8A support
   10-Aug-01    RMS     Removed register from declarations
   17-Jul-01    RMS     Moved function prototype
   07-Jun-01    RMS     Fixed bug in JMS to non-existent memory
   25-Apr-01    RMS     Added device enable/disable support
   18-Mar-01    RMS     Added DF32 support
   05-Mar-01    RMS     Added clock calibration support
   15-Feb-01    RMS     Added DECtape support
   14-Apr-99    RMS     Changed t_addr to unsigned

   The register state for the PDP-8 is:

   AC<0:11>             accumulator
   MQ<0:11>             multiplier-quotient
   L                    link flag
   PC<0:11>             program counter
   IF<0:2>              instruction field
   IB<0:2>              instruction buffer
   DF<0:2>              data field
   UF                   user flag
   UB                   user buffer
   SF<0:6>              interrupt save field

   The PDP-8 has three instruction formats: memory reference, I/O transfer,
   and operate.  The memory reference format is:

     0  1  2  3  4  5  6  7  8  9 10 11
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |   op   |in|zr|    page offset     |        memory reference
   +--+--+--+--+--+--+--+--+--+--+--+--+

   <0:2>        mnemonic        action

    000         AND             AC = AC & M[MA]
    001         TAD             L'AC = AC + M[MA]
    010         DCA             M[MA] = AC, AC = 0
    011         ISZ             M[MA] = M[MA] + 1, skip if M[MA] == 0
    100         JMS             M[MA] = PC, PC = MA + 1
    101         JMP             PC = MA

   <3:4>        mode            action
    00  page zero               MA = IF'0'IR<5:11>
    01  current page            MA = IF'PC<0:4>'IR<5:11>
    10  indirect page zero      MA = xF'M[IF'0'IR<5:11>]
    11  indirect current page   MA = xF'M[IF'PC<0:4>'IR<5:11>]

   where x is D for AND, TAD, ISZ, DCA, and I for JMS, JMP.

   Memory reference instructions can access an address space of 32K words.
   The address space is divided into eight 4K word fields; each field is
   divided into thirty-two 128 word pages.  An instruction can directly
   address, via its 7b offset, locations 0-127 on page zero or on the current
   page.  All 32k words can be accessed via indirect addressing and the
   instruction and data field registers.  If an indirect address is in
   locations 0010-0017 of any field, the indirect address is incremented
   and rewritten to memory before use.

   The I/O transfer format is as follows:

     0  1  2  3  4  5  6  7  8  9 10 11
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |   op   |      device     | pulse  |        I/O transfer
   +--+--+--+--+--+--+--+--+--+--+--+--+

   The IO transfer instruction sends the the specified pulse to the
   specified I/O device.  The I/O device may take data from the AC,
   return data to the AC, initiate or cancel operations, or skip on
   status.

   The operate format is as follows:

   +--+--+--+--+--+--+--+--+--+--+--+--+
   | 1| 1| 1| 0|  |  |  |  |  |  |  |  |        operate group 1
   +--+--+--+--+--+--+--+--+--+--+--+--+
                |  |  |  |  |  |  |  |
                |  |  |  |  |  |  |  +--- increment AC  3
                |  |  |  |  |  |  +--- rotate 1 or 2    4
                |  |  |  |  |  +--- rotate left         4
                |  |  |  |  +--- rotate right           4
                |  |  |  +--- complement L              2
                |  |  +--- complement AC                2
                |  +--- clear L                         1
                +-- clear AC                            1

   +--+--+--+--+--+--+--+--+--+--+--+--+
   | 1| 1| 1| 1|  |  |  |  |  |  |  | 0|        operate group 2
   +--+--+--+--+--+--+--+--+--+--+--+--+
                |  |  |  |  |  |  |
                |  |  |  |  |  |  +--- halt             3
                |  |  |  |  |  +--- or switch register  3
                |  |  |  |  +--- reverse skip sense     1
                |  |  |  +--- skip on L != 0            1
                |  |  +--- skip on AC == 0              1
                |  +--- skip on AC < 0                  1
                +-- clear AC                            2

   +--+--+--+--+--+--+--+--+--+--+--+--+
   | 1| 1| 1| 1|  |  |  |  |  |  |  | 1|        operate group 3
   +--+--+--+--+--+--+--+--+--+--+--+--+
                |  |  |  | \______/
                |  |  |  |     |
                |  |  +--|-----+--- EAE command         3
                |  |     +--- AC -> MQ, 0 -> AC         2
                |  +--- MQ v AC --> AC                  2
                +-- clear AC                            1

  The operate instruction can be microprogrammed to perform operations
  on the AC, MQ, and link.

  This routine is the instruction decode routine for the PDP-8.
   It is called from the simulator control program to execute
   instructions in simulated memory, starting at the simulated PC.
   It runs until 'reason' is set non-zero.

   General notes:

   1. Reasons to stop.  The simulator can be stopped by:

        HALT instruction
        breakpoint encountered
        unimplemented instruction and stop_inst flag set
        I/O error in I/O simulator

   2. Interrupts.  Interrupts are maintained by three parallel variables:

        dev_done        device done flags
        int_enable      interrupt enable flags
        int_req         interrupt requests

      In addition, int_req contains the interrupt enable flag, the
      CIF not pending flag, and the ION not pending flag.  If all
      three of these flags are set, and at least one interrupt request
      is set, then an interrupt occurs.

   3. Non-existent memory.  On the PDP-8, reads to non-existent memory
      return zero, and writes are ignored.  In the simulator, the
      largest possible memory is instantiated and initialized to zero.
      Thus, only writes outside the current field (indirect writes) need
      be checked against actual memory size.

   3. Adding I/O devices.  These modules must be modified:

        pdp8_defs.h     add device number and interrupt definitions
        pdp8_sys.c      add sim_devices table entry
*/

/* ---PiDP change------------------------------------------------------------------------------------------- */
#include "gpio-common.h"
#include "pidp8i.h"
/* ---PiDP end---------------------------------------------------------------------------------------------- */

#define PCQ_SIZE        64                              /* must be 2**n */
#define PCQ_MASK        (PCQ_SIZE - 1)
#define PCQ_ENTRY(x)    pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = x
#define UNIT_V_NOEAE    (UNIT_V_UF)                     /* EAE absent */
#define UNIT_NOEAE      (1 << UNIT_V_NOEAE)
#define UNIT_V_MSIZE    (UNIT_V_UF + 1)                 /* dummy mask */
#define UNIT_MSIZE      (1 << UNIT_V_MSIZE)
#define OP_KSF          06031                           /* for idle */

#define HIST_PC         0x40000000
#define HIST_MIN        64
#define HIST_MAX        65536

typedef struct {
    int32               pc;
    int32               ea;
    int16               ir;
    int16               opnd;
    int16               lac;
    int16               mq;
    } InstHistory;

uint16 M[MAXMEMSIZE] = { 0 };                           /* main memory */
int32 saved_LAC = 0;                                    /* saved L'AC */
int32 saved_MQ = 0;                                     /* saved MQ */
int32 saved_PC = 0;                                     /* saved IF'PC */
int32 saved_DF = 0;                                     /* saved Data Field */
int32 IB = 0;                                           /* Instruction Buffer */
int32 SF = 0;                                           /* Save Field */
int32 emode = 0;                                        /* EAE mode */
int32 gtf = 0;                                          /* EAE gtf flag */
int32 SC = 0;                                           /* EAE shift count */
int32 UB = 0;                                           /* User mode Buffer */
int32 UF = 0;                                           /* User mode Flag */
int32 SR = 0;                                           /* Switch Register */
int32 tsc_ir = 0;                                       /* TSC8-75 IR */
int32 tsc_pc = 0;                                       /* TSC8-75 PC */
int32 tsc_cdf = 0;                                      /* TSC8-75 CDF flag */
int32 tsc_enb = 0;                                      /* TSC8-75 enabled */
int32 cpu_astop = 0;                                    /* address stop */
int16 pcq[PCQ_SIZE] = { 0 };                            /* PC queue */
int32 pcq_p = 0;                                        /* PC queue ptr */
REG *pcq_r = NULL;                                      /* PC queue reg ptr */
int32 dev_done = 0;                                     /* dev done flags */
int32 int_enable = INT_INIT_ENABLE;                     /* intr enables */
int32 int_req = 0;                                      /* intr requests */
int32 stop_inst = 0;                                    /* trap on ill inst */
int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat);         /* device dispatch */
int32 hst_p = 0;                                        /* history pointer */
int32 hst_lnt = 0;                                      /* history length */
InstHistory *hst = NULL;                                /* instruction history */

t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_bool build_dev_tab (void);

/* CPU data structures

   cpu_dev      CPU device descriptor
   cpu_unit     CPU unit descriptor
   cpu_reg      CPU register list
   cpu_mod      CPU modifier list
*/

UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };

REG cpu_reg[] = {
    { ORDATAD (PC, saved_PC, 15, "program counter") },
    { ORDATAD (AC, saved_LAC, 12, "accumulator") },
    { FLDATAD (L, saved_LAC, 12, "link") },
    { ORDATAD (MQ, saved_MQ, 12, "multiplier-quotient") },
    { ORDATAD (SR, SR, 12, "front panel switches") },
    { GRDATAD (IF, saved_PC, 8, 3, 12, "instruction field") },
    { GRDATAD (DF, saved_DF, 8, 3, 12, "data field") },
    { GRDATAD (IB, IB, 8, 3, 12, "instruction field buffter") },
    { ORDATAD (SF, SF, 7, "save field") },
    { FLDATAD (UB, UB, 0, "user mode buffer") },
    { FLDATAD (UF, UF, 0, "user mode flag") },
    { ORDATAD (SC, SC, 5, "EAE shift counter") },
    { FLDATAD (GTF, gtf, 0, "EAE greater than flag") },
    { FLDATAD (EMODE, emode, 0, "EAE mode (0 = A, 1 = B)") },
    { FLDATAD (ION, int_req, INT_V_ION, "interrupt enable") },
    { FLDATAD (ION_DELAY, int_req, INT_V_NO_ION_PENDING, "interrupt enable delay for ION") },
    { FLDATAD (CIF_DELAY, int_req, INT_V_NO_CIF_PENDING, "interrupt enable delay for CIF") },
    { FLDATAD (PWR_INT, int_req, INT_V_PWR, "power fail interrupt") },
    { FLDATAD (UF_INT, int_req, INT_V_UF, "user mode violation interrupt") },
    { ORDATAD (INT, int_req, INT_V_ION+1, "interrupt pending flags"), REG_RO },
    { ORDATAD (DONE, dev_done, INT_V_DIRECT, "device done flags"), REG_RO },
    { ORDATAD (ENABLE, int_enable, INT_V_DIRECT, "device interrupt enable flags"), REG_RO },
    { BRDATAD (PCQ, pcq, 8, 15, PCQ_SIZE, "PC prior to last JMP, JMS, or interrupt;                                        most recent PC change first"), REG_RO+REG_CIRC },
    { ORDATA (PCQP, pcq_p, 6), REG_HRO },
    { FLDATAD (STOP_INST, stop_inst, 0, "stop on undefined instruction") },
    { ORDATAD (WRU, sim_int_char, 8, "interrupt character") },
    { NULL }
    };

MTAB cpu_mod[] = {
    { UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL },
    { UNIT_NOEAE, 0, "EAE", "EAE", NULL },
    { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
    { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
    { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
    { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
    { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },
    { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
    { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },
    { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
    { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },
    { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
    { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
      &cpu_set_hist, &cpu_show_hist },
    { 0 }
    };

DEVICE cpu_dev = {
    "CPU", &cpu_unit, cpu_reg, cpu_mod,
    1, 8, 15, 1, 8, 12,
    &cpu_ex, &cpu_dep, &cpu_reset,
    NULL, NULL, NULL,
    NULL, 0
    };

t_stat sim_instr (void)
{
int32 IR, MB, IF, DF, LAC, MQ;
uint32 PC, MA;
int32 device, pulse, temp, iot_data;
t_stat reason;

/* Restore register state */

if (build_dev_tab ())                                   /* build dev_tab */
    return SCPE_STOP;
PC = saved_PC & 007777;                                 /* load local copies */
IF = saved_PC & 070000;
DF = saved_DF & 070000;
LAC = saved_LAC & 017777;
MQ = saved_MQ & 07777;
int_req = INT_UPDATE;
reason = 0;


/* ---PiDP add--------------------------------------------------------------------------------------------- */
// PiDP-8/I specific flag, set when the last instruction was an IOT
// instruction to a real device.  SIMH doesn't track this, but the front
// panel needs it.
int Pause = 0;

// Set our initial IPS value from the throttle, if given.
static time_t last_update = 0;
static size_t max_skips = 0;
static const size_t pidp8i_updates_per_sec = 3200;
max_skips = get_pidp8i_initial_max_skips (pidp8i_updates_per_sec);
srand48 (time (&last_update));

// Reset display info in case we're re-entering the simulator from Ctrl-E
extern display display_bufs[2];
memset (display_bufs, 0, sizeof(display_bufs));
static size_t skip_count, dither, inst_count;
skip_count = dither = inst_count = 0;
/* ---PiDP end---------------------------------------------------------------------------------------------- */


/* Main instruction fetch/decode loop */

while (reason == 0) {                                   /* loop until halted */

    // Allow clean exit to SCP: https://github.com/simh/simh/issues/387
    if (cpu_astop != 0) {
        cpu_astop = 0;
        reason = SCPE_STOP;
        break;
        }

    if (sim_interval <= 0) {                            /* check clock queue */
        if ((reason = sim_process_event ())) {
/* ---PiDP add--------------------------------------------------------------------------------------------- */
            // We're about to leave the loop, so repaint one last time
            // in case this is a Ctrl-E and we later get a "cont"
            // command.  Set a flag that will let us auto-resume.
            extern int resumeFromInstructionLoopExit, swStop, swSingInst;
            resumeFromInstructionLoopExit = swStop = swSingInst = 1;
            set_pidp8i_leds (PC, MA, MB, IR, LAC, MQ, IF, DF, SC,
                    int_req, Pause);

            // Also copy SR hardware value to software register in case
            // the user tries poking at it from the sim> prompt.
            SR = get_switch_register();
/* ---PiDP end---------------------------------------------------------------------------------------------- */
            break;
            }
        }

/* ---PiDP add--------------------------------------------------------------------------------------------- */

    switch (handle_flow_control_switches(M, &PC, &MA, &MB, &LAC, &IF,
            &DF, &int_req)) {
        case pft_stop:
            // Tell the SIMH event queue to keep running even though
            // we're stopped.  Without this, it will ignore Ctrl-E
            // until the simulator is back in free-running mode.
            sim_interval = sim_interval - 1;

            // Have to keep display updated while stopped.  This does
            // mean if the software starts with the STOP switch held
            // down, we'll put garbage onto the display for MA, MB, and
            // IR, but that's what the real hardware does, too.  See
            // https://github.com/simh/simh/issues/386
            set_pidp8i_leds (PC, MA, MB, IR, LAC, MQ, IF, DF, SC,
                    int_req, Pause);

            // Go no further in STOP mode.  In particular, fetch no more
            // instructions, and do not touch PC!
            continue;

        case pft_halt:
            // Clear all registers and halt simulator
            PC  = saved_PC  = 0;
            IF  = saved_PC  = 0;
            DF  = saved_DF  = 0;
            LAC = saved_LAC = 0;
            MQ  = saved_MQ  = 0;
            int_req = 0;
            reason = STOP_HALT;
            continue;

        case pft_normal:
            // execute normally
            break;
    }

/* ---PiDP end---------------------------------------------------------------------------------------------- */

    if (int_req > INT_PENDING) {                        /* interrupt? */
        int_req = int_req & ~INT_ION;                   /* interrupts off */
        SF = (UF << 6) | (IF >> 9) | (DF >> 12);        /* form save field */
        PCQ_ENTRY (IF | PC);                            /* save old PC with IF */
        IF = IB = DF = UF = UB = 0;                     /* clear mem ext */
        M[0] = PC;                                      /* save PC in 0 */
        PC = 1;                                         /* fetch next from 1 */
        }

    MA = IF | PC;                                       /* form PC */
    if (sim_brk_summ && 
        sim_brk_test (MA, (1u << SIM_BKPT_V_SPC) | SWMASK ('E'))) { /* breakpoint? */
        reason = STOP_IBKPT;                            /* stop simulation */
        break;
        }

    IR = M[MA];                                         /* fetch instruction */
    if (sim_brk_summ && 
        sim_brk_test (IR, (2u << SIM_BKPT_V_SPC) | SWMASK ('I'))) { /* breakpoint? */
        reason = STOP_OPBKPT;                            /* stop simulation */
        break;
        }
    PC = (PC + 1) & 07777;                              /* increment PC */
    int_req = int_req | INT_NO_ION_PENDING;             /* clear ION delay */
    sim_interval = sim_interval - 1;

/* Instruction decoding.

   The opcode (IR<0:2>), indirect flag (IR<3>), and page flag (IR<4>)
   are decoded together.  This produces 32 decode points, four per
   major opcode.  For IOT, the extra decode points are not useful;
   for OPR, only the group flag (IR<3>) is used.

   AND, TAD, ISZ, DCA calculate a full 15b effective address.
   JMS, JMP calculate a 12b field-relative effective address.

   Autoindex calculations always occur within the same field as the
   instruction fetch.  The field must exist; otherwise, the instruction
   fetched would be 0000, and indirect addressing could not occur.

   Note that MA contains IF'PC.
*/

    if (hst_lnt) {                                      /* history enabled? */
        int32 ea;

        hst_p = (hst_p + 1);                            /* next entry */
        if (hst_p >= hst_lnt)
            hst_p = 0;
        hst[hst_p].pc = MA | HIST_PC;                   /* save PC, IR, LAC, MQ */
        hst[hst_p].ir = IR;
        hst[hst_p].lac = LAC;
        hst[hst_p].mq = MQ;
        if (IR < 06000) {                               /* mem ref? */
            if (IR & 0200)
                ea = (MA & 077600) | (IR & 0177);
            else ea = IF | (IR & 0177);                 /* direct addr */
            if (IR & 0400) {                            /* indirect? */
                if (IR < 04000) {                       /* mem operand? */
                    if ((ea & 07770) != 00010)
                        ea = DF | M[ea];
                    else ea = DF | ((M[ea] + 1) & 07777);
                    }
                else {                                  /* no, jms/jmp */
                    if ((ea & 07770) != 00010)
                        ea = IB | M[ea];
                    else ea = IB | ((M[ea] + 1) & 07777);
                    }
                }
            hst[hst_p].ea = ea;                         /* save eff addr */
            hst[hst_p].opnd = M[ea];                    /* save operand */
            }
        }

switch ((IR >> 7) & 037) {                              /* decode IR<0:4> */

/* Opcode 0, AND */

    case 000:                                           /* AND, dir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        LAC = LAC & (M[MA] | 010000);
        break;

    case 001:                                           /* AND, dir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        LAC = LAC & (M[MA] | 010000);
        break;

    case 002:                                           /* AND, indir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        LAC = LAC & (M[MA] | 010000);
        break;

    case 003:                                           /* AND, indir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        LAC = LAC & (M[MA] | 010000);
        break;

/* Opcode 1, TAD */

    case 004:                                           /* TAD, dir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        LAC = (LAC + M[MA]) & 017777;
        break;

    case 005:                                           /* TAD, dir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        LAC = (LAC + M[MA]) & 017777;
        break;

    case 006:                                           /* TAD, indir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        LAC = (LAC + M[MA]) & 017777;
        break;

    case 007:                                           /* TAD, indir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        LAC = (LAC + M[MA]) & 017777;
        break;

/* Opcode 2, ISZ */

    case 010:                                           /* ISZ, dir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        M[MA] = MB = (M[MA] + 1) & 07777;               /* field must exist */
        if (MB == 0)
            PC = (PC + 1) & 07777;
        break;

    case 011:                                           /* ISZ, dir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        M[MA] = MB = (M[MA] + 1) & 07777;               /* field must exist */
        if (MB == 0)
            PC = (PC + 1) & 07777;
        break;

    case 012:                                           /* ISZ, indir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        MB = (M[MA] + 1) & 07777;
        if (MEM_ADDR_OK (MA))
            M[MA] = MB;
        if (MB == 0)
            PC = (PC + 1) & 07777;
        break;

    case 013:                                           /* ISZ, indir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        MB = (M[MA] + 1) & 07777;
        if (MEM_ADDR_OK (MA))
            M[MA] = MB;
        if (MB == 0)
            PC = (PC + 1) & 07777;
        break;

/* Opcode 3, DCA */

    case 014:                                           /* DCA, dir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        M[MA] = LAC & 07777;
        LAC = LAC & 010000;
        break;

    case 015:                                           /* DCA, dir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        M[MA] = LAC & 07777;
        LAC = LAC & 010000;
        break;

    case 016:                                           /* DCA, indir, zero */
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        if (MEM_ADDR_OK (MA))
            M[MA] = LAC & 07777;
        LAC = LAC & 010000;
        break;

    case 017:                                           /* DCA, indir, curr */
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = DF | M[MA];
        else MA = DF | (M[MA] = (M[MA] + 1) & 07777);   /* incr before use */
        if (MEM_ADDR_OK (MA))
            M[MA] = LAC & 07777;
        LAC = LAC & 010000;
        break;

/* Opcode 4, JMS.  From Bernhard Baehr's description of the TSC8-75:

   (In user mode) the current JMS opcode is moved to the ERIOT register, the ECDF
   flag is cleared. The address of the JMS instruction is loaded into the ERTB
   register and the TSC8-75 I/O flag is raised. When the TSC8-75 is enabled, the
   target addess of the JMS is loaded into PC, but nothing else (loading of IF, UF,
   clearing the interrupt inhibit flag, storing of the return address in the first
   word of the subroutine) happens. When the TSC8-75 is disabled, the JMS is performed
   as usual. */

    case 020:                                           /* JMS, dir, zero */
        PCQ_ENTRY (MA);
        MA = IR & 0177;                                 /* dir addr, page zero */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            }
        if (UF && tsc_enb) {                            /* user mode, TSC enab? */
            tsc_pc = (PC - 1) & 07777;                  /* save PC */
            int_req = int_req | INT_TSC;                /* request intr */
            }
        else {                                          /* normal */
            IF = IB;                                    /* change IF */
            UF = UB;                                    /* change UF */
            int_req = int_req | INT_NO_CIF_PENDING;     /* clr intr inhibit */
            MA = IF | MA;
            if (MEM_ADDR_OK (MA))
                M[MA] = PC;
            }
        PC = (MA + 1) & 07777;
        break;

    case 021:                                           /* JMS, dir, curr */
        PCQ_ENTRY (MA);
        MA = (MA & 007600) | (IR & 0177);               /* dir addr, curr page */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            }
        if (UF && tsc_enb) {                            /* user mode, TSC enab? */
            tsc_pc = (PC - 1) & 07777;                  /* save PC */
            int_req = int_req | INT_TSC;                /* request intr */
            }
        else {                                          /* normal */
            IF = IB;                                    /* change IF */
            UF = UB;                                    /* change UF */
            int_req = int_req | INT_NO_CIF_PENDING;     /* clr intr inhibit */
            MA = IF | MA;
            if (MEM_ADDR_OK (MA))
                M[MA] = PC;
            }
        PC = (MA + 1) & 07777;
        break;

    case 022:                                           /* JMS, indir, zero */
        PCQ_ENTRY (MA);
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = M[MA];
        else MA = (M[MA] = (M[MA] + 1) & 07777);        /* incr before use */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            }
        if (UF && tsc_enb) {                            /* user mode, TSC enab? */
            tsc_pc = (PC - 1) & 07777;                  /* save PC */
            int_req = int_req | INT_TSC;                /* request intr */
            }
        else {                                          /* normal */
            IF = IB;                                    /* change IF */
            UF = UB;                                    /* change UF */
            int_req = int_req | INT_NO_CIF_PENDING;     /* clr intr inhibit */
            MA = IF | MA;
            if (MEM_ADDR_OK (MA))
                M[MA] = PC;
            }
        PC = (MA + 1) & 07777;
        break;

    case 023:                                           /* JMS, indir, curr */
        PCQ_ENTRY (MA);
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = M[MA];
        else MA = (M[MA] = (M[MA] + 1) & 07777);        /* incr before use */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            }
        if (UF && tsc_enb) {                            /* user mode, TSC enab? */
            tsc_pc = (PC - 1) & 07777;                  /* save PC */
            int_req = int_req | INT_TSC;                /* request intr */
            }
        else {                                          /* normal */
            IF = IB;                                    /* change IF */
            UF = UB;                                    /* change UF */
            int_req = int_req | INT_NO_CIF_PENDING;     /* clr intr inhibit */
            MA = IF | MA;
            if (MEM_ADDR_OK (MA))
                M[MA] = PC;
            }
        PC = (MA + 1) & 07777;
        break;

/* Opcode 5, JMP.  From Bernhard Baehr's description of the TSC8-75:

   (In user mode) the current JMP opcode is moved to the ERIOT register, the ECDF
   flag is cleared. The address of the JMP instruction is loaded into the ERTB
   register and the TSC8-75 I/O flag is raised. Then the JMP is performed as usual
   (including the setting of IF, UF and clearing the interrupt inhibit flag). */


    case 024:                                           /* JMP, dir, zero */
        PCQ_ENTRY (MA);
        MA = IR & 0177;                                 /* dir addr, page zero */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            if (tsc_enb) {                              /* TSC8 enabled? */
                tsc_pc = (PC - 1) & 07777;              /* save PC */
                int_req = int_req | INT_TSC;            /* request intr */
                }
            }
        IF = IB;                                        /* change IF */
        UF = UB;                                        /* change UF */
        int_req = int_req | INT_NO_CIF_PENDING;         /* clr intr inhibit */
        PC = MA;
        break;

/* If JMP direct, also check for idle (KSF/JMP *-1) and infinite loop */

    case 025:                                           /* JMP, dir, curr */
        PCQ_ENTRY (MA);
        MA = (MA & 007600) | (IR & 0177);               /* dir addr, curr page */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            if (tsc_enb) {                              /* TSC8 enabled? */
                tsc_pc = (PC - 1) & 07777;              /* save PC */
                int_req = int_req | INT_TSC;            /* request intr */
                }
            }
        if (sim_idle_enab &&                            /* idling enabled? */
            (IF == IB)) {                               /* to same bank? */
            if (MA == ((PC - 2) & 07777)) {             /* 1) JMP *-1? */
                if (!(int_req & (INT_ION|INT_TTI)) &&   /*    iof, TTI flag off? */
                    (M[IB|((PC - 2) & 07777)] == OP_KSF)) /*  next is KSF? */
                    sim_idle (TMR_CLK, FALSE);          /* we're idle */
                }                                       /* end JMP *-1 */
            else if (MA == ((PC - 1) & 07777)) {        /* 2) JMP *? */
                if (!(int_req & INT_ION))               /*    iof? */
                    reason = STOP_LOOP;                 /* then infinite loop */
                else if (!(int_req & INT_ALL))          /*    ion, not intr? */
                    sim_idle (TMR_CLK, FALSE);          /* we're idle */
                }                                       /* end JMP */
            }                                           /* end idle enabled */
        IF = IB;                                        /* change IF */
        UF = UB;                                        /* change UF */
        int_req = int_req | INT_NO_CIF_PENDING;         /* clr intr inhibit */
        PC = MA;
        break;

    case 026:                                           /* JMP, indir, zero */
        PCQ_ENTRY (MA);
        MA = IF | (IR & 0177);                          /* dir addr, page zero */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = M[MA];
        else MA = (M[MA] = (M[MA] + 1) & 07777);        /* incr before use */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            if (tsc_enb) {                              /* TSC8 enabled? */
                tsc_pc = (PC - 1) & 07777;              /* save PC */
                int_req = int_req | INT_TSC;            /* request intr */
                }
            }
        IF = IB;                                        /* change IF */
        UF = UB;                                        /* change UF */
        int_req = int_req | INT_NO_CIF_PENDING;         /* clr intr inhibit */
        PC = MA;
        break;

    case 027:                                           /* JMP, indir, curr */
        PCQ_ENTRY (MA);
        MA = (MA & 077600) | (IR & 0177);               /* dir addr, curr page */
        if ((MA & 07770) != 00010)                      /* indirect; autoinc? */
            MA = M[MA];
        else MA = (M[MA] = (M[MA] + 1) & 07777);        /* incr before use */
        if (UF) {                                       /* user mode? */
            tsc_ir = IR;                                /* save instruction */
            tsc_cdf = 0;                                /* clear flag */
            if (tsc_enb) {                              /* TSC8 enabled? */
                tsc_pc = (PC - 1) & 07777;              /* save PC */
                int_req = int_req | INT_TSC;            /* request intr */
                }
            }
        IF = IB;                                        /* change IF */
        UF = UB;                                        /* change UF */
        int_req = int_req | INT_NO_CIF_PENDING;         /* clr intr inhibit */
        PC = MA;
        break;

/* Opcode 7, OPR group 1 */

    case 034:case 035:                                  /* OPR, group 1 */
        switch ((IR >> 4) & 017) {                      /* decode IR<4:7> */
        case 0:                                         /* nop */
            break;
        case 1:                                         /* CML */
            LAC = LAC ^ 010000;
            break;
        case 2:                                         /* CMA */
            LAC = LAC ^ 07777;
            break;
        case 3:                                         /* CMA CML */
            LAC = LAC ^ 017777;
            break;
        case 4:                                         /* CLL */
            LAC = LAC & 07777;
            break;
        case 5:                                         /* CLL CML = STL */
            LAC = LAC | 010000;
            break;
        case 6:                                         /* CLL CMA */
            LAC = (LAC ^ 07777) & 07777;
            break;
        case 7:                                         /* CLL CMA CML */
            LAC = (LAC ^ 07777) | 010000;
            break;
        case 010:                                       /* CLA */
            LAC = LAC & 010000;
            break;
        case 011:                                       /* CLA CML */
            LAC = (LAC & 010000) ^ 010000;
            break;
        case 012:                                       /* CLA CMA = STA */
            LAC = LAC | 07777;
            break;
        case 013:                                       /* CLA CMA CML */
            LAC = (LAC | 07777) ^ 010000;
            break;
        case 014:                                       /* CLA CLL */
            LAC = 0;
            break;
        case 015:                                       /* CLA CLL CML */
            LAC = 010000;
            break;
        case 016:                                       /* CLA CLL CMA */
            LAC = 07777;
            break;
        case 017:                                       /* CLA CLL CMA CML */
            LAC = 017777;
            break;
            }                                           /* end switch opers */

        if (IR & 01)                                    /* IAC */
            LAC = (LAC + 1) & 017777;
        switch ((IR >> 1) & 07) {                       /* decode IR<8:10> */
        case 0:                                         /* nop */
            break;
        case 1:                                         /* BSW */
            LAC = (LAC & 010000) | ((LAC >> 6) & 077) | ((LAC & 077) << 6);
            break;
        case 2:                                         /* RAL */
            LAC = ((LAC << 1) | (LAC >> 12)) & 017777;
            break;
        case 3:                                         /* RTL */
            LAC = ((LAC << 2) | (LAC >> 11)) & 017777;
            break;
        case 4:                                         /* RAR */
            LAC = ((LAC >> 1) | (LAC << 12)) & 017777;
            break;
        case 5:                                         /* RTR */
            LAC = ((LAC >> 2) | (LAC << 11)) & 017777;
            break;
        case 6:                                         /* RAL RAR - undef */
            LAC = LAC & (IR | 010000);                  /* uses AND path */
            break;
        case 7:                                         /* RTL RTR - undef */
            LAC = (LAC & 010000) | (MA & 07600) | (IR & 0177);
            break;                                      /* uses address path */
            }                                           /* end switch shifts */
        break;                                          /* end group 1 */

/* OPR group 2.  From Bernhard Baehr's description of the TSC8-75:

   (In user mode) HLT (7402), OSR (7404) and microprogrammed combinations with
   HLT and OSR: Additional to raising a user mode interrupt, the current OPR
   opcode is moved to the ERIOT register and the ECDF flag is cleared. */

    case 036:case 037:                                  /* OPR, groups 2, 3 */
        if ((IR & 01) == 0) {                           /* group 2 */
            switch ((IR >> 3) & 017) {                  /* decode IR<6:8> */
            case 0:                                     /* nop */
                break;
            case 1:                                     /* SKP */
                PC = (PC + 1) & 07777;
                break;
            case 2:                                     /* SNL */
                if (LAC >= 010000)
                    PC = (PC + 1) & 07777;
                break;
            case 3:                                     /* SZL */
                if (LAC < 010000)
                    PC = (PC + 1) & 07777;
                break;
            case 4:                                     /* SZA */
                if ((LAC & 07777) == 0)
                    PC = (PC + 1) & 07777;
                break;
            case 5:                                     /* SNA */
                if ((LAC & 07777)
                    != 0) PC = (PC + 1) & 07777;
                break;
            case 6:                                     /* SZA | SNL */
                if ((LAC == 0) || (LAC >= 010000))
                    PC = (PC + 1) & 07777;
                break;
            case 7:                                     /* SNA & SZL */
                if ((LAC != 0) && (LAC < 010000))
                    PC = (PC + 1) & 07777;
                break;
            case 010:                                   /* SMA */
                if ((LAC & 04000) != 0)
                    PC = (PC + 1) & 07777;
                break;
            case 011:                                   /* SPA */
                if ((LAC & 04000) == 0)
                    PC = (PC + 1) & 07777;
                break;
            case 012:                                   /* SMA | SNL */
                if (LAC >= 04000)
                    PC = (PC + 1) & 07777;
                break;
            case 013:                                   /* SPA & SZL */
                if (LAC < 04000)
                    PC = (PC + 1) & 07777;
                break;
            case 014:                                   /* SMA | SZA */
                if (((LAC & 04000) != 0) || ((LAC & 07777) == 0))
                    PC = (PC + 1) & 07777;
                break;
            case 015:                                   /* SPA & SNA */
                if (((LAC & 04000) == 0) && ((LAC & 07777) != 0))
                    PC = (PC + 1) & 07777;
                break;
            case 016:                                   /* SMA | SZA | SNL */
                if ((LAC >= 04000) || (LAC == 0))
                    PC = (PC + 1) & 07777;
                break;
            case 017:                                   /* SPA & SNA & SZL */
                if ((LAC < 04000) && (LAC != 0))
                    PC = (PC + 1) & 07777;
                break;
                }                                       /* end switch skips */
            if (IR & 0200)                              /* CLA */
                LAC = LAC & 010000;
            if ((IR & 06) && UF) {                      /* user mode? */
                int_req = int_req | INT_UF;             /* request intr */
                tsc_ir = IR;                            /* save instruction */
                tsc_cdf = 0;                            /* clear flag */
                }
            else {
                if (IR & 04) {                          /* OSR */
/* ---PiDP add--------------------------------------------------------------------------------------------- */
                    SR = get_switch_register();         /* get current SR */
/* ---PiDP end---------------------------------------------------------------------------------------------- */
                    LAC = LAC | SR;
                    }
                if (IR & 02) {                          /* HLT */
//--- PiDP change-----------------------------------------------------------------------
                    // reason = STOP_HALT;
                    extern int swStop;
                    swStop = 1;
                    }
//--- end of PiDP change----------------------------------------------------------------
                }
            break;
            }                                           /* end if group 2 */

/* OPR group 3 standard

   MQA!MQL exchanges AC and MQ, as follows:

        temp = MQ;
        MQ = LAC & 07777;
        LAC = LAC & 010000 | temp;
*/

        temp = MQ;                                      /* group 3 */
        if (IR & 0200)                                  /* CLA */
            LAC = LAC & 010000;
        if (IR & 0020) {                                /* MQL */
            MQ = LAC & 07777;
            LAC = LAC & 010000;
            }
        if (IR & 0100)                                  /* MQA */
            LAC = LAC | temp;
        if ((IR & 0056) && (cpu_unit.flags & UNIT_NOEAE)) {
            reason = stop_inst;                         /* EAE not present */
            break;
            }

/* OPR group 3 EAE

   The EAE operates in two modes:

        Mode A, PDP-8/I compatible
        Mode B, extended capability

   Mode B provides eight additional subfunctions; in addition, some
   of the Mode A functions operate differently in Mode B.

   The mode switch instructions are decoded explicitly and cannot be
   microprogrammed with other EAE functions (SWAB performs an MQL as
   part of standard group 3 decoding).  If mode switching is decoded,
   all other EAE timing is suppressed.
*/

        if (IR == 07431) {                              /* SWAB */
            emode = 1;                                  /* set mode flag */
            break;
            }
        if (IR == 07447) {                              /* SWBA */
            emode = gtf = 0;                            /* clear mode, gtf */
            break;
            }

/* If not switching modes, the EAE operation is determined by the mode
   and IR<6,8:10>:

   <6:10>       mode A          mode B          comments

   0x000        NOP             NOP
   0x001        SCL             ACS
   0x010        MUY             MUY             if mode B, next = address
   0x011        DVI             DVI             if mode B, next = address
   0x100        NMI             NMI             if mode B, clear AC if
                                                 result = 4000'0000
   0x101        SHL             SHL             if mode A, extra shift
   0x110        ASR             ASR             if mode A, extra shift
   0x111        LSR             LSR             if mode A, extra shift
   1x000        SCA             SCA
   1x001        SCA + SCL       DAD
   1x010        SCA + MUY       DST
   1x011        SCA + DVI       SWBA            NOP if not detected earlier
   1x100        SCA + NMI       DPSZ            
   1x101        SCA + SHL       DPIC            must be combined with MQA!MQL
   1x110        SCA + ASR       DCM             must be combined with MQA!MQL
   1x111        SCA + LSR       SAM

   EAE instructions which fetch memory operands use the CPU's DEFER
   state to read the first word; if the address operand is in locations
   x0010 - x0017, it is autoincremented.
*/

        if (emode == 0)                                 /* mode A? clr gtf */
            gtf = 0;
        switch ((IR >> 1) & 027) {                      /* decode IR<6,8:10> */

        case 020:                                       /* mode A, B: SCA */
            LAC = LAC | SC;
            break;
        case 000:                                       /* mode A, B: NOP */
            break;

        case 021:                                       /* mode B: DAD */
            if (emode) {
                MA = IF | PC;
                if ((MA & 07770) != 00010)              /* indirect; autoinc? */
                    MA = DF | M[MA];
                else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
                MQ = MQ + M[MA];
                MA = DF | ((MA + 1) & 07777);
                LAC = (LAC & 07777) + M[MA] + (MQ >> 12);
                MQ = MQ & 07777;
                PC = (PC + 1) & 07777;
                break;
                }
            LAC = LAC | SC;                             /* mode A: SCA then */
        case 001:                                       /* mode B: ACS */
            if (emode) {
                SC = LAC & 037;
                LAC = LAC & 010000;
                }
            else {                                      /* mode A: SCL */
                SC = (~M[IF | PC]) & 037;
                PC = (PC + 1) & 07777;
                }
            break;

        case 022:                                       /* mode B: DST */
            if (emode) {
                MA = IF | PC;
                if ((MA & 07770) != 00010)              /* indirect; autoinc? */
                    MA = DF | M[MA];
                else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
                if (MEM_ADDR_OK (MA))
                    M[MA] = MQ & 07777;
                MA = DF | ((MA + 1) & 07777);
                if (MEM_ADDR_OK (MA))
                    M[MA] = LAC & 07777;
                PC = (PC + 1) & 07777;
                break;
                }
            LAC = LAC | SC;                             /* mode A: SCA then */
        case 002:                                       /* MUY */
            MA = IF | PC;
            if (emode) {                                /* mode B: defer */
                if ((MA & 07770) != 00010)              /* indirect; autoinc? */
                    MA = DF | M[MA];
                else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
                }
            temp = (MQ * M[MA]) + (LAC & 07777);
            LAC = (temp >> 12) & 07777;
            MQ = temp & 07777;
            PC = (PC + 1) & 07777;
            SC = 014;                                   /* 12 shifts */
            break;

        case 023:                                       /* mode B: SWBA */
            if (emode)
                break;
            LAC = LAC | SC;                             /* mode A: SCA then */
        case 003:                                       /* DVI */
            MA = IF | PC;
            if (emode) {                                /* mode B: defer */
                if ((MA & 07770) != 00010)              /* indirect; autoinc? */
                    MA = DF | M[MA];
                else MA = DF | (M[MA] = (M[MA] + 1) & 07777); /* incr before use */
                }
            if ((LAC & 07777) >= M[MA]) {               /* overflow? */
                LAC = LAC | 010000;                     /* set link */
                MQ = ((MQ << 1) + 1) & 07777;           /* rotate MQ */
                SC = 0;                                 /* no shifts */
                }
            else {
                temp = ((LAC & 07777) << 12) | MQ;
                MQ = temp / M[MA];
                LAC = temp % M[MA];
                SC = 015;                               /* 13 shifts */
                }
            PC = (PC + 1) & 07777;
            break;

        case 024:                                       /* mode B: DPSZ */
            if (emode) {
                if (((LAC | MQ) & 07777) == 0)
                    PC = (PC + 1) & 07777;
                break;
                }
            LAC = LAC | SC;                             /* mode A: SCA then */
        case 004:                                       /* NMI */
            temp = (LAC << 12) | MQ;                    /* preserve link */
            for (SC = 0; ((temp & 017777777) != 0) &&
                (temp & 040000000) == ((temp << 1) & 040000000); SC++)
                temp = temp << 1;
            LAC = (temp >> 12) & 017777;
            MQ = temp & 07777;
            if (emode && ((LAC & 07777) == 04000) && (MQ == 0))
                LAC = LAC & 010000;                     /* clr if 4000'0000 */
            break;

        case 025:                                       /* mode B: DPIC */
            if (emode) {
                temp = (LAC + 1) & 07777;               /* SWP already done! */
                LAC = MQ + (temp == 0);
                MQ = temp;
                break;
                }
            LAC = LAC | SC;                             /* mode A: SCA then */
        case 5:                                         /* SHL */
            SC = (M[IF | PC] & 037) + (emode ^ 1);      /* shift+1 if mode A */
            if (SC > 25)                                /* >25? result = 0 */
                temp = 0;
            else temp = ((LAC << 12) | MQ) << SC;       /* <=25? shift LAC:MQ */
            LAC = (temp >> 12) & 017777;
            MQ = temp & 07777;
            PC = (PC + 1) & 07777;
            SC = emode? 037: 0;                         /* SC = 0 if mode A */
            break;

        case 026:                                       /* mode B: DCM */
            if (emode) {
                temp = (-LAC) & 07777;                  /* SWP already done! */
                LAC = (MQ ^ 07777) + (temp == 0);
                MQ = temp;
                break;
                }
            LAC = LAC | SC;                             /* mode A: SCA then */
        case 6:                                         /* ASR */
            SC = (M[IF | PC] & 037) + (emode ^ 1);      /* shift+1 if mode A */
            temp = ((LAC & 07777) << 12) | MQ;          /* sext from AC0 */
            if (LAC & 04000)
                temp = temp | ~037777777;
            if (emode && (SC != 0))
                gtf = (temp >> (SC - 1)) & 1;
            if (SC > 25)
                temp = (LAC & 04000)? -1: 0;
            else temp = temp >> SC;
            LAC = (temp >> 12) & 017777;
            MQ = temp & 07777;
            PC = (PC + 1) & 07777;
            SC = emode? 037: 0;                         /* SC = 0 if mode A */
            break;

        case 027:                                       /* mode B: SAM */
            if (emode) {
                temp = LAC & 07777;
                LAC = MQ + (temp ^ 07777) + 1;          /* L'AC = MQ - AC */
                gtf = (temp <= MQ) ^ ((temp ^ MQ) >> 11);
                break;
                }
            LAC = LAC | SC;                             /* mode A: SCA then */
        case 7:                                         /* LSR */
            SC = (M[IF | PC] & 037) + (emode ^ 1);      /* shift+1 if mode A */
            temp = ((LAC & 07777) << 12) | MQ;          /* clear link */
            if (emode && (SC != 0))
                gtf = (temp >> (SC - 1)) & 1;
            if (SC > 24)                                /* >24? result = 0 */
                temp = 0;
            else temp = temp >> SC;                     /* <=24? shift AC:MQ */
            LAC = (temp >> 12) & 07777;
            MQ = temp & 07777;
            PC = (PC + 1) & 07777;
            SC = emode? 037: 0;                         /* SC = 0 if mode A */
            break;
            }                                           /* end switch */
        break;                                          /* end case 7 */

/* Opcode 6, IOT.  From Bernhard Baehr's description of the TSC8-75:

   (In user mode) Additional to raising a user mode interrupt, the current IOT
   opcode is moved to the ERIOT register. When the IOT is a CDF instruction (62x1),
   the ECDF flag is set, otherwise it is cleared. */

    case 030:case 031:case 032:case 033:                /* IOT */
        if (UF) {                                       /* privileged? */
            int_req = int_req | INT_UF;                 /* request intr */
            tsc_ir = IR;                                /* save instruction */
            if ((IR & 07707) == 06201)                  /* set/clear flag */
                tsc_cdf = 1;
            else tsc_cdf = 0;
            break;
            }
        device = (IR >> 3) & 077;                       /* device = IR<3:8> */
        pulse = IR & 07;                                /* pulse = IR<9:11> */
        iot_data = LAC & 07777;                         /* AC unchanged */
        switch (device) {                               /* decode IR<3:8> */

        case 000:                                       /* CPU control */
            switch (pulse) {                            /* decode IR<9:11> */

            case 0:                                     /* SKON */
                if (int_req & INT_ION)
                    PC = (PC + 1) & 07777;
                int_req = int_req & ~INT_ION;
                break;

            case 1:                                     /* ION */
                int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING;
                break;

            case 2:                                     /* IOF */
                int_req = int_req & ~INT_ION;
                break;

            case 3:                                     /* SRQ */
                if (int_req & INT_ALL)
                    PC = (PC + 1) & 07777;
                break;

            case 4:                                     /* GTF */
                LAC = (LAC & 010000) |
                      ((LAC & 010000) >> 1) | (gtf << 10) |
                      (((int_req & INT_ALL) != 0) << 9) |
                      (((int_req & INT_ION) != 0) << 7) | SF;
                break;

            case 5:                                     /* RTF */
                gtf = ((LAC & 02000) >> 10);
                UB = (LAC & 0100) >> 6;
                IB = (LAC & 0070) << 9;
                DF = (LAC & 0007) << 12;
                LAC = ((LAC & 04000) << 1) | iot_data;
                int_req = (int_req | INT_ION) & ~INT_NO_CIF_PENDING;
                break;

            case 6:                                     /* SGT */
                if (gtf)
                    PC = (PC + 1) & 07777;
                break;

            case 7:                                     /* CAF */
                gtf = 0;
                emode = 0;
                int_req = int_req & INT_NO_CIF_PENDING;
                dev_done = 0;
                int_enable = INT_INIT_ENABLE;
                LAC = 0;
                reset_all (1);                          /* reset all dev */
                break;
                }                                       /* end switch pulse */
            break;                                      /* end case 0 */

        case 020:case 021:case 022:case 023:
        case 024:case 025:case 026:case 027:            /* memory extension */
            switch (pulse) {                            /* decode IR<9:11> */

            case 1:                                     /* CDF */
                DF = (IR & 0070) << 9;
                break;

            case 2:                                     /* CIF */
                IB = (IR & 0070) << 9;
                int_req = int_req & ~INT_NO_CIF_PENDING;
                break;

            case 3:                                     /* CDF CIF */
                DF = IB = (IR & 0070) << 9;
                int_req = int_req & ~INT_NO_CIF_PENDING;
                break;

            case 4:
                switch (device & 07) {                  /* decode IR<6:8> */

                case 0:                                 /* CINT */
                    int_req = int_req & ~INT_UF;
                    break;

                case 1:                                 /* RDF */
                    LAC = LAC | (DF >> 9);
                        break;

                case 2:                                 /* RIF */
                    LAC = LAC | (IF >> 9);
                    break;

                case 3:                                 /* RIB */
                    LAC = LAC | SF;
                    break;

                case 4:                                 /* RMF */
                    UB = (SF & 0100) >> 6;
                    IB = (SF & 0070) << 9;
                    DF = (SF & 0007) << 12;
                    int_req = int_req & ~INT_NO_CIF_PENDING;
                    break;

                case 5:                                 /* SINT */
                    if (int_req & INT_UF)
                        PC = (PC + 1) & 07777;
                    break;

                case 6:                                 /* CUF */
                    UB = 0;
                    int_req = int_req & ~INT_NO_CIF_PENDING;
                    break;

                case 7:                                 /* SUF */
                    UB = 1;
                    int_req = int_req & ~INT_NO_CIF_PENDING;
                    break;
                    }                                   /* end switch device */
                break;
            
            default:
                reason = stop_inst;
                break;
                }                                       /* end switch pulse */
            break;                                      /* end case 20-27 */

        case 010:                                       /* power fail */
            switch (pulse) {                            /* decode IR<9:11> */

            case 1:                                     /* SBE */
                break;

            case 2:                                     /* SPL */
                if (int_req & INT_PWR)
                    PC = (PC + 1) & 07777;
                break;

            case 3:                                     /* CAL */
                int_req = int_req & ~INT_PWR;
                break;

            default:
                reason = stop_inst;
                break;
                }                                       /* end switch pulse */
            break;                                      /* end case 10 */

        default:                                        /* I/O device */
            if (dev_tab[device]) {                      /* dev present? */
/* ---PiDP add--------------------------------------------------------------------------------------------- */
                // Any other device will trigger IOP, so light pause
                Pause = 1;
/* ---PiDP end---------------------------------------------------------------------------------------------- */
                iot_data = dev_tab[device] (IR, iot_data);
                LAC = (LAC & 010000) | (iot_data & 07777);
                if (iot_data & IOT_SKP)
                    PC = (PC + 1) & 07777;
                if (iot_data >= IOT_REASON)
                    reason = iot_data >> IOT_V_REASON;
                }
            else reason = stop_inst;                    /* stop on flag */
            break;
            }                                           /* end switch device */
        break;                                          /* end case IOT */
        }                                               /* end switch opcode */

/* ---PiDP add--------------------------------------------------------------------------------------------- */
    // Update the front panel with this instruction's final state.
    //
    // There's no point saving *every* LED "on" count.  We just need a
    // suitable amount of oversampling.  We can skip this if we called
    // set_pidp8i_leds recently enough, avoiding all the expensive bit
    // shift and memory update work it does.
    //
    // The trick here is figuring out what "recently enough" means
    // without making expensive OS timer calls.  These timers aren't
    // hopelessly slow (http://stackoverflow.com/a/13096917/142454) but
    // we still don't want to be taking dozens of cycles per instruction
    // just to keep our update estimate current in the face of system
    // load changes and SET THROTTLE updates.
    //
    // Instead, we maintain a model of the current IPS value — seeded
    // with the initial "SET THROTTLE" value, if any — to figure out
    // how many calls we can skip while still meeting our other goals.
    // This involves a bit of math, but when paid only once a second,
    // it amortizes much nicer than estimating the skip count directly
    // based on a more accurate time source which is more expensive
    // to call.  It's also cheaper than continually asking SIMH to
    // estimate the SIMH IPS value, since it uses FP math.
    //
    // Each LED panel repaint takes about 10 ms, so we do about 100
    // full-panel updates per second.  We need a bare minimum of 32
    // discernible brightness values per update for ILS, so if we don't
    // update the LED status data at least 3,200 times per second, we
    // don't have enough data for smooth panel updates.  Fortunately,
    // computers are pretty quick, and our slowest script runs at 30
    // kIPS.  (5.script.)
    //
    // We deliberately add some timing jitter here to get stochastic
    // sampling of the incoming instructions to avoid beat frequencies
    // between our update rate and the instruction pattern being
    // executed by the front panel.  It's a form of dithering.
    //
    // You might think to move this code to the top of set_pidp8i_leds,
    // but the function call itself is a nontrivial hit.  In fact, you
    // don't even want to move all of this to a function here in this
    // module and try to get GCC to inline it: that's good for a 1 MIPS
    // speed hit in my testing!  (GCC 4.9.2, Raspbian Jessie on Pi 3B.)

    if (++skip_count >= (max_skips - dither)) {
        // Save skips to inst counter and reset
        inst_count += skip_count;
        skip_count = 0;

        // We need to update the LED data again
        set_pidp8i_leds (PC, MA, MB, IR, LAC, MQ, IF, DF, SC, int_req, Pause);
        Pause = 0;

        // Has it been ~1s since we updated our max_skips value?
        time_t now;
        if (time(&now) > last_update) {
            // Yep; simulator IPS may have changed, so freshen it.
            last_update = now;
            max_skips = inst_count / pidp8i_updates_per_sec;
            //printf("Inst./repaint: %zu - %zu; %.2f MIPS\r\n",
            //        max_skips, dither, inst_count / 1e6);
            inst_count = 0;
            }
        dither = max_skips > 32 ? lrand48() % (max_skips >> 3) : 0; // 12.5%
        }
/* ---PiDP end---------------------------------------------------------------------------------------------- */
    }                                                   /* end while */

/* Simulation halted */

saved_PC = IF | (PC & 07777);                           /* save copies */
saved_DF = DF & 070000;
saved_LAC = LAC & 017777;
saved_MQ = MQ & 07777;
pcq_r->qptr = pcq_p;                                    /* update pc q ptr */
return reason;
}                                                       /* end sim_instr */

/* Reset routine */

t_stat cpu_reset (DEVICE *dptr)
{
saved_LAC = 0;
int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING;
saved_DF = IB = saved_PC & 070000;
UF = UB = gtf = emode = 0;
pcq_r = find_reg ("PCQ", NULL, dptr);
if (pcq_r)
    pcq_r->qptr = 0;
else return SCPE_IERR;
sim_brk_types = SWMASK ('E') | SWMASK('I');
sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}

/* Set PC for boot (PC<14:12> will typically be 0) */

void cpu_set_bootpc (int32 pc)
{
saved_PC = pc;                                          /* set PC, IF */
saved_DF = IB = pc & 070000;                            /* set IB, DF */
return;
}

/* Memory examine */

t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= MEMSIZE)
    return SCPE_NXM;
if (vptr != NULL)
    *vptr = M[addr] & 07777;
return SCPE_OK;
}

/* Memory deposit */

t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= MEMSIZE)
    return SCPE_NXM;
M[addr] = val & 07777;
return SCPE_OK;
}

/* Memory size change */

t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 mc = 0;
uint32 i;

if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
    return SCPE_ARG;
for (i = val; i < MEMSIZE; i++)
    mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
    return SCPE_OK;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++)
    M[i] = 0;
return SCPE_OK;
}

/* Change device number for a device */

t_stat set_dev (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newdev;
t_stat r;

if (cptr == NULL)
    return SCPE_ARG;
if (uptr == NULL)
    return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
    return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
    return SCPE_IERR;
newdev = get_uint (cptr, 8, DEV_MAX - 1, &r);           /* get new */
if ((r != SCPE_OK) || (newdev == dibp->dev))
    return r;
dibp->dev = newdev;                                     /* store */
return SCPE_OK;
}

/* Show device number for a device */

t_stat show_dev (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;

if (uptr == NULL)
    return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
    return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
    return SCPE_IERR;
fprintf (st, "devno=%02o", dibp->dev);
if (dibp->num > 1)
    fprintf (st, "-%2o", dibp->dev + dibp->num - 1);
return SCPE_OK;
}

/* CPU device handler - should never get here! */

int32 bad_dev (int32 IR, int32 AC)
{
return (SCPE_IERR << IOT_V_REASON) | AC;                /* broken! */
}

/* Build device dispatch table */

t_bool build_dev_tab (void)
{
DEVICE *dptr;
DIB *dibp;
uint32 i, j;
static const uint8 std_dev[] = {
    000, 010, 020, 021, 022, 023, 024, 025, 026, 027
    };

for (i = 0; i < DEV_MAX; i++)                           /* clr table */
    dev_tab[i] = NULL;
for (i = 0; i < ((uint32) sizeof (std_dev)); i++)       /* std entries */
    dev_tab[std_dev[i]] = &bad_dev;
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {     /* add devices */
    dibp = (DIB *) dptr->ctxt;                          /* get DIB */
    if (dibp && !(dptr->flags & DEV_DIS)) {             /* enabled? */
        if (dibp->dsp_tbl) {                            /* dispatch table? */
            DIB_DSP *dspp = dibp->dsp_tbl;              /* set ptr */
            for (j = 0; j < dibp->num; j++, dspp++) {   /* loop thru tbl */
                if (dspp->dsp) {                        /* any dispatch? */
                    if (dev_tab[dspp->dev]) {           /* already filled? */
                        sim_printf ("%s device number conflict at %02o\n",
                            sim_dname (dptr), dibp->dev + j);
                        return TRUE;
                        }
                    dev_tab[dspp->dev] = dspp->dsp;     /* fill */
                    }                                   /* end if dsp */
                }                                       /* end for j */
            }                                           /* end if dsp_tbl */
        else {                                          /* inline dispatches */
            for (j = 0; j < dibp->num; j++) {           /* loop thru disp */
                if (dibp->dsp[j]) {                     /* any dispatch? */
                    if (dev_tab[dibp->dev + j]) {       /* already filled? */
                        sim_printf ("%s device number conflict at %02o\n",
                            sim_dname (dptr), dibp->dev + j);
                        return TRUE;
                        }
                    dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */
                    }                                   /* end if dsp */
                }                                       /* end for j */
            }                                           /* end else */
        }                                               /* end if enb */
    }                                                   /* end for i */
return FALSE;
}

/* Set history */

t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;

if (cptr == NULL) {
    for (i = 0; i < hst_lnt; i++)
        hst[i].pc = 0;
    hst_p = 0;
    return SCPE_OK;
    }
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN)))
    return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
    free (hst);
    hst_lnt = 0;
    hst = NULL;
    }
if (lnt) {
    hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
    if (hst == NULL)
        return SCPE_MEM;
    hst_lnt = lnt;
    }
return SCPE_OK;
}

/* Show history */

t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 l, k, di, lnt;
const char *cptr = (const char *) desc;
t_stat r;
t_value sim_eval;
InstHistory *h;

if (hst_lnt == 0)                                       /* enabled? */
    return SCPE_NOFNC;
if (cptr) {
    lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
    if ((r != SCPE_OK) || (lnt == 0))
        return SCPE_ARG;
    }
else lnt = hst_lnt;
di = hst_p - lnt;                                       /* work forward */
if (di < 0)
    di = di + hst_lnt;
fprintf (st, "PC     L AC    MQ    ea     IR\n\n");
for (k = 0; k < lnt; k++) {                             /* print specified */
    h = &hst[(++di) % hst_lnt];                         /* entry pointer */
    if (h->pc & HIST_PC) {                              /* instruction? */
        l = (h->lac >> 12) & 1;                         /* link */
        fprintf (st, "%05o  %o %04o  %04o  ", h->pc & ADDRMASK, l, h->lac & 07777, h->mq);
        if (h->ir < 06000)
            fprintf (st, "%05o  ", h->ea);
        else fprintf (st, "       ");
        sim_eval = h->ir;
        if ((fprint_sym (st, h->pc & ADDRMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
            fprintf (st, "(undefined) %04o", h->ir);
        if (h->ir < 04000)
            fprintf (st, "  [%04o]", h->opnd);
        fputc ('\n', st);                               /* end line */
        }                                               /* end else instruction */
    }                                                   /* end for */
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_ct.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
/* pdp8_ct.c: PDP-8 cassette tape simulator

   Copyright (c) 2006-2013, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   ct           TA8E/TU60 cassette tape

   17-Sep-07    RMS     Changed to use central set_bootpc routine
   13-Aug-07    RMS     Fixed handling of BEOT
   06-Aug-07    RMS     Foward op at BOT skips initial file gap
   30-May-07    RMS     Fixed typo (Norm Lastovica)

   Magnetic tapes are represented as a series of variable records
   of the form:

        32b byte count
        byte 0
        byte 1
        :
        byte n-2
        byte n-1
        32b byte count

   If the byte count is odd, the record is padded with an extra byte
   of junk.  File marks are represented by a byte count of 0.

   Cassette format differs in one very significant way: it has file gaps
   rather than file marks.  If the controller spaces or reads into a file
   gap and then reverses direction, the file gap is not seen again.  This
   is in contrast to magnetic tapes, where the file mark is a character
   sequence and is seen again if direction is reversed.  In addition,
   cassettes have an initial file gap which is automatically skipped on
   forward operations from beginning of tape.

   Note that the read and write sequences for the cassette are asymmetric:

   Read:    KLSA            /SELECT READ
            KGOA            /INIT READ, CLEAR DF
            <data flag sets, char in buf>
            KGOA            /READ 1ST CHAR, CLEAR DF
            DCA CHAR
            :
            <data flag sets, char in buf>
            KGOA            /READ LAST CHAR, CLEAR DF
            DCA CHAR
            <data flag sets, CRC1 in buf>
            KLSA            /SELECT CRC MODE
            KGOA            /READ 1ST CRC
            <data flag sets, CRC2 in buf>
            KGOA            /READ 2ND CRC
            <ready flag/CRC error flag sets>

   Write:   KLSA            /SELECT WRITE
            TAD CHAR        /1ST CHAR
            KGOA            /INIT WRITE, CHAR TO BUF, CLEAR DF
            <data flag sets, char to tape>
            :
            TAD CHAR        /LAST CHAR
            KGOA            /CHAR TO BUF, CLEAR DF
            <data flag sets, char to tape>
            KLSA            /SELECT CRC MODE
            KGOA            /WRITE CRC, CLEAR DF
            <ready flag sets, CRC on tape>
*/

#include "pdp8_defs.h"
#include "sim_tape.h"

#define CT_NUMDR        2                               /* #drives */
#define FNC             u3                              /* unit function */
#define UST             u4                              /* unit status */
#define CT_MAXFR        (CT_SIZE)                       /* max record lnt */
#define CT_SIZE         93000                           /* chars/tape */

/* Status Register A */

#define SRA_ENAB        0200                            /* enable */
#define SRA_V_UNIT      6                               /* unit */
#define SRA_M_UNIT      (CT_NUMDR - 1)
#define SRA_V_FNC       3                               /* function */
#define SRA_M_FNC       07
#define  SRA_READ        00
#define  SRA_REW         01
#define  SRA_WRITE       02
#define  SRA_SRF         03
#define  SRA_WFG         04
#define  SRA_SRB         05
#define  SRA_CRC         06
#define  SRA_SFF         07
#define SRA_2ND         010
#define SRA_IE          0001                            /* int enable */
#define GET_UNIT(x)     (((x) >> SRA_V_UNIT) & SRA_M_UNIT)
#define GET_FNC(x)      (((x) >> SRA_V_FNC) & SRA_M_FNC)

/* Function code flags */

#define OP_WRI          01                              /* op is a write */
#define OP_REV          02                              /* op is rev motion */
#define OP_FWD          04                              /* op is fwd motion */

/* Unit status flags */

#define UST_REV         (OP_REV)                        /* last op was rev */
#define UST_GAP         01                              /* last op hit gap */

/* Status Register B, ^ = computed on the fly */

#define SRB_WLE         0400                            /* "write lock err" */
#define SRB_CRC         0200                            /* CRC error */
#define SRB_TIM         0100                            /* timing error */
#define SRB_BEOT        0040                            /* ^BOT/EOT */
#define SRB_EOF         0020                            /* end of file */
#define SRB_EMP         0010                            /* ^drive empty */
#define SRB_REW         0004                            /* rewinding */
#define SRB_WLK         0002                            /* ^write locked */
#define SRB_RDY         0001                            /* ^ready */
#define SRB_ALLERR      (SRB_WLE|SRB_CRC|SRB_TIM|SRB_BEOT|SRB_EOF|SRB_EMP)
#define SRB_XFRERR      (SRB_WLE|SRB_CRC|SRB_TIM|SRB_EOF)

extern int32 int_req, stop_inst;
extern UNIT cpu_unit;

uint32 ct_sra = 0;                                      /* status reg A */
uint32 ct_srb = 0;                                      /* status reg B */
uint32 ct_db = 0;                                       /* data buffer */
uint32 ct_df = 0;                                       /* data flag */
uint32 ct_write = 0;                                    /* TU60 write flag */
uint32 ct_bptr = 0;                                     /* buf ptr */
uint32 ct_blnt = 0;                                     /* buf length */
int32 ct_stime = 1000;                                  /* start time */
int32 ct_ctime = 100;                                   /* char latency */
uint32 ct_stopioe = 1;                                  /* stop on error */
uint8 *ct_xb = NULL;                                    /* transfer buffer */
static uint8 ct_fnc_tab[SRA_M_FNC + 1] = {
    OP_FWD,        0     , OP_WRI|OP_FWD, OP_REV,
    OP_WRI|OP_FWD, OP_REV, 0,             OP_FWD
    };

int32 ct70 (int32 IR, int32 AC);
t_stat ct_svc (UNIT *uptr);
t_stat ct_reset (DEVICE *dptr);
t_stat ct_attach (UNIT *uptr, CONST char *cptr);
t_stat ct_detach (UNIT *uptr);
t_stat ct_boot (int32 unitno, DEVICE *dptr);
uint32 ct_updsta (UNIT *uptr);
int32 ct_go_start (int32 AC);
int32 ct_go_cont (UNIT *uptr, int32 AC);
t_stat ct_map_err (UNIT *uptr, t_stat st);
UNIT *ct_busy (void);
void ct_set_df (t_bool timchk);
t_bool ct_read_char (void);
uint32 ct_crc (uint8 *buf, uint32 cnt);

/* CT data structures

   ct_dev       CT device descriptor
   ct_unit      CT unit list
   ct_reg       CT register list
   ct_mod       CT modifier list
*/

DIB ct_dib = { DEV_CT, 1, { &ct70 } };

UNIT ct_unit[] = {
    { UDATA (&ct_svc, UNIT_ATTABLE+UNIT_ROABLE, CT_SIZE) },
    { UDATA (&ct_svc, UNIT_ATTABLE+UNIT_ROABLE, CT_SIZE) },
    };

REG ct_reg[] = {
    { ORDATAD (CTSRA, ct_sra, 8, "status register A") },
    { ORDATAD (CTSRB, ct_srb, 8, "status register B") },
    { ORDATAD (CTDB, ct_db, 8, "data buffer") },
    { FLDATAD (CTDF, ct_df, 0, "data flag") },
    { FLDATAD (RDY, ct_srb, 0, "ready flag") },
    { FLDATAD (WLE, ct_srb, 8, "write lock error") },
    { FLDATAD (WRITE, ct_write, 0, "TA60 write operation flag") },
    { FLDATAD (INT, int_req, INT_V_CT, "interrupt request") },
    { DRDATAD (BPTR, ct_bptr, 17, "buffer pointer") },
    { DRDATAD (BLNT, ct_blnt, 17, "buffer length") },
    { DRDATAD (STIME, ct_stime, 24, "operation start time"), PV_LEFT + REG_NZ },
    { DRDATAD (CTIME, ct_ctime, 24, "character latency"), PV_LEFT + REG_NZ },
    { FLDATAD (STOP_IOE, ct_stopioe, 0, "stop on I/O errors flag") },
    { URDATA (UFNC, ct_unit[0].FNC, 8, 4, 0, CT_NUMDR, REG_HRO) },
    { URDATA (UST, ct_unit[0].UST, 8, 2, 0, CT_NUMDR, REG_HRO) },
    { URDATAD (POS, ct_unit[0].pos, 10, T_ADDR_W, 0,
              CT_NUMDR, PV_LEFT | REG_RO, "position, units 0-1") },
    { FLDATA (DEVNUM, ct_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB ct_mod[] = {
    { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
    { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, 
//    { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
//      &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
    { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", NULL,
      NULL, &sim_tape_show_capac, NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE ct_dev = {
    "CT", ct_unit, ct_reg, ct_mod,
    CT_NUMDR, 10, 31, 1, 8, 8,
    NULL, NULL, &ct_reset,
    &ct_boot, &ct_attach, &ct_detach,
    &ct_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_TAPE
    };

/* IOT routines */

int32 ct70 (int32 IR, int32 AC)
{
int32 srb;
UNIT *uptr;

srb = ct_updsta (NULL);                                 /* update status */
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* KCLR */
        ct_reset (&ct_dev);                             /* reset the world */
        break;

    case 1:                                             /* KSDR */
        if (ct_df)
            AC |= IOT_SKP;
        break;

    case 2:                                             /* KSEN */
        if (srb & SRB_ALLERR)
            AC |= IOT_SKP;
        break;

    case 3:                                             /* KSBF */
        if ((srb & SRB_RDY) && !(srb & SRB_EMP))
            AC |= IOT_SKP;
        break;

    case 4:                                             /* KLSA */
        ct_sra = AC & 0377;
        ct_updsta (NULL);
        return ct_sra ^ 0377;

    case 5:                                             /* KSAF */
        if (ct_df || (srb & (SRB_ALLERR|SRB_RDY)))
            AC |= IOT_SKP;
        break;

    case 6:                                             /* KGOA */
        ct_df = 0;                                      /* clear data flag */
        if ((uptr = ct_busy ()))                        /* op in progress? */
            AC = ct_go_cont (uptr, AC);                 /* yes */
        else AC = ct_go_start (AC);                     /* no, start */
        ct_updsta (NULL);
        break;

    case 7:                                             /* KSRB */
        return srb & 0377;
        }                                               /* end switch */

return AC;
}

/* Start a new operation - cassette is not busy */

int32 ct_go_start (int32 AC)
{
UNIT *uptr = ct_dev.units + GET_UNIT (ct_sra);
uint32 fnc = GET_FNC (ct_sra);
uint32 flg = ct_fnc_tab[fnc];
uint32 old_ust = uptr->UST;

if (DEBUG_PRS (ct_dev)) fprintf (sim_deb,
    ">>CT start: op=%o, old_sta = %o, pos=%d\n",
    fnc, uptr->UST, uptr->pos);
if ((ct_sra & SRA_ENAB) && (uptr->flags & UNIT_ATT)) {  /* enabled, att? */
    ct_srb &= ~(SRB_XFRERR|SRB_REW);                    /* clear err, rew */
    if (flg & OP_WRI) {                                 /* write-type op? */
        if (sim_tape_wrp (uptr)) {                      /* locked? */
            ct_srb |= SRB_WLE;                          /* set flag, abort */
            return AC;
            }
        ct_write = 1;                                   /* set TU60 wr flag */
        ct_db = AC & 0377;
        }
    else {
        ct_write = 0;
        ct_db = 0;
        }
    ct_srb &= ~SRB_BEOT;                                /* tape in motion */
    if (fnc == SRA_REW)                                 /* rew? set flag */
        ct_srb |= SRB_REW;
    if ((fnc != SRA_REW) && !(flg & OP_WRI)) {          /* read cmd? */
        t_mtrlnt t;
        t_stat st;
        uptr->UST = flg & UST_REV;                      /* save direction */
        if (sim_tape_bot (uptr) && (flg & OP_FWD)) {    /* spc/read fwd bot? */
            st = sim_tape_rdrecf (uptr, ct_xb, &t, CT_MAXFR); /* skip file gap */
            if (st != MTSE_TMK)                         /* not there? */
                sim_tape_rewind (uptr);                 /* restore tap pos */
            else old_ust = 0;                           /* defang next */
            }
        if ((old_ust ^ uptr->UST) == (UST_REV|UST_GAP)) { /* rev in gap? */
            if (DEBUG_PRS (ct_dev)) fprintf (sim_deb,
                ">>CT skip gap: op=%o, old_sta = %o, pos=%d\n",
                fnc, uptr->UST, uptr->pos);
            if (uptr->UST)                              /* skip file gap */
                sim_tape_rdrecr (uptr, ct_xb, &t, CT_MAXFR);
            else sim_tape_rdrecf (uptr, ct_xb, &t, CT_MAXFR);
            }
        }
    else uptr->UST = 0;
    ct_bptr = 0;                                        /* init buffer */
    ct_blnt = 0;
    uptr->FNC = fnc;                                    /* save function */
    sim_activate (uptr, ct_stime);                      /* schedule op */
    }
if ((fnc == SRA_READ) || (fnc == SRA_CRC))              /* read or CRC? */
    return 0;                                           /* get "char" */
return AC;
}

/* Continue an in-progress operation - cassette is in motion */

int32 ct_go_cont (UNIT *uptr, int32 AC)
{
int32 fnc = GET_FNC (ct_sra);

switch (fnc) {                                          /* case on function */

    case SRA_READ:                                      /* read */
        return ct_db;                                   /* return data */

    case SRA_WRITE:                                     /* write */
        ct_db = AC & 0377;                              /* save data */
        break;

    case SRA_CRC:                                       /* CRC */
        if ((uptr->FNC & SRA_M_FNC) != SRA_CRC)         /* if not CRC */
            uptr->FNC = SRA_CRC;                        /* start CRC seq */
        if (!ct_write)                                  /* read? AC <- buf */
            return ct_db;
        break;

    default:
        break;
    }

return AC;
}

/* Unit service */

t_stat ct_svc (UNIT *uptr)
{
uint32 i, crc;
uint32 flgs = ct_fnc_tab[uptr->FNC & SRA_M_FNC];
t_mtrlnt tbc;
t_stat st, r;

if ((uptr->flags & UNIT_ATT) == 0) {                    /* not attached? */
    ct_updsta (uptr);                                   /* update status */
    return (ct_stopioe? SCPE_UNATT: SCPE_OK);
    }
if (((flgs & OP_REV) && sim_tape_bot (uptr)) ||         /* rev at BOT or */
    ((flgs & OP_FWD) && sim_tape_eot (uptr))) {         /* fwd at EOT? */
    ct_srb |= SRB_BEOT;                                 /* error */
    ct_updsta (uptr);                                   /* op done */
    return SCPE_OK;
    }

r = SCPE_OK;
switch (uptr->FNC) {                                    /* case on function */

    case SRA_READ:                                      /* read start */
        st = sim_tape_rdrecf (uptr, ct_xb, &ct_blnt, CT_MAXFR); /* get rec */
        if (st == MTSE_RECE)                            /* rec in err? */
            ct_srb |= SRB_CRC;
        else if (st != MTSE_OK) {                       /* other error? */
            r = ct_map_err (uptr, st);                  /* map error */
            break;
            }
        crc = ct_crc (ct_xb, ct_blnt);                  /* calculate CRC */
        ct_xb[ct_blnt++] = (crc >> 8) & 0377;           /* append to buffer */
        ct_xb[ct_blnt++] = crc & 0377;
        uptr->FNC |= SRA_2ND;                           /* next state */
        sim_activate (uptr, ct_ctime);                  /* sched next char */
        return SCPE_OK;

    case SRA_READ|SRA_2ND:                              /* read char */
        if (!ct_read_char ())                           /* read, overrun? */
            break;
        ct_set_df (TRUE);                               /* set data flag */
        sim_activate (uptr, ct_ctime);                  /* sched next char */
        return SCPE_OK;

    case SRA_WRITE:                                     /* write start */
        for (i = 0; i < CT_MAXFR; i++)                  /* clear buffer */
            ct_xb[i] = 0;
        uptr->FNC |= SRA_2ND;                           /* next state */
        sim_activate (uptr, ct_ctime);                  /* sched next char */
        return SCPE_OK;

    case SRA_WRITE|SRA_2ND:                             /* write char */
        if ((ct_bptr < CT_MAXFR) &&                     /* room in buf? */
            ((uptr->pos + ct_bptr) < uptr->capac))      /* room on tape? */
            ct_xb[ct_bptr++] = ct_db;                   /* store char */
        ct_set_df (TRUE);                               /* set data flag */
        sim_activate (uptr, ct_ctime);                  /* sched next char */
        return SCPE_OK;

    case SRA_CRC:                                       /* CRC */
        if (ct_write) {                                 /* write? */
           if ((st = sim_tape_wrrecf (uptr, ct_xb, ct_bptr)))/* write, err? */
               r = ct_map_err (uptr, st);               /* map error */
           break;                                       /* write done */
           }
        ct_read_char ();                                /* get second CRC */
        ct_set_df (FALSE);                              /* set df */
        uptr->FNC |= SRA_2ND;                           /* next state */
        sim_activate (uptr, ct_ctime);
        return SCPE_OK;

    case SRA_CRC|SRA_2ND:                               /* second read CRC */
        if (ct_bptr != ct_blnt) {                       /* partial read? */
            crc = ct_crc (ct_xb, ct_bptr);              /* actual CRC */
            if (crc != 0)                               /* must be zero */
                ct_srb |= SRB_CRC;
            }
         break;                                         /* read done */

    case SRA_WFG:                                       /* write file gap */
        if ((st = sim_tape_wrtmk (uptr)))               /* write tmk, err? */
            r = ct_map_err (uptr, st);                  /* map error */
        break;

    case SRA_REW:                                       /* rewind */
        sim_tape_rewind (uptr);
        ct_srb |= SRB_BEOT;                             /* set BOT */
        break;

    case SRA_SRB:                                       /* space rev blk */
        if ((st = sim_tape_sprecr (uptr, &tbc)))        /* space rev, err? */
            r = ct_map_err (uptr, st);                  /* map error */
         break;

    case SRA_SRF:                                       /* space rev file */
        while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
        r = ct_map_err (uptr, st);                      /* map error */
        break;

    case SRA_SFF:                                       /* space fwd file */
        while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
        r = ct_map_err (uptr, st);                      /* map error */
        break;

    default:                                            /* never get here! */
        return SCPE_IERR;        
        }                                               /* end case */

ct_updsta (uptr);                                       /* update status */
if (DEBUG_PRS (ct_dev)) fprintf (sim_deb,
    ">>CT done: op=%o, statusA = %o, statusB = %o, pos=%d\n",
    uptr->FNC, ct_sra, ct_srb, uptr->pos);
return r;
}

/* Update controller status */

uint32 ct_updsta (UNIT *uptr)
{
int32 srb;

if (uptr == NULL) {                                     /* unit specified? */
    uptr = ct_busy ();                                  /* use busy unit */
    if ((uptr == NULL) && (ct_sra & SRA_ENAB))          /* none busy? */
        uptr = ct_dev.units + GET_UNIT (ct_sra);        /* use sel unit */
    }
else if (ct_srb & SRB_EOF)                              /* save gap */
    uptr->UST |= UST_GAP;
if (uptr) {                                             /* any unit? */
    ct_srb &= ~(SRB_WLK|SRB_EMP|SRB_RDY);               /* clear dyn flags */
    if ((uptr->flags & UNIT_ATT) == 0)                  /* unattached? */
        ct_srb = (ct_srb | SRB_EMP|SRB_WLK) & ~SRB_REW; /* empty, locked */
    if (!sim_is_active (uptr)) {                        /* not busy? */
        ct_srb = (ct_srb | SRB_RDY) & ~SRB_REW;         /* ready, ~rew */
        }
    if (sim_tape_wrp (uptr) || (ct_srb & SRB_REW))      /* locked or rew? */
        ct_srb |= SRB_WLK;                              /* set locked */
    }
if (ct_sra & SRA_ENAB)                                  /* can TA see TU60? */
    srb = ct_srb;
else srb = 0;                                           /* no */
if ((ct_sra & SRA_IE) &&                                /* int enabled? */
    (ct_df || (srb & (SRB_ALLERR|SRB_RDY))))            /* any flag? */
    int_req |= INT_CT;                                  /* set int req */
else int_req &= ~INT_CT;                                /* no, clr int req */
return srb;
}

/* Set data flag */

void ct_set_df (t_bool timchk)
{
if (ct_df && timchk)                                    /* flag still set? */
    ct_srb |= SRB_TIM;
ct_df = 1;                                              /* set data flag */
if (ct_sra & SRA_IE)                                    /* if ie, int req */
    int_req |= INT_CT;
return;
}

/* Read character */

t_bool ct_read_char (void)
{
if (ct_bptr < ct_blnt) {                                /* more chars? */
    ct_db = ct_xb[ct_bptr++];
    return TRUE;
    }
ct_db = 0;
ct_srb |= SRB_CRC;                                      /* overrun */
return FALSE;
}

/* Test if controller busy */

UNIT *ct_busy (void)
{
uint32 u;
UNIT *uptr;

for (u = 0; u < CT_NUMDR; u++) {                        /* loop thru units */
    uptr = ct_dev.units + u;
    if (sim_is_active (uptr))
        return uptr;
    }
return NULL;
}

/* Calculate CRC on buffer */

uint32 ct_crc (uint8 *buf, uint32 cnt)
{
uint32 crc, i, j;

crc = 0;
for (i = 0; i < cnt; i++) {
    crc = crc ^ (((uint32) buf[i]) << 8);
    for (j = 0; j < 8; j++) {
        if (crc & 1)
            crc = (crc >> 1) ^ 0xA001;
        else crc = crc >> 1;
        }
    }
return crc;
}

/* Map error status */

t_stat ct_map_err (UNIT *uptr, t_stat st)
{
switch (st) {

    case MTSE_FMT:                                      /* illegal fmt */
    case MTSE_UNATT:                                    /* unattached */
        ct_srb |= SRB_CRC;
    case MTSE_OK:                                       /* no error */
        return SCPE_IERR;                               /* never get here! */

    case MTSE_TMK:                                      /* end of file */
        ct_srb |= SRB_EOF;
        break;

    case MTSE_IOERR:                                    /* IO error */
        ct_srb |= SRB_CRC;                              /* set crc err */
        if (ct_stopioe)
            return SCPE_IOERR;
        break;

    case MTSE_INVRL:                                    /* invalid rec lnt */
        ct_srb |= SRB_CRC;                              /* set crc err */
        return SCPE_MTRLNT;

    case MTSE_RECE:                                     /* record in error */
    case MTSE_EOM:                                      /* end of medium */
        ct_srb |= SRB_CRC;                              /* set crc err */
        break;

    case MTSE_BOT:                                      /* reverse into BOT */
        ct_srb |= SRB_BEOT;                             /* set BOT */
        break;

    case MTSE_WRP:                                      /* write protect */
        ct_srb |= SRB_WLE;                              /* set wlk err */
        break;
        }

return SCPE_OK;
}

/* Reset routine */

t_stat ct_reset (DEVICE *dptr)
{
uint32 u;
UNIT *uptr;

ct_sra = 0;
ct_srb = 0;
ct_df = 0;
ct_db = 0;
ct_write = 0;
ct_bptr = 0;
ct_blnt = 0;
int_req = int_req & ~INT_CT;                            /* clear interrupt */
for (u = 0; u < CT_NUMDR; u++) {                        /* loop thru units */
    uptr = ct_dev.units + u;
    sim_cancel (uptr);                                  /* cancel activity */
    sim_tape_reset (uptr);                              /* reset tape */
    }
if (ct_xb == NULL)
    ct_xb = (uint8 *) calloc (CT_MAXFR + 2, sizeof (uint8));
if (ct_xb == NULL)
    return SCPE_MEM;
return SCPE_OK;
}

/* Attach routine */

t_stat ct_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;

r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK)
    return r;
ct_updsta (NULL);
uptr->UST = 0;
return r;
}

/* Detach routine */

t_stat ct_detach (UNIT* uptr)
{
t_stat r;

if (!(uptr->flags & UNIT_ATT))                          /* check attached */
    return SCPE_OK;
r = sim_tape_detach (uptr);
ct_updsta (NULL);
uptr->UST = 0;
return r;
}

/* Bootstrap routine */

#define BOOT_START 04000
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))

static const uint16 boot_rom[] = {
    01237,          /* BOOT,    TAD M50     /change CRC to REW */
    01206,          /* CRCCHK,  TAD L260    /crc op */
    06704,          /*          KLSA        /load op */
    06706,          /*          KGOA        /start */
    06703,          /*          KSBF        /ready? */
    05204,          /* RDCOD,   JMP .-1     /loop */
    07264,          /* L260,    CML STA RAL /L = 1, AC = halt */
    06702,          /*          KSEN        /error? */
    07610,          /*          SKP CLA     /halt on any error */
    03211,          /*          DCA .       /except REW or FFG */
    03636,          /*          DCA I PTR   /TAD I PTR mustn't change L */
    01205,          /*          TAD RDCOD   /read op */
    06704,          /*          KLSA        /load op */
    06706,          /*          KGOA        /start */
    06701,          /* LOOP,    KSDF        /data ready? */
    05216,          /*          JMP .-1     /loop */
    07002,          /*          BSW         /to upper 6b */
    07430,          /*          SZL         /second byte? */
    01636,          /*          TAD I PTR   /yes */
    07022,          /*          CML BSW     /swap back */
    03636,          /*          DCA I PTR   /store in mem */
    07420,          /*          SNL         /done with both bytes? */
    02236,          /*          ISZ PTR     /yes, bump mem ptr */
    02235,          /*          ISZ KNT     /done with record? */
    05215,          /*          JMP LOOP    /next byte */
    07346,          /*          STA CLL RTL */
    07002,          /*          BSW         /AC = 7757 */
    03235,          /*          STA KNT     /now read 200 byte record */
    05201,          /*          JMP CRCCHK  /go check CRC */
    07737,          /* KNT,     7737        /1's compl of byte count */
    03557,          /* PTR,     3557        /load point */
    07730,          /* M50,     7730        /CLA SPA SZL */
    };

t_stat ct_boot (int32 unitno, DEVICE *dptr)
{
size_t i;
extern uint16 M[];

if ((ct_dib.dev != DEV_CT) || unitno)                   /* only std devno */
     return STOP_NOTSTD;
for (i = 0; i < BOOT_LEN; i++)
    M[BOOT_START + i] = boot_rom[i];
cpu_set_bootpc (BOOT_START);
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_defs.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/* pdp8_defs.h: PDP-8 simulator definitions

   Copyright (c) 1993-2016, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   18-Sep-16    RMS     Added support for 16 additional terminals
   18-Sep-13    RMS     Added set_bootpc prototype
   18-Apr-12    RMS     Removed separate timer for additional terminals;
                        Added clock_cosched prototype
   22-May-10    RMS     Added check for 64b definitions
   21-Aug-07    RMS     Added FPP8 support
   13-Dec-06    RMS     Added TA8E support
   30-Oct-06    RMS     Added infinite loop stop
   13-Oct-03    RMS     Added TSC8-75 support
   04-Oct-02    RMS     Added variable device number support
   20-Jan-02    RMS     Fixed bug in TTx interrupt enable initialization
   25-Nov-01    RMS     Added RL8A support
   16-Sep-01    RMS     Added multiple KL support
   18-Mar-01    RMS     Added DF32 support
   15-Feb-01    RMS     Added DECtape support
   14-Apr-99    RMS     Changed t_addr to unsigned
   19-Mar-95    RMS     Added dynamic memory size
   02-May-94    RMS     Added non-existent memory handling

   The author gratefully acknowledges the help of Max Burnet, Richie Lary,
   and Bill Haygood in resolving questions about the PDP-8
*/

#ifndef PDP8_DEFS_H_
#define PDP8_DEFS_H_   0

#include "sim_defs.h"                                   /* simulator defns */

#if defined(USE_INT64) || defined(USE_ADDR64)
#error "PDP-8 does not support 64b values!"
#endif

/* Simulator stop codes */

#define STOP_RSRV       1                               /* must be 1 */
#define STOP_HALT       2                               /* HALT */
#define STOP_IBKPT      3                               /* breakpoint */
#define STOP_OPBKPT     4                               /* Opcode/Instruction breakpoint */
#define STOP_NOTSTD     5                               /* non-std devno */
#define STOP_DTOFF      6                               /* DECtape off reel */
#define STOP_LOOP       7                               /* infinite loop */

/* Memory */

#define MAXMEMSIZE      32768                           /* max memory size */
#define MEMSIZE         (cpu_unit.capac)                /* actual memory size */
#define ADDRMASK        (MAXMEMSIZE - 1)                /* address mask */
#define MEM_ADDR_OK(x)  (((uint32) (x)) < MEMSIZE)

/* IOT subroutine return codes */

#define IOT_V_SKP       12                              /* skip */
#define IOT_V_REASON    13                              /* reason */
#define IOT_SKP         (1 << IOT_V_SKP)
#define IOT_REASON      (1 << IOT_V_REASON)
#define IORETURN(f,v)   ((f)? (v): SCPE_OK)             /* stop on error */

/* Timers */

#define TMR_CLK         0                               /* timer 0 = clock */

/* Device information block */

#define DEV_MAXBLK      8                               /* max dev block */
#define DEV_MAX         64                              /* total devices */

typedef struct {
    uint32              dev;                            /* device number */
    int32               (*dsp)(int32 IR, int32 dat);    /* dispatch */
    } DIB_DSP;

typedef struct {
    uint32              dev;                            /* base dev number */
    uint32              num;                            /* number of slots */
    int32               (*dsp[DEV_MAXBLK])(int32 IR, int32 dat);
    DIB_DSP             *dsp_tbl;                       /* optional table */
    } DIB;

/* Standard device numbers */

#define DEV_PTR         001                             /* paper tape reader */
#define DEV_PTP         002                             /* paper tape punch */
#define DEV_TTI         003                             /* console input */
#define DEV_TTO         004                             /* console output */
#define DEV_CLK         013                             /* clock */
#define DEV_TSC         036
#define DEV_KJ8         040                             /* extra terminals */
#define DEV_FPP         055                             /* floating point */
#define DEV_DF          060                             /* DF32 */
#define DEV_RF          060                             /* RF08 */
#define DEV_RL          060                             /* RL8A */
#define DEV_LPT         066                             /* line printer */
#define DEV_MT          070                             /* TM8E */
#define DEV_CT          070                             /* TA8E */
#define DEV_RK          074                             /* RK8E */
#define DEV_RX          075                             /* RX8E/RX28 */
#define DEV_DTA         076                             /* TC08 */
#define DEV_TD8E        077                             /* TD8E */

/* Extra PTO8/KL8JA devices */

#define DEV_TTI1        040
#define DEV_TTO1        041
#define DEV_TTI2        042
#define DEV_TTO2        043
#define DEV_TTI3        044
#define DEV_TTO3        045
#define DEV_TTI4        046
#define DEV_TTO4        047
#define DEV_TTI5        034
#define DEV_TTO5        035
#define DEV_TTI6        011
#define DEV_TTO6        012
#define DEV_TTI7        030
#define DEV_TTO7        031
#define DEV_TTI8        032
#define DEV_TTO8        033
#define DEV_TTI9        050
#define DEV_TTO9        051
#define DEV_TTI10       052
#define DEV_TTO10       053
#define DEV_TTI11       054
#define DEV_TTO11       055                             /* conflict: FPP */
#define DEV_TTI12       056                             /* conflict: FPP */
#define DEV_TTO12       057
#define DEV_TTI13       070                             /* conflict: CT, MT */
#define DEV_TTO13       071
#define DEV_TTI14       036                             /* conflict: TSC */
#define DEV_TTO14       037
#define DEV_TTI15       072
#define DEV_TTO15       073
#define DEV_TTI16       006
#define DEV_TTO16       007

/* Interrupt flags

   The interrupt flags consist of three groups:

   1.   Devices with individual interrupt enables.  These record
        their interrupt requests in device_done and their enables
        in device_enable, and must occupy the low bit positions.

   2.   Devices without interrupt enables.  These record their
        interrupt requests directly in int_req, and must occupy
        the middle bit positions.

   3.   Overhead.  These exist only in int_req and must occupy the
        high bit positions.

   Because the PDP-8 does not have priority interrupts, the order
   of devices within groups does not matter.

   Note: all extra KL input and output interrupts must be assigned
   to contiguous bits.
*/

#define INT_V_START     0                               /* enable start */
#define INT_V_LPT       (INT_V_START+0)                 /* line printer */
#define INT_V_PTP       (INT_V_START+1)                 /* tape punch */
#define INT_V_PTR       (INT_V_START+2)                 /* tape reader */
#define INT_V_TTO       (INT_V_START+3)                 /* terminal */
#define INT_V_TTI       (INT_V_START+4)                 /* keyboard */
#define INT_V_CLK       (INT_V_START+5)                 /* clock */
#define INT_V_TTO1      (INT_V_START+6)                 /* tto1 */
//#define INT_V_TTO2      (INT_V_START+7)                 /* tto2 */
//#define INT_V_TTO3      (INT_V_START+8)                 /* tto3 */
//#define INT_V_TTO4      (INT_V_START+9)                 /* tto4 */
#define INT_V_TTI1      (INT_V_START+10)                /* tti1 */
//#define INT_V_TTI2      (INT_V_START+11)                /* tti2 */
//#define INT_V_TTI3      (INT_V_START+12)                /* tti3 */
//#define INT_V_TTI4      (INT_V_START+13)                /* tti4 */
#define INT_V_DIRECT    (INT_V_START+14)                /* direct start */
#define INT_V_RX        (INT_V_DIRECT+0)                /* RX8E */
#define INT_V_RK        (INT_V_DIRECT+1)                /* RK8E */
#define INT_V_RF        (INT_V_DIRECT+2)                /* RF08 */
#define INT_V_DF        (INT_V_DIRECT+3)                /* DF32 */
#define INT_V_MT        (INT_V_DIRECT+4)                /* TM8E */
#define INT_V_DTA       (INT_V_DIRECT+5)                /* TC08 */
#define INT_V_RL        (INT_V_DIRECT+6)                /* RL8A */
#define INT_V_CT        (INT_V_DIRECT+7)                /* TA8E int */
#define INT_V_PWR       (INT_V_DIRECT+8)                /* power int */
#define INT_V_UF        (INT_V_DIRECT+9)                /* user int */
#define INT_V_TSC       (INT_V_DIRECT+10)               /* TSC8-75 int */
#define INT_V_FPP       (INT_V_DIRECT+11)               /* FPP8 */
#define INT_V_OVHD      (INT_V_DIRECT+12)               /* overhead start */
#define INT_V_NO_ION_PENDING (INT_V_OVHD+0)             /* ion pending */
#define INT_V_NO_CIF_PENDING (INT_V_OVHD+1)             /* cif pending */
#define INT_V_ION       (INT_V_OVHD+2)                  /* interrupts on */

#define INT_LPT         (1 << INT_V_LPT)
#define INT_PTP         (1 << INT_V_PTP)
#define INT_PTR         (1 << INT_V_PTR)
#define INT_TTO         (1 << INT_V_TTO)
#define INT_TTI         (1 << INT_V_TTI)
#define INT_CLK         (1 << INT_V_CLK)
#define INT_TTO1        (1 << INT_V_TTO1)
//#define INT_TTO2        (1 << INT_V_TTO2)
//#define INT_TTO3        (1 << INT_V_TTO3)
//#define INT_TTO4        (1 << INT_V_TTO4)
#define INT_TTI1        (1 << INT_V_TTI1)
//#define INT_TTI2        (1 << INT_V_TTI2)
//#define INT_TTI3        (1 << INT_V_TTI3)
//#define INT_TTI4        (1 << INT_V_TTI4)
#define INT_RX          (1 << INT_V_RX)
#define INT_RK          (1 << INT_V_RK)
#define INT_RF          (1 << INT_V_RF)
#define INT_DF          (1 << INT_V_DF)
#define INT_MT          (1 << INT_V_MT)
#define INT_DTA         (1 << INT_V_DTA)
#define INT_RL          (1 << INT_V_RL)
#define INT_CT          (1 << INT_V_CT)
#define INT_PWR         (1 << INT_V_PWR)
#define INT_UF          (1 << INT_V_UF)
#define INT_TSC         (1 << INT_V_TSC)
#define INT_FPP         (1 << INT_V_FPP)
#define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING)
#define INT_NO_CIF_PENDING (1 << INT_V_NO_CIF_PENDING)
#define INT_ION         (1 << INT_V_ION)
#define INT_DEV_ENABLE  ((1 << INT_V_DIRECT) - 1)       /* devices w/enables */
#define INT_ALL         ((1 << INT_V_OVHD) - 1)         /* all interrupts */
#define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \
                        (INT_TTI1+INT_TTO1)
#define INT_PENDING     (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING)
#define INT_UPDATE      ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable))

/* Function prototypes */

t_stat set_dev (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat show_dev (FILE *st, UNIT *uptr, int32 val, CONST void *desc);

void cpu_set_bootpc (int32 pc);

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_df.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/* pdp8_df.c: DF32 fixed head disk simulator

   Copyright (c) 1993-2013, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   df           DF32 fixed head disk

   17-Sep-13    RMS     Changed to use central set_bootpc routine
   03-Sep-13    RMS     Added explicit void * cast
   15-May-06    RMS     Fixed bug in autosize attach (Dave Gesswein)
   07-Jan-06    RMS     Fixed unaligned register access bug (Doug Carman)
   04-Jan-04    RMS     Changed sim_fsize calling sequence
   26-Oct-03    RMS     Cleaned up buffer copy code
   26-Jul-03    RMS     Fixed bug in set size routine
   14-Mar-03    RMS     Fixed variable platter interaction with save/restore
   03-Mar-03    RMS     Fixed autosizing
   02-Feb-03    RMS     Added variable platter and autosizing support
   04-Oct-02    RMS     Added DIBs, device number support
   28-Nov-01    RMS     Added RL8A support
   25-Apr-01    RMS     Added device enable/disable support

   The DF32 is a head-per-track disk.  It uses the three cycle data break
   facility.  To minimize overhead, the entire DF32 is buffered in memory.

   Two timing parameters are provided:

   df_time      Interword timing, must be non-zero
   df_burst     Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
                DMA occurs in a burst
*/

#include "pdp8_defs.h"
#include <math.h>

#define UNIT_V_AUTO     (UNIT_V_UF + 0)                 /* autosize */
#define UNIT_V_PLAT     (UNIT_V_UF + 1)                 /* #platters - 1 */
#define UNIT_M_PLAT     03
#define UNIT_PLAT       (UNIT_M_PLAT << UNIT_V_PLAT)
#define UNIT_GETP(x)    ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO       (1 << UNIT_V_AUTO)
#define UNIT_PLAT       (UNIT_M_PLAT << UNIT_V_PLAT)

/* Constants */

#define DF_NUMWD        2048                            /* words/track */
#define DF_NUMTR        16                              /* tracks/disk */
#define DF_DKSIZE       (DF_NUMTR * DF_NUMWD)           /* words/disk */
#define DF_NUMDK        4                               /* disks/controller */
#define DF_WC           07750                           /* word count */
#define DF_MA           07751                           /* mem address */
#define DF_WMASK        (DF_NUMWD - 1)                  /* word mask */

/* Parameters in the unit descriptor */

#define FUNC            u4                              /* function */
#define DF_READ         2                               /* read */
#define DF_WRITE        4                               /* write */

/* Status register */

#define DFS_PCA         04000                           /* photocell status */
#define DFS_DEX         03700                           /* disk addr extension */
#define DFS_MEX         00070                           /* mem addr extension */
#define DFS_DRL         00004                           /* data late error */
#define DFS_WLS         00002                           /* write lock error */
#define DFS_NXD         00002                           /* non-existent disk */
#define DFS_PER         00001                           /* parity error */
#define DFS_ERR         (DFS_DRL | DFS_WLS | DFS_PER)
#define DFS_V_DEX       6
#define DFS_V_MEX       3

#define GET_MEX(x)      (((x) & DFS_MEX) << (12 - DFS_V_MEX))
#define GET_DEX(x)      (((x) & DFS_DEX) << (12 - DFS_V_DEX))
#define GET_POS(x)      ((int) fmod (sim_gtime() / ((double) (x)), \
                        ((double) DF_NUMWD)))
#define UPDATE_PCELL    if (GET_POS (df_time) < 6) df_sta = df_sta | DFS_PCA; \
                        else df_sta = df_sta & ~DFS_PCA

extern uint16 M[];
extern int32 int_req, stop_inst;
extern UNIT cpu_unit;

int32 df_sta = 0;                                       /* status register */
int32 df_da = 0;                                        /* disk address */
int32 df_done = 0;                                      /* done flag */
int32 df_wlk = 0;                                       /* write lock */
int32 df_time = 10;                                     /* inter-word time */
int32 df_burst = 1;                                     /* burst mode flag */
int32 df_stopioe = 1;                                   /* stop on error */

int32 df60 (int32 IR, int32 AC);
int32 df61 (int32 IR, int32 AC);
int32 df62 (int32 IR, int32 AC);
t_stat df_svc (UNIT *uptr);
t_stat pcell_svc (UNIT *uptr);
t_stat df_reset (DEVICE *dptr);
t_stat df_boot (int32 unitno, DEVICE *dptr);
t_stat df_attach (UNIT *uptr, CONST char *cptr);
t_stat df_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);

/* DF32 data structures

   df_dev       RF device descriptor
   df_unit      RF unit descriptor
   pcell_unit   photocell timing unit (orphan)
   df_reg       RF register list
*/

DIB df_dib = { DEV_DF, 3, { &df60, &df61, &df62 } };

UNIT df_unit = {
    UDATA (&df_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
           DF_DKSIZE)
    };

REG df_reg[] = {
    { ORDATAD (STA, df_sta, 12, "status, disk and memory address extension") },
    { ORDATAD (DA, df_da, 12, "low order disk address") },
    { ORDATAD (WC, M[DF_WC], 12, "word count (in memory)"), REG_FIT },
    { ORDATAD (MA, M[DF_MA], 12, "memory address (in memory)"), REG_FIT },
    { FLDATAD (DONE, df_done, 0, "device done flag") },
    { FLDATAD (INT, int_req, INT_V_DF, "interrupt pending flag") },
    { ORDATAD (WLS, df_wlk, 8, "write lock switches") },
    { DRDATAD (TIME, df_time, 24, "rotational delay, per word"), REG_NZ + PV_LEFT },
    { FLDATAD (BURST, df_burst, 0, "burst flag") },
    { FLDATAD (STOP_IOE, df_stopioe, 0, "stop on I/O error") },
    { DRDATA (CAPAC, df_unit.capac, 18), REG_HRO },
    { ORDATA (DEVNUM, df_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB df_mod[] = {
    { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &df_set_size },
    { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &df_set_size },
    { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &df_set_size },
    { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &df_set_size },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE df_dev = {
    "DF", &df_unit, df_reg, df_mod,
    1, 8, 17, 1, 8, 12,
    NULL, NULL, &df_reset,
    &df_boot, &df_attach, NULL,
    &df_dib, DEV_DISABLE
    };

/* IOT routines */

int32 df60 (int32 IR, int32 AC)
{
int32 t;
int32 pulse = IR & 07;

UPDATE_PCELL;                                           /* update photocell */
if (pulse & 1) {                                        /* DCMA */
    df_da = 0;                                          /* clear disk addr */
    df_done = 0;                                        /* clear done */
    df_sta = df_sta & ~DFS_ERR;                         /* clear errors */
    int_req = int_req & ~INT_DF;                        /* clear int req */
    }
if (pulse & 6) {                                        /* DMAR, DMAW */
    df_da = df_da | AC;                                 /* disk addr |= AC */
    df_unit.FUNC = pulse & ~1;                          /* save function */
    t = (df_da & DF_WMASK) - GET_POS (df_time);         /* delta to new loc */
    if (t < 0)                                          /* wrap around? */
        t = t + DF_NUMWD;
    sim_activate (&df_unit, t * df_time);               /* schedule op */
    AC = 0;                                             /* clear AC */
    }
return AC;
}

/* Based on the hardware implementation.  DEAL and DEAC work as follows:

   6615         pulse 1 = clear df_sta<dex,mex>
                pulse 4 = df_sta = df_sta | AC<dex,mex>
                          AC = AC | old_df_sta
   6616         pulse 2 = clear AC, skip if address confirmed
                pulse 4 = df_sta = df_sta | AC<dex,mex> = 0 (nop)
                          AC = AC | old_df_sta
*/

int32 df61 (int32 IR, int32 AC)
{
int32 old_df_sta = df_sta;
int32 pulse = IR & 07;

UPDATE_PCELL;                                           /* update photocell */
if (pulse & 1)                                          /* DCEA */
    df_sta = df_sta & ~(DFS_DEX | DFS_MEX);             /* clear dex, mex */
if (pulse & 2)                                          /* DSAC */
    AC = ((df_da & DF_WMASK) == GET_POS (df_time))? IOT_SKP: 0;
if (pulse & 4) {
    df_sta = df_sta | (AC & (DFS_DEX | DFS_MEX));       /* DEAL */
    AC = AC | old_df_sta;                               /* DEAC */
    }
return AC;
}

int32 df62 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;

UPDATE_PCELL;                                           /* update photocell */
if (pulse & 1) {                                        /* DFSE */
    if ((df_sta & DFS_ERR) == 0)
        AC = AC | IOT_SKP;
    }
if (pulse & 2) {                                        /* DFSC */
    if (pulse & 4)                                      /* for DMAC */
        AC = AC & ~07777;
    else if (df_done)
        AC = AC | IOT_SKP;
    }
if (pulse & 4)                                          /* DMAC */
    AC = AC | df_da;
return AC;
}

/* Unit service

   Note that for reads and writes, memory addresses wrap around in the
   current field.  This code assumes the entire disk is buffered.
*/

t_stat df_svc (UNIT *uptr)
{
int32 pa, t, mex;
uint32 da;
int16 *fbuf = (int16 *) uptr->filebuf;

UPDATE_PCELL;                                           /* update photocell */
if ((uptr->flags & UNIT_BUF) == 0) {                    /* not buf? abort */
    df_done = 1;
    int_req = int_req | INT_DF;                         /* update int req */
    return IORETURN (df_stopioe, SCPE_UNATT);
    }

mex = GET_MEX (df_sta);
da = GET_DEX (df_sta) | df_da;                          /* form disk addr */
do {
    if (da >= uptr->capac) {                            /* nx disk addr? */
        df_sta = df_sta | DFS_NXD;
        break;
        }
    M[DF_WC] = (M[DF_WC] + 1) & 07777;                  /* incr word count */
    M[DF_MA] = (M[DF_MA] + 1) & 07777;                  /* incr mem addr */
    pa = mex | M[DF_MA];                                /* add extension */
    if (uptr->FUNC == DF_READ) {                        /* read? */
        if (MEM_ADDR_OK (pa)) M[pa] = fbuf[da];         /* if !nxm, read wd */
        }
    else {                                              /* write */
        t = (da >> 14) & 07;                            /* check wr lock */
        if ((df_wlk >> t) & 1)                          /* locked? set err */
            df_sta = df_sta | DFS_WLS;
        else {                                          /* not locked */
            fbuf[da] = M[pa];                           /* write word */
            if (da >= uptr->hwmark) uptr->hwmark = da + 1;
            }
        }
    da = (da + 1) & 0377777;                            /* incr disk addr */
    } while ((M[DF_WC] != 0) && (df_burst != 0));       /* brk if wc, no brst */

if ((M[DF_WC] != 0) && ((df_sta & DFS_ERR) == 0))       /* more to do? */
    sim_activate (&df_unit, df_time);                   /* sched next */
else {
    if (uptr->FUNC != DF_READ)
        da = (da - 1) & 0377777;
    df_done = 1;                                        /* done */
    int_req = int_req | INT_DF;                         /* update int req */
    }
df_sta = (df_sta & ~DFS_DEX) | ((da >> (12 - DFS_V_DEX)) & DFS_DEX);
df_da = da & 07777;                                     /* separate disk addr */
return SCPE_OK;
}

/* Reset routine */

t_stat df_reset (DEVICE *dptr)
{
df_sta = df_da = 0;
df_done = 1;
int_req = int_req & ~INT_DF;                            /* clear interrupt */
sim_cancel (&df_unit);
return SCPE_OK;
}

/* Bootstrap routine */

#define OS8_START       07750
#define OS8_LEN         (sizeof (os8_rom) / sizeof (int16))
#define DM4_START       00200
#define DM4_LEN         (sizeof (dm4_rom) / sizeof (int16))

static const uint16 os8_rom[] = {
    07600,                      /* 7750, CLA CLL        ; also word count */
    06603,                      /* 7751, DMAR           ; also address */
    06622,                      /* 7752, DFSC           ; done? */
    05352,                      /* 7753, JMP .-1        ; no */
    05752                       /* 7754, JMP @.-2       ; enter boot */
    };

static const uint16 dm4_rom[] = {
    00200, 07600,               /* 0200, CLA CLL */
    00201, 06603,               /* 0201, DMAR           ; read */
    00202, 06622,               /* 0202, DFSC           ; done? */
    00203, 05202,               /* 0203, JMP .-1        ; no */
    00204, 05600,               /* 0204, JMP @.-4       ; enter boot */
    07750, 07576,               /* 7750, 7576           ; word count */
    07751, 07576                /* 7751, 7576           ; address */
    };

t_stat df_boot (int32 unitno, DEVICE *dptr)
{
size_t i;

if (sim_switches & SWMASK ('D')) {
    for (i = 0; i < DM4_LEN; i = i + 2)
        M[dm4_rom[i]] = dm4_rom[i + 1];
    cpu_set_bootpc (DM4_START);
    }
else {
    for (i = 0; i < OS8_LEN; i++)
         M[OS8_START + i] = os8_rom[i];
    cpu_set_bootpc (OS8_START);
    }
return SCPE_OK;
}

/* Attach routine */

t_stat df_attach (UNIT *uptr, CONST char *cptr)
{
uint32 p, sz;
uint32 ds_bytes = DF_DKSIZE * sizeof (int16);

if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
    p = (sz + ds_bytes - 1) / ds_bytes;
    if (p >= DF_NUMDK)
        p = DF_NUMDK - 1;
    uptr->flags = (uptr->flags & ~UNIT_PLAT) |
         (p << UNIT_V_PLAT);
    }
uptr->capac = UNIT_GETP (uptr->flags) * DF_DKSIZE;
return attach_unit (uptr, cptr);
}

/* Change disk size */

t_stat df_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (val < 0)
    return SCPE_IERR;
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;
uptr->capac = UNIT_GETP (val) * DF_DKSIZE;
uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_dt.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
/* pdp8_dt.c: PDP-8 DECtape simulator

   Copyright (c) 1993-2017, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   dt           TC08/TU56 DECtape

   15-Mar-17    RMS     Fixed dt_seterr to clear successor states
   17-Sep-13    RMS     Changed to use central set_bootpc routine
   23-Jun-06    RMS     Fixed switch conflict in ATTACH
   07-Jan-06    RMS     Fixed unaligned register access bug (Doug Carman)
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   25-Jan-04    RMS     Revised for device debug support
   09-Jan-04    RMS     Changed sim_fsize calling sequence, added STOP_OFFR
   18-Oct-03    RMS     Fixed bugs in read all, tightened timing
   25-Apr-03    RMS     Revised for extended file support
   14-Mar-03    RMS     Fixed sizing interaction with save/restore
   17-Oct-02    RMS     Fixed bug in end of reel logic
   04-Oct-02    RMS     Added DIB, device number support
   12-Sep-02    RMS     Added support for 16b format
   30-May-02    RMS     Widened POS to 32b
   06-Jan-02    RMS     Changed enable/disable support
   30-Nov-01    RMS     Added read only unit, extended SET/SHOW support
   24-Nov-01    RMS     Changed POS, STATT, LASTT, FLG to arrays
   29-Aug-01    RMS     Added casts to PDP-18b packup routine
   17-Jul-01    RMS     Moved function prototype
   11-May-01    RMS     Fixed bug in reset
   25-Apr-01    RMS     Added device enable/disable support
   18-Apr-01    RMS     Changed to rewind tape before boot
   19-Mar-01    RMS     Changed bootstrap to support 4k disk monitor
   15-Mar-01    RMS     Added 129th word to PDP-8 format

   PDP-8 DECtapes are represented in memory by fixed length buffer of 16b words.
   Three file formats are supported:

        18b/36b                 256 words per block [256 x 18b]
        16b                     256 words per block [256 x 16b]
        12b                     129 words per block [129 x 12b]

   When a 16b or 18/36bb DECtape file is read in, it is converted to 12b format.

   DECtape motion is measured in 3b lines.  Time between lines is 33.33us.
   Tape density is nominally 300 lines per inch.  The format of a DECtape (as
   taken from the TD8E formatter) is:

        reverse end zone        8192 reverse end zone codes ~ 10 feet
        reverse buffer          200 interblock codes
        block 0
         :
        block n
        forward buffer          200 interblock codes
        forward end zone        8192 forward end zone codes ~ 10 feet

   A block consists of five 18b header words, a tape-specific number of data
   words, and five 18b trailer words.  All systems except the PDP-8 use a
   standard block length of 256 words; the PDP-8 uses a standard block length
   of 86 words (x 18b = 129 words x 12b).

   Because a DECtape file only contains data, the simulator cannot support
   write timing and mark track and can only do a limited implementation
   of read all and write all.  Read all assumes that the tape has been
   conventionally written forward:

        header word 0           0
        header word 1           block number (for forward reads)
        header words 2,3        0
        header word 4           checksum (for reverse reads)
        :
        trailer word 4          checksum (for forward reads)
        trailer words 3,2       0
        trailer word 1          block number (for reverse reads)
        trailer word 0          0

   Write all writes only the data words and dumps the non-data words in the
   bit bucket.
*/

#include "pdp8_defs.h"

#define DT_NUMDR        8                               /* #drives */
#define UNIT_V_WLK      (UNIT_V_UF + 0)                 /* write locked */
#define UNIT_V_8FMT     (UNIT_V_UF + 1)                 /* 12b format */
#define UNIT_V_11FMT    (UNIT_V_UF + 2)                 /* 16b format */
#define UNIT_WLK        (1 << UNIT_V_WLK)
#define UNIT_8FMT       (1 << UNIT_V_8FMT)
#define UNIT_11FMT      (1 << UNIT_V_11FMT)
#define STATE           u3                              /* unit state */
#define LASTT           u4                              /* last time update */
#define WRITTEN         u5                              /* device buffer is dirty and needs flushing */
#define DT_WC           07754                           /* word count */
#define DT_CA           07755                           /* current addr */
#define UNIT_WPRT       (UNIT_WLK | UNIT_RO)            /* write protect */

/* System independent DECtape constants */

#define DT_LPERMC       6                               /* lines per mark track */
#define DT_BLKWD        1                               /* blk no word in h/t */
#define DT_CSMWD        4                               /* checksum word in h/t */
#define DT_HTWRD        5                               /* header/trailer words */
#define DT_EZLIN        (8192 * DT_LPERMC)              /* end zone length */
#define DT_BFLIN        (200 * DT_LPERMC)               /* buffer length */
#define DT_BLKLN        (DT_BLKWD * DT_LPERMC)          /* blk no line in h/t */
#define DT_CSMLN        (DT_CSMWD * DT_LPERMC)          /* csum line in h/t */
#define DT_HTLIN        (DT_HTWRD * DT_LPERMC)          /* header/trailer lines */

/* 16b, 18b, 36b DECtape constants */

#define D18_WSIZE       6                               /* word size in lines */
#define D18_BSIZE       384                             /* block size in 12b */
#define D18_TSIZE       578                             /* tape size */
#define D18_LPERB       (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN)
#define D18_FWDEZ       (DT_EZLIN + (D18_LPERB * D18_TSIZE))
#define D18_CAPAC       (D18_TSIZE * D18_BSIZE)         /* tape capacity */

#define D18_NBSIZE      ((D18_BSIZE * D8_WSIZE) / D18_WSIZE)
#define D18_FILSIZ      (D18_NBSIZE * D18_TSIZE * sizeof (int32))
#define D11_FILSIZ      (D18_NBSIZE * D18_TSIZE * sizeof (int16))

/* 12b DECtape constants */

#define D8_WSIZE        4                               /* word size in lines */
#define D8_BSIZE        129                             /* block size in 12b */
#define D8_TSIZE        1474                            /* tape size */
#define D8_LPERB        (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN)
#define D8_FWDEZ        (DT_EZLIN + (D8_LPERB * D8_TSIZE))
#define D8_CAPAC        (D8_TSIZE * D8_BSIZE)           /* tape capacity */
#define D8_FILSIZ       (D8_CAPAC * sizeof (int16))

/* This controller */

#define DT_CAPAC        D8_CAPAC                        /* default */
#define DT_WSIZE        D8_WSIZE

/* Calculated constants, per unit */

#define DTU_BSIZE(u)    (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
#define DTU_TSIZE(u)    (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
#define DTU_LPERB(u)    (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
#define DTU_FWDEZ(u)    (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
#define DTU_CAPAC(u)    (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)

#define DT_LIN2BL(p,u)  (((p) - DT_EZLIN) / DTU_LPERB (u))
#define DT_LIN2OF(p,u)  (((p) - DT_EZLIN) % DTU_LPERB (u))
#define DT_LIN2WD(p,u)  ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE)
#define DT_BLK2LN(p,u)  (((p) * DTU_LPERB (u)) + DT_EZLIN)
#define DT_QREZ(u)      (((u)->pos) < DT_EZLIN)
#define DT_QFEZ(u)      (((u)->pos) >= ((uint32) DTU_FWDEZ (u)))
#define DT_QEZ(u)       (DT_QREZ (u) || DT_QFEZ (u))

/* Status register A */

#define DTA_V_UNIT      9                               /* unit select */
#define DTA_M_UNIT      07
#define DTA_UNIT        (DTA_M_UNIT << DTA_V_UNIT)
#define DTA_V_MOT       7                               /* motion */
#define DTA_M_MOT       03
#define DTA_V_MODE      6                               /* mode */
#define DTA_V_FNC       3                               /* function */
#define DTA_M_FNC       07
#define  FNC_MOVE        00                             /* move */
#define  FNC_SRCH        01                             /* search */
#define  FNC_READ        02                             /* read */
#define  FNC_RALL        03                             /* read all */
#define  FNC_WRIT        04                             /* write */
#define  FNC_WALL        05                             /* write all */
#define  FNC_WMRK        06                             /* write timing */
#define DTA_V_ENB       2                               /* int enable */
#define DTA_V_CERF      1                               /* clr error flag */
#define DTA_V_CDTF      0                               /* clr DECtape flag */
#define DTA_FWDRV       (1u << (DTA_V_MOT + 1))
#define DTA_STSTP       (1u << DTA_V_MOT)
#define DTA_MODE        (1u << DTA_V_MODE)
#define DTA_ENB         (1u << DTA_V_ENB)
#define DTA_CERF        (1u << DTA_V_CERF)
#define DTA_CDTF        (1u << DTA_V_CDTF)
#define DTA_RW          (07777 & ~(DTA_CERF | DTA_CDTF))

#define DTA_GETUNIT(x)  (((x) >> DTA_V_UNIT) & DTA_M_UNIT)
#define DTA_GETMOT(x)   (((x) >> DTA_V_MOT) & DTA_M_MOT)
#define DTA_GETFNC(x)   (((x) >> DTA_V_FNC) & DTA_M_FNC)

/* Status register B */

#define DTB_V_ERF       11                              /* error flag */
#define DTB_V_MRK       10                              /* mark trk err */
#define DTB_V_END       9                               /* end zone err */
#define DTB_V_SEL       8                               /* select err */
#define DTB_V_PAR       7                               /* parity err */
#define DTB_V_TIM       6                               /* timing err */
#define DTB_V_MEX       3                               /* memory extension */
#define DTB_M_MEX       07
#define DTB_MEX         (DTB_M_MEX << DTB_V_MEX)
#define DTB_V_DTF       0                               /* DECtape flag */
#define DTB_ERF         (1u << DTB_V_ERF)
#define DTB_MRK         (1u << DTB_V_MRK)
#define DTB_END         (1u << DTB_V_END)
#define DTB_SEL         (1u << DTB_V_SEL)
#define DTB_PAR         (1u << DTB_V_PAR)
#define DTB_TIM         (1u << DTB_V_TIM)
#define DTB_DTF         (1u << DTB_V_DTF)
#define DTB_ALLERR      (DTB_ERF | DTB_MRK | DTB_END | DTB_SEL | \
                        DTB_PAR | DTB_TIM)
#define DTB_GETMEX(x)   (((x) & DTB_MEX) << (12 - DTB_V_MEX))

/* DECtape state */

#define DTS_V_MOT       3                               /* motion */
#define DTS_M_MOT       07
#define  DTS_STOP        0                              /* stopped */
#define  DTS_DECF        2                              /* decel, fwd */
#define  DTS_DECR        3                              /* decel, rev */
#define  DTS_ACCF        4                              /* accel, fwd */
#define  DTS_ACCR        5                              /* accel, rev */
#define  DTS_ATSF        6                              /* @speed, fwd */
#define  DTS_ATSR        7                              /* @speed, rev */
#define DTS_DIR         01                              /* dir mask */
#define DTS_V_FNC       0                               /* function */
#define DTS_M_FNC       07
#define  DTS_OFR        7                               /* "off reel" */
#define DTS_GETMOT(x)   (((x) >> DTS_V_MOT) & DTS_M_MOT)
#define DTS_GETFNC(x)   (((x) >> DTS_V_FNC) & DTS_M_FNC)
#define DTS_V_2ND       6                               /* next state */
#define DTS_V_3RD       (DTS_V_2ND + DTS_V_2ND)         /* next next */
#define DTS_STA(y,z)    (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC))
#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z)
#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \
                        ((DTS_STA (y, z)) << DTS_V_2ND)
#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \
                        ((DTS_STA (y, z)) << DTS_V_3RD)
#define DTS_NXTSTA(x)   (x >> DTS_V_2ND)

/* Operation substates */

#define DTO_WCO         1                               /* wc overflow */
#define DTO_SOB         2                               /* start of block */

/* Logging */

#define LOG_MS          001                             /* move, search */
#define LOG_RW          002                             /* read, write */
#define LOG_BL          004                             /* block # lblk */

#define DT_UPDINT       if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \
                        int_req = int_req | INT_DTA; \
                        else int_req = int_req & ~INT_DTA;
#define ABS(x)          (((x) < 0)? (-(x)): (x))

extern uint16 M[];
extern int32 int_req;
extern UNIT cpu_unit;

int32 dtsa = 0;                                         /* status A */
int32 dtsb = 0;                                         /* status B */
int32 dt_ltime = 12;                                    /* interline time */
int32 dt_dctime = 40000;                                /* decel time */
int32 dt_substate = 0;
int32 dt_logblk = 0;
int32 dt_stopoffr = 0;

int32 dt76 (int32 IR, int32 AC);
int32 dt77 (int32 IR, int32 AC);
t_stat dt_svc (UNIT *uptr);
t_stat dt_reset (DEVICE *dptr);
t_stat dt_attach (UNIT *uptr, CONST char *cptr);
void dt_flush (UNIT *uptr);
t_stat dt_detach (UNIT *uptr);
t_stat dt_boot (int32 unitno, DEVICE *dptr);
void dt_deselect (int32 oldf);
void dt_newsa (int32 newf);
void dt_newfnc (UNIT *uptr, int32 newsta);
t_bool dt_setpos (UNIT *uptr);
void dt_schedez (UNIT *uptr, int32 dir);
void dt_seterr (UNIT *uptr, int32 e);
int32 dt_comobv (int32 val);
int32 dt_csum (UNIT *uptr, int32 blk);
int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos, int32 dir);

/* DT data structures

   dt_dev       DT device descriptor
   dt_unit      DT unit list
   dt_reg       DT register list
   dt_mod       DT modifier list
*/

DIB dt_dib = { DEV_DTA, 2, { &dt76, &dt77 } };

UNIT dt_unit[] = {
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }
    };

REG dt_reg[] = {
    { ORDATAD (DTSA, dtsa, 12, "status register A") },
    { ORDATAD (DTSB, dtsb, 12, "status register B") },
    { FLDATAD (INT, int_req, INT_V_DTA, "interrupt pending flag") },
    { FLDATAD (ENB, dtsa, DTA_V_ENB, "interrupt enable flag") },
    { FLDATAD (DTF, dtsb, DTB_V_DTF, "DECtape flag") },
    { FLDATAD (ERF, dtsb, DTB_V_ERF, "error flag") },
    { ORDATAD (WC, M[DT_WC], 12, "word count (memory location 7755)"), REG_FIT },
    { ORDATAD (CA, M[DT_CA], 12, "current address (memory location 7754)"), REG_FIT },
    { DRDATAD (LTIME, dt_ltime, 24, "time between lines"), REG_NZ | PV_LEFT },
    { DRDATAD (DCTIME, dt_dctime, 24, "time to decelerate to a full stop"), REG_NZ | PV_LEFT },
    { ORDATAD (SUBSTATE, dt_substate, 2, "read/write command substate") },
    { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN },
    { URDATAD (POS, dt_unit[0].pos, 10, T_ADDR_W, 0,
              DT_NUMDR, PV_LEFT | REG_RO, "position, in lines, units 0 to 7") },
    { URDATAD (STATT, dt_unit[0].STATE, 8, 18, 0,
              DT_NUMDR, REG_RO, "unit state, units 0 to 7") },
    { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0,
              DT_NUMDR, REG_HRO) },
    { FLDATAD (STOP_OFFR, dt_stopoffr, 0, "stop on off-reel error") },
    { ORDATA (DEVNUM, dt_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB dt_mod[] = {
    { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
    { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, 
    { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },
    { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL },
    { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEBTAB dt_deb[] = {
    { "MOTION", LOG_MS },
    { "DATA", LOG_RW },
    { "BLOCK", LOG_BL },
    { NULL, 0 }
    };

DEVICE dt_dev = {
    "DT", dt_unit, dt_reg, dt_mod,
    DT_NUMDR, 8, 24, 1, 8, 12,
    NULL, NULL, &dt_reset,
    &dt_boot, &dt_attach, &dt_detach,
    &dt_dib, DEV_DISABLE | DEV_DEBUG, 0,
    dt_deb, NULL, NULL
    };

/* IOT routines */

int32 dt76 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;
int32 old_dtsa = dtsa, fnc;
UNIT *uptr;

if (pulse & 01)                                         /* DTRA */
    AC = AC | dtsa;
if (pulse & 06) {                                       /* select */
    if (pulse & 02)                                     /* DTCA */
        dtsa = 0;
    if (pulse & 04) {                                   /* DTXA */
        if ((AC & DTA_CERF) == 0) dtsb = dtsb & ~DTB_ALLERR;
        if ((AC & DTA_CDTF) == 0) dtsb = dtsb & ~DTB_DTF;
        dtsa = dtsa ^ (AC & DTA_RW);
        AC = 0;                                         /* clr AC */
        }
    if ((old_dtsa ^ dtsa) & DTA_UNIT)
        dt_deselect (old_dtsa);
    uptr = dt_dev.units + DTA_GETUNIT (dtsa);           /* get unit */
    fnc = DTA_GETFNC (dtsa);                            /* get fnc */
    if (((uptr->flags) & UNIT_DIS) ||                   /* disabled? */
         (fnc >= FNC_WMRK) ||                           /* write mark? */
        ((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) ||
        ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)))
        dt_seterr (uptr, DTB_SEL);                      /* select err */
    else dt_newsa (dtsa);
    DT_UPDINT;
    }
return AC;
}

int32 dt77 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;

if ((pulse & 01) && (dtsb & (DTB_ERF |DTB_DTF)))        /* DTSF */
    AC = IOT_SKP | AC;
if (pulse & 02)                                         /* DTRB */
    AC = AC | dtsb;
if (pulse & 04) {                                       /* DTLB */
    dtsb = (dtsb & ~DTB_MEX) | (AC & DTB_MEX);
    AC = AC & ~07777;                                   /* clear AC */
    }
return AC;
}

/* Unit deselect */

void dt_deselect (int32 oldf)
{
int32 old_unit = DTA_GETUNIT (oldf);
UNIT *uptr = dt_dev.units + old_unit;
int32 old_mot = DTS_GETMOT (uptr->STATE);

if (old_mot >= DTS_ATSF)                                /* at speed? */
    dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR));
else if (old_mot >= DTS_ACCF)                           /* accelerating? */
    DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR);
return;
}

/* Command register change

   1. If change in motion, stop to start
        - schedule acceleration
        - set function as next state
   2. If change in motion, start to stop
        - if not already decelerating (could be reversing),
          schedule deceleration
   3. If change in direction,
        - if not decelerating, schedule deceleration
        - set accelerating (other dir) as next state
        - set function as next next state
   4. If not accelerating or at speed,
        - schedule acceleration
        - set function as next state
   5. If not yet at speed,
        - set function as next state
   6. If at speed,
        - set function as current state, schedule function
*/

void dt_newsa (int32 newf)
{
int32 new_unit, prev_mot, new_fnc;
int32 prev_mving, new_mving, prev_dir, new_dir;
UNIT *uptr;

new_unit = DTA_GETUNIT (newf);                          /* new, old units */
uptr = dt_dev.units + new_unit;
if ((uptr->flags & UNIT_ATT) == 0) {                    /* new unit attached? */
    dt_seterr (uptr, DTB_SEL);                          /* no, error */
    return;
    }
prev_mot = DTS_GETMOT (uptr->STATE);                    /* previous motion */
prev_mving = prev_mot != DTS_STOP;                      /* previous moving? */
prev_dir = prev_mot & DTS_DIR;                          /* previous dir? */
new_mving = (newf & DTA_STSTP) != 0;                    /* new moving? */
new_dir = (newf & DTA_FWDRV) != 0;                      /* new dir? */
new_fnc = DTA_GETFNC (newf);                            /* new function? */

if ((prev_mving | new_mving) == 0)                      /* stop to stop */
    return;

if (new_mving & ~prev_mving) {                          /* start? */
    if (dt_setpos (uptr))                               /* update pos */
        return;
    sim_cancel (uptr);                                  /* stop current */
    sim_activate (uptr, dt_dctime - (dt_dctime >> 2));  /* schedule acc */
    DTS_SETSTA (DTS_ACCF | new_dir, 0);                 /* state = accel */
    DTS_SET2ND (DTS_ATSF | new_dir, new_fnc);           /* next = fnc */
    return;
    }

if (prev_mving & ~new_mving) {                          /* stop? */
    if ((prev_mot & ~DTS_DIR) != DTS_DECF) {            /* !already stopping? */
        if (dt_setpos (uptr))                           /* update pos */
            return;
        sim_cancel (uptr);                              /* stop current */
        sim_activate (uptr, dt_dctime);                 /* schedule decel */
        }
    DTS_SETSTA (DTS_DECF | prev_dir, 0);                /* state = decel */
    return;
    }

if (prev_dir ^ new_dir) {                               /* dir chg? */
    if ((prev_mot & ~DTS_DIR) != DTS_DECF) {            /* !already stopping? */
        if (dt_setpos (uptr))                           /* update pos */
            return;
        sim_cancel (uptr);                              /* stop current */
        sim_activate (uptr, dt_dctime);                 /* schedule decel */
        }
    DTS_SETSTA (DTS_DECF | prev_dir, 0);                /* state = decel */
    DTS_SET2ND (DTS_ACCF | new_dir, 0);                 /* next = accel */
    DTS_SET3RD (DTS_ATSF | new_dir, new_fnc);           /* next next = fnc */
    return;
    }

if (prev_mot < DTS_ACCF) {                              /* not accel/at speed? */
    if (dt_setpos (uptr))                               /* update pos */
        return;
    sim_cancel (uptr);                                  /* cancel cur */
    sim_activate (uptr, dt_dctime - (dt_dctime >> 2));  /* sched accel */
    DTS_SETSTA (DTS_ACCF | new_dir, 0);                 /* state = accel */
    DTS_SET2ND (DTS_ATSF | new_dir, new_fnc);           /* next = fnc */
    return;
    }

if (prev_mot < DTS_ATSF) {                              /* not at speed? */
    DTS_SET2ND (DTS_ATSF | new_dir, new_fnc);           /* next = fnc */
    return;
    }

dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */
return; 
}

/* Schedule new DECtape function

   This routine is only called if
   - the selected unit is attached
   - the selected unit is at speed (forward or backward)

   This routine
   - updates the selected unit's position
   - updates the selected unit's state
   - schedules the new operation
*/

void dt_newfnc (UNIT *uptr, int32 newsta)
{
int32 fnc, dir, blk, unum, relpos, newpos;
uint32 oldpos;

oldpos = uptr->pos;                                     /* save old pos */
if (dt_setpos (uptr))                                   /* update pos */
    return;
uptr->STATE = newsta;                                   /* update state */
fnc = DTS_GETFNC (uptr->STATE);                         /* set variables */
dir = DTS_GETMOT (uptr->STATE) & DTS_DIR;
unum = (int32) (uptr - dt_dev.units);
if (oldpos == uptr->pos)                                /* bump pos */
    uptr->pos = uptr->pos + (dir? -1: 1);
blk = DT_LIN2BL (uptr->pos, uptr);

if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) {              /* wrong ez? */
    dt_seterr (uptr, DTB_END);                          /* set ez flag, stop */
    return;
    }
sim_cancel (uptr);                                      /* cancel cur op */
dt_substate = DTO_SOB;                                  /* substate = block start */
switch (fnc) {                                          /* case function */

    case DTS_OFR:                                       /* off reel */
        if (dir)                                        /* rev? < start */
            newpos = -1000;
        else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */
        break;

    case FNC_MOVE:                                      /* move */
        dt_schedez (uptr, dir);                         /* sched end zone */
        if (DEBUG_PRI (dt_dev, LOG_MS)) fprintf (sim_deb, ">>DT%d: moving %s\n",
            unum, (dir? "backward": "forward"));
        return;                                         /* done */

    case FNC_SRCH:                                      /* search */
        if (dir) newpos = DT_BLK2LN ((DT_QFEZ (uptr)?
            DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE;
        else newpos = DT_BLK2LN ((DT_QREZ (uptr)?
            0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1);
        if (DEBUG_PRI (dt_dev, LOG_MS))
            fprintf (sim_deb, ">>DT%d: searching %s]\n",
                     unum, (dir? "backward": "forward"));
        break;

    case FNC_WRIT:                                      /* write */
    case FNC_READ:                                      /* read */
    case FNC_RALL:                                      /* read all */
    case FNC_WALL:                                      /* write all */
        if (DT_QEZ (uptr)) {                            /* in "ok" end zone? */
            if (dir)
                newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE;
            else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1);
            break;
            }
        relpos = DT_LIN2OF (uptr->pos, uptr);           /* cur pos in blk */
        if ((relpos >= DT_HTLIN) &&                     /* in data zone? */
            (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
            dt_seterr (uptr, DTB_SEL);
            return;
            }
        if (dir)
            newpos = DT_BLK2LN (((relpos >= (DTU_LPERB (uptr) - DT_HTLIN))?
                blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE;
        else newpos = DT_BLK2LN (((relpos < DT_HTLIN)?
                blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1);
        break;

    default:
        dt_seterr (uptr, DTB_SEL);                      /* bad state */
        return;
        }

sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
return;
}

/* Update DECtape position

   DECtape motion is modeled as a constant velocity, with linear
   acceleration and deceleration.  The motion equations are as follows:

        t       =       time since operation started
        tmax    =       time for operation (accel, decel only)
        v       =       at speed velocity in lines (= 1/dt_ltime)

   Then:
        at speed dist = t * v
        accel dist = (t^2 * v) / (2 * tmax)
        decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax)

   This routine uses the relative (integer) time, rather than the absolute
   (floating point) time, to allow save and restore of the start times.
*/

t_bool dt_setpos (UNIT *uptr)
{
uint32 new_time, ut, ulin, udelt;
int32 mot = DTS_GETMOT (uptr->STATE);
int32 unum, delta;

new_time = sim_grtime ();                               /* current time */
ut = new_time - uptr->LASTT;                            /* elapsed time */
if (ut == 0)                                            /* no time gone? exit */
    return FALSE;
uptr->LASTT = new_time;                                 /* update last time */
switch (mot & ~DTS_DIR) {                               /* case on motion */

    case DTS_STOP:                                      /* stop */
        delta = 0;
        break;

    case DTS_DECF:                                      /* slowing */
        ulin = ut / (uint32) dt_ltime;
        udelt = dt_dctime / dt_ltime;
        delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
        break;

    case DTS_ACCF:                                      /* accelerating */
        ulin = ut / (uint32) dt_ltime;
        udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime;
        delta = (ulin * ulin) / (2 * udelt);
        break;

    case DTS_ATSF:                                      /* at speed */
        delta = ut / (uint32) dt_ltime;
        break;
        }

if (mot & DTS_DIR)                                      /* update pos */
    uptr->pos = uptr->pos - delta;
else uptr->pos = uptr->pos + delta;
if (((int32) uptr->pos < 0) ||
    ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) {
    detach_unit (uptr);                                 /* off reel? */
    uptr->STATE = uptr->pos = 0;
    unum = (int32) (uptr - dt_dev.units);
    if (unum == DTA_GETUNIT (dtsa))                     /* if selected, */
        dt_seterr (uptr, DTB_SEL);                      /* error */
    return TRUE;
    }
return FALSE;
}

/* Unit service

   Unit must be attached, detach cancels operation
*/

t_stat dt_svc (UNIT *uptr)
{
int32 mot = DTS_GETMOT (uptr->STATE);
int32 dir = mot & DTS_DIR;
int32 fnc = DTS_GETFNC (uptr->STATE);
int16 *fbuf = (int16 *) uptr->filebuf;
int32 unum = uptr - dt_dev.units;
int32 blk, wrd, ma, relpos, dat;
uint32 ba;

/* Motion cases

   Decelerating - if next state != stopped, must be accel reverse
   Accelerating - next state must be @speed, schedule function
   At speed - do functional processing
*/

switch (mot) {

    case DTS_DECF: case DTS_DECR:                       /* decelerating */
        if (dt_setpos (uptr))                           /* upd pos; off reel? */
            return IORETURN (dt_stopoffr, STOP_DTOFF);
        uptr->STATE = DTS_NXTSTA (uptr->STATE);         /* advance state */
        if (uptr->STATE)                                /* not stopped? */
            sim_activate (uptr, dt_dctime - (dt_dctime >> 2));  /* must be reversing */
        return SCPE_OK;

    case DTS_ACCF: case DTS_ACCR:                       /* accelerating */
        dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE));     /* adv state, sched */
        return SCPE_OK;

    case DTS_ATSF: case DTS_ATSR:                       /* at speed */
        break;                                          /* check function */

    default:                                            /* other */
        dt_seterr (uptr, DTB_SEL);                      /* state error */
        return SCPE_OK;
        }

/* Functional cases

   Move - must be at end zone
   Search - transfer block number, schedule next block
   Off reel - detach unit (it must be deselected)
*/

if (dt_setpos (uptr))                                   /* upd pos; off reel? */
    return IORETURN (dt_stopoffr, STOP_DTOFF);
if (DT_QEZ (uptr)) {                                    /* in end zone? */
    dt_seterr (uptr, DTB_END);                          /* end zone error */
    return SCPE_OK;
    }
blk = DT_LIN2BL (uptr->pos, uptr);                      /* get block # */
switch (fnc) {                                          /* at speed, check fnc */

    case FNC_MOVE:                                      /* move */
        dt_seterr (uptr, DTB_END);                      /* end zone error */
        return SCPE_OK;

    case FNC_SRCH:                                      /* search */
        if (dtsb & DTB_DTF) {                           /* DTF set? */
            dt_seterr (uptr, DTB_TIM);                  /* timing error */
            return SCPE_OK;
            }
        sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */
        M[DT_WC] = (M[DT_WC] + 1) & 07777;              /* incr word cnt */
        ma = DTB_GETMEX (dtsb) | M[DT_CA];              /* get mem addr */
        if (MEM_ADDR_OK (ma))                           /* store block # */
            M[ma] = blk & 07777;
        if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0))
            dtsb = dtsb | DTB_DTF;                      /* set DTF */
        break;

    case DTS_OFR:                                       /* off reel */
        detach_unit (uptr);                             /* must be deselected */
        uptr->STATE = uptr->pos = 0;                    /* no visible action */
        break;

/* Read has four subcases

   Start of block, not wc ovf - check that DTF is clear, otherwise normal
   Normal - increment MA, WC, copy word from tape to memory
        if read dir != write dir, bits must be scrambled
        if wc overflow, next state is wc overflow
        if end of block, possibly set DTF, next state is start of block
   Wc ovf, not start of block - 
        if end of block, possibly set DTF, next state is start of block
   Wc ovf, start of block - if end of block reached, timing error,
        otherwise, continue to next word
*/

    case FNC_READ:                                      /* read */
        wrd = DT_LIN2WD (uptr->pos, uptr);              /* get word # */
        switch (dt_substate) {                          /* case on substate */

        case DTO_SOB:                                   /* start of block */
            if (dtsb & DTB_DTF) {                       /* DTF set? */
                dt_seterr (uptr, DTB_TIM);              /* timing error */
                return SCPE_OK;
                }
            if (DEBUG_PRI (dt_dev, LOG_RW) ||
           (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk)))
                fprintf (sim_deb, ">>DT%d: reading block %d %s%s\n",
                    unum, blk, (dir? "backward": "forward"),
                    ((dtsa & DTA_MODE)? " continuous": " "));
            dt_substate = 0;
            /* fall through */
        case 0:                                         /* normal read */
            M[DT_WC] = (M[DT_WC] + 1) & 07777;          /* incr WC, CA */
            M[DT_CA] = (M[DT_CA] + 1) & 07777;
            ma = DTB_GETMEX (dtsb) | M[DT_CA];          /* get mem addr */
            ba = (blk * DTU_BSIZE (uptr)) + wrd;        /* buffer ptr */
            dat = fbuf[ba];                             /* get tape word */
            if (dir)                                    /* rev? comp obv */
                dat = dt_comobv (dat);
            if (MEM_ADDR_OK (ma))                       /* mem addr legal? */
                M[ma] = dat;
            if (M[DT_WC] == 0)                          /* wc ovf? */
                dt_substate = DTO_WCO;
            /* fall through */
        case DTO_WCO:                                   /* wc ovf, not sob */
            if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1))  /* not last? */
                sim_activate (uptr, DT_WSIZE * dt_ltime);
            else {
                dt_substate = dt_substate | DTO_SOB;
                sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime);
                if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0))
                    dtsb = dtsb | DTB_DTF;              /* set DTF */
                }
            break;                      

        case DTO_WCO | DTO_SOB:                         /* next block */        
            if (wrd == (dir? 0: DTU_BSIZE (uptr)))      /* end of block? */
                dt_seterr (uptr, DTB_TIM);              /* timing error */
            else sim_activate (uptr, DT_WSIZE * dt_ltime);
            break;
            }

        break;

/* Write has four subcases

   Start of block, not wc ovf - check that DTF is clear, set block direction
   Normal - increment MA, WC, copy word from memory to tape
        if wc overflow, next state is wc overflow
        if end of block, possibly set DTF, next state is start of block
   Wc ovf, not start of block -
        copy 0 to tape
        if end of block, possibly set DTF, next state is start of block
   Wc ovf, start of block - schedule end zone
*/

    case FNC_WRIT:                                      /* write */
        wrd = DT_LIN2WD (uptr->pos, uptr);              /* get word # */
        switch (dt_substate) {                          /* case on substate */

        case DTO_SOB:                                   /* start block */
            if (dtsb & DTB_DTF) {                       /* DTF set? */
                dt_seterr (uptr, DTB_TIM);              /* timing error */
                return SCPE_OK;
                }
            if (DEBUG_PRI (dt_dev, LOG_RW) ||
               (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk)))
                fprintf (sim_deb, ">>DT%d: writing block %d %s%s\n", unum, blk,
                    (dir? "backward": "forward"),
                    ((dtsa & DTA_MODE)? " continuous": " "));
            dt_substate = 0;
            /* fall through */
        case 0:                                         /* normal write */
            M[DT_WC] = (M[DT_WC] + 1) & 07777;          /* incr WC, CA */
            M[DT_CA] = (M[DT_CA] + 1) & 07777;
            /* fall through */
        case DTO_WCO:                                   /* wc ovflo */
            ma = DTB_GETMEX (dtsb) | M[DT_CA];          /* get mem addr */
            ba = (blk * DTU_BSIZE (uptr)) + wrd;        /* buffer ptr */
            dat = dt_substate? 0: M[ma];                /* get word */
            if (dir)                                    /* rev? comp obv */
                dat = dt_comobv (dat);
            fbuf[ba] = dat;                             /* write word */
            uptr->WRITTEN = TRUE;
            if (ba >= uptr->hwmark)
                uptr->hwmark = ba + 1;
            if (M[DT_WC] == 0)
                dt_substate = DTO_WCO;
            if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1))  /* not last? */
                sim_activate (uptr, DT_WSIZE * dt_ltime);
            else {
                dt_substate = dt_substate | DTO_SOB;
                sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime);
                if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0))
                    dtsb = dtsb | DTB_DTF;              /* set DTF */
                }
            break;                      

        case DTO_WCO | DTO_SOB:                         /* all done */
            dt_schedez (uptr, dir);                     /* sched end zone */
            break;
            }

        break;

/* Read all has two subcases

        Not word count overflow - increment MA, WC, copy word from tape to memory
        Word count overflow - schedule end zone
*/

    case FNC_RALL:
        switch (dt_substate) {                          /* case on substate */

        case 0: case DTO_SOB:                           /* read in progress */
            if (dtsb & DTB_DTF) {                       /* DTF set? */
                dt_seterr (uptr, DTB_TIM);              /* timing error */
                return SCPE_OK;
                }
            relpos = DT_LIN2OF (uptr->pos, uptr);       /* cur pos in blk */
            M[DT_WC] = (M[DT_WC] + 1) & 07777;          /* incr WC, CA */
            M[DT_CA] = (M[DT_CA] + 1) & 07777;
            ma = DTB_GETMEX (dtsb) | M[DT_CA];          /* get mem addr */
            if ((relpos >= DT_HTLIN) &&                 /* in data zone? */
                (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
                wrd = DT_LIN2WD (uptr->pos, uptr);
                ba = (blk * DTU_BSIZE (uptr)) + wrd;
                dat = fbuf[ba];                         /* get tape word */
                if (dir)                                /* rev? comp obv */
                    dat = dt_comobv (dat);
                }
            else dat = dt_gethdr (uptr, blk, relpos, dir);      /* get hdr */
            sim_activate (uptr, DT_WSIZE * dt_ltime);
            if (MEM_ADDR_OK (ma))                       /* mem addr legal? */
                M[ma] = dat;
            if (M[DT_WC] == 0)
                dt_substate = DTO_WCO;
            if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0))
                dtsb = dtsb | DTB_DTF;                  /* set DTF */
            break;

        case DTO_WCO: case DTO_WCO | DTO_SOB:           /* all done */
            dt_schedez (uptr, dir);                     /* sched end zone */
            break;
            }                                           /* end case substate */

        break;

/* Write all has two subcases

        Not word count overflow - increment MA, WC, copy word from memory to tape
        Word count overflow - schedule end zone
*/

    case FNC_WALL:
        switch (dt_substate) {                          /* case on substate */

        case 0: case DTO_SOB:                           /* read in progress */
            if (dtsb & DTB_DTF) {                       /* DTF set? */
                dt_seterr (uptr, DTB_TIM);              /* timing error */
                return SCPE_OK;
                }
            relpos = DT_LIN2OF (uptr->pos, uptr);       /* cur pos in blk */
            M[DT_WC] = (M[DT_WC] + 1) & 07777;          /* incr WC, CA */
            M[DT_CA] = (M[DT_CA] + 1) & 07777;
            ma = DTB_GETMEX (dtsb) | M[DT_CA];          /* get mem addr */
            if ((relpos >= DT_HTLIN) &&                 /* in data zone? */
                (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) {
                dat = M[ma];                            /* get mem word */
                if (dir)
                    dat = dt_comobv (dat);
                wrd = DT_LIN2WD (uptr->pos, uptr);
                ba = (blk * DTU_BSIZE (uptr)) + wrd;
                fbuf[ba] = dat;                         /* write word */
                if (ba >= uptr->hwmark)
                    uptr->hwmark = ba + 1;
                }
                                                        /* ignore hdr */
            sim_activate (uptr, DT_WSIZE * dt_ltime);
            if (M[DT_WC] == 0)
                dt_substate = DTO_WCO;
            if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0))
                dtsb = dtsb | DTB_DTF;                  /* set DTF */
                break;

        case DTO_WCO: case DTO_WCO | DTO_SOB:           /* all done */
            dt_schedez (uptr, dir);                     /* sched end zone */
            break;
            }                                           /* end case substate */
        break;

    default:
        dt_seterr (uptr, DTB_SEL);                      /* impossible state */
        break;
        }

DT_UPDINT;                                              /* update interrupts */
return SCPE_OK;
}

/* Reading the header is complicated, because 18b words are being parsed
   out 12b at a time.  The sequence of word numbers is directionally
   sensitive

                Forward                         Reverse
        Word    Word    Content         Word    Word    Content
        (abs)   (rel)                   (abs)   (rel)

        137     8       fwd csm'00      6       6       rev csm'00
        138     9       0000            5       5       0000
        139     10      0000            4       4       0000
        140     11      0000            3       3       0000
        141     12      00'lo rev blk   2       2       00'lo fwd blk
        142     13      hi rev blk      1       1       hi fwd blk
        143     14      0000            0       0       0000
        0       0       0000            143     14      0000
        1       1       0000            142     13      0000
        2       2       hi fwd blk      141     12      hi rev blk
        3       3       lo fwd blk'00   140     11      lo rev blk'00
        4       4       0000            139     10      0000
        5       5       0000            138     9       0000
        6       6       0000            137     8       0000
        7       7       rev csm         136     7       00'fwd csm
*/

int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos, int32 dir)
{
if (relpos >= DT_HTLIN)
    relpos = relpos - (DT_WSIZE * DTU_BSIZE (uptr));
if (dir) {                                              /* reverse */
    switch (relpos / DT_WSIZE) {
    case 6:                                             /* rev csm */
        return 077;
    case 2:                                             /* lo fwd blk */
        return dt_comobv ((blk & 077) << 6);
    case 1:                                             /* hi fwd blk */
        return dt_comobv (blk >> 6);
    case 12:                                            /* hi rev blk */
        return (blk >> 6) & 07777;
    case 11:                                            /* lo rev blk */
        return ((blk & 077) << 6);
    case 7:                                             /* fwd csum */
        return (dt_comobv (dt_csum (uptr, blk)) << 6);
    default:                                            /* others */
        return 07777;
        }
    }
else {                                                  /* forward */
    switch (relpos / DT_WSIZE) {
    case 8:                                             /* fwd csum */
        return (dt_csum (uptr, blk) << 6);
    case 12:                                            /* lo rev blk */
        return dt_comobv ((blk & 077) << 6);
    case 13:                                            /* hi rev blk */
        return dt_comobv (blk >> 6);
    case 2:                                             /* hi fwd blk */
        return ((blk >> 6) & 07777);
    case 3:                                             /* lo fwd blk */
        return ((blk & 077) << 6);
    case 7:                                             /* rev csum */
        return 077;
    default:                                            /* others */
        break;
        }
    }
return 0;
}

/* Utility routines */

/* Set error flag */

void dt_seterr (UNIT *uptr, int32 e)
{
int32 mot = DTS_GETMOT (uptr->STATE);

dtsa = dtsa & ~DTA_STSTP;                               /* clear go */
dtsb = dtsb | DTB_ERF | e;                              /* set error flag */
if (mot >= DTS_ACCF) {                                  /* ~stopped or stopping? */
    sim_cancel (uptr);                                  /* cancel activity */
    if (dt_setpos (uptr))                               /* update position */
        return;
    sim_activate (uptr, dt_dctime);                     /* sched decel */
    DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0);         /* state = decel */
    }
else DTS_SETSTA (mot, 0);                               /* clear 2nd, 3rd */
DT_UPDINT;
return;
}

/* Schedule end zone */

void dt_schedez (UNIT *uptr, int32 dir)
{
int32 newpos;

if (dir)                                                /* rev? rev ez */
    newpos = DT_EZLIN - DT_WSIZE;
else newpos = DTU_FWDEZ (uptr) + DT_WSIZE;              /* fwd? fwd ez */
sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime);
return;
}

/* Complement obverse routine */

int32 dt_comobv (int32 dat)
{
dat = dat ^ 07777;                                      /* compl obverse */
dat = ((dat >> 9) & 07) | ((dat >> 3) & 070) |
    ((dat & 070) << 3) | ((dat & 07) << 9);
return dat;
}

/* Checksum routine */

int32 dt_csum (UNIT *uptr, int32 blk)
{
int16 *fbuf = (int16 *) uptr->filebuf;
int32 ba = blk * DTU_BSIZE (uptr);
int32 i, csum, wrd;

csum = 077;                                             /* init csum */
for (i = 0; i < DTU_BSIZE (uptr); i++) {                /* loop thru buf */
    wrd = fbuf[ba + i] ^ 07777;                         /* get ~word */
    csum = csum ^ (wrd >> 6) ^ wrd;
    }
return (csum & 077);
}

/* Reset routine */

t_stat dt_reset (DEVICE *dptr)
{
int32 i, prev_mot;
UNIT *uptr;

for (i = 0; i < DT_NUMDR; i++) {                        /* stop all activity */
    uptr = dt_dev.units + i;
    if (sim_is_running) {                               /* CAF? */
        prev_mot = DTS_GETMOT (uptr->STATE);            /* get motion */
        if ((prev_mot & ~DTS_DIR) > DTS_DECF) {         /* accel or spd? */
            if (dt_setpos (uptr))                       /* update pos */
                continue;
            sim_cancel (uptr);
            sim_activate (uptr, dt_dctime);             /* sched decel */
            DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0);
            }
        }
    else {
        sim_cancel (uptr);                              /* sim reset */
        uptr->STATE = 0;  
        uptr->LASTT = sim_grtime ();
        }
    }
dtsa = dtsb = 0;                                        /* clear status */
DT_UPDINT;                                              /* reset interrupt */
return SCPE_OK;
}

/* Bootstrap routine 

   This is actually the 4K disk monitor bootstrap, which also
   works with OS/8.  The reverse is not true - the OS/8 bootstrap
   doesn't work with the disk monitor.
*/

#define BOOT_START      0200
#define BOOT_LEN        (sizeof (boot_rom) / sizeof (int16))

static const uint16 boot_rom[] = {
    07600,                      /* 200, CLA CLL */
    01216,                      /*      TAD MVB         ; move back */
    04210,                      /*      JMS DO          ; action */
    01217,                      /*      TAD K7577       ; addr */
    03620,                      /*      DCA I CA */
    01222,                      /*      TAD RDF         ; read fwd */
    04210,                      /*      JMS DO          ; action */
    05600,                      /*      JMP I 200       ; enter boot */
    00000,                      /* DO,  0 */
    06766,                      /*      DTCA!DTXA       ; start tape */
    03621,                      /*      DCA I WC        ; clear wc */
    06771,                      /*      DTSF            ; wait */
    05213,                      /*      JMP .-1 */
    05610,                      /*      JMP I DO */
    00600,                      /* MVB, 0600 */
    07577,                      /* K7577, 7757 */
    07755,                      /* CA,  7755 */
    07754,                      /* WC,  7754 */
    00220                       /* RF,  0220 */
    };

t_stat dt_boot (int32 unitno, DEVICE *dptr)
{
size_t i;

if (unitno)                                             /* only unit 0 */
    return SCPE_ARG;
if (dt_dib.dev != DEV_DTA)                              /* only std devno */
    return STOP_NOTSTD;
dt_unit[unitno].pos = DT_EZLIN;
for (i = 0; i < BOOT_LEN; i++)
    M[BOOT_START + i] = boot_rom[i];
cpu_set_bootpc (BOOT_START);
return SCPE_OK;
}

/* Attach routine

   Determine 12b, 16b, or 18b/36b format
   Allocate buffer
   If 16b or 18b, read 16b or 18b format and convert to 12b in buffer
   If 12b, read data into buffer
*/

t_stat dt_attach (UNIT *uptr, CONST char *cptr)
{
uint32 pdp18b[D18_NBSIZE];
uint16 pdp11b[D18_NBSIZE], *fbuf;
int32 i, k;
int32 u = uptr - dt_dev.units;
t_stat r;
uint32 ba, sz;

r = attach_unit (uptr, cptr);                           /* attach */
if (r != SCPE_OK) return r;                             /* fail? */
if ((sim_switches & SIM_SW_REST) == 0) {                /* not from rest? */
    uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
    if (sim_switches & SWMASK ('F'))                    /* att 18b? */
        uptr->flags = uptr->flags & ~UNIT_8FMT;
    else if (sim_switches & SWMASK ('S'))               /* att 16b? */
        uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
    else if (!(sim_switches & SWMASK ('A')) &&          /* autosize? */
        (sz = sim_fsize (uptr->fileref))) {
        if (sz == D11_FILSIZ)
            uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
        else if (sz > D8_FILSIZ)
            uptr->flags = uptr->flags & ~UNIT_8FMT;
        }
    }
uptr->capac = DTU_CAPAC (uptr);                         /* set capacity */
uptr->filebuf = calloc (uptr->capac, sizeof (uint16));
if (uptr->filebuf == NULL) {                            /* can't alloc? */
    detach_unit (uptr);
    return SCPE_MEM;
    }
fbuf = (uint16 *) uptr->filebuf;                        /* file buffer */
sim_printf ("%s%d: ", sim_dname (&dt_dev), u);
if (uptr->flags & UNIT_8FMT)
    sim_printf ("12b format");
else if (uptr->flags & UNIT_11FMT)
    sim_printf ("16b format");
else sim_printf ("18b/36b format");
sim_printf (", buffering file in memory\n");
uptr->io_flush = dt_flush;
if (uptr->flags & UNIT_8FMT)                            /* 12b? */
    uptr->hwmark = fxread (uptr->filebuf, sizeof (uint16),
            uptr->capac, uptr->fileref);
else {                                                  /* 16b/18b */
    for (ba = 0; ba < uptr->capac; ) {                  /* loop thru file */
        if (uptr->flags & UNIT_11FMT) {
            k = fxread (pdp11b, sizeof (uint16), D18_NBSIZE, uptr->fileref);
            for (i = 0; i < k; i++)
                pdp18b[i] = pdp11b[i];
            }
        else k = fxread (pdp18b, sizeof (uint32), D18_NBSIZE, uptr->fileref);
        if (k == 0)
            break;
        for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0;
        for (k = 0; k < D18_NBSIZE; k = k + 2) {        /* loop thru blk */
            fbuf[ba] = (pdp18b[k] >> 6) & 07777;
            fbuf[ba + 1] = ((pdp18b[k] & 077) << 6) |
                ((pdp18b[k + 1] >> 12) & 077);
            fbuf[ba + 2] = pdp18b[k + 1] & 07777;
            ba = ba + 3;
            }                                           /* end blk loop */
        }                                               /* end file loop */
    uptr->hwmark = ba;
    }                                                   /* end else */
uptr->flags = uptr->flags | UNIT_BUF;                   /* set buf flag */
uptr->pos = DT_EZLIN;                                   /* beyond leader */
uptr->LASTT = sim_grtime ();                            /* last pos update */
return SCPE_OK;
}

/* Detach routine

   Cancel in progress operation
   If 12b, write buffer to file
   If 16b or 18b, convert 12b buffer to 16b or 18b and write to file
   Deallocate buffer
*/
void dt_flush (UNIT* uptr)
{
uint32 pdp18b[D18_NBSIZE];
uint16 pdp11b[D18_NBSIZE], *fbuf;
int32 i, k;
uint32 ba;

if (uptr->WRITTEN && uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) {    /* any data? */
    rewind (uptr->fileref);                             /* start of file */
    fbuf = (uint16 *) uptr->filebuf;                    /* file buffer */
    if (uptr->flags & UNIT_8FMT)                        /* PDP8? */
        fxwrite (uptr->filebuf, sizeof (uint16),        /* write file */
            uptr->hwmark, uptr->fileref);
    else {                                              /* 16b/18b */
        for (ba = 0; ba < uptr->hwmark; ) {             /* loop thru buf */
            for (k = 0; k < D18_NBSIZE; k = k + 2) {
                pdp18b[k] = ((uint32) (fbuf[ba] & 07777) << 6) |
                    ((uint32) (fbuf[ba + 1] >> 6) & 077);
                pdp18b[k + 1] = ((uint32) (fbuf[ba + 1] & 077) << 12) |
                    ((uint32) (fbuf[ba + 2] & 07777));
                ba = ba + 3;
                }                                       /* end loop blk */
            if (uptr->flags & UNIT_11FMT) {             /* 16b? */
                for (i = 0; i < D18_NBSIZE; i++)
                    pdp11b[i] = pdp18b[i];
                fxwrite (pdp11b, sizeof (uint16),
                    D18_NBSIZE, uptr->fileref);
                }
            else fxwrite (pdp18b, sizeof (uint32),
                D18_NBSIZE, uptr->fileref);
            }                                           /* end loop buf */
        }                                               /* end else */
    if (ferror (uptr->fileref))
        sim_perror ("I/O error");
    }
uptr->WRITTEN = FALSE;                                  /* no longer dirty */
}

t_stat dt_detach (UNIT* uptr)
{
int u = (int)(uptr - dt_dev.units);

if (!(uptr->flags & UNIT_ATT))                          /* attached? */
    return SCPE_OK;
if (sim_is_active (uptr)) {
    sim_cancel (uptr);
    if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) {
        dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF;
        DT_UPDINT;
        }
    uptr->STATE = uptr->pos = 0;
    }
if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) {    /* any data? */
    sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u);
    dt_flush (uptr);
    }                                                   /* end if hwmark */
free (uptr->filebuf);                                   /* release buf */
uptr->flags = uptr->flags & ~UNIT_BUF;                  /* clear buf flag */
uptr->filebuf = NULL;                                   /* clear buf ptr */
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;  /* default fmt */
uptr->capac = DT_CAPAC;                                 /* default size */
return detach_unit (uptr);
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_fpp.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
/* pdp8_fpp.c: PDP-8 floating point processor (FPP8A)

   Copyright (c) 2007-2011, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   fpp          FPP8A floating point processor

   03-Jan-10    RMS     Initialized variables statically, for VMS compiler
   19-Apr-09    RHM     FPICL does not clear all command and status reg bits
                            modify fpp_reset to conform with FPP
   27-Mar-09    RHM     Fixed handling of Underflow fix (zero FAC on underflow)
                        Implemented FPP division and multiplication algorithms
                        FPP behavior on traps - FEXIT does not update APT
                        Follow FPP settings for OPADD 
                        Correct detection of DP add/sub overflow
                        Detect and handle add/sub overshift
                        Single-step mode made consistent with FPP
                        Write calculation results prior to traps
   24-Mar-09    RMS     Many fixes from Rick Murphy:
                        Fix calculation of ATX shift amount
                        Added missing () to read, write XR macros
                        Fixed indirect address calculation
                        Fixed == written as = in normalization
                        Fixed off-by-one count bug in multiplication
                        Removed extraneous ; in divide
                        Fixed direction of compare in divide
                        Fixed count direction bug in alignment

   Floating point formats:

    00 01 02 03 04 05 06 07 08 09 10 11
   +--+--+--+--+--+--+--+--+--+--+--+--+
   | S|          hi integer            | : double precision
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |             lo integer            |
   +--+--+--+--+--+--+--+--+--+--+--+--+

    00 01 02 03 04 05 06 07 08 09 10 11
   +--+--+--+--+--+--+--+--+--+--+--+--+
   | S|          exponent              | : floating point
   +--+--+--+--+--+--+--+--+--+--+--+--+
   | S|          hi fraction           |
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |             lo fraction           |
   +--+--+--+--+--+--+--+--+--+--+--+--+


    00 01 02 03 04 05 06 07 08 09 10 11
   +--+--+--+--+--+--+--+--+--+--+--+--+
   | S|          exponent              | : extended precision
   +--+--+--+--+--+--+--+--+--+--+--+--+
   | S|          hi fraction           |
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |            next fraction          |
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |            next fraction          |
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |            next fraction          |
   +--+--+--+--+--+--+--+--+--+--+--+--+
   |             lo fraction           |
   +--+--+--+--+--+--+--+--+--+--+--+--+

   Exponents are 2's complement, as are fractions.  Normalized numbers have
   the form:

   0.0...0
   0.<non-zero>
   1.<non-zero>
   1.1...0

   Note that 1.0...0 is normalized but considered illegal, since it cannot
   be represented as a positive number. When a result is normalized, 1.0...0
   is converted to 1.1...0 with exp+1.
*/

#include "pdp8_defs.h"

extern int32 int_req;
extern uint16 M[];
extern int32 stop_inst;
extern UNIT cpu_unit;

#define SEXT12(x)       (((x) & 04000)? (x) | ~07777: (x) & 03777)

/* Index registers are in memory */

#define fpp_read_xr(xr) fpp_read (fpp_xra + (xr))
#define fpp_write_xr(xr,d) fpp_write (fpp_xra + (xr), d)

/* Command register */

#define FPC_DP          04000                           /* integer double */
#define FPC_UNFX        02000                           /* exit on fl undf */
#define FPC_FIXF        01000                           /* lock mem field */
#define FPC_IE          00400                           /* int enable */
#define FPC_V_FAST      4                               /* startup bits */
#define FPC_M_FAST      017
#define FPC_LOCK        00010                           /* lockout */
#define FPC_V_APTF      0
#define FPC_M_APTF      07                              /* apta field */
#define FPC_STA         (FPC_DP|FPC_LOCK)
#define FPC_GETFAST(x)  (((x) >> FPC_V_FAST) & FPC_M_FAST)
#define FPC_GETAPTF(x)  (((x) >> FPC_V_APTF) & FPC_M_APTF)

/* Status register */

#define FPS_DP          (FPC_DP)                        /* integer double */
#define FPS_TRPX        02000                           /* trap exit */
#define FPS_HLTX        01000                           /* halt exit */
#define FPS_DVZX        00400                           /* div zero exit */
#define FPS_IOVX        00200                           /* int ovf exit */
#define FPS_FOVX        00100                           /* flt ovf exit */
#define FPS_UNF         00040                           /* underflow */
#define FPS_XXXM        00020                           /* FADDM/FMULM */
#define FPS_LOCK        (FPC_LOCK)                      /* lockout */
#define FPS_EP          00004                           /* ext prec */
#define FPS_PAUSE       00002                           /* paused */
#define FPS_RUN         00001                           /* running */

/* Floating point number: 3-6 words */

#define FPN_FRSIGN      04000
#define FPN_NFR_FP      2                               /* std precision */
#define FPN_NFR_EP      5                               /* ext precision */
#define FPN_NFR_MDS     6                               /* mul/div precision */
#define EXACT           (uint32)((fpp_sta & FPS_EP)? FPN_NFR_EP: FPN_NFR_FP)
#define EXTEND          ((uint32) FPN_NFR_EP)

typedef struct {
    int32       exp;
    uint32      fr[FPN_NFR_MDS+1];
    } FPN;

uint32 fpp_apta = 0;                                    /* APT pointer */
uint32 fpp_aptsvf = 0;                                  /* APT saved field */
uint32 fpp_opa = 0;                                     /* operand pointer */
uint32 fpp_fpc = 0;                                     /* FP PC */
uint32 fpp_bra = 0;                                     /* base reg pointer */
uint32 fpp_xra = 0;                                     /* indx reg pointer */
uint32 fpp_cmd = 0;                                     /* command */
uint32 fpp_sta = 0;                                     /* status */
uint32 fpp_flag = 0;                                    /* flag */
FPN fpp_ac;                                             /* FAC */
uint32 fpp_ssf = 0;                                     /* single-step flag */
uint32 fpp_last_lockbit = 0;                            /* last lockbit */

static FPN fpp_zero = { 0, { 0, 0, 0, 0, 0 } };
static FPN fpp_one = { 1, { 02000, 0, 0, 0, 0 } };

int32 fpp55 (int32 IR, int32 AC);
int32 fpp56 (int32 IR, int32 AC);
void fpp_load_apt (uint32 apta);
void fpp_dump_apt (uint32 apta, uint32 sta);
uint32 fpp_1wd_dir (uint32 ir);
uint32 fpp_2wd_dir (uint32 ir);
uint32 fpp_indir (uint32 ir);
uint32 fpp_ad15 (uint32 hi);
uint32 fpp_adxr (uint32 ir, uint32 base_ad);
void fpp_add (FPN *a, FPN *b, uint32 sub);
void fpp_mul (FPN *a, FPN *b);
void fpp_div (FPN *a, FPN *b);
t_bool fpp_imul (FPN *a, FPN *b);
uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b, uint32 cnt);
void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b, uint32 cnt);
void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b, t_bool fix);
t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b);
uint32 fpp_fr_neg (uint32 *a, uint32 cnt);
int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt);
int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt);
uint32 fpp_fr_abs (uint32 *a, uint32 *b, uint32 cnt);
void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt);
void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt);
void fpp_fr_lsh12 (uint32 *a, uint32 cnt);
void fpp_fr_lsh1 (uint32 *a, uint32 cnt);
void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt);
void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt);
t_bool fpp_cond_met (uint32 cond);
t_bool fpp_norm (FPN *a, uint32 cnt);
void fpp_round (FPN *a);
t_bool fpp_test_xp (FPN *a);
void fpp_copy (FPN *a, FPN *b);
void fpp_zcopy (FPN *a, FPN *b);
void fpp_read_op (uint32 ea, FPN *a);
void fpp_write_op (uint32 ea, FPN *a);
uint32 fpp_read (uint32 ea);
void fpp_write (uint32 ea, uint32 val);
uint32 apt_read (uint32 ea);
void apt_write (uint32 ea, uint32 val);
t_stat fpp_svc (UNIT *uptr);
t_stat fpp_reset (DEVICE *dptr);

/* FPP data structures

   fpp_dev      FPP device descriptor
   fpp_unit     FPP unit descriptor
   fpp_reg      FPP register list
*/

DIB fpp_dib = { DEV_FPP, 2, { &fpp55, &fpp56 } };

UNIT fpp_unit = { UDATA (&fpp_svc, 0, 0) };

REG fpp_reg[] = {
    { ORDATAD (FPACE, fpp_ac.exp, 12, "floating accumulator") },
    { ORDATAD (FPAC0, fpp_ac.fr[0], 12, "first mantissa") },
    { ORDATAD (FPAC1, fpp_ac.fr[1], 12, "second mantissa") },
    { ORDATAD (FPAC2, fpp_ac.fr[2], 12, "third mantissa") },
    { ORDATAD (FPAC3, fpp_ac.fr[3], 12, "fourth mantissa") },
    { ORDATAD (FPAC4, fpp_ac.fr[4], 12, "fifth mantissa") },
    { ORDATAD (CMD, fpp_cmd, 12, "FPP command register") },
    { ORDATAD (STA, fpp_sta, 12, "status register") },
    { ORDATAD (APTA, fpp_apta, 15, "active parameter table (APT) pointer") },
    { GRDATAD (APTSVF, fpp_aptsvf, 8, 3, 12, "APT field") },
    { ORDATAD (FPC, fpp_fpc, 15, "floating program counter") },
    { ORDATAD (BRA, fpp_bra, 15, "base register") },
    { ORDATAD (XRA, fpp_xra, 15, "pointer to index register 0") },
    { ORDATAD (OPA, fpp_opa, 15, "operand address register") },
    { ORDATAD (SSF, fpp_ssf, 12, "single step flag") },
    { ORDATAD (LASTLOCK, fpp_last_lockbit, 12, "lockout from FPCOM") },
    { FLDATAD (FLAG, fpp_flag, 0, "done flag") },
    { NULL }
    };

DEVICE fpp_dev = {
    "FPP", &fpp_unit, fpp_reg, NULL,
    1, 10, 31, 1, 8, 8,
    NULL, NULL, &fpp_reset,
    NULL, NULL, NULL,
    &fpp_dib, DEV_DISABLE | DEV_DIS
    };

/* IOT routines */

int32 fpp55 (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 1:                                             /* FPINT */
        return (fpp_flag? IOT_SKP | AC: AC);            /* skip on flag */

    case 2:                                             /* FPICL */
        fpp_reset (&fpp_dev);                           /* reset device */
        break;

    case 3:                                             /* FPCOM */
        if (!fpp_flag && !(fpp_sta & FPS_RUN)) {        /* flag clr, !run? */
            fpp_cmd = AC;                               /* load cmd */
            fpp_last_lockbit = fpp_cmd & FPS_LOCK;      /* remember lock state */
            fpp_sta = (fpp_sta & ~FPC_STA) |            /* copy flags */
                (fpp_cmd & FPC_STA);                    /* to status */
            }
        break;

    case 4:                                             /* FPHLT */
        if (fpp_sta & FPS_RUN) {                        /* running? */
            if (fpp_sta & FPS_PAUSE)                    /* paused? */
                fpp_fpc = (fpp_fpc - 1) & ADDRMASK;     /* decr FPC */
            fpp_sta &= ~FPS_PAUSE;                      /* no longer paused */
            sim_cancel (&fpp_unit);                     /* stop execution */
            fpp_dump_apt (fpp_apta, FPS_HLTX);          /* dump APT */
            fpp_ssf = 1;                                /* assume sstep */
            }
        else if (!fpp_flag)
            fpp_ssf = 1;                                /* FPST sing steps */
        if (fpp_sta & FPS_DVZX)                         /* fix diag timing */
            fpp_sta |= FPS_HLTX;
        break;

    case 5:                                             /* FPST */
        if (!fpp_flag && !(fpp_sta & FPS_RUN)) {        /* flag clr, !run? */
            if (fpp_ssf)
                fpp_sta |= fpp_last_lockbit; 
            fpp_sta &= ~FPS_HLTX;                       /* Clear halted */
            fpp_apta = (FPC_GETAPTF (fpp_cmd) << 12) | AC;
            fpp_load_apt (fpp_apta);                    /* load APT */
            fpp_opa = fpp_fpc;
            sim_activate (&fpp_unit, 0);                /* start unit */
            return IOT_SKP | AC;
            }
        if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == (FPS_RUN|FPS_PAUSE)) {
            fpp_sta &= ~FPS_PAUSE;                      /* continue */
            sim_activate (&fpp_unit, 0);                /* start unit */
            return (IOT_SKP | AC);
            }
        break;

    case 6:                                             /* FPRST */
        return fpp_sta;

    case 7:                                             /* FPIST */
        if (fpp_flag) {                                 /* if flag set */
            uint32 old_sta = fpp_sta;
            fpp_flag = 0;                               /* clr flag, status */
            fpp_sta &= ~(FPS_DP|FPS_EP|FPS_TRPX|FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF);
            int_req &= ~INT_FPP;                        /* clr int req */
            return IOT_SKP | old_sta;                   /* ret old status */
            }
        break;

    default:
        return (stop_inst << IOT_V_REASON) | AC;
        }                                               /* end switch */

return AC;
}

int32 fpp56 (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 7:                                             /* FPEP */
        if ((AC & 04000) && !(fpp_sta & FPS_RUN)) {     /* if AC0, not run, */
            fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP;     /* set ep */
            AC = 0;
            }
        break;

    default:
        return (stop_inst << IOT_V_REASON) | AC;
        }                                               /* end switch */

return AC;
}

/* Service routine */

t_stat fpp_svc (UNIT *uptr)
{
FPN x;
uint32 ir, op, op2, op3, ad, ea, wd;
uint32 i;
int32 sc;

fpp_ac.exp = SEXT12 (fpp_ac.exp);                       /* sext AC exp */
do {                                                    /* repeat */
    ir = fpp_read (fpp_fpc);                            /* get instr */
    fpp_fpc = (fpp_fpc + 1) & ADDRMASK;                 /* incr FP PC */
    op = (ir >> 7) & 037;                               /* get op+mode */
    op2 = (ir >> 3) & 017;                              /* get subop */
    op3 = ir & 07;                                      /* get field/xr */
    fpp_sta &= ~FPS_XXXM;                               /* not mem op */

    switch (op) {                                       /* case on op+mode */
    case 000:                                           /* operates */

        switch (op2) {                                  /* case on subop */
        case 000:                                       /* no-operands */
            switch (op3) {                              /* case on subsubop */

            case 0:                                     /* FEXIT */
            /* if already trapped, don't update APT, just update status */
                if (fpp_sta & (FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF)) 
                    fpp_sta |= FPS_HLTX;
                else
                    fpp_dump_apt (fpp_apta, 0);
                break;

            case 1:                                     /* FPAUSE */
                fpp_sta |= FPS_PAUSE;
                break;

            case 2:                                     /* FCLA */
                fpp_copy (&fpp_ac, &fpp_zero);          /* clear FAC */
                break;

            case 3:                                     /* FNEG */
                fpp_fr_neg (fpp_ac.fr, EXACT);          /* do exact length */
                break;

            case 4:                                     /* FNORM */
                if (!(fpp_sta & FPS_DP)) {              /* fp or ep only */
                    fpp_copy (&x, &fpp_ac);             /* copy AC */
                    fpp_norm (&x, EXACT);               /* do exact length */
                    fpp_copy (&fpp_ac, &x);             /* copy back */
                    }
                break;

            case 5:                                     /* STARTF */
                if (fpp_sta & FPS_EP) {                 /* if ep, */
                    fpp_copy (&x, &fpp_ac);             /* copy AC */
                    fpp_round (&x);                     /* round */
                    fpp_copy (&fpp_ac, &x);             /* copy back */
                    }
                fpp_sta &= ~(FPS_DP|FPS_EP);
                break;

            case 6:                                     /* STARTD */
                fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP;
                break;

            case 7:                                     /* JAC */
                fpp_fpc = ((fpp_ac.fr[0] & 07) << 12) | fpp_ac.fr[1];
                break;
                }
            break;

        case 001:                                       /* ALN */
            if (op3 != 0) {                             /* if xr, */
                wd = fpp_read_xr (op3);                 /* use val */
                fpp_opa = fpp_xra + op3;
                }
            else wd = 027;                              /* else 23 */
            if (!(fpp_sta & FPS_DP)) {                  /* fp or ep? */
                sc = (SEXT12(wd) - fpp_ac.exp) & 07777; /* alignment */
                sc = SEXT12 (sc);
                fpp_ac.exp = SEXT12(wd);                /* new exp */
                }
            else sc = SEXT12 (wd);                      /* dp - simple cnt */
            if (sc < 0)                                 /* left? */
                fpp_fr_lshn (fpp_ac.fr,  -sc, EXACT);
            else fpp_fr_algn (fpp_ac.fr, sc, EXACT);
            if (fpp_fr_test (fpp_ac.fr, 0, EXACT) == 0) /* zero? */
                fpp_ac.exp = 0;                         /* clean exp */
            break;

        case 002:                                       /* ATX */
            if (fpp_sta & FPS_DP)                       /* dp? */
                fpp_write_xr (op3, fpp_ac.fr[1]);       /* xr<-FAC<12:23> */
            else {
                fpp_copy (&x, &fpp_ac);                 /* copy AC */
                sc = 027 - x.exp;                       /* shift amt */
                if (sc < 0)                             /* left? */
                    fpp_fr_lshn (x.fr, -sc, EXACT);
                else fpp_fr_algn (x.fr, sc, EXACT);
                fpp_write_xr (op3, x.fr[1]);            /* xr<-val<12:23> */
                }
            break;

        case 003:                                       /* XTA */
            for (i = FPN_NFR_FP; i < FPN_NFR_EP; i++)
                x.fr[i] = 0;                            /* clear FOP2-4 */
            x.fr[1] = fpp_read_xr (op3);                /* get XR value */
            x.fr[0] = (x.fr[1] & 04000)? 07777: 0;
            x.exp = 027;                                /* standard exp */
            if (!(fpp_sta & FPS_DP)) {                  /* fp or ep? */
                fpp_norm (&x, EXACT);                   /* normalize */
                }
            fpp_copy (&fpp_ac, &x);                     /* result to AC */
            if (fpp_sta & FPS_DP)                       /* dp skips exp */
                fpp_ac.exp = x.exp;                     /*  so force copy */
            fpp_opa = fpp_xra + op3;
            break;

        case 004:                                       /* NOP */
            break;

        case 005:                                       /* STARTE */
            if (!(fpp_sta & FPS_EP)) {
                fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP;
                for (i = FPN_NFR_FP; i < FPN_NFR_EP; i++)
                    fpp_ac.fr[i] = 0;                   /* clear FAC2-4 */
                }
            break;

        case 010:                                       /* LDX */
            wd = fpp_ad15 (0);                          /* load XR immed */
            fpp_write_xr (op3, wd);
            fpp_opa = fpp_xra + op3;
            break;

        case 011:                                       /* ADDX */
            wd = fpp_ad15 (0);
            wd = wd + fpp_read_xr (op3);                /* add to XR immed */
            fpp_write_xr (op3, wd);                     /* trims to 12b */
            fpp_opa = fpp_xra + op3;
            break;

        default:
            return stop_inst;
            }                                           /* end case subop */
        break;

    case 001:                                           /* FLDA */
        ea = fpp_1wd_dir (ir);
        fpp_read_op (ea, &fpp_ac);
        break;

    case 002:
        ea = fpp_2wd_dir (ir);
        fpp_read_op (ea, &fpp_ac);
        if (fpp_sta & FPS_DP)
            fpp_opa = ea + 1;
        else fpp_opa = ea + 2;
        break;

    case 003:
        ea = fpp_indir (ir);
        fpp_read_op (ea, &fpp_ac);
        break;

    case 004:                                           /* jumps and sets */
        ad = fpp_ad15 (op3);                            /* get 15b address */
        switch (op2) {                                  /* case on subop */

        case 000: case 001: case 002: case 003:         /* cond jump */
        case 004: case 005: case 006: case 007:
            if (fpp_cond_met (op2))                     /* br if cond */
                fpp_fpc = ad;
            break;

        case 010:                                       /* SETX */
            fpp_xra = ad;
            break;

        case 011:                                       /* SETB */
            fpp_bra = ad;
            break;

        case 012:                                       /* JSA */
            fpp_write (ad, 01030 + (fpp_fpc >> 12));    /* save return */
            fpp_write (ad + 1, fpp_fpc);                /* trims to 12b */
            fpp_fpc = (ad + 2) & ADDRMASK;
            fpp_opa = fpp_fpc - 1;
            break;

        case 013:                                       /* JSR */
            fpp_write (fpp_bra + 1, 01030 + (fpp_fpc >> 12));
            fpp_write (fpp_bra + 2, fpp_fpc);           /* trims to 12b */
            fpp_opa = fpp_fpc = ad;
            break;

        default:
            return stop_inst;
            }                                           /* end case subop */
        break;

    case 005:                                           /* FADD */
        ea = fpp_1wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&fpp_ac, &x, 0);
        break;
        
    case 006:
        ea = fpp_2wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&fpp_ac, &x, 0);
        break;

    case 007:
        ea = fpp_indir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&fpp_ac, &x, 0);
        break;

    case 010: {                                         /* JNX */
        uint32 xrn = op2 & 07;
        ad = fpp_ad15 (op3);                            /* get 15b addr */
        wd = fpp_read_xr (xrn);                         /* read xr */
        if (op2 & 010) {                                /* inc? */
            wd = (wd + 1) & 07777;
            fpp_write_xr (xrn, wd);                     /* ++xr */
            }
        if (wd != 0)                                    /* xr != 0? */
            fpp_fpc = ad;                               /* jump */
        break;
        }
    case 011:                                           /* FSUB */
        ea = fpp_1wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&fpp_ac, &x, 1);
        break;
        
    case 012:
        ea = fpp_2wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&fpp_ac, &x, 1);
        break;

    case 013:
        ea = fpp_indir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&fpp_ac, &x, 1);
        break;

    case 014:                                           /* TRAP3 */
    case 020:                                           /* TRAP4 */
        fpp_opa = fpp_ad15 (op3);
        fpp_dump_apt (fpp_apta, FPS_TRPX);
        break;

    case 015:                                           /* FDIV */
        ea = fpp_1wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_div (&fpp_ac, &x);
        break;
        
    case 016:
        ea = fpp_2wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_div (&fpp_ac, &x);
        break;

    case 017:
        ea = fpp_indir (ir);
        fpp_read_op (ea, &x);
        fpp_div (&fpp_ac, &x);
        break;

    case 021:                                           /* FMUL */
        ea = fpp_1wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_mul (&fpp_ac, &x);
        break;
        
    case 022:
        ea = fpp_2wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_mul (&fpp_ac, &x);
        break;

    case 023:
        ea = fpp_indir (ir);
        fpp_read_op (ea, &x);
        fpp_mul (&fpp_ac, &x);
        break;

    case 024:                                           /* LTR */
        fpp_copy (&fpp_ac, (fpp_cond_met (op2 & 07)? &fpp_one: &fpp_zero));
        break;

    case 025:                                           /* FADDM */
        fpp_sta |= FPS_XXXM;
        ea = fpp_1wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&x, &fpp_ac, 0);
        fpp_write_op (ea, &x);                          /* store result */
        break;
        
    case 026:
        fpp_sta |= FPS_XXXM;
        ea = fpp_2wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&x, &fpp_ac, 0);
        fpp_write_op (ea, &x);                          /* store result */
        break;

    case 027:
        fpp_sta |= FPS_XXXM;
        ea = fpp_indir (ir);
        fpp_read_op (ea, &x);
        fpp_add (&x, &fpp_ac, 0);
        fpp_write_op (ea, &x);                          /* store result */
        break;

    case 030:                                           /* IMUL/LEA */
        ea = fpp_2wd_dir (ir);                          /* 2-word direct */
        if (fpp_sta & FPS_DP) {                         /* dp? */
            fpp_read_op (ea, &x);                       /* IMUL */
            fpp_imul (&fpp_ac, &x);
            }
        else {                                          /* LEA */
            fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP;     /* set dp */
            fpp_ac.fr[0] = (ea >> 12) & 07;
            fpp_ac.fr[1] = ea & 07777;
            }
        break;

    case 031:                                           /* FSTA */
        ea = fpp_1wd_dir (ir);
        fpp_write_op (ea, &fpp_ac);
        break;

    case 032:
        ea = fpp_2wd_dir (ir);
        fpp_write_op (ea, &fpp_ac);
        break;

    case 033:
        ea = fpp_indir (ir);
        fpp_write_op (ea, &fpp_ac);
        break;

    case 034:                                           /* IMULI/LEAI */
        ea = fpp_indir (ir);                            /* 1-word indir */
        if (fpp_sta & FPS_DP) {                         /* dp? */
            fpp_read_op (ea, &x);                       /* IMUL */
            fpp_imul (&fpp_ac, &x);
            }
        else {                                          /* LEA */
            fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP;     /* set dp */
            fpp_ac.fr[0] = (ea >> 12) & 07;
            fpp_ac.fr[1] = ea & 07777;
            fpp_opa = ea;
            }
        break;

    case 035:                                           /* FMULM */
        fpp_sta |= FPS_XXXM;
        ea = fpp_1wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_mul (&x, &fpp_ac);
        fpp_write_op (ea, &x);                          /* store result */
        break;
        
    case 036:
        fpp_sta |= FPS_XXXM;
        ea = fpp_2wd_dir (ir);
        fpp_read_op (ea, &x);
        fpp_mul (&x, &fpp_ac);
        fpp_write_op (ea, &x);                          /* store result */
        break;

    case 037:
        fpp_sta |= FPS_XXXM;
        ea = fpp_indir (ir);
        fpp_read_op (ea, &x);
        fpp_mul (&x, &fpp_ac);
        fpp_write_op (ea, &x);                          /* store result */
        break;
        }                                               /* end sw op+mode */

    if (fpp_ssf) {
        fpp_dump_apt (fpp_apta, FPS_HLTX);              /* dump APT */
        fpp_ssf = 0;
        }

    if (sim_interval)
        sim_interval = sim_interval - 1;
    } while ((sim_interval > 0) && 
             ((fpp_sta & (FPS_RUN|FPS_PAUSE|FPS_LOCK)) == (FPS_RUN|FPS_LOCK)));
if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == FPS_RUN)
    sim_activate (uptr, 1);
fpp_ac.exp &= 07777;                                    /* mask AC exp */
return SCPE_OK;
}

/* Address decoding routines */

uint32 fpp_1wd_dir (uint32 ir)
{
uint32 ad; 

ad = fpp_bra + ((ir & 0177) * 3);                       /* base + 3*7b off */
if (fpp_sta & FPS_DP)                                   /* dp? skip exp */
    ad = ad + 1;
ad = ad & ADDRMASK;
if (fpp_sta & FPS_DP)
    fpp_opa = ad + 1;
else fpp_opa = ad + 2;
return ad;
}

uint32 fpp_2wd_dir (uint32 ir)
{
uint32 ad;

ad = fpp_ad15 (ir);                                     /* get 15b addr */
return fpp_adxr (ir, ad);                               /* do indexing */
}

uint32 fpp_indir (uint32 ir)
{
uint32 ad, wd1, wd2;

ad = fpp_bra + ((ir & 07) * 3);                         /* base + 3*3b off */
wd1 = fpp_read (ad + 1);                                /* bp+off points to */
wd2 = fpp_read (ad + 2);
ad = ((wd1 & 07) << 12) | wd2;                          /* indirect ptr */

ad = fpp_adxr (ir, ad);                                 /* do indexing */
if (fpp_sta & FPS_DP)
    fpp_opa = ad + 1;
else fpp_opa = ad + 2;
return ad;
}

uint32 fpp_ad15 (uint32 hi)
{
uint32 ad;

ad = ((hi & 07) << 12) | fpp_read (fpp_fpc);            /* 15b addr */
fpp_fpc = (fpp_fpc + 1) & ADDRMASK;                     /* incr FPC */
return ad;                                              /* return addr */
}

uint32 fpp_adxr (uint32 ir, uint32 base_ad)
{
uint32 xr, wd;

xr = (ir >> 3) & 07;
wd = fpp_read_xr (xr);                                  /* get xr */
if (ir & 0100) {                                        /* increment? */
    wd = (wd + 1) & 07777;                              /* inc, rewrite */
    fpp_write_xr (xr, wd);
    }
if (xr != 0) {                                          /* indexed? */
    if (fpp_sta & FPS_EP)
        wd = wd * 6;                                    /* scale by len */
    else if (fpp_sta & FPS_DP)
        wd = wd * 2;
    else wd = wd * 3;
    return (base_ad + wd) & ADDRMASK;                   /* return index */
    }
else return base_ad & ADDRMASK;                         /* return addr */
}

/* Computation routines */

/* Fraction/floating add */

void fpp_add (FPN *a, FPN *b, uint32 sub)
{
FPN x, y, z;
uint32 c, ediff;

fpp_zcopy (&x, a);                                      /* copy opnds */
fpp_zcopy (&y, b);
if (sub)                                                /* subtract? */
    fpp_fr_neg (y.fr, EXACT);                           /* neg B, exact */
if (fpp_sta & FPS_DP) {                                 /* dp? */
    uint32 cout = fpp_fr_add (z.fr, x.fr, y.fr, EXTEND);/* z = a + b */
    uint32 zsign = z.fr[0] & FPN_FRSIGN;
    cout = (cout? 04000: 0);                            /* make sign bit */
    /* overflow is indicated when signs are equal and overflow does not
       match the result sign bit */
    fpp_copy (a, &z);                                   /* result is z */
    if (!((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) && (cout != zsign)) {
        fpp_copy (a, &z);                               /* copy out result */
        fpp_dump_apt (fpp_apta, FPS_IOVX);              /* int ovf? */
        return;
        }
    }
else {                                                  /* fp or ep */
    if (fpp_fr_test (b->fr, 0, EXACT) == 0)             /* B == 0? */
        z = x;                                          /* result is A */
    else if (fpp_fr_test (a->fr, 0, EXACT) == 0)        /* A == 0? */
        z = y;                                          /* result is B */
    else {                                              /* fp or ep */
        if (x.exp < y.exp) {                            /* |a| < |b|? */
            z = x;                                      /* exchange ops */
            x = y;
            y = z;
            }
        ediff = x.exp - y.exp;                          /* exp diff */
        if (ediff <= (uint32) ((fpp_sta & FPS_EP)? 59: 24)) { /* any add? */
            z.exp = x.exp;                              /* result exp */
            if (ediff != 0)                             /* any align? */
                fpp_fr_algn (y.fr, ediff, EXTEND);      /* align, 60b */
            c = fpp_fr_add (z.fr, x.fr, y.fr, EXTEND);  /* add fractions */
            if ((((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) == 0) && /* same signs? */
                (c ||                                   /* carry out? */
                ((~x.fr[0] & z.fr[0] & FPN_FRSIGN)))) { /* + to - change? */
                fpp_fr_rsh1 (z.fr, c << 11, EXTEND);    /* rsh, insert cout */
                z.exp = z.exp + 1;                      /* incr exp */
                }                                       /* end same signs */
            }                                           /* end in range */
            else z = x;                                 /* ovrshift */
        }                                               /* end ops != 0 */
    if (fpp_norm (&z, EXTEND))                          /* norm, !exact? */
        fpp_round (&z);                                 /* round */
    fpp_copy (a, &z);                                   /* copy out */
    fpp_test_xp (&z);                                   /* ovf, unf? */
    }                                                   /* end else */
return;
}

/* Fraction/floating multiply */

void fpp_mul (FPN *a, FPN *b)
{
FPN x, y, z;

fpp_zcopy (&x, a);                                      /* copy opnds */
fpp_zcopy (&y, b);
if ((fpp_fr_test(y.fr, 0, EXACT-1) == 0) && (y.fr[EXACT-1] < 2)) {
    y.exp = 0;
    y.fr[EXACT-1] = 0;
}
if (fpp_sta & FPS_DP)                                   /* dp? */
    fpp_fr_mul (z.fr, x.fr, y.fr, TRUE);                /* mult frac */
else {                                                  /* fp or ep */
    fpp_norm (&x, EXACT);
    fpp_norm (&y, EXACT);
    z.exp = x.exp + y.exp;                              /* add exp */
    fpp_fr_mul (z.fr, x.fr, y.fr, TRUE);                /* mult frac */
    if (fpp_norm (&z, EXTEND))                          /* norm, !exact? */
        fpp_round (&z);                                 /* round */
    fpp_copy (a, &z);
    if (z.exp > 2047)
        fpp_dump_apt (fpp_apta, FPS_FOVX);              /* trap */
    return;
    }
fpp_copy (a, &z);                                       /* result is z */
return;
}

/* Fraction/floating divide */

void fpp_div (FPN *a, FPN *b)
{
FPN x, y, z;

if (fpp_fr_test (b->fr, 0, EXACT) == 0) {               /* divisor 0? */
    fpp_dump_apt (fpp_apta, FPS_DVZX);                  /* error */
    return;
    }
if (fpp_fr_test (a->fr, 0, EXACT) == 0)                 /* dividend 0? */
    return;                                             /* quotient is 0 */
fpp_zcopy (&x, a);                                      /* copy opnds */
fpp_zcopy (&y, b);
if (fpp_sta & FPS_DP) {                                 /* dp? */
    if (fpp_fr_div (z.fr, x.fr, y.fr)) {                /* fr div, ovflo? */
        fpp_dump_apt (fpp_apta, FPS_IOVX);              /* error */
        return;
        }
    fpp_copy (a, &z);                                   /* result is z */
    }
else {                                                  /* fp or ep */
    fpp_norm (&y, EXACT);                               /* norm divisor */
    if (fpp_fr_test (x.fr, 04000, EXACT) == 0) {        /* divd 1.000...? */
        x.fr[0] = 06000;                                /* fix */
        x.exp = x.exp + 1;
        }
    z.exp = x.exp - y.exp;                              /* calc exp */
    if (fpp_fr_div (z.fr, x.fr, y.fr)) {                /* fr div, ovflo? */
        uint32 cin = (a->fr[0] ^ b->fr[0]) & FPN_FRSIGN;
        fpp_fr_rsh1 (z.fr, cin, EXTEND);                /* rsh, insert sign */
        z.exp = z.exp + 1;                              /* incr exp */
        }
    if (fpp_norm (&z, EXTEND))                          /* norm, !exact? */
        fpp_round (&z);                                 /* round */
    fpp_copy (a, &z);
    if (z.exp > 2048) {                                /* underflow? */
        if (fpp_cmd & FPC_UNFX) {                       /* trap? */
            fpp_dump_apt (fpp_apta, FPS_UNF);
            return;
            }
        }
    }
return;
}

/* Integer multiply - returns true if overflow */

t_bool fpp_imul (FPN *a, FPN *b)
{
uint32 sext;
FPN x, y, z;

fpp_zcopy (&x, a);                                      /* copy args */
fpp_zcopy (&y, b);
fpp_fr_mul (z.fr, x.fr, y.fr, FALSE);                   /* mult fracs */
a->fr[0] = z.fr[1];                                     /* low 24b */
a->fr[1] = z.fr[2];
if ((a->fr[0] == 0) && (a->fr[1] == 0))                 /* fpp zeroes exp */
    a->exp = 0;                                         /* even in dp mode */
sext = (z.fr[2] & FPN_FRSIGN)? 07777: 0;
if (((z.fr[0] | z.fr[1] | sext) != 0) &&                /* hi 25b == 0 */
    ((z.fr[0] & z.fr[1] & sext) != 07777)) {            /* or 777777774? */
    fpp_dump_apt (fpp_apta, FPS_IOVX);
    return TRUE;
    }
return FALSE;
}

/* Auxiliary floating point routines */

t_bool fpp_cond_met (uint32 cond)
{
switch (cond) {

    case 0:
        return (fpp_fr_test (fpp_ac.fr, 0, EXACT) == 0);

    case 1:
        return (fpp_fr_test (fpp_ac.fr, 0, EXACT) >= 0);

    case 2:
        return (fpp_fr_test (fpp_ac.fr, 0, EXACT) <= 0);

    case 3:
        return 1;

    case 4:
        return (fpp_fr_test (fpp_ac.fr, 0, EXACT) != 0);

    case 5:
        return (fpp_fr_test (fpp_ac.fr, 0, EXACT) < 0);

    case 6:
        return (fpp_fr_test (fpp_ac.fr, 0, EXACT) > 0);

    case 7:
        return (fpp_ac.exp > 027);
    }
return 0;
}

/* Normalization - returns TRUE if rounding possible, FALSE if exact */

t_bool fpp_norm (FPN *a, uint32 cnt)
{
if (fpp_fr_test (a->fr, 0, cnt) == 0) {                 /* zero? */
    a->exp = 0;                                         /* clean exp */
    return FALSE;                                       /* don't round */
    }
while (((a->fr[0] == 0) && !(a->fr[1] & 04000)) ||      /* lead 13b same? */
       ((a->fr[0] == 07777) && (a->fr[1] & 04000))) {
    fpp_fr_lsh12 (a->fr, cnt);                          /* move word */
    a->exp = a->exp - 12;
    }
while (((a->fr[0] ^ (a->fr[0] << 1)) & FPN_FRSIGN) == 0) { /* until norm */
    fpp_fr_lsh1 (a->fr, cnt);                           /* shift 1b */
    a->exp = a->exp - 1;
    }
if (fpp_fr_test (a->fr, 04000, EXACT) == 0) {           /* 4000...0000? */
    a->fr[0] = 06000;                                   /* chg to 6000... */
    a->exp = a->exp + 1;                                /* with exp+1 */
    return FALSE;                                       /* don't round */
    }
return TRUE;
}

/* Exact fp number copy */

void fpp_copy (FPN *a, FPN *b)
{
uint32 i;

if (!(fpp_sta & FPS_DP))
    a->exp = b->exp;
for (i = 0; i < EXACT; i++)
    a->fr[i] = b->fr[i];
return;
}

/* Zero extended fp number copy (60b) */

void fpp_zcopy (FPN *a, FPN *b)
{
uint32 i;

a->exp = b->exp;
for (i = 0; i < FPN_NFR_EP; i++) {
    if ((i < FPN_NFR_FP) || (fpp_sta & FPS_EP))
        a->fr[i] = b->fr[i];
    else a->fr[i] = 0;
    }
a->fr[i++] = 0;
a->fr[i] = 0;
return;
}

/* Test exp for overflow or underflow, returns TRUE on trap */

t_bool fpp_test_xp (FPN *a)
{
if (a->exp > 2047) {                                /* overflow? */
    fpp_dump_apt (fpp_apta, FPS_FOVX);              /* trap */
    return TRUE;
    }
if (a->exp < -2048) {                               /* underflow? */
    if (fpp_cmd & FPC_UNFX) {                       /* trap? */
        fpp_dump_apt (fpp_apta, FPS_UNF);
        return TRUE;
        }
    fpp_copy (a, &fpp_zero);                        /* flush to 0 */
    }
return FALSE;
}

/* Round dp/fp value */

void fpp_round (FPN *a)
{
int32 i;
uint32 cin, afr0_sign;

if (fpp_sta & FPS_EP)                               /* ep? */
    return;                                         /* don't round */
afr0_sign = a->fr[0] & FPN_FRSIGN;                  /* save input sign */
cin = afr0_sign? 03777: 04000;
for (i = FPN_NFR_FP; i >= 0; i--) {                 /* 3 words */
   a->fr[i] = a->fr[i] + cin;                       /* add in carry */
   cin = (a->fr[i] >> 12) & 1;
   a->fr[i] = a->fr[i] & 07777;
   }
if (!(fpp_sta & FPS_DP) &&                          /* fp? */
    (afr0_sign ^ (a->fr[0] & FPN_FRSIGN))) {        /* sign change? */
    fpp_fr_rsh1 (a->fr, afr0_sign, EXACT);          /* rsh, insert sign */
    a->exp = a->exp + 1;
    }
return;
}

/* N-precision integer routines */

/* Fraction add/sub */

uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b, uint32 cnt)

{
uint32 i, cin;

for (i = cnt, cin = 0; i > 0; i--) {
    c[i - 1] = a[i - 1] + b[i - 1] + cin;
    cin = (c[i - 1] >> 12) & 1;
    c[i - 1] = c[i - 1] & 07777;
    }
return cin;
}

void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b, uint32 cnt)
{
uint32 i, cin;

for (i = cnt, cin = 0; i > 0; i--) {
    c[i - 1] = a[i - 1] - b[i - 1] - cin;
    cin = (c[i - 1] >> 12) & 1;
    c[i - 1] = c[i - 1] & 07777;
    }
return;
}

/* Fraction multiply - always develop 60b, multiply is
   either 24b*24b or 60b*60b
   
   This is a signed multiply.  The shift in for signed multiply is
   technically ALU_N XOR ALU_V.  This can be simplified as follows:

   a-sign   c-sign  result-sign     cout    overflow    N XOR V = shift in

   0        0       0               0       0           0
   0        0       1               0       1           0
   0        1       0               1       0           0
   0        1       1               0       0           1
   1        0       0               1       0           0
   1        0       1               0       0           1
   1        1       0               1       1           1
   1        1       1               1       0           1

   If a-sign == c-sign, shift-in = a-sign
   If a-sign != c-sign, shift-in = result-sign
   */

void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b, t_bool fix)
{
uint32 i, cnt, lo, wc, fill, b_sign;

b_sign = b[0] & FPN_FRSIGN;                         /* remember b's sign */

fpp_fr_fill (c, 0, FPN_NFR_MDS);                    /* clr answer */
if (fpp_sta & FPS_EP)                               /* ep? */
    lo = FPN_NFR_EP;                                /* low order mpyr word */
else  
    lo = FPN_NFR_FP;                                /* low order mpyr word */

if (fix)
    fpp_fr_algn (a, 12, FPN_NFR_MDS + 1);           /* fill left with sign */
wc = 2;                                             /* 3 words at start */
fill = 0;
cnt = lo * 12;                                      /* total steps */
for (i = 0; i < cnt; i++) { 
    if ((i % 12) == 0) {
        wc++;                                       /* do another word */
        lo--;                                       /* and next mpyr word */
        fpp_fr_algn (c, 24, wc + 1);
        c[wc] = 0;
        c[0] = c[1] = fill;                         /* propagate sign */
        }
    if (b[lo] & FPN_FRSIGN)                         /* mpyr bit set? */
        fpp_fr_add(c, a, c, wc);
    fill = ((c[0] & FPN_FRSIGN) ? 07777 : 0);       /* remember sign */
    fpp_fr_lsh1 (c, wc);                            /* shift the result */
    fpp_fr_lsh1 (b + lo, 1);                        /* shift mpcd */
    
    }

if (!fix)                                           /* imul shifts result */
    fpp_fr_rsh1 (c, c[0] & FPN_FRSIGN, EXACT + 1);  /* result is 1 wd right */
if (b_sign) {                                       /* if mpyr was negative */
    if (fix)
        fpp_fr_lsh12 (a, FPN_NFR_MDS+1);            /* restore a */
    fpp_fr_sub (c, c, a, EXACT);                    /* adjust result */
    fpp_fr_sub (c, c, a, EXACT);
    }

return;
}

/* Fraction divide */

t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b)
{
uint32 i, old_c, lo, cnt, sign, b_sign, addsub, limit;
/* Number of words processed by each divide step */
static uint32 limits[7] = {6, 6, 5, 4, 3, 3, 2};

fpp_fr_fill (c, 0, FPN_NFR_MDS);                    /* clr answer */
sign = (a[0] ^ b[0]) & FPN_FRSIGN;                  /* sign of result */
b_sign = (b[0] & FPN_FRSIGN);
if (a[0] & FPN_FRSIGN)                              /* |a| */
    fpp_fr_neg (a, EXACT);
if (fpp_sta & FPS_EP)                               /* ep? 6 words */
    lo = FPN_NFR_EP-1;
else lo = FPN_NFR_FP-1;                             /* fp, dp? 3 words */
cnt = (lo + 1) * 12;
addsub = 04000;                                     /* setup first op */
for (i = 0; i < cnt; i++) {                         /* loop */
    limit = limits[i / 12];                         /* how many wds this time */
    fpp_fr_lsh1 (c, FPN_NFR_MDS);                   /* shift quotient */
    if (addsub ^ b_sign)                            /* diff signs, subtr */
        fpp_fr_sub (a, a, b, limit);                /* divd - divr */
    else
        fpp_fr_add (a, a, b, limit);                /* restore */
    if (!(a[0] & FPN_FRSIGN)) {
        c[lo] |= 1;                                 /* set quo bit */
        addsub = 04000;                             /* sign for nxt loop */
        }
    else addsub = 0;
    fpp_fr_lsh1 (a, limit);                         /* shift dividend */
    }
old_c = c[0];                                       /* save ho quo */
if (sign)                                           /* expect neg ans? */
    fpp_fr_neg (c, EXTEND);                         /* -quo */
if (old_c & FPN_FRSIGN)                             /* sign set before */
    return TRUE;                                    /* neg? */
return FALSE;
}

/* Negate - 24b or 60b */

uint32 fpp_fr_neg (uint32 *a, uint32 cnt)
{
uint32 i, cin;

for (i = cnt, cin = 1; i > 0; i--) {
    a[i - 1] = (~a[i - 1] + cin) & 07777;
    cin = (cin != 0 && a[i - 1] == 0);
    }
return cin;
}

/* Test (compare to x'0...0) - 24b or 60b */

int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt)
{
uint32 i;

if (a[0] != v0)
    return (a[0] & FPN_FRSIGN)? -1: +1;
for (i = 1; i < cnt; i++) {
    if (a[i] != 0)
        return (a[0] & FPN_FRSIGN)? -1: +1;
    }
return 0;
}

/* Fraction compare - 24b or 60b */

int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt)
{
uint32 i;

if ((a[0] ^ b[0]) & FPN_FRSIGN)
    return (b[0] & FPN_FRSIGN)? +1: -1;
for (i = 0; i < cnt; i++) {
    if (a[i] > b[i])
        return (b[0] & FPN_FRSIGN)? +1: -1;
    if (a[i] < b[i])
        return (b[0] & FPN_FRSIGN)? -1: +1;
    }
return 0;
}

/* Fraction fill */

void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt)
{
uint32 i;

for (i = 0; i < cnt; i++)
    a[i] = v;
return;
}

/* Left shift n (unsigned) */

void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt)
{
uint32 i;

if (sc >= (cnt * 12)) {                             /* out of range? */
    fpp_fr_fill (a, 0, cnt);
    return;
    }
while (sc >= 12) {                                  /* word shift? */
    fpp_fr_lsh12 (a, cnt);
    sc = sc - 12;
    }
if (sc == 0)                                        /* any more? */
    return;
for (i = 1; i < cnt; i++)                           /* bit shift */
    a[i - 1] = ((a[i - 1] << sc) | (a[i] >> (12 - sc))) & 07777;
a[cnt - 1] = (a[cnt - 1] << sc) & 07777;
return;
}

/* Left shift 12b (unsigned) */

void fpp_fr_lsh12 (uint32 *a, uint32 cnt)
{
uint32 i;

for (i = 1; i < cnt; i++)
    a[i - 1] = a[i];
a[cnt - 1] = 0;
return;
}

/* Left shift 1b (unsigned) */

void fpp_fr_lsh1 (uint32 *a, uint32 cnt)
{
uint32 i;

for (i = 1; i < cnt; i++)
    a[i - 1] = ((a[i - 1] << 1) | (a[i] >> 11)) & 07777;
a[cnt - 1] = (a[cnt - 1] << 1) & 07777;
return;
}

/* Right shift 1b, with shift in */

void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt)
{
uint32 i;

for (i = cnt - 1; i > 0; i--)
    a[i] = ((a[i] >> 1) | (a[i - 1] << 11)) & 07777;
a[0] = (a[0] >> 1) | sign;
return;
}

/* Right shift n (signed) */

void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt)
{
uint32 i, sign;

sign = (a[0] & FPN_FRSIGN)? 07777: 0;
if (sc >= (cnt * 12)) {                             /* out of range? */
    fpp_fr_fill (a, sign, cnt);
    return;
    }
while (sc >= 12) {
    for (i = cnt - 1; i > 0; i--)
        a[i] = a[i - 1];
    a[0] = sign;
    sc = sc - 12;
    }
if (sc == 0)
    return;
for (i = cnt - 1; i > 0; i--)
    a[i] = ((a[i] >> sc) | (a[i - 1] << (12 - sc))) & 07777;
a[0] = ((a[0] >> sc) | (sign << (12 - sc))) & 07777;
return;
}

/* Read/write routines */

void fpp_read_op (uint32 ea, FPN *a)
{
uint32 i;

if (!(fpp_sta & FPS_DP)) {
    a->exp = fpp_read (ea++);
    a->exp = SEXT12 (a->exp);
    }
for (i = 0; i < EXACT; i++)
    a->fr[i] = fpp_read (ea + i);
return;
}

void fpp_write_op (uint32 ea, FPN *a)
{
uint32 i;

fpp_opa = ea + 2;
if (!(fpp_sta & FPS_DP))
    fpp_write (ea++, a->exp);
for (i = 0; i < EXACT; i++)
    fpp_write (ea + i, a->fr[i]);
return;
}

uint32 fpp_read (uint32 ea)
{
ea = ea & ADDRMASK;
if (fpp_cmd & FPC_FIXF)
    ea = fpp_aptsvf | (ea & 07777);
return M[ea];
}

void fpp_write (uint32 ea, uint32 val)
{
ea = ea & ADDRMASK;
if (fpp_cmd & FPC_FIXF)
    ea = fpp_aptsvf | (ea & 07777);
if (MEM_ADDR_OK (ea))
    M[ea] = val & 07777;
return;
}

uint32 apt_read (uint32 ea)
{
ea = ea & ADDRMASK;
return M[ea];
}

void apt_write (uint32 ea, uint32 val)
{
ea = ea & ADDRMASK;
if (MEM_ADDR_OK (ea))
    M[ea] = val & 07777;
return;
}

/* Utility routines */

void fpp_load_apt (uint32 ad)
{
uint32 wd0, i;

wd0 = apt_read (ad++);
fpp_fpc = ((wd0 & 07) << 12) | apt_read (ad++);
if (FPC_GETFAST (fpp_cmd) != 017) {
    fpp_xra = ((wd0 & 00070) << 9) | apt_read (ad++);
    fpp_bra = ((wd0 & 00700) << 6) | apt_read (ad++);
    fpp_opa = ((wd0 & 07000) << 3) | apt_read (ad++);
    fpp_ac.exp = apt_read (ad++);
    for (i = 0; i < EXACT; i++)
        fpp_ac.fr[i] = apt_read (ad++);
    }
fpp_aptsvf = (ad - 1) & 070000;
fpp_sta |= FPS_RUN;
return;
}

void fpp_dump_apt (uint32 ad, uint32 sta)
{
uint32 wd0, i;

wd0 = (fpp_fpc >> 12) & 07;
if (FPC_GETFAST (fpp_cmd) != 017)
    wd0 = wd0 |
        ((fpp_opa >> 3) & 07000) |
        ((fpp_bra >> 6) & 00700) |
        ((fpp_xra >> 9) & 00070);
apt_write (ad++, wd0);
apt_write (ad++, fpp_fpc);
if (FPC_GETFAST (fpp_cmd) != 017) {
    apt_write (ad++, fpp_xra);
    apt_write (ad++, fpp_bra);
    apt_write (ad++, fpp_opa);
    apt_write (ad++, fpp_ac.exp);
    for (i = 0; i < EXACT; i++)
        apt_write (ad++, fpp_ac.fr[i]);
    }
fpp_sta = (fpp_sta | sta) & ~FPS_RUN;
fpp_flag = 1;
if (fpp_cmd & FPC_IE)
    int_req |= INT_FPP;
return;
}

/* Reset routine */

t_stat fpp_reset (DEVICE *dptr)
{
sim_cancel (&fpp_unit);
fpp_flag = 0;
fpp_last_lockbit = 0;
int_req &= ~INT_FPP;
if (sim_switches & SWMASK ('P')) {
    fpp_apta = 0;
    fpp_aptsvf = 0;
    fpp_fpc = 0;
    fpp_bra = 0;
    fpp_xra = 0;
    fpp_opa = 0;
    fpp_ac = fpp_zero;
    fpp_ssf = 0;
    fpp_sta = 0;
    fpp_cmd = 0;
    }
else {
    fpp_sta &= ~(FPS_DP|FPS_EP|FPS_TRPX|FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF);
    fpp_cmd &= (FPC_DP|FPC_UNFX|FPC_IE);
    }

return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_lp.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* pdp8_lp.c: PDP-8 line printer simulator

   Copyright (c) 1993-2016, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   lpt          LP8E line printer

   16-Dec-16    DJG     Added IOT 6660 to allow WPS WS78 3.4 to print
   19-Jan-07    RMS     Added UNIT_TEXT
   25-Apr-03    RMS     Revised for extended file support
   04-Oct-02    RMS     Added DIB, enable/disable, device number support
   30-May-02    RMS     Widened POS to 32b
*/

#include "pdp8_defs.h"

extern int32 int_req, int_enable, dev_done, stop_inst;

int32 lpt_err = 0;                                      /* error flag */
int32 lpt_stopioe = 0;                                  /* stop on error */

int32 lpt (int32 IR, int32 AC);
t_stat lpt_svc (UNIT *uptr);
t_stat lpt_reset (DEVICE *dptr);
t_stat lpt_attach (UNIT *uptr, CONST char *cptr);
t_stat lpt_detach (UNIT *uptr);

/* LPT data structures

   lpt_dev      LPT device descriptor
   lpt_unit     LPT unit descriptor
   lpt_reg      LPT register list
*/

DIB lpt_dib = { DEV_LPT, 1, { &lpt } };

UNIT lpt_unit = {
    UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT
    };

REG lpt_reg[] = {
    { ORDATAD (BUF, lpt_unit.buf, 8,"last data item processed") },
    { FLDATAD (ERR, lpt_err, 0, "error status flag") },
    { FLDATAD (DONE, dev_done, INT_V_LPT, "device done flag") },
    { FLDATAD (ENABLE, int_enable, INT_V_LPT, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_LPT, "interrupt pending flag") },
    { DRDATAD (POS, lpt_unit.pos, T_ADDR_W, "position in the output file"), PV_LEFT },
    { DRDATAD (TIME, lpt_unit.wait, 24, "time from I/O initiation to interrupt"), PV_LEFT },
    { FLDATAD (STOP_IOE, lpt_stopioe, 0, "stop on I/O error") },
    { ORDATA (DEVNUM, lpt_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB lpt_mod[] = {
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE lpt_dev = {
    "LPT", &lpt_unit, lpt_reg, lpt_mod,
    1, 10, 31, 1, 8, 8,
    NULL, NULL, &lpt_reset,
    NULL, &lpt_attach, &lpt_detach,
    &lpt_dib, DEV_DISABLE
    };

/* IOT routine */

int32 lpt (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* PKSTF */
        dev_done = dev_done | INT_LPT;                  /* set flag */
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 1:                                             /* PSKF */
        return (dev_done & INT_LPT)? IOT_SKP + AC: AC;

    case 2:                                             /* PCLF */
        dev_done = dev_done & ~INT_LPT;                 /* clear flag */
        int_req = int_req & ~INT_LPT;                   /* clear int req */
        return AC;

    case 3:                                             /* PSKE */
        return (lpt_err)? IOT_SKP + AC: AC;

    case 6:                                             /* PCLF!PSTB */
        dev_done = dev_done & ~INT_LPT;                 /* clear flag */
        int_req = int_req & ~INT_LPT;                   /* clear int req */

    case 4:                                             /* PSTB */
        lpt_unit.buf = AC & 0177;                       /* load buffer */
        if ((lpt_unit.buf == 015) || (lpt_unit.buf == 014) ||
            (lpt_unit.buf == 012)) {
            sim_activate (&lpt_unit, lpt_unit.wait);
            return AC;
            }
        return (lpt_svc (&lpt_unit) << IOT_V_REASON) + AC;

    case 5:                                             /* PSIE */
        int_enable = int_enable | INT_LPT;              /* set enable */
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 7:                                             /* PCIE */
        int_enable = int_enable & ~INT_LPT;             /* clear enable */
        int_req = int_req & ~INT_LPT;                   /* clear int req */
        return AC;

    default:
        return (stop_inst << IOT_V_REASON) + AC;
        }                                               /* end switch */
}

/* Unit service */

t_stat lpt_svc (UNIT *uptr)
{
dev_done = dev_done | INT_LPT;                          /* set done */
int_req = INT_UPDATE;                                   /* update interrupts */
if ((uptr->flags & UNIT_ATT) == 0) {
    lpt_err = 1;
    return IORETURN (lpt_stopioe, SCPE_UNATT);
    }
fputc (uptr->buf, uptr->fileref);                       /* print char */
uptr->pos = ftell (uptr->fileref);
if (ferror (uptr->fileref)) {                           /* error? */
    sim_perror ("LPT I/O error");
    clearerr (uptr->fileref);
    return SCPE_IOERR;
    }
return SCPE_OK;
}

/* Reset routine */

t_stat lpt_reset (DEVICE *dptr)
{
lpt_unit.buf = 0;
dev_done = dev_done & ~INT_LPT;                         /* clear done, int */
int_req = int_req & ~INT_LPT;
int_enable = int_enable | INT_LPT;                      /* set enable */
lpt_err = (lpt_unit.flags & UNIT_ATT) == 0;
sim_cancel (&lpt_unit);                                 /* deactivate unit */
return SCPE_OK;
}

/* Attach routine */

t_stat lpt_attach (UNIT *uptr, CONST char *cptr)
{
t_stat reason;

reason = attach_unit (uptr, cptr);
lpt_err = (lpt_unit.flags & UNIT_ATT) == 0;
return reason;
}

/* Detach routine */

t_stat lpt_detach (UNIT *uptr)
{
lpt_err = 1;
return detach_unit (uptr);
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































































































































Deleted src/PDP8/pdp8_mt.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
/* pdp8_mt.c: PDP-8 magnetic tape simulator

   Copyright (c) 1993-2011, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   mt           TM8E/TU10 magtape

   16-Feb-06    RMS     Added tape capacity checking
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   18-Mar-05    RMS     Added attached test to detach routine
   25-Apr-03    RMS     Revised for extended file support
   29-Mar-03    RMS     Added multiformat support
   04-Mar-03    RMS     Fixed bug in SKTR
   01-Mar-03    RMS     Fixed interrupt handling
                        Revised for magtape library
   30-Oct-02    RMS     Revised BOT handling, added error record handling
   04-Oct-02    RMS     Added DIBs, device number support
   30-Aug-02    RMS     Revamped error handling
   28-Aug-02    RMS     Added end of medium support
   30-May-02    RMS     Widened POS to 32b
   22-Apr-02    RMS     Added maximum record length test
   06-Jan-02    RMS     Changed enable/disable support
   30-Nov-01    RMS     Added read only unit, extended SET/SHOW support
   24-Nov-01    RMS     Changed UST, POS, FLG to arrays
   25-Apr-01    RMS     Added device enable/disable support
   04-Oct-98    RMS     V2.4 magtape format
   22-Jan-97    RMS     V2.3 magtape format
   01-Jan-96    RMS     Rewritten from TM8-E Maintenance Manual

   Magnetic tapes are represented as a series of variable records
   of the form:

        32b byte count
        byte 0
        byte 1
        :
        byte n-2
        byte n-1
        32b byte count

   If the byte count is odd, the record is padded with an extra byte
   of junk.  File marks are represented by a byte count of 0.
*/

#include "pdp8_defs.h"
#include "sim_tape.h"

#define MT_NUMDR        8                               /* #drives */
#define USTAT           u3                              /* unit status */
#define MT_MAXFR        (1 << 16)                       /* max record lnt */
#define WC_SIZE         (1 << 12)                       /* max word count */
#define WC_MASK         (WC_SIZE - 1)

/* Command/unit - mt_cu */

#define CU_V_UNIT       9                               /* unit */
#define CU_M_UNIT       07
#define CU_PARITY       00400                           /* parity select */
#define CU_IEE          00200                           /* error int enable */
#define CU_IED          00100                           /* done int enable */
#define CU_V_EMA        3                               /* ext mem address */
#define CU_M_EMA        07
#define CU_EMA          (CU_M_EMA << CU_V_EMA)
#define CU_DTY          00002                           /* drive type */
#define CU_UNPAK        00001                           /* 6b vs 8b mode */
#define GET_UNIT(x)     (((x) >> CU_V_UNIT) & CU_M_UNIT)
#define GET_EMA(x)      (((x) & CU_EMA) << (12 - CU_V_EMA))

/* Function - mt_fn */

#define FN_V_FNC        9                               /* function */
#define FN_M_FNC        07
#define  FN_UNLOAD       00
#define  FN_REWIND       01
#define  FN_READ         02
#define  FN_CMPARE       03
#define  FN_WRITE        04
#define  FN_WREOF        05
#define  FN_SPACEF       06
#define  FN_SPACER       07
#define FN_ERASE        00400                           /* erase */
#define FN_CRC          00200                           /* read CRC */
#define FN_GO           00100                           /* go */
#define FN_INC          00040                           /* incr mode */
#define FN_RMASK        07700                           /* readable bits */
#define GET_FNC(x)      (((x) >> FN_V_FNC) & FN_M_FNC)

/* Status - stored in mt_sta or (*) uptr->USTAT */

#define STA_ERR         (04000 << 12)                   /* error */
#define STA_REW         (02000 << 12)                   /* *rewinding */
#define STA_BOT         (01000 << 12)                   /* *start of tape */
#define STA_REM         (00400 << 12)                   /* *offline */
#define STA_PAR         (00200 << 12)                   /* parity error */
#define STA_EOF         (00100 << 12)                   /* *end of file */
#define STA_RLE         (00040 << 12)                   /* rec lnt error */
#define STA_DLT         (00020 << 12)                   /* data late */
#define STA_EOT         (00010 << 12)                   /* *end of tape */
#define STA_WLK         (00004 << 12)                   /* *write locked */
#define STA_CPE         (00002 << 12)                   /* compare error */
#define STA_ILL         (00001 << 12)                   /* illegal */
#define STA_9TK         00040                           /* 9 track */
/* #define STA_BAD      00020                         *//* bad tape?? */
#define STA_INC         00010                           /* increment error */
#define STA_LAT         00004                           /* lateral par error */
#define STA_CRC         00002                           /* CRC error */
#define STA_LON         00001                           /* long par error */

#define STA_CLR         (FN_RMASK | 00020)              /* always clear */
#define STA_DYN         (STA_REW | STA_BOT | STA_REM | STA_EOF | \
                         STA_EOT | STA_WLK)             /* kept in USTAT */

extern uint16 M[];
extern int32 int_req, stop_inst;
extern UNIT cpu_unit;

int32 mt_cu = 0;                                        /* command/unit */
int32 mt_fn = 0;                                        /* function */
int32 mt_ca = 0;                                        /* current address */
int32 mt_wc = 0;                                        /* word count */
int32 mt_sta = 0;                                       /* status register */
int32 mt_db = 0;                                        /* data buffer */
int32 mt_done = 0;                                      /* mag tape flag */
int32 mt_time = 10;                                     /* record latency */
int32 mt_stopioe = 1;                                   /* stop on error */
uint8 *mtxb = NULL;                                     /* transfer buffer */

int32 mt70 (int32 IR, int32 AC);
int32 mt71 (int32 IR, int32 AC);
int32 mt72 (int32 IR, int32 AC);
t_stat mt_svc (UNIT *uptr);
t_stat mt_reset (DEVICE *dptr);
t_stat mt_attach (UNIT *uptr, CONST char *cptr);
t_stat mt_detach (UNIT *uptr);
int32 mt_updcsta (UNIT *uptr);
int32 mt_ixma (int32 xma);
t_stat mt_map_err (UNIT *uptr, t_stat st);
t_stat mt_vlock (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
UNIT *mt_busy (void);
void mt_set_done (void);

/* MT data structures

   mt_dev       MT device descriptor
   mt_unit      MT unit list
   mt_reg       MT register list
   mt_mod       MT modifier list
*/

DIB mt_dib = { DEV_MT, 3, { &mt70, &mt71, &mt72 } };

UNIT mt_unit[] = {
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
    { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
    };

REG mt_reg[] = {
    { ORDATAD (CMD, mt_cu, 12, "command") },
    { ORDATAD (FNC, mt_fn, 12, "function") },
    { ORDATAD (CA, mt_ca, 12, "memory address") },
    { ORDATAD (WC, mt_wc, 12, "word count") },
    { ORDATAD (DB, mt_db, 12, "data buffer") },
    { GRDATAD (STA, mt_sta, 8, 12, 12, "status buffer") },
    { ORDATAD (STA2, mt_sta, 6, "secondary status") },
    { FLDATAD (DONE, mt_done, 0, "device done flag") },
    { FLDATAD (INT, int_req, INT_V_MT, "interrupt pending flag") },
    { FLDATAD (STOP_IOE, mt_stopioe, 0, "stop on I/O error") },
    { DRDATAD (TIME, mt_time, 24, "record delay"), PV_LEFT },
    { URDATAD (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0, "unit status, units 0 to 7") },
    { URDATAD (POS, mt_unit[0].pos, 10, T_ADDR_W, 0,
              MT_NUMDR, PV_LEFT | REG_RO, "position, units 0 to 7") },
    { FLDATA (DEVNUM, mt_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB mt_mod[] = {
    { MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock },
    { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mt_vlock }, 
    { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
      &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
    { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY",
      &sim_tape_set_capac, &sim_tape_show_capac, NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE mt_dev = {
    "MT", mt_unit, mt_reg, mt_mod,
    MT_NUMDR, 10, 31, 1, 8, 8,
    NULL, NULL, &mt_reset,
    NULL, &mt_attach, &mt_detach,
    &mt_dib, DEV_DISABLE | DEV_TAPE
    };

/* IOT routines */

int32 mt70 (int32 IR, int32 AC)
{
int32 f;
UNIT *uptr;

uptr = mt_dev.units + GET_UNIT (mt_cu);                 /* get unit */
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 1:                                             /* LWCR */
        mt_wc = AC;                                     /* load word count */
        return 0;

    case 2:                                             /* CWCR */
        mt_wc = 0;                                      /* clear word count */
        return AC;

    case 3:                                             /* LCAR */
        mt_ca = AC;                                     /* load mem address */
        return 0;

    case 4:                                             /* CCAR */
        mt_ca = 0;                                      /* clear mem address */
        return AC;

    case 5:                                             /* LCMR */
        if (mt_busy ())                                 /* busy? illegal op */
            mt_sta = mt_sta | STA_ILL | STA_ERR;
        mt_cu = AC;                                     /* load command reg */
        mt_updcsta (mt_dev.units + GET_UNIT (mt_cu));
        return 0;

    case 6:                                             /* LFGR */
        if (mt_busy ())                                 /* busy? illegal op */
            mt_sta = mt_sta | STA_ILL | STA_ERR;
        mt_fn = AC;                                     /* load function */
        if ((mt_fn & FN_GO) == 0) {                     /* go set? */
            mt_updcsta (uptr);                          /* update status */
            return 0;
            }
        f = GET_FNC (mt_fn);                            /* get function */
        if (((uptr->flags & UNIT_ATT) == 0) ||
              sim_is_active (uptr) ||
           (((f == FN_WRITE) || (f == FN_WREOF)) && sim_tape_wrp (uptr))
           || (((f == FN_SPACER) || (f == FN_REWIND)) && sim_tape_bot (uptr))) {
            mt_sta = mt_sta | STA_ILL | STA_ERR;        /* illegal op error */
            mt_set_done ();                             /* set done */
            mt_updcsta (uptr);                          /* update status */
            return 0;
            }
        uptr->USTAT = uptr->USTAT & STA_WLK;            /* clear status */
        if (f == FN_UNLOAD) {                           /* unload? */
            detach_unit (uptr);                         /* set offline */
            uptr->USTAT = STA_REW | STA_REM;            /* rewinding, off */
            mt_set_done ();                             /* set done */
            }
        else if (f == FN_REWIND) {                      /* rewind */
            uptr->USTAT = uptr->USTAT | STA_REW;        /* rewinding */
            mt_set_done ();                             /* set done */
            }
        else mt_done = 0;                               /* clear done */
        mt_updcsta (uptr);                              /* update status */
        sim_activate (uptr, mt_time);                   /* start io */
        return 0;

    case 7:                                             /* LDBR */
        if (mt_busy ())                                 /* busy? illegal op */
            mt_sta = mt_sta | STA_ILL | STA_ERR;
        mt_db = AC;                                     /* load buffer */
        mt_set_done ();                                 /* set done */
        mt_updcsta (uptr);                              /* update status */
        return 0;
        }                                               /* end switch */

return (stop_inst << IOT_V_REASON) + AC;                /* ill inst */
}

int32 mt71 (int32 IR, int32 AC)
{
UNIT *uptr;

uptr = mt_dev.units + GET_UNIT (mt_cu);
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 1:                                             /* RWCR */
        return mt_wc;                                   /* read word count */

    case 2:                                             /* CLT */
        mt_reset (&mt_dev);                             /* reset everything */
        return AC;

    case 3:                                             /* RCAR */
        return mt_ca;                                   /* read mem address */

    case 4:                                             /* RMSR */
        return ((mt_updcsta (uptr) >> 12) & 07777);     /* read status */

    case 5:                                             /* RCMR */
        return mt_cu;                                   /* read command */

    case 6:                                             /* RFSR */
        return (((mt_fn & FN_RMASK) | (mt_updcsta (uptr) & ~FN_RMASK))
                 & 07777);                              /* read function */

    case 7:                                             /* RDBR */
        return mt_db;                                   /* read data buffer */
        }

return (stop_inst << IOT_V_REASON) + AC;                /* ill inst */
}

int32 mt72 (int32 IR, int32 AC)
{
UNIT *uptr;

uptr = mt_dev.units + GET_UNIT (mt_cu);                 /* get unit */
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 1:                                             /* SKEF */
        return (mt_sta & STA_ERR)? IOT_SKP + AC: AC;

    case 2:                                             /* SKCB */
        return (!mt_busy ())? IOT_SKP + AC: AC;

    case 3:                                             /* SKJD */
        return mt_done? IOT_SKP + AC: AC;

    case 4:                                             /* SKTR */
        return (!sim_is_active (uptr) &&
            (uptr->flags & UNIT_ATT))? IOT_SKP + AC: AC;

    case 5:                                             /* CLF */
        if (!sim_is_active (uptr)) mt_reset (&mt_dev);  /* if TUR, zap */
        else {                                          /* just ctrl zap */
            mt_sta = 0;                                 /* clear status */
            mt_done = 0;                                /* clear done */
            mt_updcsta (uptr);                          /* update status */
            }
        return AC;
        }                                               /* end switch */

return (stop_inst << IOT_V_REASON) + AC;                /* ill inst */
}

/* Unit service

   If rewind done, reposition to start of tape, set status
   else, do operation, set done, interrupt
*/

t_stat mt_svc (UNIT *uptr)
{
int32 f, i, p, u, wc, xma;
t_mtrlnt tbc, cbc;
t_bool passed_eot;
uint16 c, c1, c2;
t_stat st, r = SCPE_OK;

u = (int32) (uptr - mt_dev.units);                      /* get unit number */
f = GET_FNC (mt_fn);                                    /* get command */
xma = GET_EMA (mt_cu) + mt_ca;                          /* get mem addr */
wc = WC_SIZE - mt_wc;                                   /* get wc */

if (uptr->USTAT & STA_REW) {                            /* rewind? */
    sim_tape_rewind (uptr);                             /* update position */
    if (uptr->flags & UNIT_ATT)                         /* still on line? */
        uptr->USTAT = (uptr->USTAT & STA_WLK) | STA_BOT;
    else uptr->USTAT = STA_REM;
    if (u == GET_UNIT (mt_cu)) {                        /* selected? */
        mt_set_done ();                                 /* set done */
        mt_updcsta (uptr);                              /* update status */
        }
    return SCPE_OK;
    }

if ((uptr->flags & UNIT_ATT) == 0) {                    /* if not attached */
    uptr->USTAT = STA_REM;                              /* unit off line */
    mt_sta = mt_sta | STA_ILL | STA_ERR;                /* illegal operation */
    mt_set_done ();                                     /* set done */
    mt_updcsta (uptr);                                  /* update status */
    return IORETURN (mt_stopioe, SCPE_UNATT);
    }

passed_eot = sim_tape_eot (uptr);                       /* passed eot? */
switch (f) {                                            /* case on function */

    case FN_READ:                                       /* read */
    case FN_CMPARE:                                     /* read/compare */
        st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR);      /* read rec */
        if (st == MTSE_RECE)                            /* rec in err? */
            mt_sta = mt_sta | STA_PAR | STA_ERR;
        else if (st != MTSE_OK) {                       /* other error? */
            r = mt_map_err (uptr, st);                  /* map error */
            mt_sta = mt_sta | STA_RLE | STA_ERR;        /* err, eof/eom, tmk */
            break;
            }
        cbc = (mt_cu & CU_UNPAK)? wc: wc * 2;           /* expected bc */
        if (tbc != cbc)                                 /* wrong size? */
            mt_sta = mt_sta | STA_RLE | STA_ERR;
        if (tbc < cbc) {                                /* record small? */
            cbc = tbc;                                  /* use smaller */
            wc = (mt_cu & CU_UNPAK)? cbc: (cbc + 1) / 2;
            }
        for (i = p = 0; i < wc; i++) {                  /* copy buffer */
            xma = mt_ixma (xma);                        /* increment xma */
            mt_wc = (mt_wc + 1) & 07777;                /* incr word cnt */
            if (mt_cu & CU_UNPAK) c = mtxb[p++];
            else {
                c1 = mtxb[p++] & 077;
                c2 = mtxb[p++] & 077;
                c = (c1 << 6) | c2;
                }
            if ((f == FN_READ) && MEM_ADDR_OK (xma))
                M[xma] = c;
            else if ((f == FN_CMPARE) && (M[xma] != c)) {
                mt_sta = mt_sta | STA_CPE | STA_ERR;
                break;
                }
            }
        break;

    case FN_WRITE:                                      /* write */
        tbc = (mt_cu & CU_UNPAK)? wc: wc * 2;
        for (i = p = 0; i < wc; i++) {                  /* copy buf to tape */
            xma = mt_ixma (xma);                        /* incr mem addr */
            if (mt_cu & CU_UNPAK)
                mtxb[p++] = M[xma] & 0377;
            else {
                mtxb[p++] = (M[xma] >> 6) & 077;
                mtxb[p++] = M[xma] & 077;
                }
            }
        if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */
            r = mt_map_err (uptr, st);                  /* map error */
            xma = GET_EMA (mt_cu) + mt_ca;              /* restore xma */
            }
        else mt_wc = 0;                                 /* ok, clear wc */
        break;

    case FN_WREOF:
        if ((st = sim_tape_wrtmk (uptr)))               /* write tmk, err? */
            r = mt_map_err (uptr, st);                  /* map error */
        break;

    case FN_SPACEF:                                     /* space forward */
        do {
            mt_wc = (mt_wc + 1) & 07777;                /* incr wc */
            if ((st = sim_tape_sprecf (uptr, &tbc))) {  /* space rec fwd, err? */
                r = mt_map_err (uptr, st);              /* map error */
                break;                                  /* stop */
                }
            } while ((mt_wc != 0) && (passed_eot || !sim_tape_eot (uptr)));
        break;

    case FN_SPACER:                                     /* space reverse */
        do {
            mt_wc = (mt_wc + 1) & 07777;                /* incr wc */
            if ((st = sim_tape_sprecr (uptr, &tbc))) {  /* space rec rev, err? */
                r = mt_map_err (uptr, st);              /* map error */
                break;                                  /* stop */
                }
            } while (mt_wc != 0);
        break;
        }                                               /* end case */

if (!passed_eot && sim_tape_eot (uptr))                 /* just passed EOT? */
    uptr->USTAT = uptr->USTAT | STA_EOT;
mt_cu = (mt_cu & ~CU_EMA) | ((xma >> (12 - CU_V_EMA)) & CU_EMA);
mt_ca = xma & 07777;                                    /* update mem addr */
mt_set_done ();                                         /* set done */
mt_updcsta (uptr);                                      /* update status */
return r;
}

/* Update controller status */

int32 mt_updcsta (UNIT *uptr)
{
mt_sta = (mt_sta & ~(STA_DYN | STA_CLR)) | (uptr->USTAT & STA_DYN);
if (((mt_sta & STA_ERR) && (mt_cu & CU_IEE)) ||
     (mt_done && (mt_cu & CU_IED)))
     int_req = int_req | INT_MT;
else int_req = int_req & ~INT_MT;
return mt_sta;
}

/* Test if controller busy */

UNIT *mt_busy (void)
{
int32 u;
UNIT *uptr;

for (u = 0; u < MT_NUMDR; u++) {                        /* loop thru units */
    uptr = mt_dev.units + u;
    if (sim_is_active (uptr) && ((uptr->USTAT & STA_REW) == 0))
        return uptr;
    }
return NULL;
}

/* Increment extended memory address */

int32 mt_ixma (int32 xma)                               /* incr extended ma */
{
int32 v;

v = ((xma + 1) & 07777) | (xma & 070000);               /* wrapped incr */
if (mt_fn & FN_INC) {                                   /* increment mode? */
    if (xma == 077777)                                  /* at limit? error */
        mt_sta = mt_sta | STA_INC | STA_ERR;
    else v = xma + 1;                                   /* else 15b incr */
    }
return v;
}

/* Set done */

void mt_set_done (void)
{
mt_done = 1;                                            /* set done */
mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC);             /* clear func<4:6> */
return;
}

/* Map tape error status */

t_stat mt_map_err (UNIT *uptr, t_stat st)
{
switch (st) {

    case MTSE_FMT:                                      /* illegal fmt */
    case MTSE_UNATT:                                    /* unattached */
        mt_sta = mt_sta | STA_ILL | STA_ERR;
    case MTSE_OK:                                       /* no error */
        return SCPE_IERR;                               /* never get here! */

    case MTSE_TMK:                                      /* end of file */
        uptr->USTAT = uptr->USTAT | STA_EOF;            /* set EOF */
        mt_sta = mt_sta | STA_ERR;
        break;

    case MTSE_IOERR:                                    /* IO error */
        mt_sta = mt_sta | STA_PAR | STA_ERR;            /* set par err */
        if (mt_stopioe)
            return SCPE_IOERR;
        break;

    case MTSE_INVRL:                                    /* invalid rec lnt */
        mt_sta = mt_sta | STA_PAR | STA_ERR;            /* set par err */
        return SCPE_MTRLNT;

    case MTSE_RECE:                                     /* record in error */
    case MTSE_EOM:                                      /* end of medium */
        mt_sta = mt_sta | STA_PAR | STA_ERR;            /* set par err */
        break;

    case MTSE_BOT:                                      /* reverse into BOT */
        uptr->USTAT = uptr->USTAT | STA_BOT;            /* set status */
        mt_sta = mt_sta | STA_ERR;
        break;

    case MTSE_WRP:                                      /* write protect */
        mt_sta = mt_sta | STA_ILL | STA_ERR;            /* illegal operation */
        break;
        }

return SCPE_OK;
}

/* Reset routine */

t_stat mt_reset (DEVICE *dptr)
{
int32 u;
UNIT *uptr;

mt_cu = mt_fn = mt_wc = mt_ca = mt_db = mt_sta = mt_done = 0;
int_req = int_req & ~INT_MT;                            /* clear interrupt */
for (u = 0; u < MT_NUMDR; u++) {                        /* loop thru units */
    uptr = mt_dev.units + u;
    sim_cancel (uptr);                                  /* cancel activity */
    sim_tape_reset (uptr);                              /* reset tape */
    if (uptr->flags & UNIT_ATT) uptr->USTAT =
        (sim_tape_bot (uptr)? STA_BOT: 0) |
        (sim_tape_wrp (uptr)? STA_WLK: 0);
    else uptr->USTAT = STA_REM;
    }
if (mtxb == NULL)
    mtxb = (uint8 *) calloc (MT_MAXFR, sizeof (uint8));
if (mtxb == NULL)
    return SCPE_MEM;
return SCPE_OK;
}

/* Attach routine */

t_stat mt_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
int32 u = uptr - mt_dev.units;                          /* get unit number */

r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK)
    return r;
uptr->USTAT = STA_BOT | (sim_tape_wrp (uptr)? STA_WLK: 0);
if (u == GET_UNIT (mt_cu))
    mt_updcsta (uptr);
return r;
}

/* Detach routine */

t_stat mt_detach (UNIT* uptr)
{
int32 u = uptr - mt_dev.units;                          /* get unit number */

if (!(uptr->flags & UNIT_ATT))                          /* check for attached */
    return SCPE_OK;
if (!sim_is_active (uptr))
    uptr->USTAT = STA_REM;
if (u == GET_UNIT (mt_cu))
    mt_updcsta (uptr);
return sim_tape_detach (uptr);
}

/* Write lock/enable routine */

t_stat mt_vlock (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 u = uptr - mt_dev.units;                          /* get unit number */

if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr)))
    uptr->USTAT = uptr->USTAT | STA_WLK;
else uptr->USTAT = uptr->USTAT & ~STA_WLK;
if (u == GET_UNIT (mt_cu))
    mt_updcsta (uptr);
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_pt.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* pdp8_pt.c: PDP-8 paper tape reader/punch simulator

   Copyright (c) 1993-2017, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   ptr,ptp      PC8E paper tape reader/punch

   13-Mar-17    RMS     Annotated fall through in switch
   17-Mar-13    RMS     Modified to use central set_bootpc routine
   25-Apr-03    RMS     Revised for extended file support
   04-Oct-02    RMS     Added DIBs
   30-May-02    RMS     Widened POS to 32b
   30-Nov-01    RMS     Added read only unit support
   30-Mar-98    RMS     Added RIM loader as PTR bootstrap
*/

#include "pdp8_defs.h"

extern int32 int_req, int_enable, dev_done, stop_inst;

int32 ptr_stopioe = 0, ptp_stopioe = 0;                 /* stop on error */

int32 ptr (int32 IR, int32 AC);
int32 ptp (int32 IR, int32 AC);
t_stat ptr_svc (UNIT *uptr);
t_stat ptp_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_reset (DEVICE *dptr);
t_stat ptr_boot (int32 unitno, DEVICE *dptr);

/* PTR data structures

   ptr_dev      PTR device descriptor
   ptr_unit     PTR unit descriptor
   ptr_reg      PTR register list
*/

DIB ptr_dib = { DEV_PTR, 1, { &ptr } };

UNIT ptr_unit = {
    UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0),
           SERIAL_IN_WAIT
    };

REG ptr_reg[] = {
    { ORDATAD (BUF, ptr_unit.buf, 8, "last data item processed") },
    { FLDATAD (DONE, dev_done, INT_V_PTR, "device done flag") },
    { FLDATAD (ENABLE, int_enable, INT_V_PTR, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_PTR, "interrupt pending flag") },
    { DRDATAD (POS, ptr_unit.pos, T_ADDR_W, "position in the input file"), PV_LEFT },
    { DRDATAD (TIME, ptr_unit.wait, 24, "time from I/O initiation to interrupt"), PV_LEFT },
    { FLDATAD (STOP_IOE, ptr_stopioe, 0, "stop on I/O error") },
    { NULL }
    };

MTAB ptr_mod[] = {
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
    { 0 }
    };

DEVICE ptr_dev = {
    "PTR", &ptr_unit, ptr_reg, ptr_mod,
    1, 10, 31, 1, 8, 8,
    NULL, NULL, &ptr_reset,
    &ptr_boot, NULL, NULL,
    &ptr_dib, 0 };

/* PTP data structures

   ptp_dev      PTP device descriptor
   ptp_unit     PTP unit descriptor
   ptp_reg      PTP register list
*/

DIB ptp_dib = { DEV_PTP, 1, { &ptp } };

UNIT ptp_unit = {
    UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
    };

REG ptp_reg[] = {
    { ORDATAD (BUF, ptp_unit.buf, 8, "last data item processed") },
    { FLDATAD (DONE, dev_done, INT_V_PTP, "device done flag") },
    { FLDATAD (ENABLE, int_enable, INT_V_PTP, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_PTP, "interrupt pending flag") },
    { DRDATAD (POS, ptp_unit.pos, T_ADDR_W, "position in the output file"), PV_LEFT },
    { DRDATAD (TIME, ptp_unit.wait, 24, "time from I/O initiation to interrupt"), PV_LEFT },
    { FLDATAD (STOP_IOE, ptp_stopioe, 0, "stop on I/O error") },
    { NULL }
    };

MTAB ptp_mod[] = {
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
    { 0 }
    };

DEVICE ptp_dev = {
    "PTP", &ptp_unit, ptp_reg, ptp_mod,
    1, 10, 31, 1, 8, 8,
    NULL, NULL, &ptp_reset,
    NULL, NULL, NULL,
    &ptp_dib, 0
    };

/* Paper tape reader: IOT routine */

int32 ptr (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* RPE */
        int_enable = int_enable | (INT_PTR+INT_PTP);    /* set enable */
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 1:                                             /* RSF */
        return (dev_done & INT_PTR)? IOT_SKP + AC: AC;  

    case 6:                                             /* RFC!RRB */
        sim_activate (&ptr_unit, ptr_unit.wait);        /* activate */
        /* fall through */
    case 2:                                             /* RRB */
        dev_done = dev_done & ~INT_PTR;                 /* clear flag */
        int_req = int_req & ~INT_PTR;                   /* clear int req */
        return (AC | ptr_unit.buf);                     /* or data to AC */

    case 4:                                             /* RFC */
        sim_activate (&ptr_unit, ptr_unit.wait);
        dev_done = dev_done & ~INT_PTR;                 /* clear flag */
        int_req = int_req & ~INT_PTR;                   /* clear int req */
        return AC;

    default:
        return (stop_inst << IOT_V_REASON) + AC;
        }                                               /* end switch */
}

/* Unit service */

t_stat ptr_svc (UNIT *uptr)
{
int32 temp;

if ((ptr_unit.flags & UNIT_ATT) == 0)                   /* attached? */
    return IORETURN (ptr_stopioe, SCPE_UNATT);
if ((temp = getc (ptr_unit.fileref)) == EOF) {
    if (feof (ptr_unit.fileref)) {
        if (ptr_stopioe)
            sim_printf ("PTR end of file\n");
        else return SCPE_OK;
        }
    else sim_perror ("PTR I/O error");
    clearerr (ptr_unit.fileref);
    return SCPE_IOERR;
    }
dev_done = dev_done | INT_PTR;                          /* set done */
int_req = INT_UPDATE;                                   /* update interrupts */
ptr_unit.buf = temp & 0377;
ptr_unit.pos = ptr_unit.pos + 1;
return SCPE_OK;
}

/* Reset routine */

t_stat ptr_reset (DEVICE *dptr)
{
ptr_unit.buf = 0;
dev_done = dev_done & ~INT_PTR;                         /* clear done, int */
int_req = int_req & ~INT_PTR;
int_enable = int_enable | INT_PTR;                      /* set enable */
sim_cancel (&ptr_unit);                                 /* deactivate unit */
return SCPE_OK;
}

/* Paper tape punch: IOT routine */

int32 ptp (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* PCE */
        int_enable = int_enable & ~(INT_PTR+INT_PTP);   /* clear enables */
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 1:                                             /* PSF */
        return (dev_done & INT_PTP)? IOT_SKP + AC: AC;

    case 2:                                             /* PCF */
        dev_done = dev_done & ~INT_PTP;                 /* clear flag */
        int_req = int_req & ~INT_PTP;                   /* clear int req */
        return AC;

    case 6:                                             /* PLS */
        dev_done = dev_done & ~INT_PTP;                 /* clear flag */
        int_req = int_req & ~INT_PTP;                   /* clear int req */
    case 4:                                             /* PPC */
        ptp_unit.buf = AC & 0377;                       /* load punch buf */
        sim_activate (&ptp_unit, ptp_unit.wait);        /* activate unit */
        return AC;

    default:
        return (stop_inst << IOT_V_REASON) + AC;
        }                                               /* end switch */
}

/* Unit service */

t_stat ptp_svc (UNIT *uptr)
{
dev_done = dev_done | INT_PTP;                          /* set done */
int_req = INT_UPDATE;                                   /* update interrupts */
if ((ptp_unit.flags & UNIT_ATT) == 0)                   /* attached? */
    return IORETURN (ptp_stopioe, SCPE_UNATT);
if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) {
    sim_perror ("PTP I/O error");
    clearerr (ptp_unit.fileref);
    return SCPE_IOERR;
    }
ptp_unit.pos = ptp_unit.pos + 1;
return SCPE_OK;
}

/* Reset routine */

t_stat ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
dev_done = dev_done & ~INT_PTP;                         /* clear done, int */
int_req = int_req & ~INT_PTP;
int_enable = int_enable | INT_PTP;                      /* set enable */
sim_cancel (&ptp_unit);                                 /* deactivate unit */
return SCPE_OK;
}

/* Bootstrap routine */

#define BOOT_START 07756
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))

static const uint16 boot_rom[] = {
    06014,                      /* 7756, RFC */
    06011,                      /* 7757, LOOP, RSF */
    05357,                      /* JMP .-1 */
    06016,                      /* RFC RRB */
    07106,                      /* CLL RTL*/
    07006,                      /* RTL */
    07510,                      /* SPA*/
    05374,                      /* JMP 7774 */
    07006,                      /* RTL */
    06011,                      /* RSF */
    05367,                      /* JMP .-1 */
    06016,                      /* RFC RRB */
    07420,                      /* SNL */
    03776,                      /* DCA I 7776 */
    03376,                      /* 7774, DCA 7776 */
    05357,                      /* JMP 7757 */
    00000,                      /* 7776, 0 */
    05301                       /* 7777, JMP 7701 */
    };

t_stat ptr_boot (int32 unitno, DEVICE *dptr)
{
size_t i;
extern uint16 M[];

if (ptr_dib.dev != DEV_PTR)                             /* only std devno */
    return STOP_NOTSTD;
for (i = 0; i < BOOT_LEN; i++)
    M[BOOT_START + i] = boot_rom[i];
cpu_set_bootpc (BOOT_START);
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_rf.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/* pdp8_rf.c: RF08 fixed head disk simulator

   Copyright (c) 1993-2013, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   rf           RF08 fixed head disk

   17-Sep-13    RMS     Changed to use central set_bootpc routine
   03-Sep-13    RMS     Added explicit void * cast
   15-May-06    RMS     Fixed bug in autosize attach (Dave Gesswein)
   07-Jan-06    RMS     Fixed unaligned register access bug (Doug Carman)
   04-Jan-04    RMS     Changed sim_fsize calling sequence
   26-Oct-03    RMS     Cleaned up buffer copy code
   26-Jul-03    RMS     Fixed bug in set size routine
   14-Mar-03    RMS     Fixed variable platter interaction with save/restore
   03-Mar-03    RMS     Fixed autosizing
   02-Feb-03    RMS     Added variable platter and autosizing support
   04-Oct-02    RMS     Added DIB, device number support
   28-Nov-01    RMS     Added RL8A support
   25-Apr-01    RMS     Added device enable/disable support
   19-Mar-01    RMS     Added disk monitor bootstrap, fixed IOT decoding
   15-Feb-01    RMS     Fixed 3 cycle data break sequence
   14-Apr-99    RMS     Changed t_addr to unsigned
   30-Mar-98    RMS     Fixed bug in RF bootstrap

   The RF08 is a head-per-track disk.  It uses the three cycle data break
   facility.  To minimize overhead, the entire RF08 is buffered in memory.

   Two timing parameters are provided:

   rf_time      Interword timing, must be non-zero
   rf_burst     Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
                DMA occurs in a burst
*/

#include "pdp8_defs.h"
#include <math.h>

#define UNIT_V_AUTO     (UNIT_V_UF + 0)                 /* autosize */
#define UNIT_V_PLAT     (UNIT_V_UF + 1)                 /* #platters - 1 */
#define UNIT_M_PLAT     03
#define UNIT_GETP(x)    ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO       (1 << UNIT_V_AUTO)
#define UNIT_PLAT       (UNIT_M_PLAT << UNIT_V_PLAT)

/* Constants */

#define RF_NUMWD        2048                            /* words/track */
#define RF_NUMTR        128                             /* tracks/disk */
#define RF_DKSIZE       (RF_NUMTR * RF_NUMWD)           /* words/disk */
#define RF_NUMDK        4                               /* disks/controller */
#define RF_WC           07750                           /* word count */
#define RF_MA           07751                           /* mem address */
#define RF_WMASK        (RF_NUMWD - 1)                  /* word mask */

/* Parameters in the unit descriptor */

#define FUNC            u4                              /* function */
#define RF_READ         2                               /* read */
#define RF_WRITE        4                               /* write */

/* Status register */

#define RFS_PCA         04000                           /* photocell status */
#define RFS_DRE         02000                           /* data req enable */
#define RFS_WLS         01000                           /* write lock status */
#define RFS_EIE         00400                           /* error int enable */
#define RFS_PIE         00200                           /* photocell int enb */
#define RFS_CIE         00100                           /* done int enable */
#define RFS_MEX         00070                           /* memory extension */
#define RFS_DRL         00004                           /* data late error */
#define RFS_NXD         00002                           /* non-existent disk */
#define RFS_PER         00001                           /* parity error */
#define RFS_ERR         (RFS_WLS + RFS_DRL + RFS_NXD + RFS_PER)
#define RFS_V_MEX       3

#define GET_MEX(x)      (((x) & RFS_MEX) << (12 - RFS_V_MEX))
#define GET_POS(x)      ((int) fmod (sim_gtime() / ((double) (x)), \
                        ((double) RF_NUMWD)))
#define UPDATE_PCELL    if (GET_POS(rf_time) < 6) rf_sta = rf_sta | RFS_PCA; \
                        else rf_sta = rf_sta & ~RFS_PCA
#define RF_INT_UPDATE   if ((rf_done && (rf_sta & RFS_CIE)) || \
                            ((rf_sta & RFS_ERR) && (rf_sta & RFS_EIE)) || \
                            ((rf_sta & RFS_PCA) && (rf_sta & RFS_PIE))) \
                            int_req = int_req | INT_RF; \
                        else int_req = int_req & ~INT_RF

extern uint16 M[];
extern int32 int_req, stop_inst;
extern UNIT cpu_unit;

int32 rf_sta = 0;                                       /* status register */
int32 rf_da = 0;                                        /* disk address */
int32 rf_done = 0;                                      /* done flag */
int32 rf_wlk = 0;                                       /* write lock */
int32 rf_time = 10;                                     /* inter-word time */
int32 rf_burst = 1;                                     /* burst mode flag */
int32 rf_stopioe = 1;                                   /* stop on error */

int32 rf60 (int32 IR, int32 AC);
int32 rf61 (int32 IR, int32 AC);
int32 rf62 (int32 IR, int32 AC);
int32 rf64 (int32 IR, int32 AC);
t_stat rf_svc (UNIT *uptr);
t_stat pcell_svc (UNIT *uptr);
t_stat rf_reset (DEVICE *dptr);
t_stat rf_boot (int32 unitno, DEVICE *dptr);
t_stat rf_attach (UNIT *uptr, CONST char *cptr);
t_stat rf_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);

/* RF08 data structures

   rf_dev       RF device descriptor
   rf_unit      RF unit descriptor
   pcell_unit   photocell timing unit (orphan)
   rf_reg       RF register list
*/

DIB rf_dib = { DEV_RF, 5, { &rf60, &rf61, &rf62, NULL, &rf64 } };

UNIT rf_unit = {
    UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+
           UNIT_BUFABLE+UNIT_MUSTBUF, RF_DKSIZE)
    };

UNIT pcell_unit = { UDATA (&pcell_svc, 0, 0) };

REG rf_reg[] = {
    { ORDATAD (STA, rf_sta, 12, "status") },
    { ORDATAD (DA, rf_da, 20, "low order disk address") },
    { ORDATAD (WC, M[RF_WC], 12, "word count (in memory)"), REG_FIT },
    { ORDATAD (MA, M[RF_MA], 12, "memory address (in memory)"), REG_FIT },
    { FLDATAD (DONE, rf_done, 0, "device done flag") },
    { FLDATAD (INT, int_req, INT_V_RF, "interrupt pending flag") },
    { ORDATAD (WLK, rf_wlk, 32, "write lock switches") },
    { DRDATAD (TIME, rf_time, 24, "rotational delay, per word"), REG_NZ + PV_LEFT },
    { FLDATAD (BURST, rf_burst, 0, "burst flag") },
    { FLDATAD (STOP_IOE, rf_stopioe, 0, "stop on I/O error") },
    { DRDATA (CAPAC, rf_unit.capac, 21), REG_HRO },
    { ORDATA (DEVNUM, rf_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB rf_mod[] = {
    { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
    { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
    { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
    { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
    { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE rf_dev = {
    "RF", &rf_unit, rf_reg, rf_mod,
    1, 8, 20, 1, 8, 12,
    NULL, NULL, &rf_reset,
    &rf_boot, &rf_attach, NULL,
    &rf_dib, DEV_DISABLE | DEV_DIS
    };

/* IOT routines */

int32 rf60 (int32 IR, int32 AC)
{
int32 t;
int32 pulse = IR & 07;

UPDATE_PCELL;                                           /* update photocell */
if (pulse & 1) {                                        /* DCMA */
    rf_da = rf_da & ~07777;                             /* clear DAR<8:19> */
    rf_done = 0;                                        /* clear done */
    rf_sta = rf_sta & ~RFS_ERR;                         /* clear errors */
    RF_INT_UPDATE;                                      /* update int req */
    }
if (pulse & 6) {                                        /* DMAR, DMAW */
    rf_da = rf_da | AC;                                 /* DAR<8:19> |= AC */
    rf_unit.FUNC = pulse & ~1;                          /* save function */
    t = (rf_da & RF_WMASK) - GET_POS (rf_time);         /* delta to new loc */
    if (t < 0)                                          /* wrap around? */
        t = t + RF_NUMWD;
    sim_activate (&rf_unit, t * rf_time);               /* schedule op */
    AC = 0;                                             /* clear AC */
    }
return AC;
}

int32 rf61 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;

UPDATE_PCELL;                                           /* update photocell */
switch (pulse) {                                        /* decode IR<9:11> */

    case 1:                                             /* DCIM */
        rf_sta = rf_sta & 07007;                        /* clear STA<3:8> */
        int_req = int_req & ~INT_RF;                    /* clear int req */
        sim_cancel (&pcell_unit);                       /* cancel photocell */
        return AC;

    case 2:                                             /* DSAC */
        return ((rf_da & RF_WMASK) == GET_POS (rf_time))? IOT_SKP: 0;

    case 5:                                             /* DIML */
        rf_sta = (rf_sta & 07007) | (AC & 0770);        /* STA<3:8> <- AC */
        if (rf_sta & RFS_PIE)                           /* photocell int? */
            sim_activate (&pcell_unit, (RF_NUMWD - GET_POS (rf_time)) *
                rf_time);
        else sim_cancel (&pcell_unit);
        RF_INT_UPDATE;                                  /* update int req */
        return 0;                                       /* clear AC */

    case 6:                                             /* DIMA */
        return rf_sta;                                  /* AC <- STA<0:11> */
        }

return AC;
}

int32 rf62 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;

UPDATE_PCELL;                                           /* update photocell */
if (pulse & 1) {                                        /* DFSE */
    if (rf_sta & RFS_ERR)
        AC = AC | IOT_SKP;
    }
if (pulse & 2) {                                        /* DFSC */
    if (pulse & 4)                                      /* for DMAC */
        AC = AC & ~07777;
    else if (rf_done)
        AC = AC | IOT_SKP;
    }
if (pulse & 4)                                          /* DMAC */
    AC = AC | (rf_da & 07777);
return AC;
}

int32 rf64 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;

UPDATE_PCELL;                                           /* update photocell */
switch (pulse) {                                        /* decode IR<9:11> */

    case 1:                                             /* DCXA */
        rf_da = rf_da & 07777;                          /* clear DAR<0:7> */
        break;

    case 3:                                             /* DXAL */
        rf_da = rf_da & 07777;                          /* clear DAR<0:7> */
    case 2:                                             /* DXAL w/o clear */
        rf_da = rf_da | ((AC & 0377) << 12);            /* DAR<0:7> |= AC */
        AC = 0;                                         /* clear AC */
        break;

    case 5:                                             /* DXAC */
        AC = 0;                                         /* clear AC */
    case 4:                                             /* DXAC w/o clear */
        AC = AC | ((rf_da >> 12) & 0377);               /* AC |= DAR<0:7> */
        break;

    default:
        AC = (stop_inst << IOT_V_REASON) + AC;
        break;
        }                                               /* end switch */

if ((uint32) rf_da >= rf_unit.capac)
    rf_sta = rf_sta | RFS_NXD;
else rf_sta = rf_sta & ~RFS_NXD;
RF_INT_UPDATE;
return AC;
}

/* Unit service

   Note that for reads and writes, memory addresses wrap around in the
   current field.  This code assumes the entire disk is buffered.
*/

t_stat rf_svc (UNIT *uptr)
{
int32 pa, t, mex;
int16 *fbuf = (int16 *) uptr->filebuf;

UPDATE_PCELL;                                           /* update photocell */
if ((uptr->flags & UNIT_BUF) == 0) {                    /* not buf? abort */
    rf_sta = rf_sta | RFS_NXD;
    rf_done = 1;
    RF_INT_UPDATE;                                      /* update int req */
    return IORETURN (rf_stopioe, SCPE_UNATT);
    }

mex = GET_MEX (rf_sta);
do {
    if ((uint32) rf_da >= rf_unit.capac) {              /* disk overflow? */
        rf_sta = rf_sta | RFS_NXD;
        break;
        }
    M[RF_WC] = (M[RF_WC] + 1) & 07777;                  /* incr word count */
    M[RF_MA] = (M[RF_MA] + 1) & 07777;                  /* incr mem addr */
    pa = mex | M[RF_MA];                                /* add extension */
    if (uptr->FUNC == RF_READ) {                        /* read? */
        if (MEM_ADDR_OK (pa))                           /* if !nxm */
            M[pa] = fbuf[rf_da];                        /* read word */
        }
    else {                                              /* write */
        t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
        if ((rf_wlk >> t) & 1)                          /* write locked? */
            rf_sta = rf_sta | RFS_WLS;
        else {                                          /* not locked */
            fbuf[rf_da] = M[pa];                        /* write word */
            if (((uint32) rf_da) >= uptr->hwmark)
                uptr->hwmark = rf_da + 1;
            }
        }
    rf_da = (rf_da + 1) & 03777777;                     /* incr disk addr */
    } while ((M[RF_WC] != 0) && (rf_burst != 0));       /* brk if wc, no brst */

if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0))       /* more to do? */
    sim_activate (&rf_unit, rf_time);                   /* sched next */
else {
    rf_done = 1;                                        /* done */
    RF_INT_UPDATE;                                      /* update int req */
    }
return SCPE_OK;
}

/* Photocell unit service */

t_stat pcell_svc (UNIT *uptr)
{
rf_sta = rf_sta | RFS_PCA;                              /* set photocell */
if (rf_sta & RFS_PIE) {                                 /* int enable? */
    sim_activate (&pcell_unit, RF_NUMWD * rf_time);
    int_req = int_req | INT_RF;
    }
return SCPE_OK;
}

/* Reset routine */

t_stat rf_reset (DEVICE *dptr)
{
rf_sta = rf_da = 0;
rf_done = 1;
int_req = int_req & ~INT_RF;                            /* clear interrupt */
sim_cancel (&rf_unit);
sim_cancel (&pcell_unit);
return SCPE_OK;
}

/* Bootstrap routine */

#define OS8_START       07750
#define OS8_LEN         (sizeof (os8_rom) / sizeof (int16))
#define DM4_START       00200
#define DM4_LEN         (sizeof (dm4_rom) / sizeof (int16))

static const uint16 os8_rom[] = {
    07600,                      /* 7750, CLA CLL        ; also word count */
    06603,                      /* 7751, DMAR           ; also address */
    06622,                      /* 7752, DFSC           ; done? */
    05352,                      /* 7753, JMP .-1        ; no */
    05752                       /* 7754, JMP @.-2       ; enter boot */
    };

static const uint16 dm4_rom[] = {
    00200, 07600,               /* 0200, CLA CLL */
    00201, 06603,               /* 0201, DMAR           ; read */
    00202, 06622,               /* 0202, DFSC           ; done? */
    00203, 05202,               /* 0203, JMP .-1        ; no */
    00204, 05600,               /* 0204, JMP @.-4       ; enter boot */
    07750, 07576,               /* 7750, 7576           ; word count */
    07751, 07576                /* 7751, 7576           ; address */
    };

t_stat rf_boot (int32 unitno, DEVICE *dptr)
{
size_t i;

if (rf_dib.dev != DEV_RF)                               /* only std devno */
    return STOP_NOTSTD;
if (sim_switches & SWMASK ('D')) {
    for (i = 0; i < DM4_LEN; i = i + 2)
        M[dm4_rom[i]] = dm4_rom[i + 1];
    cpu_set_bootpc (DM4_START);
    }
else {
    for (i = 0; i < OS8_LEN; i++)
        M[OS8_START + i] = os8_rom[i];
    cpu_set_bootpc (OS8_START);
    }
return SCPE_OK;
}

/* Attach routine */

t_stat rf_attach (UNIT *uptr, CONST char *cptr)
{
uint32 sz, p;
uint32 ds_bytes = RF_DKSIZE * sizeof (int16);

if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
    p = (sz + ds_bytes - 1) / ds_bytes;
    if (p >= RF_NUMDK)
        p = RF_NUMDK - 1;
    uptr->flags = (uptr->flags & ~UNIT_PLAT) |
        (p << UNIT_V_PLAT);
    }
uptr->capac = UNIT_GETP (uptr->flags) * RF_DKSIZE;
return attach_unit (uptr, cptr);
}

/* Change disk size */

t_stat rf_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (val < 0)
    return SCPE_IERR;
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;
uptr->capac = UNIT_GETP (val) * RF_DKSIZE;
uptr->flags = uptr->flags & ~UNIT_AUTO;
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_rk.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
/* pdp8_rk.c: RK8E cartridge disk simulator

   Copyright (c) 1993-2013, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   rk           RK8E/RK05 cartridge disk

   17-Sep-13    RMS     Changed to use central set_bootpc routine
   18-Mar-13    RMS     Raised RK_MIN so that RKLFMT will work (Mark Pizzolato)
   25-Apr-03    RMS     Revised for extended file support
   04-Oct-02    RMS     Added DIB, device number support
   06-Jan-02    RMS     Changed enable/disable support
   30-Nov-01    RMS     Added read only unit, extended SET/SHOW support
   24-Nov-01    RMS     Converted FLG to array, made register names consistent
   25-Apr-01    RMS     Added device enable/disable support
   29-Jun-96    RMS     Added unit enable/disable support
*/

#include "pdp8_defs.h"

/* Constants */

#define RK_NUMSC        16                              /* sectors/surface */
#define RK_NUMSF        2                               /* surfaces/cylinder */
#define RK_NUMCY        203                             /* cylinders/drive */
#define RK_NUMWD        256                             /* words/sector */
#define RK_SIZE         (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD)
                                                        /* words/drive */
#define RK_NUMDR        4                               /* drives/controller */
#define RK_M_NUMDR      03

/* Flags in the unit flags word */

#define UNIT_V_HWLK     (UNIT_V_UF + 0)                 /* hwre write lock */
#define UNIT_V_SWLK     (UNIT_V_UF + 1)                 /* swre write lock */
#define UNIT_HWLK       (1 << UNIT_V_HWLK)
#define UNIT_SWLK       (1 << UNIT_V_SWLK)
#define UNIT_WPRT       (UNIT_HWLK|UNIT_SWLK|UNIT_RO)   /* write protect */

/* Parameters in the unit descriptor */

#define CYL             u3                              /* current cylinder */
#define FUNC            u4                              /* function */

/* Status register */

#define RKS_DONE        04000                           /* transfer done */
#define RKS_HMOV        02000                           /* heads moving */
#define RKS_SKFL        00400                           /* drive seek fail */
#define RKS_NRDY        00200                           /* drive not ready */
#define RKS_BUSY        00100                           /* control busy error */
#define RKS_TMO         00040                           /* timeout error */
#define RKS_WLK         00020                           /* write lock error */
#define RKS_CRC         00010                           /* CRC error */
#define RKS_DLT         00004                           /* data late error */
#define RKS_STAT        00002                           /* drive status error */
#define RKS_CYL         00001                           /* cyl address error */
#define RKS_ERR         (RKS_BUSY+RKS_TMO+RKS_WLK+RKS_CRC+RKS_DLT+RKS_STAT+RKS_CYL)

/* Command register */

#define RKC_M_FUNC      07                              /* function */
#define  RKC_READ       0
#define  RKC_RALL       1
#define  RKC_WLK        2
#define  RKC_SEEK       3
#define  RKC_WRITE      4
#define  RKC_WALL       5
#define RKC_V_FUNC      9
#define RKC_IE          00400                           /* interrupt enable */
#define RKC_SKDN        00200                           /* set done on seek done */
#define RKC_HALF        00100                           /* 128W sector */
#define RKC_MEX         00070                           /* memory extension */
#define RKC_V_MEX       3
#define RKC_M_DRV       03                              /* drive select */
#define RKC_V_DRV       1
#define RKC_CYHI        00001                           /* high cylinder addr */

#define GET_FUNC(x)     (((x) >> RKC_V_FUNC) & RKC_M_FUNC)
#define GET_DRIVE(x)    (((x) >> RKC_V_DRV) & RKC_M_DRV)
#define GET_MEX(x)      (((x) & RKC_MEX) << (12 - RKC_V_MEX))

/* Disk address */

#define RKD_V_SECT      0                               /* sector */
#define RKD_M_SECT      017
#define RKD_V_SUR       4                               /* surface */
#define RKD_M_SUR       01
#define RKD_V_CYL       5                               /* cylinder */
#define RKD_M_CYL       0177
#define GET_CYL(x,y)    ((((x) & RKC_CYHI) << (12-RKD_V_CYL)) | \
                        (((y) >> RKD_V_CYL) & RKD_M_CYL))
#define GET_DA(x,y)     ((((x) & RKC_CYHI) << 12) | y)

/* Reset commands */

#define RKX_CLS         0                               /* clear status */
#define RKX_CLC         1                               /* clear control */
#define RKX_CLD         2                               /* clear drive */
#define RKX_CLSA        3                               /* clear status alt */

#define RK_INT_UPDATE   if (((rk_sta & (RKS_DONE + RKS_ERR)) != 0) && \
                            ((rk_cmd & RKC_IE) != 0)) \
                            int_req = int_req | INT_RK; \
                        else int_req = int_req & ~INT_RK
#define RK_MIN          50
#define MAX(x,y)        (((x) > (y))? (x): (y))

extern uint16 M[];
extern int32 int_req, stop_inst;
extern UNIT cpu_unit;

int32 rk_busy = 0;                                      /* controller busy */
int32 rk_sta = 0;                                       /* status register */
int32 rk_cmd = 0;                                       /* command register */
int32 rk_da = 0;                                        /* disk address */
int32 rk_ma = 0;                                        /* memory address */
int32 rk_swait = 10, rk_rwait = 10;                     /* seek, rotate wait */
int32 rk_stopioe = 1;                                   /* stop on error */

int32 rk (int32 IR, int32 AC);
t_stat rk_svc (UNIT *uptr);
t_stat rk_reset (DEVICE *dptr);
t_stat rk_boot (int32 unitno, DEVICE *dptr);
void rk_go (int32 function, int32 cylinder);

/* RK-8E data structures

   rk_dev       RK device descriptor
   rk_unit      RK unit list
   rk_reg       RK register list
   rk_mod       RK modifiers list
*/

DIB rk_dib = { DEV_RK, 1, { &rk } };

UNIT rk_unit[] = {
    { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
             UNIT_ROABLE, RK_SIZE) },
    { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
             UNIT_ROABLE, RK_SIZE) },
    { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
             UNIT_ROABLE, RK_SIZE) },
    { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
             UNIT_ROABLE, RK_SIZE) }
    };

REG rk_reg[] = {
    { ORDATAD (RKSTA, rk_sta, 12, "status") },
    { ORDATAD (RKCMD, rk_cmd, 12, "disk command") },
    { ORDATAD (RKDA, rk_da, 12, "disk address") },
    { ORDATAD (RKMA, rk_ma, 12, "current memory address") },
    { FLDATAD (BUSY, rk_busy, 0, "control busy flag") },
    { FLDATAD (INT, int_req, INT_V_RK, "interrupt pending flag") },
    { DRDATAD (STIME, rk_swait, 24, "seek time, per cylinder"), PV_LEFT },
    { DRDATAD (RTIME, rk_rwait, 24, "rotational delay"), PV_LEFT },
    { FLDATAD (STOP_IOE, rk_stopioe, 0, "stop on I/O error") },
    { ORDATA (DEVNUM, rk_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB rk_mod[] = {
    { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL },
    { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE rk_dev = {
    "RK", rk_unit, rk_reg, rk_mod,
    RK_NUMDR, 8, 24, 1, 8, 12,
    NULL, NULL, &rk_reset,
    &rk_boot, NULL, NULL,
    &rk_dib, DEV_DISABLE
    };

/* IOT routine */

int32 rk (int32 IR, int32 AC)
{
int32 i;
UNIT *uptr;

switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* unused */
        return (stop_inst << IOT_V_REASON) + AC;

    case 1:                                             /* DSKP */
        return (rk_sta & (RKS_DONE + RKS_ERR))?         /* skip on done, err */
            IOT_SKP + AC: AC;

    case 2:                                             /* DCLR */
        rk_sta = 0;                                     /* clear status */
        switch (AC & 03) {                              /* decode AC<10:11> */

        case RKX_CLS:                                   /* clear status */
            if (rk_busy != 0) rk_sta = rk_sta | RKS_BUSY;
        case RKX_CLSA:                                  /* clear status alt */
            break;

        case RKX_CLC:                                   /* clear control */
            rk_cmd = rk_busy = 0;                       /* clear registers */
            rk_ma = rk_da = 0;
            for (i = 0; i < RK_NUMDR; i++)
                sim_cancel (&rk_unit[i]);
            break;

        case RKX_CLD:                                   /* reset drive */
            if (rk_busy != 0)
                rk_sta = rk_sta | RKS_BUSY;
            else rk_go (RKC_SEEK, 0);                   /* seek to 0 */
            break;
            }                                           /* end switch AC */
        break;

    case 3:                                             /* DLAG */
        if (rk_busy != 0)
            rk_sta = rk_sta | RKS_BUSY;
        else {
            rk_da = AC;                                 /* load disk addr */
            rk_go (GET_FUNC (rk_cmd), GET_CYL (rk_cmd, rk_da));
            }
        break;

    case 4:                                             /* DLCA */
        if (rk_busy != 0)
            rk_sta = rk_sta | RKS_BUSY;
        else rk_ma = AC;                                /* load curr addr */
        break;

    case 5:                                             /* DRST */
        uptr = rk_dev.units + GET_DRIVE (rk_cmd);       /* selected unit */
        rk_sta = rk_sta & ~(RKS_HMOV + RKS_NRDY);       /* clear dynamic */
        if ((uptr->flags & UNIT_ATT) == 0)
            rk_sta = rk_sta | RKS_NRDY;
        if (sim_is_active (uptr))
            rk_sta = rk_sta | RKS_HMOV;
        return rk_sta;

    case 6:                                             /* DLDC */
        if (rk_busy != 0)
            rk_sta = rk_sta | RKS_BUSY;
        else {
            rk_cmd = AC;                                /* load command */
            rk_sta = 0;                                 /* clear status */
            }
        break;

    case 7:                                             /* DMAN */
        break;
        }                                               /* end case pulse */

RK_INT_UPDATE;                                          /* update int req */
return 0;                                               /* clear AC */
}

/* Initiate new function

   Called with function, cylinder, to allow recalibrate as well as
   load and go to be processed by this routine.

   Assumes that the controller is idle, and that updating of interrupt
   request will be done by the caller.
*/

void rk_go (int32 func, int32 cyl)
{
int32 t;
UNIT *uptr;

if (func == RKC_RALL)                                   /* all? use standard */
    func = RKC_READ;
if (func == RKC_WALL)
func = RKC_WRITE;
uptr = rk_dev.units + GET_DRIVE (rk_cmd);               /* selected unit */
if ((uptr->flags & UNIT_ATT) == 0) {                    /* not attached? */
    rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT;
    return;
    }
if (sim_is_active (uptr) || (cyl >= RK_NUMCY)) {        /* busy or bad cyl? */
    rk_sta = rk_sta | RKS_DONE | RKS_STAT;
    return;
    }
if ((func == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) {
    rk_sta = rk_sta | RKS_DONE | RKS_WLK;               /* write and locked? */
    return;
    }
if (func == RKC_WLK) {                                  /* write lock? */
    uptr->flags = uptr->flags | UNIT_SWLK;
    rk_sta = rk_sta | RKS_DONE;
    return;
    }
t = abs (cyl - uptr->CYL) * rk_swait;                   /* seek time */
if (func == RKC_SEEK) {                                 /* seek? */
    sim_activate (uptr, MAX (RK_MIN, t));               /* schedule */
    rk_sta = rk_sta | RKS_DONE;                         /* set done */
    }
else {
    sim_activate (uptr, t + rk_rwait);                  /* schedule */
    rk_busy = 1;                                        /* set busy */
    }
uptr->FUNC = func;                                      /* save func */
uptr->CYL = cyl;                                        /* put on cylinder */
return;
}

/* Unit service

   If seek, complete seek command
   Else complete data transfer command

   The unit control block contains the function and cylinder address for
   the current command.

   Note that memory addresses wrap around in the current field.
*/

static uint16 fill[RK_NUMWD/2] = { 0 };
t_stat rk_svc (UNIT *uptr)
{
int32 err, wc, wc1, awc, swc, pa, da;
UNIT *seluptr;

if (uptr->FUNC == RKC_SEEK) {                           /* seek? */
    seluptr = rk_dev.units + GET_DRIVE (rk_cmd);        /* see if selected */
    if ((uptr == seluptr) && ((rk_cmd & RKC_SKDN) != 0)) {
        rk_sta = rk_sta | RKS_DONE;
        RK_INT_UPDATE;
        }
    return SCPE_OK;
    }

if ((uptr->flags & UNIT_ATT) == 0) {                    /* not att? abort */
    rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT;
    rk_busy = 0;
    RK_INT_UPDATE;
    return IORETURN (rk_stopioe, SCPE_UNATT);
    }

if ((uptr->FUNC == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) {
    rk_sta = rk_sta | RKS_DONE | RKS_WLK;               /* write and locked? */
    rk_busy = 0;
    RK_INT_UPDATE;
    return SCPE_OK;
    }

pa = GET_MEX (rk_cmd) | rk_ma;                          /* phys address */
da = GET_DA (rk_cmd, rk_da) * RK_NUMWD * sizeof (int16);/* disk address */
swc = wc = (rk_cmd & RKC_HALF)? RK_NUMWD / 2: RK_NUMWD; /* get transfer size */
if ((wc1 = ((rk_ma + wc) - 010000)) > 0)                /* if wrap, limit */
    wc = wc - wc1;
err = fseek (uptr->fileref, da, SEEK_SET);              /* locate sector */

if ((uptr->FUNC == RKC_READ) && (err == 0) && MEM_ADDR_OK (pa)) { /* read? */
    awc = fxread (&M[pa], sizeof (int16), wc, uptr->fileref);
    for ( ; awc < wc; awc++)                            /* fill if eof */
        M[pa + awc] = 0;
    err = ferror (uptr->fileref);
    if ((wc1 > 0) && (err == 0))  {                     /* field wraparound? */
        pa = pa & 070000;                               /* wrap phys addr */
        awc = fxread (&M[pa], sizeof (int16), wc1, uptr->fileref);
        for ( ; awc < wc1; awc++)                       /* fill if eof */
            M[pa + awc] = 0;
        err = ferror (uptr->fileref);
        }
    }

if ((uptr->FUNC == RKC_WRITE) && (err == 0)) {          /* write? */
    fxwrite (&M[pa], sizeof (int16), wc, uptr->fileref);
    err = ferror (uptr->fileref);
    if ((wc1 > 0) && (err == 0)) {                      /* field wraparound? */
        pa = pa & 070000;                               /* wrap phys addr */
        fxwrite (&M[pa], sizeof (int16), wc1, uptr->fileref);
        err = ferror (uptr->fileref);
        }
    if ((rk_cmd & RKC_HALF) && (err == 0)) {            /* fill half sector */
        fxwrite (fill, sizeof (int16), RK_NUMWD/2, uptr->fileref);
        err = ferror (uptr->fileref);
        }
    }

rk_ma = (rk_ma + swc) & 07777;                          /* incr mem addr reg */
rk_sta = rk_sta | RKS_DONE;                             /* set done */
rk_busy = 0;
RK_INT_UPDATE;

if (err != 0) {
    sim_perror ("RK I/O error");
    clearerr (uptr->fileref);
    return SCPE_IOERR;
    }
return SCPE_OK;
}

/* Reset routine */

t_stat rk_reset (DEVICE *dptr)
{
int32 i;
UNIT *uptr;

rk_cmd = rk_ma = rk_da = rk_sta = rk_busy = 0;
int_req = int_req & ~INT_RK;                            /* clear interrupt */
for (i = 0; i < RK_NUMDR; i++) {                        /* stop all units */
    uptr = rk_dev.units + i;
    sim_cancel (uptr);
    uptr->flags = uptr->flags & ~UNIT_SWLK;
    uptr->CYL = uptr->FUNC = 0;
    }
return SCPE_OK;
}

/* Bootstrap routine */

#define BOOT_START 023
#define BOOT_UNIT 032
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))

static const uint16 boot_rom[] = {
    06007,                      /* 23, CAF */
    06744,                      /* 24, DLCA             ; addr = 0 */
    01032,                      /* 25, TAD UNIT         ; unit no */
    06746,                      /* 26, DLDC             ; command, unit */
    06743,                      /* 27, DLAG             ; disk addr, go */
    01032,                      /* 30, TAD UNIT         ; unit no, for OS */
    05031,                      /* 31, JMP . */
    00000                       /* UNIT, 0              ; in bits <9:10> */
    };

t_stat rk_boot (int32 unitno, DEVICE *dptr)
{
size_t i;

if (rk_dib.dev != DEV_RK)                               /* only std devno */
    return STOP_NOTSTD;
for (i = 0; i < BOOT_LEN; i++)
    M[BOOT_START + i] = boot_rom[i];
M[BOOT_UNIT] = (unitno & RK_M_NUMDR) << 1;
cpu_set_bootpc (BOOT_START);
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_rl.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
/* pdp8_rl.c: RL8A cartridge disk simulator

   Copyright (c) 1993-2013, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   rl           RL8A cartridge disk

   17-Sep-13    RMS     Changed to use central set_bootpc routine
   25-Oct-05    RMS     Fixed IOT 61 decode bug (David Gesswein)
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   04-Jan-04    RMS     Changed attach routine to use sim_fsize
   25-Apr-03    RMS     Revised for extended file support
   04-Oct-02    RMS     Added DIB, device number support
   06-Jan-02    RMS     Changed enable/disable support
   30-Nov-01    RMS     Cloned from RL11

   The RL8A is a four drive cartridge disk subsystem.  An RL01 drive
   consists of 256 cylinders, each with 2 surfaces containing 40 sectors
   of 256 bytes.  An RL02 drive has 512 cylinders.

   The RL8A controller has several serious complications.
   - Seeking is relative to the current disk address; this requires
     keeping accurate track of the current cylinder.
   - The RL8A will not switch heads or cross cylinders during transfers.
   - The RL8A operates in 8b and 12b mode, like the RX8E; in 12b mode, it
     packs 2 12b words into 3 bytes, creating a 170 "word" sector with
     one wasted byte.  Multi-sector transfers in 12b mode don't work.
*/

#include "pdp8_defs.h"

/* Constants */

#define RL_NUMBY        256                             /* 8b bytes/sector */
#define RL_NUMSC        40                              /* sectors/surface */
#define RL_NUMSF        2                               /* surfaces/cylinder */
#define RL_NUMCY        256                             /* cylinders/drive */
#define RL_NUMDR        4                               /* drives/controller */
#define RL_MAXFR        (1 << 12)                       /* max transfer */
#define RL01_SIZE       (RL_NUMCY*RL_NUMSF*RL_NUMSC*RL_NUMBY)  /* words/drive */
#define RL02_SIZE       (RL01_SIZE * 2)                 /* words/drive */
#define RL_BBMAP        014                             /* sector for bblk map */
#define RL_BBID         0123                            /* ID for bblk map */

/* Flags in the unit flags word */

#define UNIT_V_WLK      (UNIT_V_UF + 0)                 /* write lock */
#define UNIT_V_RL02     (UNIT_V_UF + 1)                 /* RL01 vs RL02 */
#define UNIT_V_AUTO     (UNIT_V_UF + 2)                 /* autosize enable */
#define UNIT_V_DUMMY    (UNIT_V_UF + 3)                 /* dummy flag */
#define UNIT_DUMMY      (1u << UNIT_V_DUMMY)
#define UNIT_WLK        (1u << UNIT_V_WLK)
#define UNIT_RL02       (1u << UNIT_V_RL02)
#define UNIT_AUTO       (1u << UNIT_V_AUTO)
#define UNIT_WPRT       (UNIT_WLK | UNIT_RO)            /* write protect */

/* Parameters in the unit descriptor */

#define TRK             u3                              /* current cylinder */
#define STAT            u4                              /* status */

/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */

#define RLDS_LOAD       0                               /* no cartridge */
#define RLDS_LOCK       5                               /* lock on */
#define RLDS_BHO        0000010                         /* brushes home NI */
#define RLDS_HDO        0000020                         /* heads out NI */
#define RLDS_CVO        0000040                         /* cover open NI */
#define RLDS_HD         0000100                         /* head select ^ */
#define RLDS_RL02       0000200                         /* RL02 */
#define RLDS_DSE        0000400                         /* drv sel err NI */
#define RLDS_VCK        0001000                         /* vol check * */
#define RLDS_WGE        0002000                         /* wr gate err * */
#define RLDS_SPE        0004000                         /* spin err * */
#define RLDS_STO        0010000                         /* seek time out NI */
#define RLDS_WLK        0020000                         /* wr locked */
#define RLDS_HCE        0040000                         /* hd curr err NI */
#define RLDS_WDE        0100000                         /* wr data err NI */
#define RLDS_ATT        (RLDS_HDO+RLDS_BHO+RLDS_LOCK)   /* att status */
#define RLDS_UNATT      (RLDS_CVO+RLDS_LOAD)            /* unatt status */
#define RLDS_ERR        (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
                         RLDS_VCK+RLDS_DSE)             /* errors bits */

/* RLCSA, seek = offset/rw = address (also uptr->TRK) */

#define RLCSA_DIR       04000                           /* direction */
#define RLCSA_HD        02000                           /* head select */
#define RLCSA_CYL       00777                           /* cyl offset */
#define GET_CYL(x)      ((x) & RLCSA_CYL)
#define GET_TRK(x)      ((((x) & RLCSA_CYL) * RL_NUMSF) + \
                        (((x) & RLCSA_HD)? 1: 0))
#define GET_DA(x)       ((GET_TRK(x) * RL_NUMSC) + rlsa)

/* RLCSB, function/unit select */

#define RLCSB_V_FUNC    0                               /* function */
#define RLCSB_M_FUNC    07
#define  RLCSB_MNT      0
#define  RLCSB_CLRD     1
#define  RLCSB_GSTA     2
#define  RLCSB_SEEK     3
#define  RLCSB_RHDR     4
#define  RLCSB_WRITE    5
#define  RLCSB_READ     6
#define  RLCSB_RNOHDR   7
#define RLCSB_V_MEX     3                               /* memory extension */
#define RLCSB_M_MEX     07
#define RLCSB_V_DRIVE   6                               /* drive */
#define RLCSB_M_DRIVE   03
#define RLCSB_V_IE      8                               /* int enable */
#define RLCSB_IE        (1u << RLCSB_V_IE)
#define RLCSB_8B        01000                           /* 12b/8b */
#define RCLS_MNT        02000                           /* maint NI */
#define RLCSB_RW        0001777                         /* read/write */
#define GET_FUNC(x)     (((x) >> RLCSB_V_FUNC) & RLCSB_M_FUNC)
#define GET_MEX(x)      (((x) >> RLCSB_V_MEX) & RLCSB_M_MEX)
#define GET_DRIVE(x)    (((x) >> RLCSB_V_DRIVE) & RLCSB_M_DRIVE)

/* RLSA, disk sector */

#define RLSA_V_SECT     6                               /* sector */
#define RLSA_M_SECT     077
#define GET_SECT(x)     (((x) >> RLSA_V_SECT) & RLSA_M_SECT)

/* RLER, error register */

#define RLER_DRDY       00001                           /* drive ready */
#define RLER_DRE        00002                           /* drive error */
#define RLER_HDE        01000                           /* header error */
#define RLER_INCMP      02000                           /* incomplete */
#define RLER_ICRC       04000                           /* CRC error */
#define RLER_MASK       07003

/* RLSI, silo register, used only in read header */

#define RLSI_V_TRK      6                               /* track */

extern uint16 M[];
extern int32 int_req;
extern UNIT cpu_unit;

uint8 *rlxb = NULL;                                     /* xfer buffer */
int32 rlcsa = 0;                                        /* control/status A */
int32 rlcsb = 0;                                        /* control/status B */
int32 rlma = 0;                                         /* memory address */
int32 rlwc = 0;                                         /* word count */
int32 rlsa = 0;                                         /* sector address */
int32 rler = 0;                                         /* error register */
int32 rlsi = 0, rlsi1 = 0, rlsi2 = 0;                   /* silo queue */
int32 rl_lft = 0;                                       /* silo left/right */
int32 rl_done = 0;                                      /* done flag */
int32 rl_erf = 0;                                       /* error flag */
int32 rl_swait = 10;                                    /* seek wait */
int32 rl_rwait = 10;                                    /* rotate wait */
int32 rl_stopioe = 1;                                   /* stop on error */

int32 rl60 (int32 IR, int32 AC);
int32 rl61 (int32 IR, int32 AC);
t_stat rl_svc (UNIT *uptr);
t_stat rl_reset (DEVICE *dptr);
void rl_set_done (int32 error);
t_stat rl_boot (int32 unitno, DEVICE *dptr);
t_stat rl_attach (UNIT *uptr, CONST char *cptr);
t_stat rl_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat rl_set_bad (UNIT *uptr, int32 val, CONST char *cptr, void *desc);

/* RL8A data structures

   rl_dev       RL device descriptor
   rl_unit      RL unit list
   rl_reg       RL register list
   rl_mod       RL modifier list
*/

DIB rl_dib = { DEV_RL, 2, { &rl60, &rl61 } };

UNIT rl_unit[] = {
    { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
             UNIT_ROABLE, RL01_SIZE) },
    { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
             UNIT_ROABLE, RL01_SIZE) },
    { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
             UNIT_ROABLE, RL01_SIZE) },
    { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
             UNIT_ROABLE, RL01_SIZE) }
    };

REG rl_reg[] = {
    { ORDATAD (RLCSA, rlcsa, 12, "control/status A") },
    { ORDATAD (RLCSB, rlcsb, 12, "control/status B") },
    { ORDATAD (RLMA, rlma, 12, "memory address") },
    { ORDATAD (RLWC, rlwc, 12, "word count") },
    { ORDATAD (RLSA, rlsa, 6, "sector address") },
    { ORDATAD (RLER, rler, 12, "error flags") },
    { ORDATAD (RLSI, rlsi, 16, "silo top word") },
    { ORDATAD (RLSI1, rlsi1, 16, "silo second word") },
    { ORDATAD (RLSI2, rlsi2, 16, "silo third word") },
    { FLDATAD (RLSIL, rl_lft, 0, "silo read left/right flag") },
    { FLDATAD (INT, int_req, INT_V_RL, "interrupt request") },
    { FLDATAD (DONE, rl_done, INT_V_RL, "done flag") },
    { FLDATA (IE, rlcsb, RLCSB_V_IE) },
    { FLDATAD (ERR, rl_erf, 0, "composite error flag") },
    { DRDATAD (STIME, rl_swait, 24, "seek time, per cylinder"), PV_LEFT },
    { DRDATAD (RTIME, rl_rwait, 24, "rotational delay"), PV_LEFT },
    { URDATA (CAPAC, rl_unit[0].capac, 10, T_ADDR_W, 0,
              RL_NUMDR, PV_LEFT + REG_HRO) },
    { FLDATAD (STOP_IOE, rl_stopioe, 0, "stop on I/O error") },
    { ORDATA (DEVNUM, rl_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB rl_mod[] = {
    { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
    { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
    { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad },
    { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
    { (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
    { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL },
    { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL },
    { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
    { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
    { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size },
    { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE rl_dev = {
    "RL", rl_unit, rl_reg, rl_mod,
    RL_NUMDR, 8, 24, 1, 8, 8,
    NULL, NULL, &rl_reset,
    &rl_boot, &rl_attach, NULL,
    &rl_dib, DEV_DISABLE | DEV_DIS
    };

/* IOT routines */

int32 rl60 (int32 IR, int32 AC)
{
int32 curr, offs, newc, maxc;
UNIT *uptr;

switch (IR & 07) {                                      /* case IR<9:11> */

    case 0:                                             /* RLDC */
        rl_reset (&rl_dev);                             /* reset device */
        break;

    case 1:                                             /* RLSD */
        if (rl_done)                                    /* skip if done */
            AC = IOT_SKP;
        else AC = 0;
        rl_done = 0;                                    /* clear done */
        int_req = int_req & ~INT_RL;                    /* clear intr */
        return AC;

    case 2:                                             /* RLMA */
        rlma = AC;
        break;

    case 3:                                             /* RLCA */
        rlcsa = AC;
        break;

    case 4:                                             /* RLCB */
        rlcsb = AC;
        rl_done = 0;                                    /* clear done */
        rler = rl_erf = 0;                              /* clear errors */
        int_req = int_req & ~INT_RL;                    /* clear intr */
        rl_lft = 0;                                     /* clear silo ptr */
        uptr = rl_dev.units + GET_DRIVE (rlcsb);        /* select unit */
        switch (GET_FUNC (rlcsb)) {                     /* case on func */

        case RLCSB_CLRD:                                /* clear drive */
            uptr->STAT = uptr->STAT & ~RLDS_ERR;        /* clear errors */
        case RLCSB_MNT:                                 /* mnt */
            rl_set_done (0);
            break;

        case RLCSB_SEEK:                                /* seek */
            curr = GET_CYL (uptr->TRK);                 /* current cylinder */
            offs = GET_CYL (rlcsa);                     /* offset */
            if (rlcsa & RLCSA_DIR) {                    /* in or out? */
                newc = curr + offs;                     /* out */
                maxc = (uptr->flags & UNIT_RL02)?
                        RL_NUMCY * 2: RL_NUMCY;
                if (newc >= maxc) newc = maxc - 1;
                }
            else {
                newc = curr - offs;                     /* in */
                if (newc < 0) newc = 0;
                }
            uptr->TRK = newc | (rlcsa & RLCSA_HD);
            sim_activate (uptr, rl_swait * abs (newc - curr));
            break;

        default:                                        /* data transfer */
            sim_activate (uptr, rl_swait);              /* activate unit */
            break;
            }                                           /* end switch func */
        break;

    case 5:                                             /* RLSA */
        rlsa = GET_SECT (AC);
        break;

    case 6:                                             /* spare */
        return 0;

    case 7:                                             /* RLWC */
        rlwc = AC;
        break;
        }                                               /* end switch pulse */

return 0;                                               /* clear AC */
}

int32 rl61 (int32 IR, int32 AC)
{
int32 dat;
UNIT *uptr;

switch (IR & 07) {                                      /* case IR<9:11> */

    case 0:                                             /* RRER */
        uptr = rl_dev.units + GET_DRIVE (rlcsb);        /* select unit */
        if (!sim_is_active (uptr) &&                    /* update drdy */
            (uptr->flags & UNIT_ATT))
            rler = rler | RLER_DRDY;
        else rler = rler & ~RLER_DRDY;
        dat = rler & RLER_MASK;
        break;

    case 1:                                             /* RRWC */
        dat = rlwc;
        break;

    case 2:                                             /* RRCA */
        dat = rlcsa;
        break;

    case 3:                                             /* RRCB */
        dat = rlcsb;
        break;

    case 4:                                             /* RRSA */
        dat = (rlsa << RLSA_V_SECT) & 07777;
        break;

    case 5:                                             /* RRSI */
        if (rl_lft) {                                   /* silo left? */
            dat = (rlsi >> 8) & 0377;                   /* get left 8b */
            rlsi = rlsi1;                               /* ripple */
            rlsi1 = rlsi2;
            }
        else dat = rlsi & 0377;                         /* get right 8b */
        rl_lft = rl_lft ^ 1;                            /* change side */
        break;

    case 6:                                             /* spare */
        return AC;

    case 7:                                             /* RLSE */
        if (rl_erf)                                     /* skip if err */
            dat = IOT_SKP | AC;
        else dat = AC;
        rl_erf = 0;
        break;
        }                                               /* end switch pulse */

return dat;
}

/* Service unit timeout

   If seek in progress, complete seek command
   Else complete data transfer command

   The unit control block contains the function and cylinder for
   the current command.
*/

t_stat rl_svc (UNIT *uptr)
{
int32 err, wc, maxc;
int32 i, j, func, da, bc, wbc;
uint32 ma;

func = GET_FUNC (rlcsb);                                /* get function */
if (func == RLCSB_GSTA) {                               /* get status? */
    rlsi = uptr->STAT | 
        ((uptr->TRK & RLCSA_HD)? RLDS_HD: 0) |
        ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
    if (uptr->flags & UNIT_RL02)
        rlsi = rlsi | RLDS_RL02;
    if (uptr->flags & UNIT_WPRT)
        rlsi = rlsi | RLDS_WLK;
    rlsi2 = rlsi1 = rlsi;
    rl_set_done (0);                                    /* done */
    return SCPE_OK;
    }

if ((uptr->flags & UNIT_ATT) == 0) {                    /* attached? */
    uptr->STAT = uptr->STAT | RLDS_SPE;                 /* spin error */
    rl_set_done (RLER_INCMP);                           /* flag error */
    return IORETURN (rl_stopioe, SCPE_UNATT);
    }

if ((func == RLCSB_WRITE) && (uptr->flags & UNIT_WPRT)) {
    uptr->STAT = uptr->STAT | RLDS_WGE;                 /* write and locked */
    rl_set_done (RLER_DRE);                             /* flag error */
    return SCPE_OK;
    }

if (func == RLCSB_SEEK) {                               /* seek? */
    rl_set_done (0);                                    /* done */
    return SCPE_OK;
    }

if (func == RLCSB_RHDR) {                               /* read header? */
    rlsi = (GET_TRK (uptr->TRK) << RLSI_V_TRK) | rlsa;
    rlsi1 = rlsi2 = 0;
    rl_set_done (0);                                    /* done */
    return SCPE_OK;
    }

if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr->TRK) != GET_CYL (rlcsa)))
   || (rlsa >= RL_NUMSC)) {                             /* bad cyl or sector? */
    rl_set_done (RLER_HDE | RLER_INCMP);                /* flag error */
    return SCPE_OK;
    }
    
ma = (GET_MEX (rlcsb) << 12) | rlma;                    /* get mem addr */
da = GET_DA (rlcsa) * RL_NUMBY;                         /* get disk addr */
wc = 010000 - rlwc;                                     /* get true wc */
if (rlcsb & RLCSB_8B) {                                 /* 8b mode? */
    bc = wc;                                            /* bytes to xfr */
    maxc = (RL_NUMSC - rlsa) * RL_NUMBY;                /* max transfer */
    if (bc > maxc)                                      /* trk ovrun? limit */
        wc = bc = maxc;
    }
else {
    bc = ((wc * 3) + 1) / 2;                            /* 12b mode */
    if (bc > RL_NUMBY) {                                /* > 1 sector */
        bc = RL_NUMBY;                                  /* cap xfer */
        wc = (RL_NUMBY * 2) / 3;
        }
    }

err = fseek (uptr->fileref, da, SEEK_SET);

if ((func >= RLCSB_READ) && (err == 0) &&               /* read (no hdr)? */
    MEM_ADDR_OK (ma)) {                                 /* valid bank? */
    i = fxread (rlxb, sizeof (int8), bc, uptr->fileref);
    err = ferror (uptr->fileref);
    for ( ; i < bc; i++)                                /* fill buffer */
        rlxb[i] = 0;
    for (i = j = 0; i < wc; i++) {                      /* store buffer */
        if (rlcsb & RLCSB_8B)                           /* 8b mode? */
            M[ma] = rlxb[i] & 0377;                     /* store */
        else if (i & 1) {                               /* odd wd 12b? */
            M[ma] = ((rlxb[j + 1] >> 4) & 017) |
                (((uint16) rlxb[j + 2]) << 4);
            j = j + 3;
            }
        else M[ma] = rlxb[j] |                          /* even wd 12b */
            ((((uint16) rlxb[j + 1]) & 017) << 8);      
        ma = (ma & 070000) + ((ma + 1) & 07777);
        }                                               /* end for */
    }                                                   /* end if wr */

if ((func == RLCSB_WRITE) && (err == 0)) {              /* write? */
    for (i = j = 0; i < wc; i++) {                      /* fetch buffer */
        if (rlcsb & RLCSB_8B)                           /* 8b mode? */
            rlxb[i] = M[ma] & 0377;                     /* fetch */
        else if (i & 1) {                               /* odd wd 12b? */
            rlxb[j + 1] = rlxb[j + 1] | ((M[ma] & 017) << 4);
            rlxb[j + 2] = ((M[ma] >> 4) & 0377);
            j = j + 3;
            }
        else {                                          /* even wd 12b */
            rlxb[j] = M[ma] & 0377;
            rlxb[j + 1] = (M[ma] >> 8) & 017;
            }
        ma = (ma & 070000) + ((ma + 1) & 07777);
        }                                               /* end for */
    wbc = (bc + (RL_NUMBY - 1)) & ~(RL_NUMBY - 1);      /* clr to */
    for (i = bc; i < wbc; i++)                          /* end of blk */
        rlxb[i] = 0;
    fxwrite (rlxb, sizeof (int8), wbc, uptr->fileref);
    err = ferror (uptr->fileref);
    }                                                   /* end write */

rlwc = (rlwc + wc) & 07777;                             /* final word count */
if (rlwc != 0)                                          /* completed? */
    rler = rler | RLER_INCMP;
rlma = (rlma + wc) & 07777;                             /* final word addr */
rlsa = rlsa + ((bc + (RL_NUMBY - 1)) / RL_NUMBY);
rl_set_done (0);

if (err != 0) {                                         /* error? */
    sim_perror ("RL I/O error");
    clearerr (uptr->fileref);
    return SCPE_IOERR;
    }
return SCPE_OK;
}

/* Set done and possibly errors */

void rl_set_done (int32 status)
{
rl_done = 1;
rler = rler | status;
if (rler)
    rl_erf = 1;
if (rlcsb & RLCSB_IE)
    int_req = int_req | INT_RL;
else int_req = int_req & ~INT_RL;
return;
}

/* Device reset

   Note that the RL8A does NOT recalibrate its drives on RESET
*/

t_stat rl_reset (DEVICE *dptr)
{
int32 i;
UNIT *uptr;

rlcsa = rlcsb = rlsa = rler = 0;
rlma = rlwc = 0;
rlsi = rlsi1 = rlsi2 = 0;
rl_lft = 0;
rl_done = 0;
rl_erf = 0;
int_req = int_req & ~INT_RL;
for (i = 0; i < RL_NUMDR; i++) {
    uptr = rl_dev.units + i;
    sim_cancel (uptr);
    uptr->STAT = 0;
    }
if (rlxb == NULL)
    rlxb = (uint8 *) calloc (RL_MAXFR, sizeof (uint8));
if (rlxb == NULL)
    return SCPE_MEM;
return SCPE_OK;
}

/* Attach routine */

t_stat rl_attach (UNIT *uptr, CONST char *cptr)
{
uint32 p;
t_stat r;

uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
r = attach_unit (uptr, cptr);                           /* attach unit */
if (r != SCPE_OK)                                       /* error? */
    return r;
uptr->TRK = 0;                                          /* cyl 0 */
uptr->STAT = RLDS_VCK;                                  /* new volume */
if ((p = sim_fsize (uptr->fileref)) == 0) {             /* new disk image? */
    if (uptr->flags & UNIT_RO)
        return SCPE_OK;
    return rl_set_bad (uptr, 0, NULL, NULL);
    }
if ((uptr->flags & UNIT_AUTO) == 0)                     /* autosize? */
    return r;
if (p > (RL01_SIZE * sizeof (int16))) {
    uptr->flags = uptr->flags | UNIT_RL02;
    uptr->capac = RL02_SIZE;
    }
else {
    uptr->flags = uptr->flags & ~UNIT_RL02;
    uptr->capac = RL01_SIZE;
    }
return SCPE_OK;
}

/* Set size routine */

t_stat rl_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;
uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
return SCPE_OK;
}

/* Factory bad block table creation routine

   This routine writes the OS/8 specific bad block map in track 0, sector 014 (RL_BBMAP):

        words 0 magic number = 0123 (RL_BBID)
        words 1-n       block numbers
         :
        words n+1       end of table = 0

   Inputs:
        uptr    =       pointer to unit
        val     =       ignored
   Outputs:
        sta     =       status code
*/

t_stat rl_set_bad (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i, da = RL_BBMAP * RL_NUMBY;

if ((uptr->flags & UNIT_ATT) == 0)
    return SCPE_UNATT;
if (uptr->flags & UNIT_RO)
    return SCPE_RO;
if (!get_yn ("Create bad block table? [N]", FALSE))
    return SCPE_OK;
if (fseek (uptr->fileref, da, SEEK_SET))
    return SCPE_IOERR;
rlxb[0] = RL_BBID;
for (i = 1; i < RL_NUMBY; i++)
    rlxb[i] = 0;
fxwrite (rlxb, sizeof (uint8), RL_NUMBY, uptr->fileref);
if (ferror (uptr->fileref))
    return SCPE_IOERR;
return SCPE_OK;
}

/* Bootstrap */

#define BOOT_START 1                                    /* start */
#define BOOT_UNIT 02006                                 /* unit number */
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))

static const uint16 boot_rom[] = {
    06600,                      /* BT, RLDC             ; reset */
    07201,                      /* 02, CLA IAC          ; clr drv = 1 */
    04027,                      /* 03, JMS GO           ; do io */
    01004,                      /* 04, TAD 4            ; rd hdr fnc */
    04027,                      /* 05, JMS GO           ; do io */
    06615,                      /* 06, RRSI             ; rd hdr lo */
    07002,                      /* 07, BSW              ; swap */
    07012,                      /* 10, RTR              ; lo cyl to L */
    06615,                      /* 11, RRSI             ; rd hdr hi */
    00025,                      /* 12, AND 25           ; mask = 377 */
    07004,                      /* 13, RTL              ; get cyl */
    06603,                      /* 14, RLCA             ; set addr */
    07325,                      /* 15, CLA STL IAC RAL  ; seek = 3 */
    04027,                      /* 16, JMS GO           ; do io */
    07332,                      /* 17, CLA STL RTR      ; dir in = 2000 */
    06605,                      /* 20, RLSA             ; sector */             
    01026,                      /* 21, TAD (-200)       ; one sector */
    06607,                      /* 22, RLWC             ; word cnt */
    07327,                      /* 23, CLA STL IAC RTL  ; read = 6*/
    04027,                      /* 24, JMS GO           ; do io */
    00377,                      /* 25, JMP 377          ; start */
    07600,                      /* 26, -200             ; word cnt */
    00000,                      /* GO, 0                ; subr */
    06604,                      /* 30, RLCB             ; load fnc */
    06601,                      /* 31, RLSD             ; wait */
    05031,                      /* 32, JMP .-1          ; */
    06617,                      /* 33, RLSE             ; error? */
    05427,                      /* 34, JMP I GO         ; no, ok */
    05001                       /* 35, JMP BT           ; restart */
    };


t_stat rl_boot (int32 unitno, DEVICE *dptr)
{
size_t i;

if (unitno)                                             /* only unit 0 */
    return SCPE_ARG;
if (rl_dib.dev != DEV_RL)                               /* only std devno */
    return STOP_NOTSTD;
rl_unit[unitno].TRK = 0;
for (i = 0; i < BOOT_LEN; i++)
    M[BOOT_START + i] = boot_rom[i];
cpu_set_bootpc (BOOT_START);
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_rx.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
/* pdp8_rx.c: RX8E/RX01, RX28/RX02 floppy disk simulator

   Copyright (c) 1993-2013, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   rx           RX8E/RX01, RX28/RX02 floppy disk

   17-Sep-13    RMS     Changed to use central set_bootpc routine
   03-Sep-13    RMS     Added explicit void * cast
   15-May-06    RMS     Fixed bug in autosize attach (Dave Gesswein)
   04-Jan-04    RMS     Changed sim_fsize calling sequence
   05-Nov-03    RMS     Fixed bug in RX28 read status (Charles Dickman)
   26-Oct-03    RMS     Cleaned up buffer copy code, fixed double density write
   25-Apr-03    RMS     Revised for extended file support
   14-Mar-03    RMS     Fixed variable size interaction with save/restore
   03-Mar-03    RMS     Fixed autosizing
   08-Oct-02    RMS     Added DIB, device number support
                        Fixed reset to work with disabled device
   15-Sep-02    RMS     Added RX28/RX02 support
   06-Jan-02    RMS     Changed enable/disable support
   30-Nov-01    RMS     Added read only unit, extended SET/SHOW support
   24-Nov-01    RMS     Converted FLG to array
   17-Jul-01    RMS     Fixed warning from VC++ 6
   26-Apr-01    RMS     Added device enable/disable support
   13-Apr-01    RMS     Revised for register arrays
   14-Apr-99    RMS     Changed t_addr to unsigned
   15-Aug-96    RMS     Fixed bug in LCD

   An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B.
   An RX02 diskette consists of 77 tracks, each with 26 sectors of 128B
   (single density) or 256B (double density).  Tracks are numbered 0-76,
   sectors 1-26.  The RX8E (RX28) can store data in 8b mode or 12b mode.
   In 8b mode, the controller reads or writes 128 bytes (128B or 256B)
   per sector.  In 12b mode, it reads or writes 64 (64 or 128) 12b words
   per sector.  The 12b words are bit packed into the first 96 (192) bytes
   of the sector; the last 32 (64) bytes are zeroed on writes.
*/

#include "pdp8_defs.h"

#define RX_NUMTR        77                              /* tracks/disk */
#define RX_M_TRACK      0377
#define RX_NUMSC        26                              /* sectors/track */
#define RX_M_SECTOR     0177                            /* cf Jones!! */
#define RX_NUMBY        128                             /* bytes/sector */
#define RX2_NUMBY       256
#define RX_NUMWD        (RX_NUMBY / 2)                  /* words/sector */
#define RX2_NUMWD       (RX2_NUMBY / 2)
#define RX_SIZE         (RX_NUMTR * RX_NUMSC * RX_NUMBY)        /* bytes/disk */
#define RX2_SIZE        (RX_NUMTR * RX_NUMSC * RX2_NUMBY)
#define RX_NUMDR        2                               /* drives/controller */
#define RX_M_NUMDR      01
#define UNIT_V_WLK      (UNIT_V_UF + 0)                 /* write locked */
#define UNIT_V_DEN      (UNIT_V_UF + 1)                 /* double density */
#define UNIT_V_AUTO     (UNIT_V_UF + 2)                 /* autosize */
#define UNIT_WLK        (1u << UNIT_V_WLK)
#define UNIT_DEN        (1u << UNIT_V_DEN)
#define UNIT_AUTO       (1u << UNIT_V_AUTO)
#define UNIT_WPRT       (UNIT_WLK | UNIT_RO)            /* write protect */

#define IDLE            0                               /* idle state */
#define CMD8            1                               /* 8b cmd, ho next */
#define RWDS            2                               /* rw, sect next */
#define RWDT            3                               /* rw, track next */
#define RWXFR           4                               /* rw, transfer */
#define FILL            5                               /* fill buffer */
#define EMPTY           6                               /* empty buffer */
#define SDCNF           7                               /* set dens, conf next */
#define SDXFR           8                               /* set dens, transfer */
#define CMD_COMPLETE    9                               /* set done next */
#define INIT_COMPLETE   10                              /* init compl next */

#define RXCS_V_FUNC     1                               /* function */
#define RXCS_M_FUNC     7
#define  RXCS_FILL      0                               /* fill buffer */
#define  RXCS_EMPTY     1                               /* empty buffer */
#define  RXCS_WRITE     2                               /* write sector */
#define  RXCS_READ      3                               /* read sector */
#define  RXCS_SDEN      4                               /* set density (RX28) */
#define  RXCS_RXES      5                               /* read status */
#define  RXCS_WRDEL     6                               /* write del data */
#define  RXCS_ECODE     7                               /* read error code */
#define RXCS_DRV        0020                            /* drive */
#define RXCS_MODE       0100                            /* mode */
#define RXCS_MAINT      0200                            /* maintenance */
#define RXCS_DEN        0400                            /* density (RX28) */
#define RXCS_GETFNC(x)  (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC)

#define RXES_CRC        0001                            /* CRC error NI */
#define RXES_ID         0004                            /* init done */
#define RXES_RX02       0010                            /* RX02 (RX28) */
#define RXES_DERR       0020                            /* density err (RX28) */
#define RXES_DEN        0040                            /* density (RX28) */
#define RXES_DD         0100                            /* deleted data */
#define RXES_DRDY       0200                            /* drive ready */

#define TRACK u3                                        /* current track */
#define READ_RXDBR      ((rx_csr & RXCS_MODE)? AC | (rx_dbr & 0377): rx_dbr)
#define CALC_DA(t,s,b)  (((t) * RX_NUMSC) + ((s) - 1)) * b

extern int32 int_req, int_enable, dev_done;

int32 rx_28 = 0;                                        /* controller type */
int32 rx_tr = 0;                                        /* xfer ready flag */
int32 rx_err = 0;                                       /* error flag */
int32 rx_csr = 0;                                       /* control/status */
int32 rx_dbr = 0;                                       /* data buffer */
int32 rx_esr = 0;                                       /* error status */
int32 rx_ecode = 0;                                     /* error code */
int32 rx_track = 0;                                     /* desired track */
int32 rx_sector = 0;                                    /* desired sector */
int32 rx_state = IDLE;                                  /* controller state */
int32 rx_cwait = 100;                                   /* command time */
int32 rx_swait = 10;                                    /* seek, per track */
int32 rx_xwait = 1;                                     /* tr set time */
int32 rx_stopioe = 0;                                   /* stop on error */
uint8 rx_buf[RX2_NUMBY] = { 0 };                        /* sector buffer */
int32 rx_bptr = 0;                                      /* buffer pointer */

int32 rx (int32 IR, int32 AC);
t_stat rx_svc (UNIT *uptr);
t_stat rx_reset (DEVICE *dptr);
t_stat rx_boot (int32 unitno, DEVICE *dptr);
t_stat rx_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat rx_attach (UNIT *uptr, CONST char *cptr);
void rx_cmd (void);
void rx_done (int32 esr_flags, int32 new_ecode);
t_stat rx_settype (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, CONST void *desc);

/* RX8E data structures

   rx_dev       RX device descriptor
   rx_unit      RX unit list
   rx_reg       RX register list
   rx_mod       RX modifier list
*/

DIB rx_dib = { DEV_RX, 1, { &rx } };

UNIT rx_unit[] = {
    { UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+
             UNIT_ROABLE, RX_SIZE) },
    { UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+
             UNIT_ROABLE, RX_SIZE) }
    };

REG rx_reg[] = {
    { ORDATAD (RXCS, rx_csr, 12, "status") },
    { ORDATAD (RXDB, rx_dbr, 12, "data buffer") },
    { ORDATAD (RXES, rx_esr, 12, "error status") },
    { ORDATA (RXERR, rx_ecode, 8) },
    { ORDATAD (RXTA, rx_track, 8, "current track") },
    { ORDATAD (RXSA, rx_sector, 8, "current sector") },
    { DRDATAD (STAPTR, rx_state, 4, "controller state"), REG_RO },
    { DRDATAD (BUFPTR, rx_bptr, 8, "buffer pointer")  },
    { FLDATAD (TR, rx_tr, 0, "transfer ready flag") },
    { FLDATAD (ERR, rx_err, 0, "error flag") },
    { FLDATAD (DONE, dev_done, INT_V_RX, "done flag") },
    { FLDATAD (ENABLE, int_enable, INT_V_RX, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_RX, "interrupt pending flag") },
    { DRDATAD (CTIME, rx_cwait, 24, "command completion time"), PV_LEFT },
    { DRDATAD (STIME, rx_swait, 24, "seek time per track"), PV_LEFT },
    { DRDATAD (XTIME, rx_xwait, 24, "transfer ready delay"), PV_LEFT },
    { FLDATAD (STOP_IOE, rx_stopioe, 0, "stop on I/O error") },
    { BRDATAD (SBUF, rx_buf, 8, 8, RX2_NUMBY, "sector buffer array") },
    { FLDATA (RX28, rx_28, 0), REG_HRO },
    { URDATA (CAPAC, rx_unit[0].capac, 10, T_ADDR_W, 0,
              RX_NUMDR, REG_HRO | PV_LEFT) },
    { ORDATA (DEVNUM, rx_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB rx_mod[] = {
    { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
    { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
    { MTAB_XTD | MTAB_VDV, 1, NULL, "RX28", &rx_settype, NULL, NULL },
    { MTAB_XTD | MTAB_VDV, 0, NULL, "RX8E", &rx_settype, NULL, NULL },
    { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &rx_showtype, NULL },
    { (UNIT_DEN+UNIT_ATT), UNIT_ATT, "single density", NULL, NULL },
    { (UNIT_DEN+UNIT_ATT), (UNIT_DEN+UNIT_ATT), "double density", NULL, NULL },
    { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), 0, "single density", NULL, NULL },
    { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), UNIT_DEN, "double density", NULL, NULL },
    { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
    { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
    { (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &rx_set_size },
    { (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &rx_set_size },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { 0 }
    };

DEVICE rx_dev = {
    "RX", rx_unit, rx_reg, rx_mod,
    RX_NUMDR, 8, 20, 1, 8, 8,
    NULL, NULL, &rx_reset,
    &rx_boot, &rx_attach, NULL,
    &rx_dib, DEV_DISABLE
    };

/* IOT routine */

int32 rx (int32 IR, int32 AC)
{
int32 drv = ((rx_csr & RXCS_DRV)? 1: 0);                /* get drive number */

switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* unused */
        break;

    case 1:                                             /* LCD */
        if (rx_state != IDLE)                           /* ignore if busy */
            return AC;
        dev_done = dev_done & ~INT_RX;                  /* clear done, int */
        int_req = int_req & ~INT_RX;
        rx_tr = rx_err = 0;                             /* clear flags */
        rx_bptr = 0;                                    /* clear buf pointer */
        if (rx_28 && (AC & RXCS_MODE)) {                /* RX28 8b mode? */
            rx_dbr = rx_csr = AC & 0377;                /* save 8b */
            rx_tr = 1;                                  /* xfer is ready */
            rx_state = CMD8;                            /* wait for part 2 */
            }
        else {
            rx_dbr = rx_csr = AC;                       /* save new command */
            rx_cmd ();                                  /* issue command */
            }
        return 0;                                       /* clear AC */

    case 2:                                             /* XDR */
        switch (rx_state & 017) {                       /* case on state */

        case EMPTY:                                     /* emptying buffer */
            sim_activate (&rx_unit[drv], rx_xwait);     /* sched xfer */
            return READ_RXDBR;                          /* return data reg */

        case CMD8:                                      /* waiting for cmd */
            rx_dbr = AC & 0377;
            rx_csr = (rx_csr & 0377) | ((AC & 017) << 8);
            rx_cmd ();
            break;

        case RWDS:case RWDT:case FILL:case SDCNF:       /* waiting for data */
            rx_dbr = AC;                                /* save data */
            sim_activate (&rx_unit[drv], rx_xwait);     /* schedule */
            break;

        default:                                        /* default */
            return READ_RXDBR;                          /* return data reg */
            }
        break;

    case 3:                                             /* STR */
        if (rx_tr != 0) {
            rx_tr = 0;
            return IOT_SKP + AC;
            }
        break;

    case 4:                                             /* SER */
        if (rx_err != 0) {
            rx_err = 0;
            return IOT_SKP + AC;
            }
        break;

    case 5:                                             /* SDN */
        if ((dev_done & INT_RX) != 0) {
            dev_done = dev_done & ~INT_RX;
            int_req = int_req & ~INT_RX;
            return IOT_SKP + AC;
            }
        break;

    case 6:                                             /* INTR */
        if (AC & 1)
            int_enable = int_enable | INT_RX;
        else int_enable = int_enable & ~INT_RX;
        int_req = INT_UPDATE;
        break;

    case 7:                                             /* INIT */
        rx_reset (&rx_dev);                             /* reset device */
        break;
        }                                               /* end case pulse */

return AC;
}

void rx_cmd (void)
{
int32 drv = ((rx_csr & RXCS_DRV)? 1: 0);                /* get drive number */

switch (RXCS_GETFNC (rx_csr)) {                         /* decode command */

    case RXCS_FILL:
        rx_state = FILL;                                /* state = fill */
        rx_tr = 1;                                      /* xfer is ready */
        rx_esr = rx_esr & RXES_ID;                      /* clear errors */
        break;

    case RXCS_EMPTY:
        rx_state = EMPTY;                               /* state = empty */
        rx_esr = rx_esr & RXES_ID;                      /* clear errors */
        sim_activate (&rx_unit[drv], rx_xwait);         /* sched xfer */
        break;

    case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:
        rx_state = RWDS;                                /* state = get sector */
        rx_tr = 1;                                      /* xfer is ready */
        rx_esr = rx_esr & RXES_ID;                      /* clear errors */
        break;

    case RXCS_SDEN:
        if (rx_28) {                                    /* RX28? */
            rx_state = SDCNF;                           /* state = get conf */
            rx_tr = 1;                                  /* xfer is ready */
            rx_esr = rx_esr & RXES_ID;                  /* clear errors */
            break;
            }                                           /* else fall thru */
    default:
        rx_state = CMD_COMPLETE;                        /* state = cmd compl */
        sim_activate (&rx_unit[drv], rx_cwait);         /* sched done */
        break;
        }                                               /* end switch func */

return;
}

/* Unit service; the action to be taken depends on the transfer state:

   IDLE         Should never get here
   RWDS         Save sector, set TR, set RWDT
   RWDT         Save track, set RWXFR
   RWXFR        Read/write buffer
   FILL         copy dbr to rx_buf[rx_bptr], advance ptr
                if rx_bptr > max, finish command, else set tr
   EMPTY        if rx_bptr > max, finish command, else
                copy rx_buf[rx_bptr] to dbr, advance ptr, set tr
   CMD_COMPLETE copy requested data to dbr, finish command
   INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command

   For RWDT and CMD_COMPLETE, the input argument is the selected drive;
   otherwise, it is drive 0.
*/

t_stat rx_svc (UNIT *uptr)
{
int32 i, func, byptr, bps, wps;
int8 *fbuf = (int8 *) uptr->filebuf;
uint32 da;
#define PTR12(x) (((x) + (x) + (x)) >> 1)

if (rx_28 && (uptr->flags & UNIT_DEN))                  /* RX28 and double density? */
    bps = RX2_NUMBY;                                    /* double bytes/sector */
else bps = RX_NUMBY;                                    /* RX8E, normal count */
wps = bps / 2;
func = RXCS_GETFNC (rx_csr);                            /* get function */
switch (rx_state) {                                     /* case on state */

    case IDLE:                                          /* idle */
        return SCPE_IERR;

    case EMPTY:                                         /* empty buffer */
        if (rx_csr & RXCS_MODE) {                       /* 8b xfer? */
            if (rx_bptr >= bps) {                       /* done? */
                rx_done (0, 0);                         /* set done */
                break;                                  /* and exit */
                }
            rx_dbr = rx_buf[rx_bptr];                   /* else get data */
            }
        else {
            byptr = PTR12 (rx_bptr);                    /* 12b xfer */
            if (rx_bptr >= wps) {                       /* done? */
                rx_done (0, 0);                         /* set done */
                break;                                  /* and exit */
                }
            rx_dbr = (rx_bptr & 1)?                     /* get data */
                ((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]:
                (rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017);
            }
        rx_bptr = rx_bptr + 1;
        rx_tr = 1;
        break;

    case FILL:                                          /* fill buffer */
        if (rx_csr & RXCS_MODE) {                       /* 8b xfer? */
            rx_buf[rx_bptr] = rx_dbr;                   /* fill buffer */
            rx_bptr = rx_bptr + 1;
            if (rx_bptr < bps)                          /* if more, set xfer */
                rx_tr = 1;
            else rx_done (0, 0);                        /* else done */
            }
        else {
            byptr = PTR12 (rx_bptr);                    /* 12b xfer */
            if (rx_bptr & 1) {                          /* odd or even? */
                rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017);
                rx_buf[byptr + 1] = rx_dbr & 0377;
                }
            else {
                rx_buf[byptr] = (rx_dbr >> 4) & 0377;
                rx_buf[byptr + 1] = (rx_dbr & 017) << 4;
                }
            rx_bptr = rx_bptr + 1;
            if (rx_bptr < wps)                          /* if more, set xfer */
                rx_tr = 1;
            else {
                for (i = PTR12 (wps); i < bps; i++)
                    rx_buf[i] = 0;                      /* else fill sector */
                rx_done (0, 0);                         /* set done */
                }
            }
        break;

    case RWDS:                                          /* wait for sector */
        rx_sector = rx_dbr & RX_M_SECTOR;               /* save sector */
        rx_tr = 1;                                      /* set xfer ready */
        rx_state = RWDT;                                /* advance state */
        return SCPE_OK;

    case RWDT:                                          /* wait for track */
        rx_track = rx_dbr & RX_M_TRACK;                 /* save track */
        rx_state = RWXFR;
        sim_activate (uptr,                             /* sched done */
            rx_swait * abs (rx_track - uptr->TRACK));
        return SCPE_OK;

    case RWXFR:                                         /* transfer */
        if ((uptr->flags & UNIT_BUF) == 0) {            /* not buffered? */
            rx_done (0, 0110);                          /* done, error */
            return IORETURN (rx_stopioe, SCPE_UNATT);
            }
        if (rx_track >= RX_NUMTR) {                     /* bad track? */
            rx_done (0, 0040);                          /* done, error */
            break;
            }
        uptr->TRACK = rx_track;                         /* now on track */
        if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) {       /* bad sect? */
            rx_done (0, 0070);                          /* done, error */
            break;
            }
        if (rx_28 &&                                    /* RX28? */
            (((uptr->flags & UNIT_DEN) != 0) ^
             ((rx_csr & RXCS_DEN) != 0))) {             /* densities agree? */
            rx_done (RXES_DERR, 0240);                  /* no, error */
            break;
            }
        da = CALC_DA (rx_track, rx_sector, bps);        /* get disk address */
        if (func == RXCS_WRDEL)                         /* del data? */
            rx_esr = rx_esr | RXES_DD;
        if (func == RXCS_READ) {                        /* read? */
            for (i = 0; i < bps; i++) rx_buf[i] = fbuf[da + i];
            }
        else {                                          /* write */
            if (uptr->flags & UNIT_WPRT) {              /* locked? */
                rx_done (0, 0100);                      /* done, error */
                break;
                }
            for (i = 0; i < bps; i++)
                fbuf[da + i] = rx_buf[i];
            da = da + bps;
            if (da > uptr->hwmark)
                uptr->hwmark = da;
            }
        rx_done (0, 0);                                 /* done */
        break;

    case SDCNF:                                         /* confirm set density */
        if ((rx_dbr & 0377) != 0111) {                  /* confirmed? */
            rx_done (0, 0250);                          /* no, error */
            break;
            }
        rx_state = SDXFR;                               /* next state */
        sim_activate (uptr, rx_cwait * 100);            /* schedule operation */
        break;

    case SDXFR:                                         /* erase disk */
        for (i = 0; i < (int32) uptr->capac; i++)
            fbuf[i] = 0;
        uptr->hwmark = uptr->capac;
        if (rx_csr & RXCS_DEN)
            uptr->flags = uptr->flags | UNIT_DEN;
        else uptr->flags = uptr->flags & ~UNIT_DEN;
        rx_done (0, 0);
        break;

    case CMD_COMPLETE:                                  /* command complete */
        if (func == RXCS_ECODE) {                       /* read ecode? */
            rx_dbr = rx_ecode;                          /* set dbr */
            rx_done (0, -1);                            /* don't update */
            }
        else if (rx_28) {                               /* no, read sta; RX28? */
            rx_esr = rx_esr & ~RXES_DERR;               /* assume dens match */
            if (((uptr->flags & UNIT_DEN) != 0) ^       /* densities mismatch? */
                ((rx_csr & RXCS_DEN) != 0))
                rx_done (RXES_DERR, 0240);              /* yes, error */
            else rx_done (0, 0);                        /* no, ok */
            }
        else rx_done (0, 0);                            /* RX8E status */
        break;

    case INIT_COMPLETE:                                 /* init complete */
        rx_unit[0].TRACK = 1;                           /* drive 0 to trk 1 */
        rx_unit[1].TRACK = 0;                           /* drive 1 to trk 0 */
        if ((rx_unit[0].flags & UNIT_BUF) == 0) {       /* not buffered? */
            rx_done (RXES_ID, 0010);                    /* init done, error */
            break;
            }
        da = CALC_DA (1, 1, bps);                       /* track 1, sector 1 */
        for (i = 0; i < bps; i++)                       /* read sector */
            rx_buf[i] = fbuf[da + i];
        rx_done (RXES_ID, 0);                           /* set done */
        if ((rx_unit[1].flags & UNIT_ATT) == 0)
            rx_ecode = 0020;
        break;
        }                                               /* end case state */

return SCPE_OK;
}

/* Command complete.  Set done and put final value in interface register,
   return to IDLE state.
*/

void rx_done (int32 esr_flags, int32 new_ecode)
{
int32 drv = (rx_csr & RXCS_DRV)? 1: 0;

rx_state = IDLE;                                        /* now idle */
dev_done = dev_done | INT_RX;                           /* set done */
int_req = INT_UPDATE;                                   /* update ints */
rx_esr = (rx_esr | esr_flags) & ~(RXES_DRDY|RXES_RX02|RXES_DEN);
if (rx_28)                                              /* RX28? */
    rx_esr = rx_esr | RXES_RX02;
if (rx_unit[drv].flags & UNIT_ATT) {                    /* update drv rdy */
    rx_esr = rx_esr | RXES_DRDY;
    if (rx_unit[drv].flags & UNIT_DEN)                  /* update density */
        rx_esr = rx_esr | RXES_DEN;
    }
if (new_ecode > 0)                                      /* test for error */
    rx_err = 1;
if (new_ecode < 0)                                      /* don't update? */
    return;
rx_ecode = new_ecode;                                   /* update ecode */
rx_dbr = rx_esr;                                        /* update RXDB */
return;
}

/* Reset routine.  The RX is one of the few devices that schedules
   an I/O transfer as part of its initialization */

t_stat rx_reset (DEVICE *dptr)
{
rx_dbr = rx_csr = 0;                                    /* 12b mode, drive 0 */
rx_esr = rx_ecode = 0;                                  /* clear error */
rx_tr = rx_err = 0;                                     /* clear flags */
rx_track = rx_sector = 0;                               /* clear address */
rx_state = IDLE;                                        /* ctrl idle */
dev_done = dev_done & ~INT_RX;                          /* clear done, int */
int_req = int_req & ~INT_RX;
int_enable = int_enable & ~INT_RX;
sim_cancel (&rx_unit[1]);                               /* cancel drive 1 */
if (dptr->flags & DEV_DIS)                              /* disabled? */
    sim_cancel (&rx_unit[0]);
else if (rx_unit[0].flags & UNIT_BUF)  {                /* attached? */
    rx_state = INIT_COMPLETE;                           /* yes, sched init */
    sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK));
    }
else rx_done (rx_esr | RXES_ID, 0010);                  /* no, error */
return SCPE_OK;
}

/* Attach routine */

t_stat rx_attach (UNIT *uptr, CONST char *cptr)
{
uint32 sz;

if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
    if (sz > RX_SIZE)
        uptr->flags = uptr->flags | UNIT_DEN;
    else uptr->flags = uptr->flags & ~UNIT_DEN;
    }
uptr->capac = (uptr->flags & UNIT_DEN)? RX2_SIZE: RX_SIZE;
return attach_unit (uptr, cptr);
}

/* Set size routine */

t_stat rx_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;
if ((rx_28 == 0) && val)                                /* not on RX8E */
    return SCPE_NOFNC;
uptr->capac = val? RX2_SIZE: RX_SIZE;
return SCPE_OK;
}

/* Set controller type */

t_stat rx_settype (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i;

if ((val < 0) || (val > 1) || (cptr != NULL))
    return SCPE_ARG;
if (val == rx_28)
    return SCPE_OK;
for (i = 0; i < RX_NUMDR; i++) {
    if (rx_unit[i].flags & UNIT_ATT)
        return SCPE_ALATT;
    }
for (i = 0; i < RX_NUMDR; i++) {
    if (val)
        rx_unit[i].flags = rx_unit[i].flags | UNIT_DEN | UNIT_AUTO;
    else rx_unit[i].flags = rx_unit[i].flags & ~(UNIT_DEN | UNIT_AUTO);
    rx_unit[i].capac = val? RX2_SIZE: RX_SIZE;
    }
rx_28 = val;
return SCPE_OK;
}

/* Show controller type */

t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (rx_28) fprintf (st, "RX28");
else fprintf (st, "RX8E");
return SCPE_OK;
}

/* Bootstrap routine */

#define BOOT_START      022
#define BOOT_ENTRY      022
#define BOOT_INST       060
#define BOOT_LEN        (sizeof (boot_rom) / sizeof (int16))
#define BOOT2_START     020
#define BOOT2_ENTRY     033
#define BOOT2_LEN       (sizeof (boot2_rom) / sizeof (int16))

static const uint16 boot_rom[] = {
    06755,                      /* 22, SDN */
    05022,                      /* 23, JMP .-1 */
    07126,                      /* 24, CLL CML RTL      ; read command + */
    01060,                      /* 25, TAD UNIT         ; unit no */
    06751,                      /* 26, LCD              ; load read+unit */
    07201,                      /* 27, CLA IAC          ; AC = 1 */
    04053,                      /* 30, JMS LOAD         ; load sector */
    04053,                      /* 31, JMS LOAD         ; load track */
    07104,                      /* 32, CLL RAL          ; AC = 2 */
    06755,                      /* 33, SDN */
    05054,                      /* 34, JMP LOAD+1 */
    06754,                      /* 35, SER */
    07450,                      /* 36, SNA              ; more to do? */
    07610,                      /* 37, CLA SKP          ; error */
    05046,                      /* 40, JMP 46           ; go empty */
    07402,                      /* 41-45, HALT          ; error */
    07402,
    07402,
    07402,
    07402,
    06751,                      /* 46, LCD              ; load empty */
    04053,                      /* 47, JMS LOAD         ; get data */
    03002,                      /* 50, DCA 2            ; store */
    02050,                      /* 51, ISZ 50           ; incr store */
    05047,                      /* 52, JMP 47           ; loop until done */
    00000,                      /* LOAD, 0 */
    06753,                      /* 54, STR */
    05033,                      /* 55, JMP 33 */
    06752,                      /* 56, XDR */
    05453,                      /* 57, JMP I LOAD */
    07024,                      /* UNIT, CML RAL        ; for unit 1 */
    06030                       /* 61, KCC */
    };

static const uint16 boot2_rom[] = {
    01061,                      /* READ, TAD UNIT       ; next unit+den */
    01046,                      /* 21, TAD CON360       ; add in 360 */
    00060,                      /* 22, AND CON420       ; mask to 420 */
    03061,                      /* 23, DCA UNIT         ; 400,420,0,20... */
    07327,                      /* 24, STL CLA IAC RTL  ; AC = 6 = read */
    01061,                      /* 25, TAD UNIT         ; +unit+den */
    06751,                      /* 26, LCD              ; load cmd */
    07201,                      /* 27, CLA IAC;         ; AC = 1 = trksec */
    04053,                      /* 30, JMS LOAD         ; load trk */
    04053,                      /* 31, JMS LOAD         ; load sec */
    07004,                      /* CN7004, RAL          ; AC = 2 = empty */
    06755,                      /* START, SDN           ; done? */
    05054,                      /* 34, JMP LOAD+1       ; check xfr */
    06754,                      /* 35, SER              ; error? */
    07450,                      /* 36, SNA              ; AC=0 on start */
    05020,                      /* 37, JMP RD           ; try next den,un */
    01061,                      /* 40, TAD UNIT         ; +unit+den */
    06751,                      /* 41, LCD              ; load cmd */
    01061,                      /* 42, TAD UNIT         ; set 60 for sec boot */
    00046,                      /* 43, AND CON360       ; only density */
    01032,                      /* 44, TAD CN7004       ; magic */
    03060,                      /* 45, DCA 60 */
    00360,                      /* CON360, 360          ; NOP */
    04053,                      /* 47, JMS LOAD         ; get data */
    03002,                      /* 50, DCA 2            ; store */
    02050,                      /* 51, ISZ .-1          ; incr store */
    05047,                      /* 52, JMP .-3          ; loop until done */
    00000,                      /* LOAD, 0 */
    06753,                      /* 54, STR              ; xfr ready? */
    05033,                      /* 55, JMP 33           ; no, chk done */
    06752,                      /* 56, XDR              ; get word */
    05453,                      /* 57, JMP I 53         ; return */
    00420,                      /* CON420, 420          ; toggle */
    00020                       /* UNIT, 20             ; unit+density */
    };

t_stat rx_boot (int32 unitno, DEVICE *dptr)
{
size_t i;
extern uint16 M[];

if (rx_dib.dev != DEV_RX)                               /* only std devno */
    return STOP_NOTSTD;
if (rx_28) {
    for (i = 0; i < BOOT2_LEN; i++)
        M[BOOT2_START + i] = boot2_rom[i];
    cpu_set_bootpc (BOOT2_ENTRY);
    }
else {
    for (i = 0; i < BOOT_LEN; i++)
        M[BOOT_START + i] = boot_rom[i];
    M[BOOT_INST] = unitno? 07024: 07004;
    cpu_set_bootpc (BOOT_ENTRY);
    }
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_sys.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
/* pdp8_sys.c: PDP-8 simulator interface

   Copyright (c) 1993-2016, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   15-Dec-16    RMS     Added PKSTF (Dave Gesswein)
   17-Sep-13    RMS     Fixed recognition of initial field change (Dave Gesswein)
   24-Mar-09    RMS     Added link to FPP
   24-Jun-08    RMS     Fixed bug in new rim loader (Don North)
   24-May-08    RMS     Fixed signed/unsigned declaration inconsistency
   03-Sep-07    RMS     Added FPP8 support
                        Rewrote rim and binary loaders
   15-Dec-06    RMS     Added TA8E support, IOT disambiguation
   30-Oct-06    RMS     Added infinite loop stop
   18-Oct-06    RMS     Re-ordered device list
   17-Oct-03    RMS     Added TSC8-75, TD8E support, DECtape off reel message
   25-Apr-03    RMS     Revised for extended file support
   30-Dec-01    RMS     Revised for new TTX
   26-Nov-01    RMS     Added RL8A support
   17-Sep-01    RMS     Removed multiconsole support
   16-Sep-01    RMS     Added TSS/8 packed char support, added KL8A support
   27-May-01    RMS     Added multiconsole support
   18-Mar-01    RMS     Added DF32 support
   14-Mar-01    RMS     Added extension detection of RIM binary tapes
   15-Feb-01    RMS     Added DECtape support
   30-Oct-00    RMS     Added support for examine to file
   27-Oct-98    RMS     V2.4 load interface
   10-Apr-98    RMS     Added RIM loader support
   17-Feb-97    RMS     Fixed bug in handling of bin loader fields
*/

#include "pdp8_defs.h"
#include <ctype.h>

extern DEVICE cpu_dev;
extern UNIT cpu_unit;
extern DEVICE tsc_dev;
extern DEVICE fpp_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev;
extern DEVICE clk_dev, lpt_dev;
extern DEVICE rk_dev, rl_dev;
extern DEVICE rx_dev;
extern DEVICE df_dev, rf_dev;
extern DEVICE dt_dev, td_dev;
extern DEVICE mt_dev, ct_dev;
extern DEVICE ttix_dev, ttox_dev;
extern REG cpu_reg[];
extern uint16 M[];

t_stat fprint_sym_fpp (FILE *of, t_value *val);
t_stat parse_sym_fpp (CONST char *cptr, t_value *val);
CONST char *parse_field (CONST char *cptr, uint32 max, uint32 *val, uint32 c);
CONST char *parse_fpp_xr (CONST char *cptr, uint32 *xr, t_bool inc);
int32 test_fpp_addr (uint32 ad, uint32 max);

/* SCP data structures and interface routines

   sim_name             simulator name string
   sim_PC               pointer to saved PC register descriptor
   sim_emax             maximum number of words for examine/deposit
   sim_devices          array of pointers to simulated devices
   sim_consoles         array of pointers to consoles (if more than one)
   sim_stop_messages    array of pointers to stop messages
   sim_load             binary loader
*/

char sim_name[] = "PDP-8";

REG *sim_PC = &cpu_reg[0];

int32 sim_emax = 4;

DEVICE *sim_devices[] = {
    &cpu_dev,
    &tsc_dev,
    &fpp_dev,
    &clk_dev,
    &ptr_dev,
    &ptp_dev,
    &tti_dev,
    &tto_dev,
    &ttix_dev,
    &ttox_dev,
    &lpt_dev,
    &rk_dev,
    &rl_dev,
    &rx_dev,
    &df_dev,
    &rf_dev,
    &dt_dev,
    &td_dev,
    &mt_dev,
    &ct_dev,
    NULL
    };

const char *sim_stop_messages[] = {
    "Unknown error",
    "Unimplemented instruction",
    "HALT instruction",
    "Breakpoint",
    "Opcode Breakpoint",
    "Non-standard device number",
    "DECtape off reel",
    "Infinite loop"
    };

/* Ambiguous device list - these devices have overlapped IOT codes */

DEVICE *amb_dev[] = {
    &rl_dev,
    &ct_dev,
    &td_dev,
    NULL
    };

#define AMB_RL      (1 << 12)
#define AMB_CT      (2 << 12)
#define AMB_TD      (3 << 12)

/* RIM loader format consists of alternating pairs of addresses and 12-bit
   words.  It can only operate in field 0 and is not checksummed.
*/

t_stat sim_load_rim (FILE *fi)
{
int32 origin, hi, lo, wd;

origin = 0200;
do {                                                    /* skip leader */
    if ((hi = getc (fi)) == EOF)
        return SCPE_FMT;
    } while ((hi == 0) || (hi >= 0200));
do {                                                    /* data block */
    if ((lo = getc (fi)) == EOF)
        return SCPE_FMT;
    wd = (hi << 6) | lo;
    if (wd > 07777)
        origin = wd & 07777;
    else M[origin++ & 07777] = wd;
    if ((hi = getc (fi)) == EOF)
        return SCPE_FMT;
    } while (hi < 0200);                                /* until trailer */
return SCPE_OK;
}

/* BIN loader format consists of a string of 12-bit words (made up from
   7-bit characters) between leader and trailer (200).  The last word on
   tape is the checksum.  A word with the "link" bit set is a new origin;
   a character > 0200 indicates a change of field.
*/

int32 sim_bin_getc (FILE *fi, uint32 *newf)
{
int32 c, rubout;

rubout = 0;                                             /* clear toggle */
while ((c = getc (fi)) != EOF) {                        /* read char */
    if (rubout)                                         /* toggle set? */
        rubout = 0;                                     /* clr, skip */
    else if (c == 0377)                                 /* rubout? */
        rubout = 1;                                     /* set, skip */
    else if (c > 0200)                                  /* channel 8 set? */
        *newf = (c & 070) << 9;                         /* change field */
    else return c;                                      /* otherwise ok */
    }
return EOF;
}

t_stat sim_load_bin (FILE *fi)
{
int32 hi, lo, wd, csum, t;
uint32 field, newf, origin;
int32 sections_read = 0;

for (;;) {
    csum = origin = field = newf = 0;                   /* init */
    do {                                                /* skip leader */
        if ((hi = sim_bin_getc (fi, &newf)) == EOF) {
            if (sections_read != 0) {
                sim_printf ("%d sections sucessfully read\n\r", sections_read);
                return SCPE_OK;
                } 
            else
                return SCPE_FMT;
            }
        } while ((hi == 0) || (hi >= 0200));
    for (;;) {                                          /* data blocks */
        if ((lo = sim_bin_getc (fi, &newf)) == EOF)     /* low char */
            return SCPE_FMT;
        wd = (hi << 6) | lo;                            /* form word */
        t = hi;                                         /* save for csum */
        if ((hi = sim_bin_getc (fi, &newf)) == EOF)     /* next char */
            return SCPE_FMT;
        if (hi == 0200) {                               /* end of tape? */
            if ((csum - wd) & 07777) {                  /* valid csum? */
                if (sections_read != 0)
                    sim_printf ("%d sections sucessfully read\n\r", sections_read);
                return SCPE_CSUM;
                }
            if (!(sim_switches & SWMASK ('A')))        /* Load all sections? */
                return SCPE_OK;
            sections_read++;
            break;
            }
        csum = csum + t + lo;                           /* add to csum */
        if (wd > 07777)                                 /* chan 7 set? */
            origin = wd & 07777;                        /* new origin */
        else {                                          /* no, data */
            if ((field | origin) >= MEMSIZE) 
                return SCPE_NXM;
            M[field | origin] = wd;
            origin = (origin + 1) & 07777;
            }
        field = newf;                                   /* update field */
        }
    }
return SCPE_IERR;
}

/* Binary loader
   Two loader formats are supported: RIM loader (-r) and BIN (-b) loader. */

t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
{
if ((*cptr != 0) || (flag != 0))
    return SCPE_ARG;
if ((sim_switches & SWMASK ('R')) ||                    /* RIM format? */
    (match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B'))))
    return sim_load_rim (fileref);
else return sim_load_bin (fileref);                     /* no, BIN */
}

/* Symbol tables */

#define I_V_FL          18                              /* flag start */
#define I_M_FL          07                              /* flag mask */
#define I_V_NPN         0                               /* no operand */
#define I_V_FLD         1                               /* field change */
#define I_V_MRF         2                               /* mem ref */
#define I_V_IOT         3                               /* general IOT */
#define I_V_OP1         4                               /* operate 1 */
#define I_V_OP2         5                               /* operate 2 */
#define I_V_OP3         6                               /* operate 3 */
#define I_V_IOA         7                               /* ambiguous IOT */
#define I_NPN           (I_V_NPN << I_V_FL)
#define I_FLD           (I_V_FLD << I_V_FL)
#define I_MRF           (I_V_MRF << I_V_FL)
#define I_IOT           (I_V_IOT << I_V_FL)
#define I_OP1           (I_V_OP1 << I_V_FL)
#define I_OP2           (I_V_OP2 << I_V_FL)
#define I_OP3           (I_V_OP3 << I_V_FL)
#define I_IOA           (I_V_IOA << I_V_FL)

static const int32 masks[] = {
    07777, 07707, 07000, 07000,
    07416, 07571, 017457, 077777,
    };

/* Ambiguous device mnemonics must precede default mnemonics */

static const char *opcode[] = {
 "SKON", "ION", "IOF", "SRQ",                           /* std IOTs */
 "GTF", "RTF", "SGT", "CAF",
 "RPE", "RSF", "RRB", "RFC", "RFC RRB",                 /* reader/punch */
 "PCE", "PSF", "PCF", "PPC", "PLS",
 "KCF", "KSF", "KCC", "KRS", "KIE", "KRB",              /* console */
 "TLF", "TSF", "TCF", "TPC", "SPI", "TLS",
 "SBE", "SPL", "CAL",                                   /* power fail */
 "CLEI", "CLDI", "CLSC", "CLLE", "CLCL", "CLSK",        /* clock */
 "CINT", "RDF", "RIF", "RIB",                           /* mem mmgt */
 "RMF", "SINT", "CUF", "SUF",
 "RLDC", "RLSD", "RLMA", "RLCA",                        /* RL - ambiguous */
 "RLCB", "RLSA", "RLWC",
 "RRER", "RRWC", "RRCA", "RRCB",
 "RRSA", "RRSI", "RLSE",
 "KCLR", "KSDR", "KSEN", "KSBF",                        /* CT - ambiguous */
 "KLSA", "KSAF", "KGOA", "KRSB",
 "SDSS", "SDST", "SDSQ",                                /* TD - ambiguous */
 "SDLC", "SDLD", "SDRC", "SDRD",
 "ADCL", "ADLM", "ADST", "ADRB",                        /* A/D */
 "ADSK", "ADSE", "ADLE", "ADRS",
 "DCMA", "DMAR", "DMAW",                                /* DF/RF */
 "DCIM", "DSAC", "DIML", "DIMA",
 "DCEA",         "DEAL", "DEAC",
 "DFSE", "DFSC", "DISK", "DMAC",
 "DCXA", "DXAL", "DXAC",
 "PKSTF", "PSKF", "PCLF", "PSKE",                                /* LPT */
 "PSTB", "PSIE", "PCLF PSTB", "PCIE",
 "LWCR", "CWCR", "LCAR",                                /* MT */
 "CCAR", "LCMR", "LFGR", "LDBR",
 "RWCR", "CLT", "RCAR",
 "RMSR", "RCMR", "RFSR", "RDBR",
 "SKEF", "SKCB", "SKJD", "SKTR", "CLF",
 "DSKP", "DCLR", "DLAG",                                /* RK */
 "DLCA", "DRST", "DLDC", "DMAN",
 "LCD", "XDR", "STR",                                   /* RX */
 "SER", "SDN", "INTR", "INIT",
 "DTRA", "DTCA", "DTXA", "DTLA",                        /* DT */
 "DTSF", "DTRB", "DTLB",
 "ETDS", "ESKP", "ECTF", "ECDF",                        /* TSC75 */
 "ERTB", "ESME", "ERIOT", "ETEN",
 "FFST", "FPINT", "FPICL", "FPCOM",                     /* FPP8 */
 "FPHLT", "FPST", "FPRST", "FPIST",
        "FMODE",        "FMRB",
 "FMRP", "FMDO",        "FPEP",

 "CDF", "CIF", "CIF CDF",
 "AND", "TAD", "ISZ", "DCA", "JMS", "JMP", "IOT",
 "NOP", "NOP2", "NOP3", "SWAB", "SWBA",
 "STL", "GLK", "STA", "LAS", "CIA",
 "BSW", "RAL", "RTL", "RAR", "RTR", "RAL RAR", "RTL RTR",
 "SKP", "SNL", "SZL",
 "SZA", "SNA", "SZA SNL", "SNA SZL",
 "SMA", "SPA", "SMA SNL", "SPA SZL",
 "SMA SZA", "SPA SNA", "SMA SZA SNL", "SPA SNA SZL",
 "SCL", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",
 "SCA", "SCA SCL", "SCA MUY", "SCA DVI",
 "SCA NMI", "SCA SHL", "SCA ASR", "SCA LSR",
 "ACS", "MUY", "DVI", "NMI", "SHL", "ASR", "LSR",
 "SCA", "DAD", "DST", "SWBA",
 "DPSZ", "DPIC", "DCIM", "SAM",
 "CLA", "CLL", "CMA", "CML", "IAC",                     /* encode only */
 "CLA", "OAS", "HLT",
 "CLA", "MQA", "MQL",
 NULL, NULL, NULL, NULL,                                /* decode only */
 NULL
 };
 
static const int32 opc_val[] = {
 06000+I_NPN, 06001+I_NPN, 06002+I_NPN, 06003+I_NPN,
 06004+I_NPN, 06005+I_NPN, 06006+I_NPN, 06007+I_NPN,
 06010+I_NPN, 06011+I_NPN, 06012+I_NPN, 06014+I_NPN, 06016+I_NPN,
 06020+I_NPN, 06021+I_NPN, 06022+I_NPN, 06024+I_NPN, 06026+I_NPN,
 06030+I_NPN, 06031+I_NPN, 06032+I_NPN, 06034+I_NPN, 06035+I_NPN, 06036+I_NPN,
 06040+I_NPN, 06041+I_NPN, 06042+I_NPN, 06044+I_NPN, 06045+I_NPN, 06046+I_NPN,
 06101+I_NPN, 06102+I_NPN, 06103+I_NPN,
 06131+I_NPN, 06132+I_NPN, 06133+I_NPN, 06135+I_NPN, 06136+I_NPN, 06137+I_NPN,
 06204+I_NPN, 06214+I_NPN, 06224+I_NPN, 06234+I_NPN,
 06244+I_NPN, 06254+I_NPN, 06264+I_NPN, 06274+I_NPN,
 06600+I_IOA+AMB_RL, 06601+I_IOA+AMB_RL, 06602+I_IOA+AMB_RL, 06603+I_IOA+AMB_RL,
 06604+I_IOA+AMB_RL, 06605+I_IOA+AMB_RL, 06607+I_IOA+AMB_RL,
 06610+I_IOA+AMB_RL, 06611+I_IOA+AMB_RL, 06612+I_IOA+AMB_RL, 06613+I_IOA+AMB_RL,
 06614+I_IOA+AMB_RL, 06615+I_IOA+AMB_RL, 06617+I_IOA+AMB_RL,
 06700+I_IOA+AMB_CT, 06701+I_IOA+AMB_CT, 06702+I_IOA+AMB_CT, 06703+I_IOA+AMB_CT,
 06704+I_IOA+AMB_CT, 06705+I_IOA+AMB_CT, 06706+I_IOA+AMB_CT, 06707+I_IOA+AMB_CT,
 06771+I_IOA+AMB_TD, 06772+I_IOA+AMB_TD, 06773+I_IOA+AMB_TD,
 06774+I_IOA+AMB_TD, 06775+I_IOA+AMB_TD, 06776+I_IOA+AMB_TD, 06777+I_IOA+AMB_TD,
 06530+I_NPN, 06531+I_NPN, 06532+I_NPN, 06533+I_NPN,    /* AD */
 06534+I_NPN, 06535+I_NPN, 06536+I_NPN, 06537+I_NPN,
 06660+I_NPN, 06601+I_NPN, 06603+I_NPN, 06605+I_NPN,                 /* DF/RF */
 06611+I_NPN, 06612+I_NPN, 06615+I_NPN, 06616+I_NPN,
 06611+I_NPN,              06615+I_NPN, 06616+I_NPN,
 06621+I_NPN, 06622+I_NPN, 06623+I_NPN, 06626+I_NPN,
 06641+I_NPN, 06643+I_NPN, 06645+I_NPN,
 06661+I_NPN, 06662+I_NPN, 06663+I_NPN,                 /* LPT */
 06664+I_NPN, 06665+I_NPN, 06666+I_NPN, 06667+I_NPN,
 06701+I_NPN, 06702+I_NPN, 06703+I_NPN,                 /* MT */
 06704+I_NPN, 06705+I_NPN, 06706+I_NPN, 06707+I_NPN,
 06711+I_NPN, 06712+I_NPN, 06713+I_NPN,
 06714+I_NPN, 06715+I_NPN, 06716+I_NPN, 06717+I_NPN,
 06721+I_NPN, 06722+I_NPN, 06723+I_NPN, 06724+I_NPN, 06725+I_NPN,
 06741+I_NPN, 06742+I_NPN, 06743+I_NPN,                 /* RK */
 06744+I_NPN, 06745+I_NPN, 06746+I_NPN, 06747+I_NPN,
 06751+I_NPN, 06752+I_NPN, 06753+I_NPN,                 /* RX */
 06754+I_NPN, 06755+I_NPN, 06756+I_NPN, 06757+I_NPN,
 06761+I_NPN, 06762+I_NPN, 06764+I_NPN, 06766+I_NPN,    /* DT */
 06771+I_NPN, 06772+I_NPN, 06774+I_NPN,
 06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN,    /* TSC */
 06364+I_NPN, 06365+I_NPN, 06366+I_NPN, 06367+I_NPN,
 06550+I_NPN, 06551+I_NPN, 06552+I_NPN, 06553+I_NPN,    /* FPP8 */
 06554+I_NPN, 06555+I_NPN, 06556+I_NPN, 06557+I_NPN,
              06561+I_NPN,              06563+I_NPN,
 06564+I_NPN, 06565+I_NPN,              06567+I_NPN,

 06201+I_FLD, 06202+I_FLD, 06203+I_FLD,
 00000+I_MRF, 01000+I_MRF, 02000+I_MRF, 03000+I_MRF,
 04000+I_MRF, 05000+I_MRF, 06000+I_IOT,
 07000+I_NPN, 07400+I_NPN, 07401+I_NPN, 07431+I_NPN, 07447+I_NPN,
 07120+I_NPN, 07204+I_NPN, 07240+I_NPN, 07604+I_NPN, 07041+I_NPN,
 07002+I_OP1, 07004+I_OP1, 07006+I_OP1,
 07010+I_OP1, 07012+I_OP1, 07014+I_OP1, 07016+I_OP1,
 07410+I_OP2, 07420+I_OP2, 07430+I_OP2,
 07440+I_OP2, 07450+I_OP2, 07460+I_OP2, 07470+I_OP2,
 07500+I_OP2, 07510+I_OP2, 07520+I_OP2, 07530+I_OP2,
 07540+I_OP2, 07550+I_OP2, 07560+I_OP2, 07570+I_OP2,
 07403+I_OP3, 07405+I_OP3, 07407+I_OP3,
 07411+I_OP3, 07413+I_OP3, 07415+I_OP3, 07417+I_OP3,
 07441+I_OP3, 07443+I_OP3, 07445+I_OP3, 07447+I_OP3,
 07451+I_OP3, 07453+I_OP3, 07455+I_OP3, 07457+I_OP3,
 017403+I_OP3, 017405+I_OP3, 0174017+I_OP3,
 017411+I_OP3, 017413+I_OP3, 017415+I_OP3, 017417+I_OP3,
 017441+I_OP3, 017443+I_OP3, 017445+I_OP3, 017447+I_OP3,
 017451+I_OP3, 017453+I_OP3, 017455+I_OP3, 017457+I_OP3,
 07200+I_OP1, 07100+I_OP1, 07040+I_OP1, 07020+I_OP1, 07001+I_OP1,
 07600+I_OP2, 07404+I_OP2, 07402+I_OP2,
 07601+I_OP3, 07501+I_OP3, 07421+I_OP3,
 07000+I_OP1, 07400+I_OP2, 07401+I_OP3, 017401+I_OP3,
 -1
 };

/* Symbol tables for FPP-8 */

#define F_V_FL          18                              /* flag start */
#define F_M_FL          017                             /* flag mask */
#define F_V_NOP12       0                               /* no opnd 12b */
#define F_V_NOP9        1                               /* no opnd 9b */
#define F_V_AD15        2                               /* 15b dir addr */
#define F_V_AD15X       3                               /* 15b dir addr indx */
#define F_V_IMMX        4                               /* 12b immm indx */
#define F_V_X           5                               /* index */
#define F_V_MRI         6                               /* mem ref ind */
#define F_V_MR1D        7                               /* mem ref dir 1 word */
#define F_V_MR2D        8                               /* mem ref dir 2 word */
#define F_V_LEMU        9                               /* LEA/IMUL */
#define F_V_LEMUI       10                              /* LEAI/IMULI */
#define F_V_LTR         11                              /* LTR */
#define F_V_MRD         12                              /* mem ref direct (enc) */
#define F_NOP12         (F_V_NOP12 << F_V_FL)
#define F_NOP9          (F_V_NOP9 << F_V_FL)
#define F_AD15          (F_V_AD15 << F_V_FL)
#define F_AD15X         (F_V_AD15X << F_V_FL)
#define F_IMMX          (F_V_IMMX << F_V_FL)
#define F_X             (F_V_X << F_V_FL)
#define F_MRI           (F_V_MRI << F_V_FL)
#define F_MR1D          (F_V_MR1D << F_V_FL)
#define F_MR2D          (F_V_MR2D << F_V_FL)
#define F_LEMU          (F_V_LEMU << F_V_FL)
#define F_LEMUI         (F_V_LEMUI << F_V_FL)
#define F_LTR           (F_V_LTR << F_V_FL)
#define F_MRD           (F_V_MRD << F_V_FL)

static const uint32 fmasks[] = {
    07777, 07770, 07770, 07600,
    07770, 07770, 07600, 07600,
    07600, 017600, 017600, 07670,
    07777
    };

/* Memory references are encode dir / decode 1D / decode 2D / indirect */

static const char *fopcode[] = {
    "FEXIT",    "FPAUSE",   "FCLA",     "FNEG",
    "FNORM",    "STARTF",   "STARTD",   "JAC",
                "ALN",      "ATX",      "XTA",
    "FNOP",     "STARTE",
    "LDX",      "ADDX",
    "FLDA",     "FLDA",     "FLDA",     "FLDAI",
    "JEQ",      "JGE",      "JLE",      "JA",
    "JNE",      "JLT",      "JGT",      "JAL",
    "SETX",     "SETB",     "JSA",      "JSR",
    "FADD",     "FADD",     "FADD",     "FADDI",
    "JNX",
    "FSUB",     "FSUB",     "FSUB",     "FSUBI",
    "TRAP3",
    "FDIV",     "FDIV",     "FDIV",     "FDIVI",
    "TRAP4",
    "FMUL",     "FMUL",     "FMUL",     "FMULI",
    "LTREQ",    "LTRGE",    "LTRLE",    "LTRA",
    "LTRNE",    "LTRLT",    "LTRGT",    "LTRAL",
    "FADDM",    "FADDM",    "FADDM",    "FADDMI",
    "IMUL",     "LEA",
    "FSTA",     "FSTA",     "FSTA",     "FSTAI",
    "IMULI",    "LEAI",
    "FMULM",    "FMULM",    "FMULM",    "FMULMI",
    NULL
    };

static const int32 fop_val[] = {
    00000+F_NOP12,  00001+F_NOP12,  00002+F_NOP12,  00003+F_NOP12,
    00004+F_NOP12,  00005+F_NOP12,  00006+F_NOP12,  00007+F_NOP12,
                    00010+F_X,      00020+F_X,      00030+F_X,
    00040+F_NOP9,   00050+F_NOP9,
    00100+F_IMMX,   00110+F_IMMX,
    00000+F_MRD,    00200+F_MR1D,   00400+F_MR2D,   00600+F_MRI,
    01000+F_AD15,   01010+F_AD15,   01020+F_AD15,   01030+F_AD15,
    01040+F_AD15,   01050+F_AD15,   01060+F_AD15,   01070+F_AD15,
    01100+F_AD15,   01110+F_AD15,   01120+F_AD15,   01130+F_AD15,
    01000+F_MRD,    01200+F_MR1D,   01400+F_MR2D,   01600+F_MRI,
    02000+F_AD15X,
    02000+F_MRD,    02200+F_MR1D,   02400+F_MR2D,   02600+F_MRI,
    03000+F_AD15,
    03000+F_MRD,    03200+F_MR1D,   03400+F_MR2D,   03600+F_MRI,
    04000+F_AD15,
    04000+F_MRD,    04200+F_MR1D,   04400+F_MR2D,   04600+F_MRI,
    05000+F_LTR,    05010+F_LTR,    05020+F_LTR,    05030+F_LTR,
    05040+F_LTR,    05050+F_LTR,    05060+F_LTR,    05070+F_LTR,
    05000+F_MRD,    05200+F_MR1D,   05400+F_MR2D,   05600+F_MRI,
    016000+F_LEMU,  006000+F_LEMU,
    06000+F_MRD,    06200+F_MR1D,   06400+F_MR2D,   06600+F_MRI,
    017000+F_LEMUI, 007000+F_LEMUI,
    07000+F_MRD,    07200+F_MR1D,   07400+F_MR2D,   07600+F_MRI,
    -1
    };

/* Operate decode

   Inputs:
        *of     =       output stream
        inst    =       mask bits
        Class   =       instruction class code
        sp      =       space needed?
   Outputs:
        status  =       space needed
*/

int32 fprint_opr (FILE *of, int32 inst, int32 Class, int32 sp)
{
int32 i, j;

for (i = 0; opc_val[i] >= 0; i++) {                     /* loop thru ops */
    j = (opc_val[i] >> I_V_FL) & I_M_FL;                /* get class */
    if ((j == Class) && (opc_val[i] & inst)) {          /* same class? */
        inst = inst & ~opc_val[i];                      /* mask bit set? */
        fprintf (of, (sp? " %s": "%s"), opcode[i]);
        sp = 1;
        }
    }
return sp;
}

/* Symbolic decode

   Inputs:
        *of     =       output stream
        addr    =       current PC
        *val    =       pointer to data
        *uptr   =       pointer to unit 
        sw      =       switches
   Outputs:
        return  =       status code
*/

#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
#define SIXTOASC(x) (((x) >= 040)? (x): (x) + 0100)
#define TSSTOASC(x) ((x) + 040)

t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
    UNIT *uptr, int32 sw)
{
int32 cflag, i, j, sp, inst, disp, opc;
extern int32 emode;
t_stat r;

cflag = (uptr == NULL) || (uptr == &cpu_unit);
inst = val[0];
if (sw & SWMASK ('A')) {                                /* ASCII? */
    if (inst > 0377)
        return SCPE_ARG;
    fprintf (of, FMTASC (inst & 0177));
    return SCPE_OK;
    }
if (sw & SWMASK ('C')) {                                /* characters? */
    fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077));
    fprintf (of, "%c", SIXTOASC (inst & 077));
    return SCPE_OK;
    }
if (sw & SWMASK ('T')) {                                /* TSS8 packed? */
    fprintf (of, "%c", TSSTOASC ((inst >> 6) & 077));
    fprintf (of, "%c", TSSTOASC (inst & 077));
    return SCPE_OK;
    }
if ((sw & SWMASK ('F')) &&                              /* FPP8? */
    ((r = fprint_sym_fpp (of, val)) != SCPE_ARG))
    return r;
if (!(sw & SWMASK ('M')))
    return SCPE_ARG;

/* Instruction decode */

opc = (inst >> 9) & 07;                                 /* get major opcode */
if (opc == 07)                                          /* operate? */
    inst = inst | ((emode & 1) << 12);                  /* include EAE mode */
if (opc == 06) {                                        /* IOT? */
    DEVICE *dptr;
    DIB *dibp;
    uint32 dno = (inst >> 3) & 077;
    for (i = 0; (dptr = amb_dev[i]) != NULL; i++) {     /* check amb devices */
        if ((dptr->ctxt == NULL) ||                     /* no DIB or */
            (dptr->flags & DEV_DIS)) continue;          /* disabled? skip */
        dibp = (DIB *) dptr->ctxt;                      /* get DIB */
        if ((dno >= dibp->dev) ||                       /* IOT for this dev? */
            (dno < (dibp->dev + dibp->num))) {
            inst = inst | ((i + 1) << 12);              /* disambiguate */
            break;                                      /* done */
            }
        }
    }
        
for (i = 0; opc_val[i] >= 0; i++) {                     /* loop thru ops */
    j = (opc_val[i] >> I_V_FL) & I_M_FL;                /* get class */
    if ((opc_val[i] & 077777) == (inst & masks[j])) {   /* match? */

        switch (j) {                                    /* case on class */

        case I_V_NPN: case I_V_IOA:                     /* no operands */
            fprintf (of, "%s", opcode[i]);              /* opcode */
            break;

        case I_V_FLD:                                   /* field change */
            fprintf (of, "%s %-o", opcode[i], (inst >> 3) & 07);
            break;

        case I_V_MRF:                                   /* mem ref */
            disp = inst & 0177;                         /* displacement */
            fprintf (of, "%s%s", opcode[i], ((inst & 00400)? " I ": " "));
            if (inst & 0200) {                          /* current page? */
                if (cflag)
                    fprintf (of, "%-o", (addr & 07600) | disp);
                else fprintf (of, "C %-o", disp);
                }
            else fprintf (of, "%-o", disp);             /* page zero */
            break;

        case I_V_IOT:                                   /* IOT */
            fprintf (of, "%s %-o", opcode[i], inst & 0777);
            break;

        case I_V_OP1:                                   /* operate group 1 */
            sp = fprint_opr (of, inst & 0361, j, 0);
            if (opcode[i])
                fprintf (of, (sp? " %s": "%s"), opcode[i]);
            break;

        case I_V_OP2:                                   /* operate group 2 */
            if (opcode[i])
                fprintf (of, "%s", opcode[i]); /* skips */
            fprint_opr (of, inst & 0206, j, opcode[i] != NULL);
            break;      

        case I_V_OP3:                                   /* operate group 3 */
            sp = fprint_opr (of, inst & 0320, j, 0);
            if (opcode[i])
                fprintf (of, (sp? " %s": "%s"), opcode[i]);
            break;
            }                                           /* end case */

        return SCPE_OK;
        }                                               /* end if */
    }                                                   /* end for */
return SCPE_ARG;
}

/* Symbolic input

   Inputs:
        *cptr   =       pointer to input string
        addr    =       current PC
        *uptr   =       pointer to unit
        *val    =       pointer to output values
        sw      =       switches
   Outputs:
        status  =       error status
*/

t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
uint32 cflag, d, i, j, k;
t_stat r;
char gbuf[CBUFSIZE];

cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++;                         /* absorb spaces */
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
    if (cptr[0] == 0)                                   /* must have 1 char */
        return SCPE_ARG;
    val[0] = (t_value) cptr[0] | 0200;
    return SCPE_OK;
    }
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
    if (cptr[0] == 0)                                   /* must have 1 char */
        return SCPE_ARG;
    val[0] = (((t_value) cptr[0] & 077) << 6) |
              ((t_value) cptr[1] & 077);
    return SCPE_OK;
    }
if ((sw & SWMASK ('T')) || ((*cptr == '"') && cptr++)) { /* TSS8 string? */
    if (cptr[0] == 0)                                   /* must have 1 char */
        return SCPE_ARG;
    val[0] = (((t_value) (cptr[0] - 040) & 077) << 6) |
              ((t_value) (cptr[1] - 040) & 077);
    return SCPE_OK;
    }
if ((r = parse_sym_fpp (cptr, val)) != SCPE_ARG)        /* FPP8 inst? */
    return r;

/* Instruction parse */

cptr = get_glyph (cptr, gbuf, 0);                       /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL)
    return SCPE_ARG;
val[0] = opc_val[i] & 07777;                            /* get value */
j = (opc_val[i] >> I_V_FL) & I_M_FL;                    /* get class */

switch (j) {                                            /* case on class */

    case I_V_IOT:                                       /* IOT */
        if ((cptr = parse_field (cptr, 0777, &d, 0)) == NULL)
            return SCPE_ARG;                            /* get dev+pulse */
        val[0] = val[0] | d;
        break;

    case I_V_FLD:                                       /* field */
        for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
            cptr = get_glyph (cptr, gbuf, 0)) {
            for (i = 0; (opcode[i] != NULL) &&
                        (strcmp (opcode[i], gbuf) != 0) ; i++) ;
            if (opcode[i] != NULL) {
                k = (opc_val[i] >> I_V_FL) & I_M_FL;
                if (k != j)
                    return SCPE_ARG;
                val[0] = val[0] | (opc_val[i] & 07777);
                }
            else {
                d = get_uint (gbuf, 8, 07, &r);
                if (r != SCPE_OK)
                    return SCPE_ARG;
                val[0] = val[0] | (d << 3);
                break;
                }
            }
        break;

    case I_V_MRF:                                       /* mem ref */
        cptr = get_glyph (cptr, gbuf, 0);               /* get next field */
        if (strcmp (gbuf, "I") == 0) {                  /* indirect? */
            val[0] = val[0] | 0400;
            cptr = get_glyph (cptr, gbuf, 0);
            }
        if ((k = (strcmp (gbuf, "C") == 0)) || (strcmp (gbuf, "Z") == 0)) {
            if ((cptr = parse_field (cptr, 0177, &d, 0)) == NULL)
                return SCPE_ARG;
            val[0] = val[0] | d | (k? 0200: 0);
            }
        else {
            d = get_uint (gbuf, 8, 07777, &r);
            if (r != SCPE_OK)
                return SCPE_ARG;
            if (d <= 0177)
                val[0] = val[0] | d;
            else if (cflag && (((addr ^ d) & 07600) == 0))
                val[0] = val[0] | (d & 0177) | 0200;
            else return SCPE_ARG;
            }
        break;

    case I_V_OP1: case I_V_OP2: case I_V_OP3:           /* operates */
    case I_V_NPN: case I_V_IOA:
        for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0;
            cptr = get_glyph (cptr, gbuf, 0)) {
            for (i = 0; (opcode[i] != NULL) &&
                        (strcmp (opcode[i], gbuf) != 0) ; i++) ;
            k = opc_val[i] & 07777;
            if ((opcode[i] == NULL) || (((k ^ val[0]) & 07000) != 0))
                return SCPE_ARG;
            val[0] = val[0] | k;
            }
        break;
        }                                               /* end case */

if (*cptr != 0) return SCPE_ARG;                        /* junk at end? */
return SCPE_OK;
}

/* FPP8 instruction decode */

t_stat fprint_sym_fpp (FILE *of, t_value *val)
{
uint32 wd1, wd2, xr4b, xr3b, ad15;
uint32 i, j;
extern uint32 fpp_bra, fpp_cmd;

wd1 = (uint32) val[0] | ((fpp_cmd & 04000) << 1);
wd2 = (uint32) val[1];
xr4b = (wd1 >> 3) & 017;
xr3b = wd1 & 07;
ad15 = (xr3b << 12) | wd2;

for (i = 0; fop_val[i] >= 0; i++) {                     /* loop thru ops */
    j = (fop_val[i] >> F_V_FL) & F_M_FL;                /* get class */
    if ((fop_val[i] & 017777) == (wd1 & fmasks[j])) {   /* match? */

        switch (j) {                                    /* case on class */
        case F_V_NOP12:
        case F_V_NOP9:
        case F_V_LTR:                                   /* no operands */
            fprintf (of, "%s", fopcode[i]);
            break;

        case F_V_X:                                     /* index */
            fprintf (of, "%s %o", fopcode[i], xr3b);
            break;

        case F_V_IMMX:                                  /* index imm */
            fprintf (of, "%s %-o,%o", fopcode[i], wd2, xr3b);
            return -1;                                  /* extra word */

        case F_V_AD15:                                  /* 15b address */
            fprintf (of, "%s %-o", fopcode[i], ad15);
            return -1;                                  /* extra word */

        case F_V_AD15X:                                 /* 15b addr, indx */
            fprintf (of, "%s %-o", fopcode[i], ad15);
            if (xr4b >= 010)
                fprintf (of, ",%o+", xr4b & 7);
            else fprintf (of, ",%o", xr4b);
            return -1;                                  /* extra word */

        case F_V_MR1D:                                  /* 1 word direct */
            ad15 = (fpp_bra + (3 * (wd1 & 0177))) & ADDRMASK;
            fprintf (of, "%s %-o", fopcode[i], ad15);
            break;

        case F_V_LEMU:
        case F_V_MR2D:                                  /* 2 word direct */
            fprintf (of, "%s %-o", fopcode[i], ad15);
            if (xr4b >= 010)
                fprintf (of, ",%o+", xr4b & 7);
            else if (xr4b != 0)
                fprintf (of, ",%o", xr4b);
            return -1;                                  /* extra word */

        case F_V_LEMUI:
        case F_V_MRI:                                   /* indirect */
            ad15 = (fpp_bra + (3 * xr3b)) & ADDRMASK;
            fprintf (of, "%s %-o", fopcode[i], ad15);
            if (xr4b >= 010)
                fprintf (of, ",%o+", xr4b & 7);
            else if (xr4b != 0)
                fprintf (of, ",%o", xr4b);
            break;

        case F_V_MRD:                                   /* encode only */
            return SCPE_IERR;
            }

        return SCPE_OK;
        }                                               /* end if */
    }                                                   /* end for */
return SCPE_ARG;
}

/* FPP8 instruction parse */

t_stat parse_sym_fpp (CONST char *cptr, t_value *val)
{
uint32 i, j, ad, xr;
int32 broff, nwd;
char gbuf[CBUFSIZE];

cptr = get_glyph (cptr, gbuf, 0);                       /* get opcode */
for (i = 0; (fopcode[i] != NULL) && (strcmp (fopcode[i], gbuf) != 0) ; i++) ;
if (fopcode[i] == NULL) return SCPE_ARG;
val[0] = fop_val[i] & 07777;                            /* get value */
j = (fop_val[i] >> F_V_FL) & F_M_FL;                    /* get class */
xr = 0;
nwd = 0;

switch (j) {                                            /* case on class */

    case F_V_NOP12:
    case F_V_NOP9:
    case F_V_LTR:                                       /* no operands */
        break;

    case F_V_X:                                         /* 3b XR */
        if ((cptr = parse_field (cptr, 07, &xr, 0)) == NULL)
            return SCPE_ARG;
        val[0] |= xr;
        break;

    case F_V_IMMX:                                      /* 12b, XR */
        if ((cptr = parse_field (cptr, 07777, &ad, ',')) == NULL)
            return SCPE_ARG;
        if ((*cptr == 0) ||
            ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL))
            return SCPE_ARG;
        val[0] |= xr;
        val[++nwd] = ad;
        break;

    case F_V_AD15:                                      /* 15b addr */
        if ((cptr = parse_field (cptr, 077777, &ad, 0)) == NULL)
            return SCPE_ARG;
        val[0] |= (ad >> 12) & 07;
        val[++nwd] = ad & 07777;
        break;

    case F_V_AD15X:                                     /* 15b addr, idx */
        if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
            return SCPE_ARG;
        if ((*cptr == 0) ||
            ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL))
            return SCPE_ARG;
        val[0] |= ((xr << 3) | ((ad >> 12) & 07));
        val[++nwd] = ad & 07777;
        break;

    case F_V_LEMUI:
    case F_V_MRI:                                       /* indirect */
        if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
            return SCPE_ARG;
        if ((*cptr != 0) &&
            ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))
            return SCPE_ARG;
        if ((broff = test_fpp_addr (ad, 07)) < 0)
            return SCPE_ARG;
        val[0] |= ((xr << 3) | broff);
        break;

    case F_V_MRD:                                       /* direct */
        if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
            return SCPE_ARG;
        if (((broff = test_fpp_addr (ad, 0177)) < 0) ||
            (*cptr != 0)) {
            if ((*cptr != 0) &&
                ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))
                return SCPE_ARG;
            val[0] |= (00400 | (xr << 3) | ((ad >> 12) & 07));
            val[++nwd] = ad & 07777;
            }
        else val[0] |= (00200 | broff);
        break;

    case F_V_LEMU:
        if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL)
            return SCPE_ARG;
        if ((*cptr != 0) &&
            ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL))
            return SCPE_ARG;
        val[0] |= ((xr << 3) | ((ad >> 12) & 07));
        val[++nwd] = ad & 07777;
        break;

    case F_V_MR1D:
    case F_V_MR2D:
        return SCPE_IERR;          
        }                                               /* end case */

if (*cptr != 0) return SCPE_ARG;                        /* junk at end? */
return -nwd;
}

/* Parse field */

CONST char *parse_field (CONST char *cptr, uint32 max, uint32 *val, uint32 c)
{
char gbuf[CBUFSIZE];
t_stat r;

cptr = get_glyph (cptr, gbuf, c);                       /* get field */
*val = get_uint (gbuf, 8, max, &r);
if (r != SCPE_OK)
    return NULL;
return cptr;
}

/* Parse index register */

CONST char *parse_fpp_xr (CONST char *cptr, uint32 *xr, t_bool inc)
{
char gbuf[CBUFSIZE];
uint32 len;
t_stat r;

cptr = get_glyph (cptr, gbuf, 0);                      /* get field */
len = strlen (gbuf);
if (gbuf[len - 1] == '+') {
    if (!inc)
        return NULL;
    gbuf[len - 1] = 0;
    *xr = 010;
    }
else *xr = 0;
*xr += get_uint (gbuf, 8, 7, &r);
if (r != SCPE_OK)
    return NULL;
return cptr;
}

/* Test address in range of base register */

int32 test_fpp_addr (uint32 ad, uint32 max)
{
uint32 off;
extern uint32 fpp_bra;

off = ad - fpp_bra;
if (((off % 3) != 0) ||
    (off > (max * 3)))
    return -1;
return ((int32) off / 3);
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_td.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
/* pdp8_td.c: PDP-8 simple DECtape controller (TD8E) simulator

   Copyright (c) 1993-2013, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   This module was inspired by Gerold Pauler's TD8E simulator for Doug Jones'
   PDP8 simulator but tracks the hardware implementation more closely.

   td           TD8E/TU56 DECtape

   17-Sep-13    RMS     Changed to use central set_bootpc routine
   23-Mar-11    RMS     Fixed SDLC to clear AC (from Dave Gesswein)
   23-Jun-06    RMS     Fixed switch conflict in ATTACH
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   09-Jan-04    RMS     Changed sim_fsize calling sequence, added STOP_OFFR

   PDP-8 DECtapes are represented in memory by fixed length buffer of 12b words.
   Three file formats are supported:

        18b/36b                 256 words per block [256 x 18b]
        16b                     256 words per block [256 x 16b]
        12b                     129 words per block [129 x 12b]

   When a 16b or 18/36b DECtape file is read in, it is converted to 12b format.

   DECtape motion is measured in 3b lines.  Time between lines is 33.33us.
   Tape density is nominally 300 lines per inch.  The format of a DECtape (as
   taken from the TD8E formatter) is:

        reverse end zone        8192 reverse end zone codes ~ 10 feet
        reverse buffer          200 interblock codes
        block 0
         :
        block n
        forward buffer          200 interblock codes
        forward end zone        8192 forward end zone codes ~ 10 feet

   A block consists of five 18b header words, a tape-specific number of data
   words, and five 18b trailer words.  All systems except the PDP-8 use a
   standard block length of 256 words; the PDP-8 uses a standard block length
   of 86 words (x 18b = 129 words x 12b).

   Because a DECtape file only contains data, the simulator cannot support
   write timing and mark track and can only do a limited implementation
   of non-data words.  Read assumes that the tape has been conventionally
   written forward:

        header word 0           0
        header word 1           block number (for forward reads)
        header words 2,3        0
        header word 4           checksum (for reverse reads)
        :
        trailer word 4          checksum (for forward reads)
        trailer words 3,2       0
        trailer word 1          block number (for reverse reads)
        trailer word 0          0

   Write modifies only the data words and dumps the non-data words in the
   bit bucket.
*/

#include "pdp8_defs.h"

#define DT_NUMDR        2                               /* #drives */
#define UNIT_V_WLK      (UNIT_V_UF + 0)                 /* write locked */
#define UNIT_V_8FMT     (UNIT_V_UF + 1)                 /* 12b format */
#define UNIT_V_11FMT    (UNIT_V_UF + 2)                 /* 16b format */
#define UNIT_WLK        (1 << UNIT_V_WLK)
#define UNIT_8FMT       (1 << UNIT_V_8FMT)
#define UNIT_11FMT      (1 << UNIT_V_11FMT)
#define STATE           u3                              /* unit state */
#define LASTT           u4                              /* last time update */
#define WRITTEN         u5                              /* device buffer is dirty and needs flushing */
#define UNIT_WPRT       (UNIT_WLK | UNIT_RO)            /* write protect */

/* System independent DECtape constants */

#define DT_LPERMC       6                               /* lines per mark track */
#define DT_EZLIN        (8192 * DT_LPERMC)              /* end zone length */
#define DT_BFLIN        (200 * DT_LPERMC)               /* end zone buffer */
#define DT_HTLIN        (5 * DT_LPERMC)                 /* lines per hdr/trlr */

/* 16b, 18b, 36b DECtape constants */

#define D18_WSIZE       6                               /* word size in lines */
#define D18_BSIZE       384                             /* block size in 12b */
#define D18_TSIZE       578                             /* tape size */
#define D18_LPERB       (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN)
#define D18_FWDEZ       (DT_EZLIN + (D18_LPERB * D18_TSIZE))
#define D18_CAPAC       (D18_TSIZE * D18_BSIZE)         /* tape capacity */

#define D18_NBSIZE      ((D18_BSIZE * D8_WSIZE) / D18_WSIZE)
#define D18_FILSIZ      (D18_NBSIZE * D18_TSIZE * sizeof (int32))
#define D11_FILSIZ      (D18_NBSIZE * D18_TSIZE * sizeof (int16))

/* 12b DECtape constants */

#define D8_WSIZE        4                               /* word size in lines */
#define D8_BSIZE        129                             /* block size in 12b */
#define D8_TSIZE        1474                            /* tape size */
#define D8_LPERB        (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN)
#define D8_FWDEZ        (DT_EZLIN + (D8_LPERB * D8_TSIZE))
#define D8_CAPAC        (D8_TSIZE * D8_BSIZE)           /* tape capacity */
#define D8_FILSIZ       (D8_CAPAC * sizeof (int16))

/* This controller */

#define DT_CAPAC        D8_CAPAC                        /* default */
#define DT_WSIZE        D8_WSIZE

/* Calculated constants, per unit */

#define DTU_BSIZE(u)    (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE)
#define DTU_TSIZE(u)    (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE)
#define DTU_LPERB(u)    (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB)
#define DTU_FWDEZ(u)    (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ)
#define DTU_CAPAC(u)    (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC)

#define DT_LIN2BL(p,u)  (((p) - DT_EZLIN) / DTU_LPERB (u))
#define DT_LIN2OF(p,u)  (((p) - DT_EZLIN) % DTU_LPERB (u))

/* Command register */

#define TDC_UNIT        04000                           /* unit select */
#define TDC_FWDRV       02000                           /* fwd/rev */
#define TDC_STPGO       01000                           /* stop/go */
#define TDC_RW          00400                           /* read/write */
#define TDC_MASK        07400                           /* implemented */
#define TDC_GETUNIT(x)  (((x) & TDC_UNIT)? 1: 0)

/* Status register */

#define TDS_WLO         00200                           /* write lock */
#define TDS_TME         00100                           /* timing/sel err */

/* Mark track register and codes */

#define MTK_MASK        077
#define MTK_REV_END     055                             /* rev end zone */
#define MTK_INTER       025                             /* interblock */
#define MTK_FWD_BLK     026                             /* fwd block */
#define MTK_REV_GRD     032                             /* reverse guard */
#define MTK_FWD_PRE     010                             /* lock, etc */
#define MTK_DATA        070                             /* data */
#define MTK_REV_PRE     073                             /* lock, etc */
#define MTK_FWD_GRD     051                             /* fwd guard */
#define MTK_REV_BLK     045                             /* rev block */
#define MTK_FWD_END     022                             /* fwd end zone */

/* DECtape state */

#define STA_STOP        0                               /* stopped */
#define STA_DEC         2                               /* decelerating */
#define STA_ACC         4                               /* accelerating */
#define STA_UTS         6                               /* up to speed */
#define STA_DIR         1                               /* fwd/rev */

#define ABS(x)          (((x) < 0)? (-(x)): (x))
#define MTK_BIT(c,p)    (((c) >> (DT_LPERMC - 1 - ((p) % DT_LPERMC))) & 1)

/* State and declarations */

int32 td_cmd = 0;                                       /* command */
int32 td_dat = 0;                                       /* data */
int32 td_mtk = 0;                                       /* mark track */
int32 td_slf = 0;                                       /* single line flag */
int32 td_qlf = 0;                                       /* quad line flag */
int32 td_tme = 0;                                       /* timing error flag */
int32 td_csum = 0;                                      /* save check sum */
int32 td_qlctr = 0;                                     /* quad line ctr */
int32 td_ltime = 20;                                    /* interline time */
int32 td_dctime = 40000;                                /* decel time */
int32 td_stopoffr = 0;
static uint8 tdb_mtk[DT_NUMDR][D18_LPERB];              /* mark track bits */

int32 td77 (int32 IR, int32 AC);
t_stat td_svc (UNIT *uptr);
t_stat td_reset (DEVICE *dptr);
t_stat td_attach (UNIT *uptr, CONST char *cptr);
void td_flush (UNIT *uptr);
t_stat td_detach (UNIT *uptr);
t_stat td_boot (int32 unitno, DEVICE *dptr);
t_bool td_newsa (int32 newf);
t_bool td_setpos (UNIT *uptr);
int32 td_header (UNIT *uptr, int32 blk, int32 line);
int32 td_trailer (UNIT *uptr, int32 blk, int32 line);
int32 td_read (UNIT *uptr, int32 blk, int32 line);
void td_write (UNIT *uptr, int32 blk, int32 line, int32 datb);
int32 td_set_mtk (int32 code, int32 u, int32 k);
t_stat td_show_pos (FILE *st, UNIT *uptr, int32 val, CONST void *desc);

extern uint16 M[];

/* TD data structures

   td_dev       DT device descriptor
   td_unit      DT unit list
   td_reg       DT register list
   td_mod       DT modifier list
*/

DIB td_dib = { DEV_TD8E, 1, { &td77 } };

UNIT td_unit[] = {
    { UDATA (&td_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) },
    { UDATA (&td_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+
             UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }
    };

REG td_reg[] = {
    { GRDATAD (TDCMD, td_cmd, 8, 4, 8, "command register") },
    { ORDATAD (TDDAT, td_dat, 12, "data register") },
    { ORDATAD (TDMTK, td_mtk, 6, "mark track register") },
    { FLDATAD (TDSLF, td_slf, 0, "single line flag") },
    { FLDATAD (TDQLF, td_qlf, 0, "quad line flag") },
    { FLDATAD (TDTME, td_tme, 0, "timing error flag") },
    { ORDATAD (TDQL, td_qlctr, 2, "quad line counter") },
    { ORDATA (TDCSUM, td_csum, 6), REG_RO },
    { DRDATAD (LTIME, td_ltime, 31, "time between lines"), REG_NZ | PV_LEFT },
    { DRDATAD (DCTIME, td_dctime, 31, "time to decelerate to a full stop"), REG_NZ | PV_LEFT },
    { URDATAD (POS, td_unit[0].pos, 10, T_ADDR_W, 0,
              DT_NUMDR, PV_LEFT | REG_RO, "positions, in lines, units 0 and 1") },
    { URDATAD (STATT, td_unit[0].STATE, 8, 18, 0,
              DT_NUMDR, REG_RO, "unit state, units 0 and 1") },
    { URDATA (LASTT, td_unit[0].LASTT, 10, 32, 0,
              DT_NUMDR, REG_HRO) },
    { FLDATAD (STOP_OFFR, td_stopoffr, 0, "stop on off-reel error") },
    { ORDATA (DEVNUM, td_dib.dev, 6), REG_HRO },
    { NULL }
    };

MTAB td_mod[] = {
    { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
    { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, 
    { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL },
    { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL },
    { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
      &set_dev, &show_dev, NULL },
    { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "POSITION", NULL, NULL, &td_show_pos },
    { 0 }
    };

DEVICE td_dev = {
    "TD", td_unit, td_reg, td_mod,
    DT_NUMDR, 8, 24, 1, 8, 12,
    NULL, NULL, &td_reset,
    &td_boot, &td_attach, &td_detach,
    &td_dib, DEV_DISABLE | DEV_DIS
    };

/* IOT routines */

int32 td77 (int32 IR, int32 AC)
{
int32 pulse = IR & 07;
int32 u = TDC_GETUNIT (td_cmd);                         /* get unit */
int32 diff, t;

switch (pulse) {

    case 01:                                            /* SDSS */
        if (td_slf)
            return AC | IOT_SKP;
        break;

    case 02:                                            /* SDST */
        if (td_tme)
            return AC | IOT_SKP;
        break;

    case 03:                                            /* SDSQ */
        if (td_qlf)
            return AC | IOT_SKP;
        break;

    case 04:                                            /* SDLC */
        td_tme = 0;                                     /* clear tim err */
        diff = (td_cmd ^ AC) & TDC_MASK;                /* cmd changes */
        td_cmd = AC & TDC_MASK;                         /* update cmd */
        if ((diff != 0) && (diff != TDC_RW)) {          /* signif change? */
            if (td_newsa (td_cmd))                      /* new command */
                return AC | (IORETURN (td_stopoffr, STOP_DTOFF) << IOT_V_REASON);
            }
        AC = 0;
        break;

    case 05:                                            /* SDLD */
        td_slf = 0;                                     /* clear flags */
        td_qlf = 0;
        td_qlctr = 0;
        td_dat = AC;                                    /* load data reg */
        break;

    case 06:                                            /* SDRC */
        td_slf = 0;                                     /* clear flags */
        td_qlf = 0;
        td_qlctr = 0;
        t = td_cmd | td_mtk;                            /* form status */
        if (td_tme || !(td_unit[u].flags & UNIT_ATT))   /* tim/sel err? */
            t = t | TDS_TME;
        if (td_unit[u].flags & UNIT_WPRT)               /* write locked? */
            t = t | TDS_WLO;
        return t;                                       /* return status */

    case 07:                                            /* SDRD */
        td_slf = 0;                                     /* clear flags */
        td_qlf = 0;
        td_qlctr = 0;
        return td_dat;                                  /* return data */
        }

return AC;
}

/* Command register change (start/stop, forward/reverse, new unit)

   1. If change in motion, stop to start
        - schedule up to speed
        - set function as next state
   2. If change in motion, start to stop, or change in direction
        - schedule stop
*/

t_bool td_newsa (int32 newf)
{
int32 prev_mving, new_mving, prev_dir, new_dir;
UNIT *uptr;

uptr = td_dev.units + TDC_GETUNIT (newf);               /* new unit */
if ((uptr->flags & UNIT_ATT) == 0)                      /* new unit attached? */
    return FALSE;

new_mving = ((newf & TDC_STPGO) != 0);                  /* new moving? */
prev_mving = (uptr->STATE != STA_STOP);                 /* previous moving? */
new_dir = ((newf & TDC_FWDRV) != 0);                    /* new dir? */
prev_dir = ((uptr->STATE & STA_DIR) != 0);              /* previous dir? */

td_mtk = 0;                                             /* mark trk reg cleared */

if (!prev_mving && !new_mving)                          /* stop from stop? */
    return FALSE;

if (new_mving && !prev_mving) {                         /* start from stop? */
    if (td_setpos (uptr))                               /* update pos */
        return TRUE;
    sim_cancel (uptr);                                  /* stop current */
    sim_activate (uptr, td_dctime - (td_dctime >> 2));  /* sched accel */
    uptr->STATE = STA_ACC | new_dir;                    /* set status */
    td_slf = td_qlf = td_qlctr = 0;                     /* clear state */
    return FALSE;
    }

if ((prev_mving && !new_mving) ||                       /* stop from moving? */
    (prev_dir != new_dir)) {                            /* dir chg while moving? */
    if (uptr->STATE >= STA_ACC) {                       /* not stopping? */
        if (td_setpos (uptr))                           /* update pos */
            return TRUE;
        sim_cancel (uptr);                              /* stop current */
        sim_activate (uptr, td_dctime);                 /* schedule decel */
        uptr->STATE = STA_DEC | prev_dir;               /* set status */
        td_slf = td_qlf = td_qlctr = 0;                 /* clear state */
        }
    return FALSE;
    }

return FALSE;   
}

/* Update DECtape position

   DECtape motion is modeled as a constant velocity, with linear
   acceleration and deceleration.  The motion equations are as follows:

        t       =       time since operation started
        tmax    =       time for operation (accel, decel only)
        v       =       at speed velocity in lines (= 1/td_ltime)

   Then:
        at speed dist = t * v
        accel dist = (t^2 * v) / (2 * tmax)
        decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax)

   This routine uses the relative (integer) time, rather than the absolute
   (floating point) time, to allow save and restore of the start times.
*/

t_bool td_setpos (UNIT *uptr)
{
uint32 new_time, ut, ulin, udelt;
int32 delta;

new_time = sim_grtime ();                               /* current time */
ut = new_time - uptr->LASTT;                            /* elapsed time */
if (ut == 0)                                            /* no time gone? exit */
    return FALSE;
uptr->LASTT = new_time;                                 /* update last time */
switch (uptr->STATE & ~STA_DIR) {                       /* case on motion */

    case STA_STOP:                                      /* stop */
        delta = 0;
        break;

    case STA_DEC:                                       /* slowing */
        ulin = ut / (uint32) td_ltime;
        udelt = td_dctime / td_ltime;
        delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt);
        break;

    case STA_ACC:                                       /* accelerating */
        ulin = ut / (uint32) td_ltime;
        udelt = (td_dctime - (td_dctime >> 2)) / td_ltime;
        delta = (ulin * ulin) / (2 * udelt);
        break;

    case STA_UTS:                                       /* at speed */
        delta = ut / (uint32) td_ltime;
        break;
        }

if (uptr->STATE & STA_DIR)                              /* update pos */
    uptr->pos = uptr->pos - delta;
else uptr->pos = uptr->pos + delta;
if (((int32) uptr->pos < 0) ||
    ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) {
    detach_unit (uptr);                                 /* off reel */
    sim_cancel (uptr);                                  /* no timing pulses */
    return TRUE;
    }
return FALSE;
}

/* Unit service - unit is either changing speed, or it is up to speed */

t_stat td_svc (UNIT *uptr)
{
int32 mot = uptr->STATE & ~STA_DIR;
int32 dir = uptr->STATE & STA_DIR;
int32 unum = uptr - td_dev.units;
int32 su = TDC_GETUNIT (td_cmd);
int32 mtkb, datb;

/* Motion cases

   Decelerating - if go, next state must be accel as specified by td_cmd
   Accelerating - next state must be up to speed, fall through
   Up to speed - process line */

if (mot == STA_STOP)                                    /* stopped? done */
    return SCPE_OK;
if ((uptr->flags & UNIT_ATT) == 0) {                    /* not attached? */
    uptr->STATE = uptr->pos = 0;                        /* also done */
    return SCPE_UNATT;
    }

switch (mot) {                                          /* case on motion */

    case STA_DEC:                                       /* deceleration */
        if (td_setpos (uptr))                           /* upd pos; off reel? */
            return IORETURN (td_stopoffr, STOP_DTOFF);
        if ((unum != su) || !(td_cmd & TDC_STPGO))      /* not sel or stop? */
            uptr->STATE = 0;                            /* stop */
        else {                                          /* selected and go */
            uptr->STATE = STA_ACC |                     /* accelerating */
                ((td_cmd & TDC_FWDRV)? STA_DIR: 0);     /* in new dir */
            sim_activate (uptr, td_dctime - (td_dctime >> 2));
            }
        return SCPE_OK;

    case STA_ACC:                                       /* accelerating */
        if (td_setpos (uptr))                           /* upd pos; off reel? */
            return IORETURN (td_stopoffr, STOP_DTOFF);
        uptr->STATE = STA_UTS | dir;                    /* set up to speed */
        break;

    case STA_UTS:                                       /* up to speed */
        if (dir)                                        /* adjust position */
            uptr->pos = uptr->pos - 1;
        else uptr->pos = uptr->pos + 1;
        uptr->LASTT = sim_grtime ();                    /* save time */
        if (((int32) uptr->pos < 0) ||                  /* off reel? */
           (uptr->pos >= (((uint32) DTU_FWDEZ (uptr)) + DT_EZLIN))) {
            detach_unit (uptr);
            return IORETURN (td_stopoffr, STOP_DTOFF);
            }
        break;                                          /* check function */
        }

/* At speed - process the current line

   Once the TD8E is running at speed, it operates line by line.  If reading,
   the current mark track bit is shifted into the mark track register, and
   the current data nibble (3b) is shifted into the data register.  If
   writing, the current mark track bit is shifted into the mark track
   register, the top nibble from the data register is written to tape, and
   the data register is shifted up.  The complexity here comes from 
   synthesizing the mark track, based on tape position, and the header data. */

sim_activate (uptr, td_ltime);                          /* sched next line */
if (unum != su)                                         /* not sel? done */
    return SCPE_OK;
td_slf = 1;                                             /* set single */
td_qlctr = (td_qlctr + 1) % DT_WSIZE;                   /* count words */
if (td_qlctr == 0) {                                    /* lines mod 4? */
    if (td_qlf) {                                       /* quad line set? */
        td_tme = 1;                                     /* timing error */
        td_cmd = td_cmd & ~TDC_RW;                      /* clear write */
        }
    else td_qlf = 1;                                    /* no, set quad */
    }

datb = 0;                                               /* assume no data */
if (uptr->pos < (DT_EZLIN - DT_BFLIN))                  /* rev end zone? */
    mtkb = MTK_BIT (MTK_REV_END, uptr->pos);
else if (uptr->pos < DT_EZLIN)                          /* rev buffer? */
    mtkb = MTK_BIT (MTK_INTER, uptr->pos);
else if (uptr->pos < ((uint32) DTU_FWDEZ (uptr))) {     /* data zone? */
    int32 blkno = DT_LIN2BL (uptr->pos, uptr);          /* block # */
    int32 lineno = DT_LIN2OF (uptr->pos, uptr);         /* line # within block */
    if (lineno < DT_HTLIN) {                            /* header? */
        if ((td_cmd & TDC_RW) == 0)                     /* read? */                     
            datb = td_header (uptr, blkno, lineno);     /* get nibble */
        }
    else if (lineno < (DTU_LPERB (uptr) - DT_HTLIN)) {  /* data? */
        if (td_cmd & TDC_RW)                            /* write? */
            td_write (uptr, blkno,                      /* write data nibble */
                      lineno - DT_HTLIN,                /* data rel line num */
                      (td_dat >> 9) & 07);
        else datb = td_read (uptr, blkno,               /* no, read */
                             lineno - DT_HTLIN);
        }
    else if ((td_cmd & TDC_RW) == 0)                    /* trailer; read? */
        datb = td_trailer (uptr, blkno, lineno -        /* get trlr nibble */
                           (DTU_LPERB (uptr) - DT_HTLIN));
    mtkb = tdb_mtk[unum][lineno];
    }
else if (uptr->pos < (((uint32) DTU_FWDEZ (uptr)) + DT_BFLIN))
    mtkb = MTK_BIT (MTK_INTER, uptr->pos);              /* fwd buffer? */
else mtkb = MTK_BIT (MTK_FWD_END, uptr->pos);           /* fwd end zone */

if (dir) {                                              /* reverse? */
    mtkb = mtkb ^ 01;                                   /* complement mark bit, */
    datb = datb ^ 07;                                   /* data bits */
    }
td_mtk = ((td_mtk << 1) | mtkb) & MTK_MASK;             /* shift mark reg */
td_dat = ((td_dat << 3) | datb) & 07777;                /* shift data reg */
return SCPE_OK;
}

/* Header read - reads out 18b words in 3b increments

        word    lines           contents
        0       0-5             0
        1       6-11            block number
        2       12-17           0
        3       18-23           0
        4       24-29           reverse checksum (0777777)
*/

int32 td_header (UNIT *uptr, int32 blk, int32 line)
{
int32 nibp;

switch (line) {

    case 8: case 9: case 10: case 11:                   /* block num */
        nibp = 3 * (DT_LPERMC - 1 - (line % DT_LPERMC));
        return (blk >> nibp) & 07;

    case 24: case 25: case 26: case 27: case 28: case 29: /* rev csum */
        return 07;                                      /* 777777 */

    default:
        return 0;
        }
}

/* Trailer read - reads out 18b words in 3b increments
   Checksum is stored to avoid double calculation

   word         lines           contents
   0            0-5             forward checksum (lines 0-1, rest 0)
   1            6-11            0
   2            12-17           0
   3            18-23           reverse block mark
   4            24-29           0

   Note that the reverse block mark (when read forward) appears
   as the complement obverse (3b nibbles swapped end for end and
   complemented).
*/

int32 td_trailer (UNIT *uptr, int32 blk, int32 line)
{
int32 nibp, i, ba;
int16 *fbuf= (int16 *) uptr->filebuf;

switch (line) {

    case 0:
        td_csum = 07777;                                /* init csum */
        ba = blk * DTU_BSIZE (uptr);
        for (i = 0; i < DTU_BSIZE (uptr); i++)          /* loop thru buf */
            td_csum = (td_csum ^ ~fbuf[ba + i]) & 07777;
        td_csum = ((td_csum >> 6) ^ td_csum) & 077;
        return (td_csum >> 3) & 07;

    case 1:
        return (td_csum & 07);

    case 18: case 19: case 20: case 21:
        nibp = 3 * (line % DT_LPERMC);
        return ((blk >> nibp) & 07) ^ 07;

    default:
        return 0;
        }
}

/* Data read - convert block number/data line # to offset in data array */

int32 td_read (UNIT *uptr, int32 blk, int32 line)
{
int16 *fbuf = (int16 *) uptr->filebuf;                  /* buffer */
uint32 ba = blk * DTU_BSIZE (uptr);                     /* block base */
int32 nibp = 3 * (DT_WSIZE - 1 - (line % DT_WSIZE));    /* nibble pos */

ba = ba + (line / DT_WSIZE);                            /* block addr */
return (fbuf[ba] >> nibp) & 07;                         /* get data nibble */
}

/* Data write - convert block number/data line # to offset in data array */

void td_write (UNIT *uptr, int32 blk, int32 line, int32 dat)
{
int16 *fbuf = (int16 *) uptr->filebuf;                  /* buffer */
uint32 ba = blk * DTU_BSIZE (uptr);                     /* block base */
int32 nibp = 3 * (DT_WSIZE - 1 - (line % DT_WSIZE));    /* nibble pos */

ba = ba + (line / DT_WSIZE);                            /* block addr */
fbuf[ba] = (fbuf[ba] & ~(07 << nibp)) | (dat << nibp);  /* upd data nibble */
uptr->WRITTEN = TRUE;
if (ba >= uptr->hwmark)                                 /* upd length */
    uptr->hwmark = ba + 1;
return;
}

/* Reset routine */

t_stat td_reset (DEVICE *dptr)
{
int32 i;
UNIT *uptr;

for (i = 0; i < DT_NUMDR; i++) {                        /* stop all activity */
    uptr = td_dev.units + i;
    if (sim_is_running) {                               /* CAF? */
        if (uptr->STATE >= STA_ACC) {                   /* accel or uts? */
            if (td_setpos (uptr))                       /* update pos */
                continue;
            sim_cancel (uptr);
            sim_activate (uptr, td_dctime);             /* sched decel */
            uptr->STATE = STA_DEC | (uptr->STATE & STA_DIR);
            }
         }
    else {
        sim_cancel (uptr);                              /* sim reset */
        uptr->STATE = 0;  
        uptr->LASTT = sim_grtime ();
        }
    }
td_slf = td_qlf = td_qlctr = 0;                         /* clear state */
td_cmd = td_dat = td_mtk = 0;
td_csum = 0;
return SCPE_OK;
}

/* Bootstrap routine - OS/8 only 

   1) Read reverse until reverse end zone (mark track is complement obverse)
   2) Read forward until mark track code 031.  This is a composite code from
      the last 4b of the forward block number and the first two bits of the
      reverse guard (01 -0110 01- 1010).  There are 16 lines before the first
      data word.
   3) Store data words from 7354 to end of page.  This includes header and
      trailer words.
   4) Continue at location 7400.
*/

#define BOOT_START      07300
#define BOOT_LEN        (sizeof (boot_rom) / sizeof (int16))

static const uint16 boot_rom[] = {
    01312,                      /* ST,  TAD L4MT        ;=2000, reverse */
    04312,                      /*      JMS L4MT        ; rev lk for 022 */
    04312,                      /*      JMS L4MT        ; fwd lk for 031 */
    06773,                      /* DAT, SDSQ            ; wait for 12b */
    05303,                      /*      JMP .-1 */
    06777,                      /*      SDRD            ; read word */
    03726,                      /*      DCA I BUF       ; store */
    02326,                      /*      ISZ BUF         ; incr ptr */
    05303,                      /*      JMP DAT         ; if not 0, cont */
    05732,                      /*      JMP I SCB       ; jump to boot */
    02000,                      /* L4MT,2000            ; overwritten */
    01300,                      /*      TAD ST          ; =1312, go */
    06774,                      /*      SDLC            ; new command */
    06771,                      /* MTK, SDSS            ; wait for mark */
    05315,                      /*      JMP .-1 */
    06776,                      /*      SDRC            ; get mark code */
    00331,                      /*      AND K77         ; mask to 6b */
    01327,                      /* CMP, TAD MCD         ; got target code? */
    07640,                      /*      SZA CLA         ; skip if yes */
    05315,                      /*      JMP MTK         ; wait for mark */
    02321,                      /*      ISZ CMP         ; next target */
    05712,                      /*      JMP I L4MT      ; exit */
    07354,                      /* BUF, 7354            ; loading point */
    07756,                      /* MCD, -22             ; target 1 */
    07747,                      /*      -31             ; target 2 */
    00077,                      /*      77              ; mask */
    07400                       /* SCB, 7400            ; secondary boot */
    };

t_stat td_boot (int32 unitno, DEVICE *dptr)
{
size_t i;

if (unitno)
    return SCPE_ARG;                                    /* only unit 0 */
if (td_dib.dev != DEV_TD8E)
    return STOP_NOTSTD;                                 /* only std devno */
td_unit[unitno].pos = DT_EZLIN;
for (i = 0; i < BOOT_LEN; i++)
    M[BOOT_START + i] = boot_rom[i];
cpu_set_bootpc (BOOT_START);
return SCPE_OK;
}

/* Attach routine

   Determine 12b, 16b, or 18b/36b format
   Allocate buffer
   If 16b or 18b, read 16b or 18b format and convert to 12b in buffer
   If 12b, read data into buffer
   Set up mark track bit array
*/

t_stat td_attach (UNIT *uptr, CONST char *cptr)
{
uint32 pdp18b[D18_NBSIZE];
uint16 pdp11b[D18_NBSIZE], *fbuf;
int32 i, k, mtkpb;
int32 u = uptr - td_dev.units;
t_stat r;
uint32 ba, sz;

r = attach_unit (uptr, cptr);                           /* attach */
if (r != SCPE_OK)                                       /* fail? */
    return r;
if ((sim_switches & SIM_SW_REST) == 0) {                /* not from rest? */
    uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;
    if (sim_switches & SWMASK ('F'))                    /* att 18b? */
        uptr->flags = uptr->flags & ~UNIT_8FMT;
    else if (sim_switches & SWMASK ('S'))               /* att 16b? */
        uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
    else if (!(sim_switches & SWMASK ('A')) &&          /* autosize? */
        (sz = sim_fsize (uptr->fileref))) {
        if (sz == D11_FILSIZ)
            uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT;
        else if (sz > D8_FILSIZ)
            uptr->flags = uptr->flags & ~UNIT_8FMT;
        }
    }
uptr->capac = DTU_CAPAC (uptr);                         /* set capacity */
uptr->filebuf = calloc (uptr->capac, sizeof (int16));
if (uptr->filebuf == NULL) {                            /* can't alloc? */
    detach_unit (uptr);
    return SCPE_MEM;
    }
fbuf = (uint16 *) uptr->filebuf;                        /* file buffer */
sim_printf ("%s%d: ", sim_dname (&td_dev), u);
if (uptr->flags & UNIT_8FMT)
    sim_printf ("12b format");
else if (uptr->flags & UNIT_11FMT)
    sim_printf ("16b format");
else sim_printf ("18b/36b format");
sim_printf (", buffering file in memory\n");
uptr->io_flush = td_flush;
if (uptr->flags & UNIT_8FMT)                            /* 12b? */
    uptr->hwmark = fxread (uptr->filebuf, sizeof (uint16),
            uptr->capac, uptr->fileref);
else {                                                  /* 16b/18b */
    for (ba = 0; ba < uptr->capac; ) {                  /* loop thru file */
        if (uptr->flags & UNIT_11FMT) {
            k = fxread (pdp11b, sizeof (uint16), D18_NBSIZE, uptr->fileref);
            for (i = 0; i < k; i++)
                pdp18b[i] = pdp11b[i];
            }
        else k = fxread (pdp18b, sizeof (uint32), D18_NBSIZE, uptr->fileref);
        if (k == 0)
            break;
        for ( ; k < D18_NBSIZE; k++)
            pdp18b[k] = 0;
        for (k = 0; k < D18_NBSIZE; k = k + 2) {        /* loop thru blk */
            fbuf[ba] = (pdp18b[k] >> 6) & 07777;
            fbuf[ba + 1] = ((pdp18b[k] & 077) << 6) |
                ((pdp18b[k + 1] >> 12) & 077);
            fbuf[ba + 2] = pdp18b[k + 1] & 07777;
            ba = ba + 3;
            }                                           /* end blk loop */
        }                                               /* end file loop */
    uptr->hwmark = ba;
    }                                                   /* end else */
uptr->flags = uptr->flags | UNIT_BUF;                   /* set buf flag */
uptr->pos = DT_EZLIN;                                   /* beyond leader */
uptr->LASTT = sim_grtime ();                            /* last pos update */
uptr->STATE = STA_STOP;                                 /* stopped */

mtkpb = (DTU_BSIZE (uptr) * DT_WSIZE) / DT_LPERMC;      /* mtk codes per blk */
k = td_set_mtk (MTK_INTER, u, 0);                       /* fill mark track */
k = td_set_mtk (MTK_FWD_BLK, u, k);                     /* bit array */
k = td_set_mtk (MTK_REV_GRD, u, k);
for (i = 0; i < 4; i++)
    k = td_set_mtk (MTK_FWD_PRE, u, k);
for (i = 0; i < (mtkpb - 4); i++)
    k = td_set_mtk (MTK_DATA, u, k);
for (i = 0; i < 4; i++)
    k = td_set_mtk (MTK_REV_PRE, u, k);
k = td_set_mtk (MTK_FWD_GRD, u, k);
k = td_set_mtk (MTK_REV_BLK, u, k);
k = td_set_mtk (MTK_INTER, u, k);
return SCPE_OK;
}

/* Detach routine

   If 12b, write buffer to file
   If 16b or 18b, convert 12b buffer to 16b or 18b and write to file
   Deallocate buffer
*/

void td_flush (UNIT* uptr)
{
uint32 pdp18b[D18_NBSIZE];
uint16 pdp11b[D18_NBSIZE], *fbuf;
int32 i, k;
uint32 ba;

if (uptr->WRITTEN && uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) {    /* any data? */
    rewind (uptr->fileref);                             /* start of file */
    fbuf = (uint16 *) uptr->filebuf;                    /* file buffer */
    if (uptr->flags & UNIT_8FMT)                        /* PDP8? */
        fxwrite (uptr->filebuf, sizeof (uint16),        /* write file */
            uptr->hwmark, uptr->fileref);
    else {                                              /* 16b/18b */
        for (ba = 0; ba < uptr->hwmark; ) {             /* loop thru buf */
            for (k = 0; k < D18_NBSIZE; k = k + 2) {
                pdp18b[k] = ((uint32) (fbuf[ba] & 07777) << 6) |
                    ((uint32) (fbuf[ba + 1] >> 6) & 077);
                pdp18b[k + 1] = ((uint32) (fbuf[ba + 1] & 077) << 12) |
                    ((uint32) (fbuf[ba + 2] & 07777));
                ba = ba + 3;
                }                                       /* end loop blk */
            if (uptr->flags & UNIT_11FMT) {             /* 16b? */
                for (i = 0; i < D18_NBSIZE; i++)
                    pdp11b[i] = pdp18b[i];
                fxwrite (pdp11b, sizeof (uint16),
                    D18_NBSIZE, uptr->fileref);
                }
            else fxwrite (pdp18b, sizeof (uint32),
                D18_NBSIZE, uptr->fileref);
            }                                           /* end loop buf */
        }                                               /* end else */
    if (ferror (uptr->fileref))
        sim_perror ("I/O error");
    }
uptr->WRITTEN = FALSE;                                  /* no longer dirty */
}

t_stat td_detach (UNIT* uptr)
{
int u = (int)(uptr - td_dev.units);

if (!(uptr->flags & UNIT_ATT))
    return SCPE_OK;
if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) {    /* any data? */
    sim_printf ("%s%d: writing buffer to file\n", sim_dname (&td_dev), u);
    td_flush (uptr);
    }                                                   /* end if hwmark */
free (uptr->filebuf);                                   /* release buf */
uptr->flags = uptr->flags & ~UNIT_BUF;                  /* clear buf flag */
uptr->filebuf = NULL;                                   /* clear buf ptr */
uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT;  /* default fmt */
uptr->capac = DT_CAPAC;                                 /* default size */
uptr->pos = uptr->STATE = 0;
sim_cancel (uptr);                                      /* no more pulses */
return detach_unit (uptr);
}

/* Set mark track code into bit array */

int32 td_set_mtk (int32 code, int32 u, int32 k)
{
int32 i;

for (i = 5; i >= 0; i--)
    tdb_mtk[u][k++] = (code >> i) & 1;
return k;
}

/* Show position */

t_stat td_show_pos (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
if (uptr->pos < DT_EZLIN)                               /* rev end zone? */
    fprintf (st, "Reverse end zone\n");
else if (uptr->pos < ((uint32) DTU_FWDEZ (uptr))) {     /* data zone? */
    int32 blkno = DT_LIN2BL (uptr->pos, uptr);          /* block # */
    int32 lineno = DT_LIN2OF (uptr->pos, uptr);         /* line # within block */
    fprintf (st, "Block %d, line %d, ", blkno, lineno);
    if (lineno < DT_HTLIN)                              /* header? */
        fprintf (st, "header cell %d, nibble %d\n",
            lineno / DT_LPERMC, lineno % DT_LPERMC);
    else if (lineno < (DTU_LPERB (uptr) - DT_HTLIN))    /* data? */
        fprintf (st, "data word %d, nibble %d\n",
            (lineno - DT_HTLIN) / DT_WSIZE, (lineno - DT_HTLIN) % DT_WSIZE);
    else fprintf (st, "trailer cell %d, nibble %d\n",
        (lineno - (DTU_LPERB (uptr) - DT_HTLIN)) / DT_LPERMC,
        (lineno - (DTU_LPERB (uptr) - DT_HTLIN)) % DT_LPERMC);
    }
else fprintf (st, "Forward end zone\n");                /* fwd end zone */
return SCPE_OK;
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_tsc.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* pdp8_tsc.c: PDP-8 ETOS timesharing option board (TSC8-75)

   Copyright (c) 2003-2011, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   This module is based on Bernhard Baehr's PDP-8/E simulator

        PDP-8/E Simulator Source Code

        Copyright ) 2001-2003 Bernhard Baehr

        TSC8iots.c - IOTs for the TSC8-75 Board plugin

        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

   tsc          TSC8-75 option board
*/

#include "pdp8_defs.h"

extern int32 int_req;
extern int32 SF;
extern int32 tsc_ir;                                    /* "ERIOT" */
extern int32 tsc_pc;                                    /* "ERTB" */
extern int32 tsc_cdf;                                   /* "ECDF" */
extern int32 tsc_enb;                                   /* enable */

#define UNIT_V_SN699    (UNIT_V_UF + 0)                 /* SN 699 or above */
#define UNIT_SN699      (1 << UNIT_V_SN699)

int32 tsc (int32 IR, int32 AC);
t_stat tsc_reset (DEVICE *dptr);

/* TSC data structures

   tsc_dev      TSC device descriptor
   tsc_unit     TSC unit descriptor
   tsc_reg      TSC register list
*/

DIB tsc_dib = { DEV_TSC, 1, { &tsc } };

UNIT tsc_unit = { UDATA (NULL, UNIT_SN699, 0) };

REG tsc_reg[] = {
    { ORDATAD (IR, tsc_ir, 12, "most recently trapped instruction") },
    { ORDATAD (PC, tsc_pc, 12, "PC of most recently trapped instruction") },
    { FLDATAD (CDF, tsc_cdf, 0, "1 if trapped instruction is CDF, 0 otherwise") },
    { FLDATAD (ENB, tsc_enb, 0, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_TSC, "interrupt pending flag") },
    { NULL }
    };

MTAB tsc_mod[] = {
    { UNIT_SN699, UNIT_SN699, "ESME", "ESME", NULL },
    { UNIT_SN699, 0, "no ESME", "NOESME", NULL },
    { 0 }
    };

DEVICE tsc_dev = {
    "TSC", &tsc_unit, tsc_reg, tsc_mod,
    1, 10, 31, 1, 8, 8,
    NULL, NULL, &tsc_reset,
    NULL, NULL, NULL,
    &tsc_dib, DEV_DISABLE | DEV_DIS
    };

/* IOT routine */

int32 tsc (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* ETDS */
        tsc_enb = 0;                                    /* disable int req */
        int_req = int_req & ~INT_TSC;                   /* clear flag */
        break;

    case 1:                                             /* ESKP */
        return (int_req & INT_TSC)? IOT_SKP + AC: AC;   /* skip on int req */

    case 2:                                             /* ECTF */
        int_req = int_req & ~INT_TSC;                   /* clear int req */
        break;

    case 3:                                             /* ECDF */
        AC = AC | ((tsc_ir >> 3) & 07);                 /* read "ERIOT"<6:8> */
        if (tsc_cdf)                                    /* if cdf, skip */
            AC = AC | IOT_SKP;
        tsc_cdf = 0;
        break;

    case 4:                                             /* ERTB */
        return tsc_pc;

    case 5:                                             /* ESME */
        if (tsc_unit.flags & UNIT_SN699) {              /* enabled? */
            if (tsc_cdf && ((tsc_ir & 070) >> 3) == (SF & 07)) {
                AC = AC | IOT_SKP;
                tsc_cdf = 0;
                }
            }
        break;

    case 6:                                             /* ERIOT */
        return tsc_ir;

    case 7:                                             /* ETEN */
        tsc_enb = 1;
        break;
        }                                               /* end switch */

return AC;
}

/* Reset routine */

t_stat tsc_reset (DEVICE *dptr)
{
tsc_ir = 0;
tsc_pc = 0;
tsc_cdf = 0;
tsc_enb = 0;
int_req = int_req & ~INT_TSC;
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































Deleted src/PDP8/pdp8_tt.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/* pdp8_tt.c: PDP-8 console terminal simulator

   Copyright (c) 1993-2016, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   tti,tto      KL8E terminal input/output

   18-Apr-12    RMS     Revised to use clock coscheduling
   18-Jun-07    RMS     Added UNIT_IDLE flag to console input
   18-Oct-06    RMS     Synced keyboard to clock
   30-Sep-06    RMS     Fixed handling of non-printable characters in KSR mode
   22-Nov-05    RMS     Revised for new terminal processing routines
   28-May-04    RMS     Removed SET TTI CTRL-C
   29-Dec-03    RMS     Added console output backpressure support
   25-Apr-03    RMS     Revised for extended file support
   02-Mar-02    RMS     Added SET TTI CTRL-C
   22-Dec-02    RMS     Added break support
   01-Nov-02    RMS     Added 7B/8B support
   04-Oct-02    RMS     Added DIBs, device number support
   30-May-02    RMS     Widened POS to 32b
   07-Sep-01    RMS     Moved function prototypes
*/

#include "pdp8_defs.h"
#include "sim_tmxr.h"
#include <ctype.h>

extern int32 int_req, int_enable, dev_done, stop_inst;
extern int32 tmxr_poll;

int32 tti (int32 IR, int32 AC);
int32 tto (int32 IR, int32 AC);
t_stat tti_svc (UNIT *uptr);
t_stat tto_svc (UNIT *uptr);
t_stat tti_reset (DEVICE *dptr);
t_stat tto_reset (DEVICE *dptr);
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc);

/* TTI data structures

   tti_dev      TTI device descriptor
   tti_unit     TTI unit descriptor
   tti_reg      TTI register list
   tti_mod      TTI modifiers list
*/

DIB tti_dib = { DEV_TTI, 1, { &tti } };

UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_KSR, 0), SERIAL_IN_WAIT };

REG tti_reg[] = {
    { ORDATAD (BUF, tti_unit.buf, 8, "last data item processed") },
    { FLDATAD (DONE, dev_done, INT_V_TTI, "device done flag") },
    { FLDATAD (ENABLE, int_enable, INT_V_TTI, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_TTI, "interrupt pending flag") },
    { DRDATAD (POS, tti_unit.pos, T_ADDR_W, "number of characters input"), PV_LEFT },
    { DRDATAD (TIME, tti_unit.wait, 24, "input polling interval (if 0, the keyboard is polled synchronously with the clock)"), PV_LEFT+REG_NZ },
    { NULL }
    };

MTAB tti_mod[] = {
    { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
    { TT_MODE, TT_MODE_7B,  "7b",  "7B",  &tty_set_mode },
    { TT_MODE, TT_MODE_8B,  "8b",  "8B",  &tty_set_mode },
    { TT_MODE, TT_MODE_7P,  "7b",  NULL,  NULL },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev, NULL },
    { 0 }
    };

DEVICE tti_dev = {
    "TTI", &tti_unit, tti_reg, tti_mod,
    1, 10, 31, 1, 8, 8,
    NULL, NULL, &tti_reset,
    NULL, NULL, NULL,
    &tti_dib, 0
    };

uint32 tti_buftime;                                     /* time input character arrived */

/* TTO data structures

   tto_dev      TTO device descriptor
   tto_unit     TTO unit descriptor
   tto_reg      TTO register list
*/

DIB tto_dib = { DEV_TTO, 1, { &tto } };

UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT };

REG tto_reg[] = {
    { ORDATAD (BUF, tto_unit.buf, 8, "last date item processed") },
    { FLDATAD (DONE, dev_done, INT_V_TTO, "device done flag") },
    { FLDATAD (ENABLE, int_enable, INT_V_TTO, "interrupt enable flag") },
    { FLDATAD (INT, int_req, INT_V_TTO, "interrupt pending flag") },
    { DRDATAD (POS, tto_unit.pos, T_ADDR_W, "number of characters output"), PV_LEFT },
    { DRDATAD (TIME, tto_unit.wait, 24, "time form I/O initiation to interrupt"), PV_LEFT },
    { NULL }
    };

MTAB tto_mod[] = {
    { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode },
    { TT_MODE, TT_MODE_7B,  "7b",  "7B",  &tty_set_mode },
    { TT_MODE, TT_MODE_8B,  "8b",  "8B",  &tty_set_mode },
    { TT_MODE, TT_MODE_7P,  "7p",  "7P",  &tty_set_mode },
    { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev },
    { 0 }
    };

DEVICE tto_dev = {
    "TTO", &tto_unit, tto_reg, tto_mod,
    1, 10, 31, 1, 8, 8,
    NULL, NULL, &tto_reset, 
    NULL, NULL, NULL,
    &tto_dib, 0
    };

/* Terminal input: IOT routine */

int32 tti (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */
    case 0:                                             /* KCF */
        dev_done = dev_done & ~INT_TTI;                 /* clear flag */
        int_req = int_req & ~INT_TTI;
        return AC;

    case 1:                                             /* KSF */
        return (dev_done & INT_TTI)? IOT_SKP + AC: AC;

    case 2:                                             /* KCC */
        dev_done = dev_done & ~INT_TTI;                 /* clear flag */
        int_req = int_req & ~INT_TTI;
        return 0;                                       /* clear AC */

    case 4:                                             /* KRS */
        return (AC | tti_unit.buf);                     /* return buffer */

    case 5:                                             /* KIE */
        if (AC & 1)
            int_enable = int_enable | (INT_TTI+INT_TTO);
        else int_enable = int_enable & ~(INT_TTI+INT_TTO);
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 6:                                             /* KRB */
        dev_done = dev_done & ~INT_TTI;                 /* clear flag */
        int_req = int_req & ~INT_TTI;
        sim_activate_abs (&tti_unit, tti_unit.wait);    /* check soon for more input */
        return (tti_unit.buf);                          /* return buffer */

    default:
        return (stop_inst << IOT_V_REASON) + AC;
        }                                               /* end switch */
}

/* Unit service */

t_stat tti_svc (UNIT *uptr)
{
int32 c;

sim_clock_coschedule (uptr, tmxr_poll);                 /* continue poll */
if ((dev_done & INT_TTI) &&                             /* prior character still pending and < 500ms? */
    ((sim_os_msec () - tti_buftime) < 500))
    return SCPE_OK;
if ((c = sim_poll_kbd ()) < SCPE_KFLAG)                 /* no char or error? */
    return c;
if (c & SCPE_BREAK)                                     /* break? */
    uptr->buf = 0;
else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR);
tti_buftime = sim_os_msec ();
uptr->pos = uptr->pos + 1;
dev_done = dev_done | INT_TTI;                          /* set done */
int_req = INT_UPDATE;                                   /* update interrupts */
return SCPE_OK;
}

/* Reset routine */

t_stat tti_reset (DEVICE *dptr)
{
tmxr_set_console_units (&tti_unit, &tto_unit);
tti_unit.buf = 0;
dev_done = dev_done & ~INT_TTI;                         /* clear done, int */
int_req = int_req & ~INT_TTI;
int_enable = int_enable | INT_TTI;                      /* set enable */
if (!sim_is_running)                                    /* RESET (not CAF)? */
    sim_activate (&tti_unit, tmxr_poll);
return SCPE_OK;
}

/* Terminal output: IOT routine */

int32 tto (int32 IR, int32 AC)
{
switch (IR & 07) {                                      /* decode IR<9:11> */

    case 0:                                             /* TLF */
        dev_done = dev_done | INT_TTO;                  /* set flag */
        int_req = INT_UPDATE;                           /* update interrupts */
        return AC;

    case 1:                                             /* TSF */
        return (dev_done & INT_TTO)? IOT_SKP + AC: AC;

    case 2:                                             /* TCF */
        dev_done = dev_done & ~INT_TTO;                 /* clear flag */
        int_req = int_req & ~INT_TTO;                   /* clear int req */
        return AC;

    case 5:                                             /* SPI */
        return (int_req & (INT_TTI+INT_TTO))? IOT_SKP + AC: AC;

    case 6:                                             /* TLS */
        dev_done = dev_done & ~INT_TTO;                 /* clear flag */
        int_req = int_req & ~INT_TTO;                   /* clear int req */
    case 4:                                             /* TPC */
        sim_activate (&tto_unit, tto_unit.wait);        /* activate unit */
        tto_unit.buf = AC;                              /* load buffer */
        return AC;

    default:
        return (stop_inst << IOT_V_REASON) + AC;
        }                                               /* end switch */
}

/* Unit service */

t_stat tto_svc (UNIT *uptr)
{
int32 c;
t_stat r;

c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR);
if (c >= 0) {
    if ((r = sim_putchar_s (c)) != SCPE_OK) {           /* output char; error? */
        sim_activate (uptr, uptr->wait);                /* try again */
        return ((r == SCPE_STALL)? SCPE_OK: r);         /* if !stall, report */
        }
    }
dev_done = dev_done | INT_TTO;                          /* set done */
int_req = INT_UPDATE;                                   /* update interrupts */
uptr->pos = uptr->pos + 1;
return SCPE_OK;
}

/* Reset routine */

t_stat tto_reset (DEVICE *dptr)
{
tto_unit.buf = 0;
dev_done = dev_done & ~INT_TTO;                         /* clear done, int */
int_req = int_req & ~INT_TTO;
int_enable = int_enable | INT_TTO;                      /* set enable */
sim_cancel (&tto_unit);                                 /* deactivate unit */
return SCPE_OK;
}

t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
tti_unit.flags = (tti_unit.flags & ~TT_MODE) | val;
tto_unit.flags = (tto_unit.flags & ~TT_MODE) | val;
return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































Deleted src/PDP8/pdp8_ttx.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
/* pdp8_ttx.c: PDP-8 additional terminals simulator

   Copyright (c) 1993-2016, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   ttix,ttox    PT08/KL8JA terminal input/output

   18-Sep-16    RMS     Expanded support to 16 terminals
   11-Oct-13    RMS     Poll TTIX immediately to pick up initial connect (Mark Pizzolato)
   18-Apr-12    RMS     Revised to use clock coscheduling
   19-Nov-08    RMS     Revised for common TMXR show routines
   07-Jun-06    RMS     Added UNIT_IDLE flag
   06-Jul-06    RMS     Fixed bug in DETACH routine
   22-Nov-05    RMS     Revised for new terminal processing routines
   29-Jun-05    RMS     Added SET TTOXn DISCONNECT
                        Fixed bug in SET LOG/NOLOG
   21-Jun-05    RMS     Fixed bug in SHOW CONN/STATS
   05-Jan-04    RMS     Revised for tmxr library changes
   09-May-03    RMS     Added network device flag
   25-Apr-03    RMS     Revised for extended file support
   22-Dec-02    RMS     Added break support
   02-Nov-02    RMS     Added 7B/8B support
   04-Oct-02    RMS     Added DIB, device number support
   22-Aug-02    RMS     Updated for changes to sim_tmxr.c
   06-Jan-02    RMS     Added device enable/disable support
   30-Dec-01    RMS     Complete rebuild
   30-Nov-01    RMS     Added extended SET/SHOW support

   This module implements 1-16 individual serial interfaces similar in function
   to the console.  These interfaces are mapped to Telnet based connections as
   though they were the four lines of a terminal multiplexor.  The connection
   polling mechanism is superimposed onto the keyboard of the first interface.

   The done and enable flags are maintained locally, and only a master interrupt
   request is maintained in global register dev_done. Because this is actually
   an interrupt request flag, the corresponding bit in int_enable must always
   be set to 1.
*/

#include "pdp8_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>

#define TTX_MAXL        16
#define TTX_INIL        4

#define TTX_GETLN(x)    (((x) >> 4) & TTX_MASK)

extern int32 int_req, int_enable, dev_done, stop_inst;
extern int32 tmxr_poll;

uint32 ttix_done = 0;                                   /* input ready flags */
uint32 ttox_done = 0;                                   /* output ready flags */
uint32 ttx_enbl = 0;                                    /* intr enable flags */
uint8 ttix_buf[TTX_MAXL] = { 0 };                       /* input buffers */
uint8 ttox_buf[TTX_MAXL] = { 0 };                       /* output buffers */
TMLN ttx_ldsc[TTX_MAXL] = { {0} };                      /* line descriptors */
TMXR ttx_desc = { TTX_INIL, 0, 0, ttx_ldsc };           /* mux descriptor */
#define ttx_lines	ttx_desc.lines

int32 ttix (int32 IR, int32 AC);
int32 ttox (int32 IR, int32 AC);
t_stat ttix_svc (UNIT *uptr);
t_stat ttox_svc (UNIT *uptr);
int32 ttx_getln (int32 inst);
void ttx_new_flags (uint32 newi, uint32 newo, uint32 newe);
t_stat ttx_reset (DEVICE *dptr);
t_stat ttx_attach (UNIT *uptr, CONST char *cptr);
t_stat ttx_detach (UNIT *uptr);
void ttx_reset_ln (int32 i);
t_stat ttx_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat ttx_show_devno (FILE *st, UNIT *uptr, int32 val, CONST void *desc);

#define TTIX_SET_DONE(ln)       ttx_new_flags (ttix_done | (1u << (ln)), ttox_done, ttx_enbl)
#define TTIX_CLR_DONE(ln)       ttx_new_flags (ttix_done & ~(1u << (ln)), ttox_done, ttx_enbl)
#define TTIX_TST_DONE(ln)       ((ttix_done & (1u << (ln))) != 0)
#define TTOX_SET_DONE(ln)       ttx_new_flags (ttix_done, ttox_done | (1u << (ln)), ttx_enbl)
#define TTOX_CLR_DONE(ln)       ttx_new_flags (ttix_done, ttox_done & ~(1u << (ln)), ttx_enbl)
#define TTOX_TST_DONE(ln)       ((ttox_done & (1u << (ln))) != 0)
#define TTX_SET_ENBL(ln)        ttx_new_flags (ttix_done, ttox_done, ttx_enbl | (1u << (ln)))
#define TTX_CLR_ENBL(ln)        ttx_new_flags (ttix_done, ttox_done, ttx_enbl & ~(1u << (ln)))
#define TTX_TST_ENBL(ln)        ((ttx_enbl & (1u << (ln))) != 0)

/* TTIx data structures

   ttix_dev     TTIx device descriptor
   ttix_unit    TTIx unit descriptor
   ttix_reg     TTIx register list
   ttix_mod     TTIx modifiers list
*/

DIB_DSP ttx_dsp[TTX_MAXL * 2] = {
    { DEV_TTI1,  &ttix }, { DEV_TTO1,  &ttox },
    { DEV_TTI2,  &ttix }, { DEV_TTO2,  &ttox },
    { DEV_TTI3,  &ttix }, { DEV_TTO3,  &ttox },
    { DEV_TTI4,  &ttix }, { DEV_TTO4,  &ttox },
    { DEV_TTI5,  &ttix }, { DEV_TTO5,  &ttox },
    { DEV_TTI6,  &ttix }, { DEV_TTO6,  &ttox },
    { DEV_TTI7,  &ttix }, { DEV_TTO7,  &ttox },
    { DEV_TTI8,  &ttix }, { DEV_TTO8,  &ttox },
    { DEV_TTI9,  &ttix }, { DEV_TTO9,  &ttox },
    { DEV_TTI10, &ttix }, { DEV_TTO10, &ttox },
    { DEV_TTI11, &ttix }, { DEV_TTO11, &ttox },
    { DEV_TTI12, &ttix }, { DEV_TTO12, &ttox },
    { DEV_TTI13, &ttix }, { DEV_TTO13, &ttox },
    { DEV_TTI14, &ttix }, { DEV_TTO14, &ttox },
    { DEV_TTI15, &ttix }, { DEV_TTO15, &ttox },
    { DEV_TTI16, &ttix }, { DEV_TTO16, &ttox }
    };

DIB ttx_dib = { DEV_TTI1, TTX_INIL * 2, { &ttix, &ttox }, ttx_dsp };

UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_IDLE|UNIT_ATTABLE, 0), SERIAL_IN_WAIT };

REG ttix_reg[] = {
    { BRDATAD (BUF, ttix_buf, 8, 8, TTX_MAXL, "input buffer, lines 0 to 15") },
    { ORDATAD (DONE, ttix_done, TTX_MAXL, "device done flag (line 0 rightmost)") },
    { ORDATAD (ENABLE, ttx_enbl, TTX_MAXL, "interrupt enable flag") },
    { FLDATA  (SUMDONE, dev_done, INT_V_TTI1), REG_HRO },
    { FLDATA  (SUMENABLE, int_enable, INT_V_TTI1), REG_HRO },
    { DRDATAD (TIME, ttix_unit.wait, 24, "initial polling interval"), REG_NZ + PV_LEFT },
    { DRDATA  (LINES, ttx_desc.lines, 6), REG_HRO },
    { NULL }
    };

MTAB ttix_mod[] = {
    { MTAB_VDV,            0,       "LINES",      "LINES", &ttx_vlines,  &tmxr_show_lines, (void *) &ttx_desc },
    { MTAB_VDV,            0,      "DEVNO",          NULL, NULL,         &ttx_show_devno, (void *) &ttx_desc },
    { UNIT_ATT,     UNIT_ATT,     "SUMMARY",         NULL, NULL,         &tmxr_show_summ,  (void *) &ttx_desc },
    { MTAB_VDV,            1,          NULL, "DISCONNECT", &tmxr_dscln,  NULL,             (void *) &ttx_desc },
    { MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS",         NULL, NULL,         &tmxr_show_cstat, (void *) &ttx_desc },
    { MTAB_VDV | MTAB_NMO, 0, "STATISTICS",          NULL, NULL,         &tmxr_show_cstat, (void *) &ttx_desc },
    { 0 }
    };

/* debugging bitmaps */
#define DBG_XMT  TMXR_DBG_XMT                           /* display Transmitted Data */
#define DBG_RCV  TMXR_DBG_RCV                           /* display Received Data */
#define DBG_RET  TMXR_DBG_RET                           /* display Returned Received Data */
#define DBG_CON  TMXR_DBG_CON                           /* display connection activities */
#define DBG_TRC  TMXR_DBG_TRC                           /* display trace routine calls */

DEBTAB ttx_debug[] = {
  {"XMT",    DBG_XMT, "Transmitted Data"},
  {"RCV",    DBG_RCV, "Received Data"},
  {"RET",    DBG_RET, "Returned Received Data"},
  {"CON",    DBG_CON, "connection activities"},
  {"TRC",    DBG_TRC, "trace routine calls"},
  {0}
};

DEVICE ttix_dev = {
    "TTIX", &ttix_unit, ttix_reg, ttix_mod,
    1, 10, 31, 1, 8, 8,
    &tmxr_ex, &tmxr_dep, &ttx_reset,
    NULL, &ttx_attach, &ttx_detach,
    &ttx_dib, DEV_MUX | DEV_DISABLE | DEV_DEBUG,
    0, ttx_debug
    };

/* TTOx data structures

   ttox_dev     TTOx device descriptor
   ttox_unit    TTOx unit descriptor
   ttox_reg     TTOx register list
*/

UNIT ttox_unit[] = {
    { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT },
    { UDATA (&ttox_svc, TT_MODE_UC+UNIT_DIS, 0), SERIAL_OUT_WAIT }
    };

REG ttox_reg[] = {
    { BRDATAD (BUF, ttox_buf, 8, 8, TTX_MAXL, "last data item processed, lines 0 to 3") },
    { ORDATAD  (DONE, ttox_done, TTX_MAXL, "device done flag (line 0 rightmost)") },
    { ORDATAD  (ENABLE, ttx_enbl, TTX_MAXL, "interrupt enable flag") },
    { FLDATA  (SUMDONE, dev_done, INT_V_TTO1), REG_HRO },
    { FLDATA  (SUMENABLE, int_enable, INT_V_TTO1), REG_HRO },
    { URDATAD (TIME, ttox_unit[0].wait, 10, 24, 0,
              TTX_MAXL, PV_LEFT, "line from I/O initiation to interrupt, lines 0 to 3") },
    { NULL }
    };

MTAB ttox_mod[] = {
    { TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
    { TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
    { TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
    { TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
    { MTAB_VDV, 0, "DEVNO", NULL, NULL, &ttx_show_devno, &ttx_desc },
    { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
      &tmxr_dscln, NULL, &ttx_desc },
    { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
      &tmxr_set_log, &tmxr_show_log, &ttx_desc },
    { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
      &tmxr_set_nolog, NULL, &ttx_desc },
    { 0 }
    };

DEVICE ttox_dev = {
    "TTOX", ttox_unit, ttox_reg, ttox_mod,
    TTX_MAXL, 10, 31, 1, 8, 8,
    NULL, NULL, &ttx_reset, 
    NULL, NULL, NULL,
    NULL, DEV_DISABLE | DEV_DEBUG,
    0, ttx_debug
    };

/* Terminal input: IOT routine */

int32 ttix (int32 inst, int32 AC)
{
int32 pulse = inst & 07;                                /* IOT pulse */
int32 ln = ttx_getln (inst);                            /* line # */

if (ln < 0)                                             /* bad line #? */
    return (SCPE_IERR << IOT_V_REASON) | AC;

switch (pulse) {                                        /* case IR<9:11> */

    case 0:                                             /* KCF */
        TTIX_CLR_DONE (ln);                             /* clear flag */
        break;

    case 1:                                             /* KSF */
        return (TTIX_TST_DONE (ln))? IOT_SKP | AC: AC;

    case 2:                                             /* KCC */
        TTIX_CLR_DONE (ln);                             /* clear flag */
        sim_activate_abs (&ttix_unit, ttix_unit.wait);  /* check soon for more input */
        return 0;                                       /* clear AC */

    case 4:                                             /* KRS */
        return (AC | ttix_buf[ln]);                     /* return buf */

    case 5:                                             /* KIE */
        if (AC & 1)
            TTX_SET_ENBL (ln);
        else TTX_CLR_ENBL (ln);
        break;

    case 6:                                             /* KRB */
        TTIX_CLR_DONE (ln);                             /* clear flag */
        sim_activate_abs (&ttix_unit, ttix_unit.wait);  /* check soon for more input */
        return ttix_buf[ln];                            /* return buf */

    default:
        return (stop_inst << IOT_V_REASON) | AC;
        }                                               /* end switch */

return AC;
}

/* Unit service */

t_stat ttix_svc (UNIT *uptr)
{
int32 ln, c, temp;

if ((uptr->flags & UNIT_ATT) == 0)                      /* attached? */
    return SCPE_OK;
sim_clock_coschedule (uptr, tmxr_poll);                 /* continue poll */
ln = tmxr_poll_conn (&ttx_desc);                        /* look for connect */
if (ln >= 0)                                            /* got one? */
    ttx_ldsc[ln].rcve = 1;                              /* set rcv enable */
tmxr_poll_rx (&ttx_desc);                               /* poll for input */
for (ln = 0; ln < ttx_lines; ln++) {                    /* loop thru lines */
    if (ttx_ldsc[ln].conn) {                            /* connected? */
        if (TTIX_TST_DONE (ln))                         /* last char still pending? */
            continue;
        if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) {    /* get char */
            if (temp & SCPE_BREAK)                      /* break? */
                c = 0;
            else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags));
            ttix_buf[ln] = c;
            TTIX_SET_DONE (ln);                         /* set flag */
            }
        }
    }
return SCPE_OK;
}

/* Terminal output: IOT routine */

int32 ttox (int32 inst, int32 AC)
{
int32 pulse = inst & 07;                                /* pulse */
int32 ln = ttx_getln (inst);                            /* line # */

if (ln < 0)                                             /* bad line #? */
    return (SCPE_IERR << IOT_V_REASON) | AC;

switch (pulse) {                                        /* case IR<9:11> */

    case 0:                                             /* TLF */
        TTOX_SET_DONE (ln);                             /* set flag */
        break;

    case 1:                                             /* TSF */
        return (TTOX_TST_DONE (ln))? IOT_SKP | AC: AC;

    case 2:                                             /* TCF */
        TTOX_CLR_DONE (ln);                             /* clear flag */
        break;

    case 5:                                             /* SPI */
        if ((TTIX_TST_DONE (ln) || TTOX_TST_DONE (ln))  /* either done set */
            && TTX_TST_ENBL (ln))                       /* and enabled? */
            return IOT_SKP | AC;
        return AC;

    case 6:                                             /* TLS */
        TTOX_CLR_DONE (ln);                             /* clear flag */
    case 4:                                             /* TPC */
        sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */
        ttox_buf[ln] = AC & 0377;                       /* load buffer */
        break;

   default:
        return (stop_inst << IOT_V_REASON) | AC;
        }                                               /* end switch */

return AC;
}

/* Unit service */

t_stat ttox_svc (UNIT *uptr)
{
int32 c, ln = uptr - ttox_unit;                         /* line # */

if (ttx_ldsc[ln].conn) {                                /* connected? */
    if (ttx_ldsc[ln].xmte) {                            /* tx enabled? */
        TMLN *lp = &ttx_ldsc[ln];                       /* get line */
        c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags));
        if (c >= 0)                                     /* output char */
            tmxr_putc_ln (lp, c);
        tmxr_poll_tx (&ttx_desc);                       /* poll xmt */
        }
    else {
        tmxr_poll_tx (&ttx_desc);                       /* poll xmt */
        sim_activate (uptr, ttox_unit[ln].wait);        /* wait */
        return SCPE_OK;
        }
    }
TTOX_SET_DONE (ln);                                     /* set done */
return SCPE_OK;
}

/* Flag routine

   Global dev_done is used as a master interrupt; therefore, global
   int_enable must always be set
*/

void ttx_new_flags (uint32 newidone, uint32 newodone, uint32 newenbl)
{
ttix_done = newidone;
ttox_done = newodone;
ttx_enbl = newenbl;
if ((ttix_done & ttx_enbl) != 0)
    dev_done |= INT_TTI1;
else dev_done &= ~INT_TTI1;
if ((ttox_done & ttx_enbl) != 0)
    dev_done |= INT_TTO1;
else dev_done &= ~INT_TTO1;
int_enable |= (INT_TTI1 | INT_TTO1);
int_req = INT_UPDATE;
return;
}

/* Compute relative line number, based on table of device numbers */

int32 ttx_getln (int32 inst)
{
int32 i;
int32 device = (inst >> 3) & 077;                       /* device = IR<3:8> */

for (i = 0; i < (ttx_lines * 2); i++) {                 /* loop thru disp tbl */
    if (device == ttx_dsp[i].dev)                       /* dev # match? */
        return (i >> 1);                                /* return line # */
    }
return -1;
}

/* Reset routine */

t_stat ttx_reset (DEVICE *dptr)
{
int32 ln;

if (dptr->flags & DEV_DIS) {                            /* sync enables */
    ttix_dev.flags |= DEV_DIS;
    ttox_dev.flags |= DEV_DIS;
    }
else {
    ttix_dev.flags &= ~DEV_DIS;
    ttox_dev.flags &= ~DEV_DIS;
    }
if (ttix_unit.flags & UNIT_ATT)                         /* if attached, */
    sim_activate (&ttix_unit, tmxr_poll);               /* activate */
else sim_cancel (&ttix_unit);                           /* else stop */
for (ln = 0; ln < TTX_MAXL; ln++)                       /* for all lines */
    ttx_reset_ln (ln);                                  /* reset line */
int_enable |= (INT_TTI1 | INT_TTO1);                    /* set master enable */
return SCPE_OK;
}

/* Reset line n */

void ttx_reset_ln (int32 ln)
{
uint32 mask = (1u << ln);

ttix_buf[ln] = 0;                                       /* clr buf */
ttox_buf[ln] = 0;                                       /* clr done, set enbl */
ttx_new_flags (ttix_done & ~mask, ttox_done & ~mask, ttx_enbl | mask);
sim_cancel (&ttox_unit[ln]);                            /* stop output */
return;
}

/* Attach master unit */

t_stat ttx_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;

r = tmxr_attach (&ttx_desc, uptr, cptr);                /* attach */
if (r != SCPE_OK)                                       /* error */
    return r;
sim_activate (uptr, 0);                                 /* start poll at once */
return SCPE_OK;
}

/* Detach master unit */

t_stat ttx_detach (UNIT *uptr)
{
int32 i;
t_stat r;

r = tmxr_detach (&ttx_desc, uptr);                      /* detach */
for (i = 0; i < TTX_MAXL; i++)                         /* all lines, */
    ttx_ldsc[i].rcve = 0;                               /* disable rcv */
sim_cancel (uptr);                                      /* stop poll */
return r;
}

/* Change number of lines */

t_stat ttx_vlines (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;

if (cptr == NULL)
    return SCPE_ARG;
newln = get_uint (cptr, 10, TTX_MAXL, &r);
if ((r != SCPE_OK) || (newln == ttx_lines))
    return r;
if (newln == 0)
    return SCPE_ARG;
if (newln < ttx_lines) {
    for (i = newln, t = 0; i < ttx_lines; i++)
        t = t | ttx_ldsc[i].conn;
    if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
        return SCPE_OK;
    for (i = newln; i < ttx_lines; i++) {
        if (ttx_ldsc[i].conn) {
            tmxr_linemsg (&ttx_ldsc[i], "\r\nOperator disconnected line\r\n");
            tmxr_reset_ln (&ttx_ldsc[i]);               /* reset line */
            }
        ttox_unit[i].flags |= UNIT_DIS;
        ttx_reset_ln (i);
        }
    }
else {
    for (i = ttx_lines; i < newln; i++) {
        ttox_unit[i].flags &= ~UNIT_DIS;
        ttx_reset_ln (i);
        }
    }
ttx_lines = newln;
ttx_dib.num = newln * 2;
return SCPE_OK;
}

/* Show device numbers */
t_stat ttx_show_devno (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 i, dev_offset;
DEVICE *dptr;

if (uptr == NULL)
    return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
    return SCPE_IERR;
/* Select correct devno entry for Input or Output device */
if (dptr->name[2] == 'O')
    dev_offset = 1;
else
    dev_offset = 0;

fprintf(st, "devno=");
for (i = 0; i < ttx_lines; i++) {
    fprintf(st, "%02o%s", ttx_dsp[i*2+dev_offset].dev, i < ttx_lines-1 ? 
         "," : "");
}
return SCPE_OK;
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pidp8i.c.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
/* pidp8i.c: PiDP-8/I additions to the PDP-8 simulator

   Copyright © 2015-2017 by Oscar Vermeulen, Ian Schofield, and
   Warren Young

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the names of the authors above shall
   not be used in advertising or otherwise to promote the sale, use or other
   dealings in this Software without prior written authorization from those
   authors.
*/

#include "pidp8i.h"

#include "../gpio-common.h"

#include <assert.h>
#include <dirent.h> // for USB stick searching


//// MODULE GLOBALS ////////////////////////////////////////////////////

// handle_sing_step() sets this to nonzero and returns a value breaking
// us out of the PDP-8 simulator's sim_instr() loop, which causes SCP to
// call our build_pidp8i_scp_cmd(), which gives SCP a command to run:
// either "exit" when it wants the simulator to stop (e.g the shutdown
// and reboot combos) or "do $script" on IF + SING_STEP combo.
//
// We loop the flow control from this module out into the generic SIMH
// code and then back in here so we don't have to export this global.
// Basically, this module global lets us remember what handle_sing_step
// wants SCP to do in the window between switch handling time and SCP
// command handling time.
static enum {
    CMD_NONE = 0,            // "do nothing" idle case
    CMD_DO_BOOTSCRIPT_1,     // SING_STEP + IF combos
    CMD_DO_BOOTSCRIPT_2,
    CMD_DO_BOOTSCRIPT_3,
    CMD_DO_BOOTSCRIPT_4,
    CMD_DO_BOOTSCRIPT_5,
    CMD_DO_BOOTSCRIPT_6,
    CMD_DO_BOOTSCRIPT_7,
    CMD_EXIT,
} insert_scp_cmd = CMD_NONE;


//// build_pidp8i_scp_cmd //////////////////////////////////////////////
// If insert_scp_cmd is nonzero, we return the corresponding SCP command 
// we want run to make the simulator do something else.

char *build_pidp8i_scp_cmd (char *cbuf, size_t cbufsize)
{
    if (insert_scp_cmd == CMD_NONE) {
        return 0;                               // nothing to do yet
    }
    else if ((insert_scp_cmd > 0) && (insert_scp_cmd <= 7)) {
        // We got one of the IF + SING_STEP combos, so restart the
        // simulator with the corresponding init script.
        char path[256];
        snprintf (path, sizeof (path), "@BOOTDIR@/%d.script", insert_scp_cmd);
        insert_scp_cmd = CMD_NONE;              // it's a one-shot
        if (access(path, R_OK) == 0) {
            snprintf (cbuf, cbufsize, "do %s", path);
            return cbuf;
        }
        else {
            // That boot script doesn't exist or isn't readable.
            //
            // Fall through to the "exit" command builder below because
            // we don't want to keep coming back in here at host CPU
            // speed, failing the same way and issuing the same error
            // until the slow human manages to flip the offending switch
            // back.  This is especially annoying when the PiDP-8/I is
            // attached to a slow serial console.  Ask me how I know.
            int access_errno = errno;      // preserve it from getcwd()
            char cwd[256];
            getcwd (cwd, sizeof (cwd));
            printf ("Cannot read %s from %s: %s!\n", path, cwd,
                    strerror (access_errno));
        }
    }
    else if (insert_scp_cmd > CMD_EXIT) {
        printf ("Invalid PiDP-8/I SCP command value %d given!\n",
                insert_scp_cmd);
    }
    else {
        // C doesn't require that "if" statements handle all cases
        // statically, so do a runtime check to make sure we have
        // exhausted all the other cases above.
        //
        // We can get in here by means other than programmer error in
        // modifying the enum: some C compilers allow signed values
        // to be assigned to enums, so we could get in here on negative
        // values.  We can't test for that above because one of the C
        // compilers we build under (clang on macOS 10.12+) won't allow
        // that short of nasty low-level hackery, so it complains if we
        // test for negative values, claiming it can never happen.
        assert (insert_scp_cmd == CMD_EXIT);
    }

    // If we get here, we got a nonzero command value but didn't get
    // into the happy path above, so die.
    return strncpy (cbuf, "exit", cbufsize);
}


//// set_pidp8i_led ////////////////////////////////////////////////////
// Sets the current state for a single LED at the given row and column
// on the PiDP-8/I PCB.  Also increments the LED on-count value for 
// that LED.
//
// You may say, "You can't just use the C postincrement operator here!
// Look at the assembly output!  You must use an atomic increment for
// this!"  And indeed, there is a big difference between the two
// methods: https://godbolt.org/g/0Qt0Ap
//
// The thing is, both structures referred to by pdis_* are fixed in RAM,
// and the two threads involved are arranged in a strict producer-and-
// consumer fashion, so it doesn't actually matter if pdis_update gets
// swapped for pdis_paint while we're halfway through an increment: we
// get a copy of the pointer to dereference here, so we'll finish our
// increment within the same structure we started with, even if
// pdis_update points at the other display structure before we leave.

static inline void set_pidp8i_led (display *pd, size_t row, size_t col)
{
    ++pd->on[row][col];
    pd->curr[row] |= 1 << col;
}


//// set_pidp8i_row_leds ///////////////////////////////////////////////
// Like set_pidp8i_led, except that it takes a 12-bit state value for
// setting all LEDs on the given row.  Because we copy the pdis_update
// pointer before making changes, if the display swap happens while
// we're working, we'll simply finish updating what has become the
// paint-from display, which is what you want; you don't want the
// updates spread over both displays.

static inline void set_pidp8i_row_leds (display *pd, size_t row,
        uint16 state)
{
    size_t *prow = pd->on[row];
    pd->curr[row] = state;
    for (size_t col = 0, mask = 1; col < NCOLS; ++col, mask <<= 1) {
        if (state & mask) ++prow[col];
    }
}


//// set_3_pidp8i_leds /////////////////////////////////////////////////
// Special case of set_pidp8i_row_leds for the DF and IF LEDs: we only
// pay attention to bits 12, 13, and 14 of the given state value,
// because SIMH's PDP-8 simulator shifts those 3 bits up there so it can
// simply OR these 3-bit registers with PC to produce a 15-bit extended
// address.
//
// We don't take a row parameter because we know which row they're on,
// but we do take a column parameter so we can generalize for IF & DF.

static inline void set_3_pidp8i_leds (display *pd, size_t col,
        uint16 state)
{
    static const int row = 7;       // DF and IF are on row 6
    size_t *prow = pd->on[row];
    size_t last_col = col + 3;
    pd->curr[row] |= state >> (12 - col);
    for (size_t mask = 1 << 12; col < last_col; ++col, mask <<= 1) {
        if (state & mask) ++prow[col];
    }
}


//// set_5_pidp8i_leds /////////////////////////////////////////////////
// Like set_3... but for the 5-bit SC register.  Because it's only used
// for that purpose, we don't need the col parameter.

static inline void set_5_pidp8i_leds (display *pd, uint16 state)
{
    static const int row = 6;       // SC is on row 6
    size_t *prow = pd->on[row];
    size_t last_col = 7;
    pd->curr[row] |= (state & 0x1f) << 2;
    for (size_t col = 2, mask = 1; col < last_col; ++col, mask <<= 1) {
        if (state & mask) ++prow[col];
    }
}


//// get_pidp8i_initial_max_skips //////////////////////////////////////
// Return the number of times we should skip updating the front panel
// LEDs the first time thru, to give the simulator time to settle.
// If we don't do this, the front panel LEDs can start out dim and
// slowly rise or they can overshoot and then take a while to recover
// with the IPS.

size_t get_pidp8i_initial_max_skips (size_t updates_per_sec)
{
    DEVICE *pthrot = find_dev ("INT-THROTTLE");
    if (pthrot) {
        REG *ptyper = find_reg ("THROT_TYPE", NULL, pthrot);
        REG *pvalr  = find_reg ("THROT_VAL", NULL, pthrot);
        if (ptyper && pvalr) {
            uint32 *ptype = ptyper->loc;
            uint32 *pval  =  pvalr->loc;
            size_t ips = 0;
            switch (*ptype) {
                case SIM_THROT_MCYC: ips = *pval * 1e6; break;
                case SIM_THROT_KCYC: ips = *pval * 1e3; break;
            }
            if (ips) {
                printf("PiDP-8/I initial throttle = %zu IPS\r\n", ips);
                return ips / updates_per_sec;
            }
        }
    }

    // No better idea, so give a plausible value for an unthrottled Pi 1
    return 200;
}


//// set_pidp8i_leds ///////////////////////////////////////////////////
// Given all of the PDP-8's internal registers that affect the front
// panel display, modify the GPIO thread's LED state values accordingly.
//
// Also update the LED brightness values based on those new states.

void set_pidp8i_leds (uint32 sPC, uint32 sMA, uint16 sMB,
    uint16 sIR, int32 sLAC, int32 sMQ, int32 sIF, int32 sDF,
    int32 sSC, int32 int_req, int Pause)
{
    // Bump the instruction count.  This should always be equal to the
    // Fetch LED's value, but integers are too cheap to get cute here.
    //
    // Note that we only update pdis_update directly once in this whole
    // process.  This is in case the display swap happens while we're
    // working: we want to finish work on the same display even though
    // it's now called the paint-from display, so it's consistent.
    display* pd = pdis_update;
    ++pd->inst_count;

    // Rows 0-4, easy cases: single-register LED strings
    set_pidp8i_row_leds (pd, 0, sPC);
    set_pidp8i_row_leds (pd, 1, sMA);
    set_pidp8i_row_leds (pd, 2, sMB);
    set_pidp8i_row_leds (pd, 3, sLAC & 07777);
    set_pidp8i_row_leds (pd, 4, sMQ);

#if 0   // debugging
    static time_t last = 0, now;
    if (time(&now) != last) {
        uint16* pcurr = pd->curr;
        printf("\r\nSET: [PC:%04o] [MA:%04o] [MB:%04o] [AC:%04o] [MQ:%04o]",
                pcurr[0], pcurr[1], pcurr[2], pcurr[3], pcurr[4]);
        last = now;
    }
#endif

    // Row 5a: instruction type column, decoded from high octal
    // digit of IR value
    pd->curr[5] = 0;
    uint16 inst_type = sIR & 07000;
    switch (inst_type) {
        case 00000: set_pidp8i_led (pd, 5, 11); break; // 000 AND
        case 01000: set_pidp8i_led (pd, 5, 10); break; // 001 TAD
        case 02000: set_pidp8i_led (pd, 5,  9); break; // 010 DCA
        case 03000: set_pidp8i_led (pd, 5,  8); break; // 011 ISZ
        case 04000: set_pidp8i_led (pd, 5,  7); break; // 100 JMS
        case 05000: set_pidp8i_led (pd, 5,  6); break; // 101 JMP
        case 06000: set_pidp8i_led (pd, 5,  5); break; // 110 IOT
        case 07000: set_pidp8i_led (pd, 5,  4); break; // 111 OPR 1 & 2
    }

    // Row 5b: set the Defer LED if...
    if ((inst_type <= 05000) &&  // it's a memory reference instruction
            (sIR & 00400)) {     // and indirect addressing flag is set
        set_pidp8i_led (pd, 5, 1);
    }

    // Row 5c: The Fetch LED is bumped once per CPU instruction, as is
    // Execute while we're not in STOP state.  They're set at different
    // times, but they're twiddled so rapidly that they both just become
    // a 50% blur in normal operation, so we don't make the CPU core set
    // these "on-time."  It just doesn't matter.
    extern int swStop, swSingInst;
    int running = !swStop && !swSingInst;
    if (running) set_pidp8i_led (pd, 5, 2);    // Execute
    set_pidp8i_led (pd, 5, 3);                 // Fetch

    // Row 6a: Remaining LEDs in upper right block
    pd->curr[6] = 0;
    if (running)           set_pidp8i_led (pd, 6, 7); // bump Run LED
    if (Pause)             set_pidp8i_led (pd, 6, 8); // bump Pause LED
    if (int_req & INT_ION) set_pidp8i_led (pd, 6, 9); // bump ION LED

    // Row 6b: The Step Count LEDs are also on row 6
    set_5_pidp8i_leds (pd, sSC);

    // Row 7: DF, IF, and Link.
    pd->curr[7] = 0;
    set_3_pidp8i_leds (pd, 9, sDF);
    set_3_pidp8i_leds (pd, 6, sIF);
    if (sLAC & 010000) set_pidp8i_led (pd, 7, 5);

    // If we're stopped or single-stepped, the display-swapping code
    // won't happen, so copy the above over to the paint-from version.
    extern int resumeFromInstructionLoopExit;
    if (!running || resumeFromInstructionLoopExit) {
        memcpy(pdis_paint, pdis_update, sizeof(struct display));
    }
}


//// mount_usb_stick_file //////////////////////////////////////////////
// Search for a PDP-8 media image in one of the Pi's USB auto-mount
// directories and attempt to ATTACH it to the simulator.

static void mount_usb_stick_file (int devNo, char *devCode)
{
    char    sFoundFile[CBUFSIZE] = { '\0' };
    char    sUSBPath[CBUFSIZE];     // will be "/media/usb0" etc
    char    fileExtension[4];       // will be ".RX" etc
    int     i, j;

    // Build expected file name extension from the first two characters of
    // the passed-in device code.
    fileExtension[0] = '.';                     // extension starts with a .
    strncpy (fileExtension + 1, devCode, 2);    // extension is PT, RX, RL etc
    fileExtension[3] = '\0';                    // chop off device number

#if 0   // debugging
    printf("\r\nMOUNT USB: [DEV:%d] [CODE:%s], [EXT:%s]",
            devNo, devCode, fileExtension);
#endif

    // Forget the prior file attached to this PDP-8 device.  The only reason
    // we keep track is so we don't have the same media image file attached
    // to both devices of a given type we support.  That is, you can't have
    // a given floppy image file attached to both RX01 drives, but you *can*
    // repeatedly re-ATTACH the same floppy image to the first RX01 drive.
    static char mountedFiles[8][CBUFSIZE];
    mountedFiles[devNo][0] = '\0';

    for (i = 0; i < 8 && sFoundFile[0] == '\0'; ++i) {
        // search all 8 USB mount points, numbered 0-7
        snprintf (sUSBPath, sizeof (sUSBPath), "/media/usb%d", i);
        DIR *pDir = opendir (sUSBPath);
        if (pDir) {
            struct dirent* pDirent;
            while ((pDirent = readdir (pDir)) != 0) { // search all files in directory
                if (pDirent->d_name[0] == '.') continue;    // dotfiles clutter debug output

                char* pext = strstr (pDirent->d_name, fileExtension);
                if (pext && (pext == (pDirent->d_name + strlen (pDirent->d_name) - 3))) {
                    snprintf (sFoundFile, sizeof (sFoundFile), "%s/%s",
                            sUSBPath, pDirent->d_name);
#if 0   // debugging
                    printf("\r\nFound candidate file %s for dev %s, ext *%s...",
                            sFoundFile, devCode, fileExtension);
#endif
                    for (j = 0; j < 7; ++j) {
                        if (strncmp (mountedFiles[j], sFoundFile, CBUFSIZE) == 0) {
#if 0   // debugging
                            printf("\r\nAlready have %s mounted, slot %d; will not remount.",
                                    sFoundFile, j);
#endif
                            sFoundFile[0] = '\0';   // don't leave outer loop; keep looking
                            break;
                        }
                    }
                    if (j == 7) {
                        // Media image file is not already mounted, so leave while
                        // loop with path set to mount it
                        break;
                    }
                }
#if 0   // debugging
                else {
                    printf("\r\nFile %s on %s doesn't match *%s...",
                            pDirent->d_name, sUSBPath, fileExtension);
                }
#endif
            }

            closedir (pDir);
        }
        else {
            // Not a Pi or the USB auto-mounting software isn't installed
            printf ("\r\nCannot open %s: %s\r\n", sUSBPath, strerror (errno));
            return;
        }
    }

    if (sFoundFile[0]) {            // no file found, exit
        if (access (sFoundFile, R_OK) == 0) {
            char sAttachCmd[CBUFSIZE] = { '\0' };
            snprintf (sAttachCmd, sizeof(sAttachCmd), "%s %s",
                    devCode, sFoundFile);
            t_stat scpCode = attach_cmd ((int32) 0, sAttachCmd);
            if (scpCode == SCPE_OK) {
                // add file to mount list
                strncpy (mountedFiles[devNo], sFoundFile, CBUFSIZE);
                printf ("\r\nMounted %s %s\r\n", devCode, mountedFiles[devNo]);
            }
            else {
                // SIMH ATTACH command failed
                printf ("\r\nSIMH error mounting %s on %s: %s\r\n",
                        sFoundFile, devCode, sim_error_text (scpCode));
            }
        }
        else {
            printf ("\r\nCannot read medium image %s from USB: %s\r\n",
                    sFoundFile, strerror (errno));
        }
    }
    else {
        printf ("\r\nNo unmounted %s file found\r\n", devCode);
    }
}


//// handle_sing_step //////////////////////////////////////////////////
// Handle SING_STEP combinations as nonstandard functions with respect
// to a real PDP-8, since SIMH doesn't try to emulate the PDP-8's
// single-stepping mode — not to be confused with single-instruction
// mode, which SIMH *does* emulate — so the SING_STEP switch is free
// for our nonstandard uses.
//
// This is separate from handle_flow_control_switches only because
// there are so many cases here that it would obscure the overall flow
// of our calling function to do all this there.

static pidp8i_flow_t handle_sing_step (int closed)
{
    // If SING_STEP is open, we do nothing here except reset the single-shot
    // flag if it was set.
    static int single_shot = 0;
    if (!closed) {
        single_shot = 0;
        return pft_normal;
    }

    // There are two sets of SING_STEP combos: first up are those where the
    // other switches involved have to be set already, and the function is
    // triggered as soon as SING_STEP closes.  These are functions we don't
    // want re-executing repeatedly while SING_STEP remains closed.
    if (single_shot == 0) {
        // SING_STEP switch was open last we knew, and now it's closed, so
        // set the single-shot flag.
        single_shot = 1;

        // 1. Convert DF switch values to a device number, which
        // we will map to a PDP-8 device type, then attempt to
        // ATTACH some unmounted medium from USB to that device
        //
        // We treat DF == 0 as nothing to mount, since we use
        // SING_STEP for other things, so we need a way to
        // decide which meaning of SING_STEP to take here.
        //
        // The shift by 9 is how many non-DF bits are below
        // DF in switchstatus[1]
        //
        // The bit complement is because closed DF switches show
        // as 0, because they're dragging the pull-up down, but
        // we want those treated as 1s, and vice versa.
        uint16_t css1 = ~switchstatus[1]; 
        int swDevice = (css1 & SS1_DF_ALL) >> 9;
        if (swDevice) {
            char swDevCode[4] = { '\0' };
            switch (swDevice) {
                case 1: strcpy (swDevCode, "ptr"); break; // PTR paper tape reader
                case 2: strcpy (swDevCode, "ptp"); break; // High speed paper tape punch
                case 3: strcpy (swDevCode, "dt0"); break; // TC08 DECtape (#8 is first!)
                case 4: strcpy (swDevCode, "dt1"); break;
                case 5: strcpy (swDevCode, "rx0"); break; // RX8E (8/e peripheral!)
                case 6: strcpy (swDevCode, "rx1"); break;
                case 7: strcpy (swDevCode, "rk1"); break; // second RK05 disk pack
            }
            if (swDevCode[0]) mount_usb_stick_file (swDevice, swDevCode);
        }

        // 2. Do the same with IF, except that the switch value
        // is used to decide which boot script to restart with via
        // SIMH's DO command.
        //
        // The shift value of 6 is because the IF switches are 3
        // down from the DF switches above.
        int swScript = (css1 & SS1_IF_ALL) >> 6;
        if (swScript) {
            printf ("\r\n\nRestarting with IF == %d...\r\n\r\n", swScript);
            insert_scp_cmd = swScript;
            return pft_halt;
        }
    } // end if single-shot flag clear
    else {
        // Now handle the second set of SING_STEP special-function
        // combos, being those where the switches can be pressed in any
        // order, so that we take action when the last one of the set
        // closes, no matter which one that is.  These immediately exit
        // the SIMH instruction interpreter, so they won't re-execute
        // merely because the human isn't fast enough to lift his finger
        // by the time the next iteration of that loop starts.

        // 3. Scan for host poweroff command (Sing_Step + Sing_Inst + Stop)
        if ((switchstatus[2] & (SS2_S_INST | SS2_STOP)) == 0) {
            printf ("\r\nShutdown\r\n\r\n");
            insert_scp_cmd = CMD_EXIT;
            if (spawn_cmd (0, "sudo /bin/systemctl poweroff") != SCPE_OK) {
                printf ("\r\n\r\npoweroff failed\r\n\r\n");
            }
            return pft_halt;
        }

        // 4. Scan for host reboot command (Sing_Step + Sing_Inst + Start)
        if ((switchstatus[2] & (SS2_S_INST | SS2_START)) == 0) {
            printf ("\r\nReboot\r\n\r\n");
            insert_scp_cmd = CMD_EXIT;
            if (spawn_cmd (0, "sudo /bin/systemctl reboot") != SCPE_OK) {
                printf ("\r\n\r\nreboot failed\r\n\r\n");
            }
            return pft_halt;
        }

        #if 0
        // These combos once meant something, but no longer do.  If you
        // reassign them, think carefully whether they should continue to
        // be handled here and not above in the "if" branch.  If nothing
        // prevents your function from being re-executed while SING_STEP
        // remains closed and re-execution would be bad, move the test
        // under the aegis of the single_shot flag.

        // 5. Sing_Step + Sing_Inst + Load Add
        if ((switchstatus[2] & (SS2_S_INST | SS2_L_ADD)) == 0) { }

        // 6. Sing_Step + Sing_Inst + Deposit
        if ((switchstatus[2] & (SS2_S_INST | SS2_DEP)) == 0) { }
        #endif
    }

    return pft_normal;
}


//// handle_flow_control_switches //////////////////////////////////////
// Process all of the PiDP-8/I front panel switches that can affect the
// flow path of the PDP-8 simulator's instruction interpretation loop,
// returning a code telling the simulator our decision.
//
// The simulator passes in pointers to PDP-8 registers we may modify as
// a side effect of handling these switches.

pidp8i_flow_t handle_flow_control_switches (uint16* pM,
    uint32 *pPC, uint32 *pMA, int32 *pMB, int32 *pLAC, int32 *pIF,
    int32 *pDF, int32* pint_req)
{
    // Exit early if the blink thread has not attached itself to the GPIO
    // peripheral in the Pi, since that means we cannot safely interpret the
    // data in the switchstatus array.  This is especially important on
    // non-Pi hosts, since switchstatus will remain zeroed, which we would
    // interpret as "all switches are pressed!", causing havoc.
    //
    // It would be cheaper for our caller to check this for us and skip the
    // call, but there's no good reason to expose such implementations
    // details to it.  We're trying to keep the PDP-8 simulator's CPU core
    // as free of PiDP-8/I details as is practical.
    if (!pidp8i_gpio_present) return pft_normal;

    // Handle the nonstandard SING_STEP + X combos, some of which halt
    // the processor.
    if (handle_sing_step ((switchstatus[2] & SS2_S_STEP) == 0) == pft_halt) {
        return pft_halt;
    }

    // Check for SING_INST switch close...
    extern int swSingInst;
    if (((switchstatus[2] & SS2_S_INST) == 0) && (swSingInst == 0)) {
        // Put the processor in single-instruction mode until we get a
        // CONT or START switch closure.  Technically this is wrong
        // according to DEC's docs: we're supposed to finish executing
        // the next instruction before we "clear the RUN flip-flop" in
        // DEC terms, whereas we're testing these switches before we
        // fetch the next instruction.  Show me how it matters, and
        // I'll fix it. :)
        swSingInst = 1;
    }

    // ...and SING_INST switch open
    extern int swStop;
    if (swSingInst && (switchstatus[2] & SS2_S_INST)) {
        swSingInst = 0;
        swStop = 1;     // still stopped on leaving SING_INST mode
    }

    // Check for START switch press...
    static int swStart = 0;
    if (((switchstatus[2] & SS2_START) == 0) && (swStart == 0)) {
        // Reset the CPU.
        extern DEVICE cpu_dev;
        extern t_stat cpu_reset (DEVICE *);
        cpu_reset (&cpu_dev);

        // DEC's docs say there are a few additional things START does
        // that cpu_reset() doesn't do for us.
        //
        // Don't need to do anything with MA and IR, as SIMH does that
        // shortly after this function returns.
        *pLAC = *pMB = 0;

        // cpu_reset() does its thing to the saved_* register copies
        // in a few cases, but we need it to happen to the "real"
        // registers instead, since our STOP/START behavior doesn't
        // make use of saved_*.
        REG* pibr = find_reg ("IB", NULL, &cpu_dev);
        int32* pIB = pibr ? pibr->loc : 0 /* force segfault on err */ ;
        *pIB = *pIF;

        // Reset our switch flags, too
        swStop = 0;            // START cancels STOP mode
        swSingInst = 0;        // allow SING INST mode re-entry
        swStart = 1;           // make it single-shot

#if 0   // debugging
        printf("\r\nSTART: [DF:%o] [IF:%o] [IB:%o] [PC:%04o] "
                "[MA:%04o] [MB:%04o] [L:%d] [AC:%04o]",
                (*pDF >> 12), (*pIF >> 12), (*pIB >> 12), (*pPC & 07777),
                *pMA, *pMB, !!(*pLAC & 010000), *pLAC & 07777);
#endif
    }

    // ...and START switch release
    if (swStart && (switchstatus[2] & SS2_START)) {
        swStart = 0;
    }

    // Check for CONT switch press...
    static int swCont = 0;
    extern int resumeFromInstructionLoopExit;
    if ((((switchstatus[2] & SS2_CONT) == 0) && (swCont == 0)) ||
            resumeFromInstructionLoopExit) {
        // The initial CONT press is special: how we handle it
        // depends on the processor's state.
        //
        // FIXME: Are we handling MB correctly? [973271ae36]
        swCont = 1;                 // make it single-shot
        resumeFromInstructionLoopExit = 0;
        if (swSingInst) {
            // On the initial CONT press while in SING_INST mode, run
            // one instruction only.
            return pft_normal;
        }
        else if (swStop) {
            // We were HLTed or STOPped, so CONT returns us to
            // free-running mode.
            swStop = 0;

#if 0   // debugging
            printf("\r\nCONT: [DF:%o] [IF:%o] [PC:%04o] "
                    "[MA:%04o] [MB:%04o] [L:%d] [AC:%04o]",
                    (*pDF >> 12), (*pIF >> 12), (*pPC & 07777),
                    *pMA, *pMB, !!(*pLAC & 010000), *pLAC & 07777);
#endif
        }
        // else, CONT has no effect in this state
    }

    // ...and CONT switch release
    if (swCont && (switchstatus[2] & SS2_CONT)) {
        swCont = 0;
    }

    // Check for LOAD_ADD switch press.  The only reason we bother
    // making it single-shot is in case debugging is enabled.
    // Otherwise, it matters not how long the slow human holds this
    // swithc down, and thus how often we apply the values: all else
    // but our printf() here is idempotent.
    static int swLAdd = 0;
    if ((swLAdd == 0) && (switchstatus[2] & SS2_L_ADD) == 0) {
        // Copy SR into PC.  Have to flip the bits because GPIO gives
        // 0 for a closed switch and 1 for open, opposite what we want.
        *pPC = (~switchstatus[0]) & 07777;
                               
        // Copy DF switch settings to DF register
        //
        // The shift is because the DF positions inside the switchstatus[1]
        // register happen to be 3 bit positions off of where we want them
        // in DF here: we want to be able to logically OR PC and DF to make
        // 15-bit data access addresses.
        //
        // We complement the bits here for the same reason we did above
        uint16_t css1 = ~switchstatus[1]; 
        *pDF = (css1 & SS1_DF_ALL) << 3;

        // Do the same for IF.  The only difference comes from the fact
        // that IF is the next 3 bits down in switchstatus[1].
        *pIF = (css1 & SS1_IF_ALL) << 6;

#if 0   // debugging
        printf("\r\nL_ADD: [DF:%o] [IF:%o] [PC:%04o] "
                "[MA:%04o] [MB:%04o] [L:%d] [AC:%04o]",
                (*pDF >> 12), (*pIF >> 12), (*pPC & 07777),
                *pMA, *pMB, !!(*pLAC & 010000), *pLAC & 07777);
#endif
        swLAdd = 1;                 // make it single-shot
    }

    // ...and L_ADD switch release
    if (swLAdd && (switchstatus[2] & SS2_L_ADD)) {
        swLAdd = 0;
    }

    // Check for DEP switch press...
    static int swDep = 0;
    if (((switchstatus[2] & SS2_DEP) == 0) && (swDep == 0)) {
        uint16 sSR = (~switchstatus[0]) & 07777; // bit flip justified above
        *pPC = *pPC & 07777;  // sometimes high bits get set; squish 'em

#if 0   // debugging
        printf("\r\nDEP: [IF:%o] [PC:%04o] [SR:%04o]",
                (*pIF >> 12), *pPC, sSR);
#endif

        /* ??? in 66 handbook: strictly speaking, SR goes into AC,
           then AC into MB. Does it clear AC afterwards? If not, needs fix */
        pM[*pPC] = sSR;             // FIXME: shouldn't we use IF/DF here?
        *pMB = sSR;
        *pMA = *pPC & 07777;        // MA trails PC on FP; FIXME: OR in IF?
        *pPC = (*pPC + 1) & 07777;  // increment PC
        swDep = 1;                  // make it single-shot
    }

    // ...and DEP switch release
    if (swDep && (switchstatus[2] & SS2_DEP)) {
        swDep = 0;
    }

    // Check for EXAM switch press...
    static int swExam = 0;
    if (((switchstatus[2] & SS2_EXAM) == 0) && (swExam == 0)) {
        *pMB = pM[*pPC];
        *pMA = *pPC & 07777;          // MA trails PC on FP
        *pPC = (*pPC + 1) & 07777;    // increment PC
        swExam = 1;                   // make it single-shot
    }

    // ...and EXAM switch release
    if (swExam && (switchstatus[2] & SS2_EXAM)) {
        swExam = 0;
    }

    // Check for STOP switch press.  No "and release" because we get out of
    // STOP mode with START or CONT, not by releasing STOP, and while in
    // STOP mode, this switch's function is idempotent.
    if (!swStop && ((switchstatus[2] & SS2_STOP) == 0)) {
        swStop = 1;

#if 0   // debugging
            printf("\r\nSTOP: [DF:%o] [IF:%o] [PC:%04o] "
                    "[MA:%04o] [MB:%04o] [L:%d] [AC:%04o]",
                    (*pDF >> 12), (*pIF >> 12), (*pPC & 07777),
                    *pMA, *pMB, !!(*pLAC & 010000), *pLAC & 07777);
#endif
    }

    // If any of the above put us into STOP or SING_INST mode, go no
    // further.  In particular, fetch no more instructions, and do not
    // touch PC!  The only way to get un-stuck is CONT or STOP.
    return (swStop || swSingInst) ? pft_stop : pft_normal;
}


//// get_switch_register ///////////////////////////////////////////////
// Return the current contents of the switch register

int32 get_switch_register (void)
{
    return switchstatus[0] ^ 07777;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/PDP8/pidp8i.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* pidp8i.h: Interface between PiDP-8/I additions and the stock SIMH PDP-8
   simulator

   Copyright © 2015-2017 by Oscar Vermeulen and Warren Young

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the names of the authors above shall
   not be used in advertising or otherwise to promote the sale, use or other
   dealings in this Software without prior written authorization from those
   authors.
*/

#if !defined(PIDP8I_H)
#define PIDP8I_H

#include "pdp8_defs.h"

typedef enum {
    pft_normal,
    pft_halt,
    pft_stop,
} pidp8i_flow_t;

extern char *build_pidp8i_scp_cmd (char* cbuf, size_t cbufsize); 

extern int32 get_switch_register (void);
extern size_t get_pidp8i_initial_max_skips (size_t updates_per_sec);

extern pidp8i_flow_t handle_flow_control_switches (uint16* pM,
        uint32 *pPC, uint32 *pMA, int32 *pMB, int32 *pLAC, int32 *pIF,
        int32 *pDF, int32* pint_req);

extern void set_pidp8i_leds (uint32 sPC, uint32 sMA, uint16 sMB,
        uint16 sIR, int32 sLAC, int32 sMQ, int32 sIF, int32 sDF,
        int32 sSC, int32 int_req, int Pause);

#endif // !defined(PIDP8I_H)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































Deleted src/gpio-common.c.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
/*
 * gpio-common.c: functions common to both gpio.c and gpio-nls.c
 *
 * Copyright © 2015-2017 Oscar Vermeulen and Warren Young
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the names of the authors above shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from those
 * authors.
 *
 * www.obsolescenceguaranteed.blogspot.com
 * 
 * This is part of the GPIO thread, which communicates with the
 * simulator's main thread via *pdis_update and switchstatus[].
 * All of this module's other external interfaces are only called
 * by the other gpio-* modules, from the GPIO thread.
*/

#include "gpio-common.h"

#include "config.h"

#include "PDP8/pidp8i.h"

#include <pthread.h>
#include <sys/file.h>
#include <sys/time.h>

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_TIME_H
#   include <time.h>
#endif

#define BLOCK_SIZE (4*1024)


//// GLOBALS ///////////////////////////////////////////////////////////

// Flag set after we successfully init the GPIO mechanism.  While this
// is false, the rest of the code knows not to expect useful values for
// LED and switch states.  It is also useful as a cross-thread signal,
// since merely starting the blink() thread doesn't tell you whether it
// managed to lock the GPIO device.
uint8_t pidp8i_gpio_present;

// Flag external programs can set to make us use the old-style (and
// simpler, hence still supported) ledstatus[] interface for updating
// the LED values when swapping displays internally.  The external
// program doesn't need to know anything about struct display.
int pidp8i_simple_gpio_mode = 0;

// GPIO peripheral info, initted in start_pidp8i_gpio_thread()
struct bcm2835_peripheral gpio;
#define pgpio (&gpio)
#ifdef PCB_SERIAL_MOD_JLW
struct bcm2835_peripheral gpio2;
#endif


// A constant meaning "indeterminate milliseconds", used for error
// returns from ms_time() and for the case where the switch is in the
// stable state in the switch_state array.
static const ms_time_t na_ms = (ms_time_t)-1;


// Adjust columns to scan based on whether Oscar Vermeulen's serial mod
// was done, as that affects the free GPIOs for our use, and how the PCB
// connects them to the LED matrix.  James L-W's mod leaves GPIO pin
// numbering unchanged relative to the stock circuit design.
#ifdef PCB_SERIAL_MOD_OV
uint8_t cols[NCOLS] = {13, 12, 11,    10, 9, 8,    7, 6, 5,    4, 3, 2};
#else
uint8_t cols[NCOLS] = {13, 12, 11,    10, 9, 8,    7, 6, 5,    4, 15, 14};
#endif

uint8_t ledrows[NLEDROWS] = {20, 21, 22, 23, 24, 25, 26, 27};

uint8_t rows[NROWS] = {16, 17, 18};


// Current switch states, as reported by the debouncing algorithm.  Set
// from the GPIO thread to control the SIMH CPU thread.
uint16_t switchstatus[NROWS];

// Double-buffered LED display brightness values.  The update-to copy is
// modified by the SIMH CPU thread as it executes instructions, and the
// paint-from copy is read by the gpio-*.c module in its "set LEDs"
// loop.  When the GPIO thread is finished with the paint-from copy, it
// zeroes it and swaps it for the current "update-to" copy, giving the
// CPU thread a blank slate, and giving the GPIO thread a stable set of
// LED "on" time values to work with.
display display_bufs[2];
display* pdis_update = display_bufs + 0;    // exported to SIMH CPU thread
display* pdis_paint  = display_bufs + 1;    // exported to gpio-*.c


// GPIO thread control variables manipulated by start/stop_*() below
static pthread_t gpio_thread_info;
static int terminate_gpio_thread = 0;
static pthread_mutex_t gpio_start_mutex;


// Time-delayed reaction to switch changes to debounce the contacts.
// This is especially important with the incandescent lamp simulation
// feature enabled since that speeds up the GPIO scanning loop, making
// it more susceptible to contact bounce.
struct switch_state {
    // switch state currently reported via switchstatus[]
    int stable_state;

    // ms the switch state has been != stable_state, or na_ms
    // if it is currently in that same state
    ms_time_t last_change;      
};
static struct switch_state gss[NROWS][NCOLS];
static int gss_initted = 0;
static const ms_time_t debounce_ms = 50;    // time switch state must remain stable


// Flow-control switch states which are owned by -- that is, primarily
// modified by -- the PDP8/pidp8i module, but we can't define these
// there because we refer to them below, and not all programs that link
// to us link to that module as well.  For such programs, it's fine if
// these two flags stay 0.
int swStop = 0, swSingInst = 0;

// Flag set when sim_instr() exits due to some SIMH event like Ctrl-E,
// which lets us resume from our imposed "pause" display state.
int resumeFromInstructionLoopExit = 0;


//// MEMORY MAPPED GPIO FUNCTIONS //////////////////////////////////////

//// map_peripheral ////////////////////////////////////////////////////
// Exposes the physical address defined in the passed structure

int map_peripheral(struct bcm2835_peripheral *p, int exclusive)
{
    // Name of GPIO memory-mapped device
    static const char* gpio_mem_dev = "/dev/gpiomem";

    if (access(gpio_mem_dev, F_OK) < 0) {
        // That dev node isn't even present, so it's probably not a Pi
        return -1;
    }

    // Open the GPIO device
    if ((p->mem_fd = open(gpio_mem_dev, O_RDWR|O_SYNC)) < 0) {
#ifdef DEBUG
        printf("Failed to open %s: %s\n", gpio_mem_dev, strerror(errno));
        puts("Disabling PiDP-8/I front panel functionality.");
#endif
        return -1;
    }

    // Attempt to lock it.  If we can't, another program has it locked,
    // so we shouldn't keep running; it'll just end in tears.
    if (exclusive && (flock(p->mem_fd, LOCK_EX | LOCK_NB) < 0)) {
        if (errno == EWOULDBLOCK) {
            printf("Failed to lock %s.  Only one PiDP-8/I\n", gpio_mem_dev);
            puts("program can be running at a given time.");
        }
        else {
            printf("Failed to lock %s: %s\n", gpio_mem_dev, strerror(errno));
            puts("Only one PiDP-8/I program can be running at a given time.");
        }
        return -1;
    }

    // Map the GPIO peripheral into our address space
    if ((p->map = mmap(
            NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED,
            p->mem_fd,
            p->addr_p)) == MAP_FAILED) {
        perror("mmap");
        return -1;
    }

    // Success!
    p->addr = (volatile unsigned int *)p->map;
    pidp8i_gpio_present = 1;
    return 0;
}


//// unmap_peripheral //////////////////////////////////////////////////
// Unwind the map_peripheral() steps in reverse order

void unmap_peripheral(struct bcm2835_peripheral *p)
{
    if (pidp8i_gpio_present) {
        if (p->mem_fd > 0) {
            if (p->map) munmap(p->map, BLOCK_SIZE);
            flock(p->mem_fd, LOCK_UN);
            close(p->mem_fd);
        }
        pidp8i_gpio_present = 0;
    }
}


//// bcm_host_get_peripheral_address ///////////////////////////////////
// Find Pi's GPIO base address

unsigned bcm_host_get_peripheral_address(void)
{
    unsigned address = ~0;
    FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb");
    if (fp)
    {   unsigned char buf[4];
        fseek(fp, 4, SEEK_SET);
        if (fread(buf, 1, sizeof buf, fp) == sizeof buf)
            address = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
        fclose(fp);
    }

    return address == ~0 ? 0x20000000 : address;
}


//// DOUBLE BUFFERED DISPLAY MANIPULATION FUNCTIONS ////////////////////

//// swap_displays ////////////////////////////////////////////////////
// Clear the current "paint-from" display, then exchange the double-
// buffered display pointers atomically, saving the current update-to
// display pointer as our paint-from display pointer and re-pointing
// the update-to pointer at the now-zeroed paint-from values.  This
// gives the CPU thread a blank slate to begin modifying while the GPIO
// thread consumes the values provided by the CPU thread.

#define SWAP(dir) \
    __atomic_exchange_n (&pdis_update, display_bufs + dir, __ATOMIC_SEQ_CST)

void swap_displays ()
{
    if (!swStop && !swSingInst) {
        if (pidp8i_simple_gpio_mode) {
            // We're linked to a program that wants to use the old
            // ledstatus[] interface for updating the display, so copy
            // its values into the paint-from display structure and
            // return.  We don't need to touch the update-to display or
            // swap anything, because set_pidp8i_leds won't be called.
            static const int levels = 32;
            memcpy (pdis_paint->curr, ledstatus, 
                    sizeof (pdis_paint->curr));
            pdis_paint->inst_count = levels;

            for (size_t row = 0; row < NLEDROWS; ++row) {
                size_t *prow = pdis_paint->on[row];
                for (size_t col = 0, mask = 1; col < NCOLS;
                        ++col, mask <<= 1) {
                    prow[col] = !!(ledstatus[row] & mask) * levels;
                }
            }
        }
        else {
            // Clear old paint-from display
            memset (pdis_paint, 0, sizeof(display));

            // Send old paint-from display to CPU as new update-to
            // display, and overwrite paint-from pointer with prior
            // update-to pointer.
            pdis_paint = pdis_update == display_bufs + 0 ?
                    SWAP(1) :
                    SWAP(0);
        }
    }
    // else, leave current LED values as-is so we don't go to a black
    // screen while in STOP mode, either from front panel or HLT
}


//// FINE GRAINED SLEEP FUNCTIONS //////////////////////////////////////

//// sleep_ns //////////////////////////////////////////////////////////
// Like sleep(2) except that it takes nanoseconds instead of seconds

void sleep_ns(ns_time_t ns)
{
    struct timespec ts = { 0, ns };
#if defined(HAVE_CLOCK_NANOSLEEP)
    clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL);
#elif defined(HAVE_NANOSLEEP)
    nanosleep(&ts, NULL);
#elif defined(HAVE_USLEEP)
    usleep(ns / 1000);
#else
#   error Cannot build GPIO controller without high-res "sleep" function!
#endif
}


//// ms_time ///////////////////////////////////////////////////////////
// Like time(2) except that it returns milliseconds since the Unix epoch

ms_time_t ms_time(ms_time_t* pt)
{
    struct timeval tv;
    if (gettimeofday(&tv, 0) == 0) {
        ms_time_t t =
                tv.tv_sec  * 1000.0 +
                tv.tv_usec / 1000.0;
        if (pt) *pt = t;
        return t;
    }
    else {
        return na_ms;
    }
}


//// SWITCH DEBOUNCING and READING FUNCTIONS ///////////////////////////

//// report_ss /////////////////////////////////////////////////////////
// Save given switch state ss into the exported switchstatus bitfield
// so the simulator core will see it.  (Constrast the gss matrix,
// which holds our internal view of the unstable truth.)

static void report_ss(int row, int col, int ss,
        struct switch_state* pss)
{
    pss->stable_state = ss;
    pss->last_change = na_ms;

    int mask = 1 << col;
    if (ss) switchstatus[row] |=  mask;
    else    switchstatus[row] &= ~mask;

    #ifdef DEBUG
        printf("%cSS[%d][%02d] = %d  ", gss_initted ? 'N' : 'I', row, col, ss);
    #endif
}


//// debounce_switch ///////////////////////////////////////////////////
// Given the state of the switch at (row,col), work out if this requires
// a change in our exported switch state.

static void debounce_switch(int row, int col, int ss, ms_time_t now_ms)
{
    struct switch_state* pss = &gss[row][col];

    if (!gss_initted) {
        // First time thru, so set this switch's module-global and
        // exported state to its defaults now that we know the switch's
        // initial state.
        report_ss(row, col, ss, pss);
    }
    else if (ss == pss->stable_state) {
        // This switch is still/again in the state we consider "stable",
        // which we are reporting in our switchstatus bitfield.  Reset
        // the debounce timer in case it is returning to its stable
        // state from a brief blip into the other state.
        pss->last_change = na_ms;
    }
    else if (pss->last_change == na_ms) {
        // This switch just left what we consider the "stable" state, so
        // start the debounce timer.
        pss->last_change = now_ms;
    }
    else if ((now_ms - pss->last_change) > debounce_ms) {
        // Switch has been in the new state long enough for the contacts
        // to have stopped bouncing: report its state change to outsiders.
        report_ss(row, col, ss, pss);
    }
    // else, switch was in the new state both this time and the one prior,
    // but it hasn't been there long enough to report it
}


//// read_switches /////////////////////////////////////////////////////
// Iterate through the switch GPIO pins, passing them to the debouncing
// mechanism above for eventual reporting to the PDP-8 CPU thread.

void read_switches (ns_time_t delay)
{
    // Save current ms-since-epoch for debouncer.  No point making it
    // retrieve this value for each switch.
    ms_time_t now_ms;
    ms_time(&now_ms);

    // Flip columns to input.  Since the internal pull-ups are enabled,
    // this pulls all switch GPIO pins high that aren't shorted to the
    // row line by the switch.
    for (size_t i = 0; i < NCOLS; ++i) {
        INP_GPIO(cols[i]);
    }

    // Read the switch rows
    for (size_t i = 0; i < NROWS; ++i) {
        // Put 0V out on the switch row so that closed switches will
        // drag its column line down; give it time to settle.
        OUT_GPIO(rows[i]);
        GPIO_CLR = 1 << rows[i];
        sleep_ns (delay);

        // Read all the switches in this row
        for (size_t j = 0; j < NCOLS; ++j) {
            int ss = GPIO_READ(cols[j]);
            debounce_switch(i, j, !!ss, now_ms);
        }

        // Stop sinking current from this row of switches
        INP_GPIO(rows[i]);
    }

    fflush(stdout);
    gss_initted = 1;
}


//// UNGROUPED FUNCTIONS ///////////////////////////////////////////////

//// pi_type ///////////////////////////////////////////////////////////
// Return a short string succinctly describing the type of Raspberry Pi
// we're running on, or "cake" if it's not a pi.

static const char* pi_type()
{
    static char ac[60] = { '\0' };
    static const char* prefix = "Raspberry Pi ";

    FILE* fp = fopen("/proc/device-tree/model", "r");
    if (fp &&
            fgets(ac, sizeof(ac), fp) &&
            (strlen(ac) > 20) &&
            (strstr(ac, prefix) == ac)) {
        const char* kind = ac + strlen(prefix);
        int series = 1;
        if (kind[0] == 'M') {
            // It's one of the "plus" models.
            const char* pm = kind + strlen("Model ");
            char model = *pm;
            model = (isalpha(model) && isupper(model)) ?
                    tolower(model) : 'x';
            snprintf(ac, sizeof(ac), "pi%d%c", series, model);
        }
        else if (kind[0] == 'C') {
            // It's one of the compute modules.  We don't actually
            // support these, but we need to report them in case
            // someone tries it.
            const char* ps = kind + strlen("Compute Module");
            char series = *ps;
            if (series) {
                // It's should be one of the later Compute Module series.
                series = isdigit(ps[1]) ? ps[1] : 'x';
                snprintf(ac, sizeof(ac), "picm%c", series);
            }
            else {
                // We're at the end of the string, so it's the original
                // Compute Module.
                return "picm1";
            }
        }
        else if (kind[0] == 'Z') {
            // It's a Pi Zero
            return "pi0";
        }
        else if ((series = atoi(kind)) > 1) {
            // Pi 2 and newer have a number after the "Pi"
            char* pm = strstr(kind, " Model ");
            snprintf(ac, sizeof(ac), "pi%d%c", series,
                    pm ? tolower(pm[7]) : 'x');
        }
        else {
            // Not a model string we can parse, but it's some kind of
            // RPi.  Two 'x's stand for unknown series and model.
            return "pixx";
        }
    }
    else {
        return "cake";      // not pi
    }

    return ac;
}


//// update_led_states /////////////////////////////////////////////////
// Generic front panel LED updater used by NLS full time and by ILS
// while the CPU is in STOP mode.  Just uses the paint-from display's
// bitfields to turn the LEDs on full-brightness.

void update_led_states (const us_time_t delay)
{
    uint16_t *pcurr = pdis_paint->curr;

#if 0   // debugging
    static time_t last = 0, now;
    if (time(&now) != last) {
        printf("\r\nLED: [PC:%04o] [MA:%04o] [MB:%04o] [AC:%04o] [MQ:%04o]",
                pcurr[0], pcurr[1], pcurr[2], pcurr[3], pcurr[4]);
        last = now;
    }
#endif
    
    // Override Execute and Run LEDs if the CPU is currently stopped,
    // since we only get set_pidp8i_leds calls while the CPU's running.
    if (swStop || swSingInst) {
        pdis_paint->curr[5] &= ~(1 << 2);
        pdis_paint->curr[6] &= ~(1 << 7);
    }

    for (size_t row = 0; row < NLEDROWS; ++row) {
        for (size_t col = 0; col < NCOLS; ++col) {
            if ((pcurr[row] & (1 << col)) == 0) {
                GPIO_SET = 1 << cols[col];
            }
            else {
                GPIO_CLR = 1 << cols[col];
            }
        }

        // Toggle this LED row on
        INP_GPIO (ledrows[row]);
        GPIO_SET = 1 << ledrows[row];
        OUT_GPIO (ledrows[row]);

        sleep_us (delay);

        // Toggle this LED row off
        GPIO_CLR = 1 << ledrows[row]; // superstition
        INP_GPIO (ledrows[row]);

        // Small delay to reduce UDN2981 ghosting
        sleep_us (10);
    }
}


//// turn_off_pidp8i_leds //////////////////////////////////////////////
// Set GPIO pins into a state that disconnects all the LEDs from power.
// Doesn't pay any attention to the panel values.

void turn_off_pidp8i_leds ()
{
    for (size_t i = 0; i < NCOLS; ++i) {
        OUT_GPIO(cols[i]);
    }
    for (size_t row = 0; row < NLEDROWS; ++row) {
        INP_GPIO (ledrows[row]);
    }
}


//// gpio_thread ///////////////////////////////////////////////////////
// The GPIO thread entry point: initializes GPIO and then calls
// the gpio_core () implementation linked to this program.

static void *gpio_thread (void *terminate)
{
    // Set thread to real time priority
    struct sched_param sp;
    sp.sched_priority = 4;  // not high, just above the minimum of 1
    int rt = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp) == 0;

    // Tell the user about our configuration, succinctly
    const char* pt = pi_type();
    printf(
        "PiDP-8/I @VERSION@ [%s] [%cls] [%spcb] [%sgpio]"
#ifdef DEBUG
        " [debug]"
#endif
        "%s",
        pt,
        ILS_MODE ? 'i' : 'n',
        pt[0] == 'p' ? 
#ifdef PCB_SERIAL_MOD_OV
            "sermod" : 
#elif PCB_SERIAL_MOD_JLW
            "altser" : 
#else
            "std" : 
#endif
            "no",
        (pidp8i_gpio_present ? "" : "no"),
        (rt ? " [rt]" : "")
    );

    // It's okay for our caller to resume executing, if it's locked
    // waiting for us to finish the initialization bits that can only
    // happen in this thread.
    pthread_mutex_unlock (&gpio_start_mutex);

    // If we didn't map the GPIO peripheral and get here, it was
    // optional, and we've done all we can without it.
    if (!pidp8i_gpio_present) return (void*)-1;

    // initialise GPIO (all pins used as inputs, with pull-ups enabled on cols)
    int i;
    for (i = 0; i < NLEDROWS; i++) {     // Define ledrows as input
        INP_GPIO(ledrows[i]);
        GPIO_CLR = 1 << ledrows[i];     // so go to Low when switched to output
    }
    for (i = 0; i < NCOLS; i++) {       // Define cols as input
        INP_GPIO(cols[i]);
    }
    for (i = 0; i < NROWS; i++) {       // Define rows as input
        INP_GPIO(rows[i]);
    }

    // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
    GPIO_PULL = 2;  // pull-up
    usleep(1);  // must wait 150 cycles
#ifdef PCB_SERIAL_MOD_OV
    // Oscar Vermeulen's serial mod the PiDP-8/I board rearranges the
    // GPIO matrix to use Pi GPIO pins 2..13, freeing up the hardware
    // serial port on GPIO pins 14 & 15.
    GPIO_PULLCLK0 = 0x03ffc;
#else
    // The standard PiDP-8/I board drive scheme uses Pi GPIO pins 4..15.
    // (James L-W's alternative serial mod also uses this scheme.)
    GPIO_PULLCLK0 = 0x0fff0;
#endif
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary

    // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
    GPIO_PULL = 1;  // pull-down to avoid ghosting (dec2015)
    usleep(1);  // must wait 150 cycles
    GPIO_PULLCLK0 = 0x0ff00000; // selects GPIO pins 20..27
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary

    // BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
    GPIO_PULL = 0;  // no pull-up no pull down just float
    usleep(1);  // must wait 150 cycles
    GPIO_PULLCLK0 = 0x070000; // selects GPIO pins 16..18
    usleep(1);
    GPIO_PULL = 0; // reset GPPUD register
    usleep(1);
    GPIO_PULLCLK0 = 0; // remove clock
    usleep(1); // probably unnecessary

    // Hand off control to the gpio_core () variant linked to this
    // program: either the new incandescent lamp simulator or the old
    // stock version.
    extern void gpio_core (struct bcm2835_peripheral*, int* terminate);
    gpio_core (&gpio, (int*)terminate);

    // gpio_core () leaves all cols, rows, ledrows are set to input, and
    // it's safe to leave them in that state.  No need to de-init GPIO.
    gss_initted = 0;
    return 0;
}


//// start/stop_pidp8i_gpio_thread /////////////////////////////////////
// Start and stop gpio_thread().  We export these functions rather than
// export gpio_thread() directly so this module's users don't have to
// know anything about pthreads and such.

int start_pidp8i_gpio_thread (const char* must_map)
{
    char errs[100];

    // Find GPIO address (it varies by Pi model)
    unsigned int gpio_base_addr = bcm_host_get_peripheral_address();
    gpio.addr_p = gpio_base_addr + 0x200000;

    // Attempt to map the GPIO peripheral for our exclusive use.  Some
    // callers care if this fails, and some don't.
    map_peripheral (&gpio, 1);
    if (must_map && !pidp8i_gpio_present) return EFAULT;

#ifdef PCB_SERIAL_MOD_JLW
    // James L-W's alternative serial mods were declared to be done here
    // at configure time, so disable the hysteresis on the GPIO inputs.
    map_peripheral (&gpio2, 0);  // assume success since prior mapping worked
    gpio2.addr_p = gpio_base_addr + 0x100000;
    gpio2.addr[0x0B] = (gpio2.addr[0x0B] & 0xF7) | (0x5A << 24);
#endif

    // Until gpio_core () reads the switches for the first time, we need
    // to mark them as all-open, lest we have a race condition with the
    // simulator where it interprets the all-0 initial switchstatus[]
    // value as "all switches closed," which includes the shutdown seq!
    memset (switchstatus, 0xFF, sizeof (switchstatus));

    // Create the startup sequencing mutex and lock it once to block the
    // GPIO thread after it's sufficiently initialized.
    int pcerr;
    if (    ((pcerr = pthread_mutex_init (&gpio_start_mutex, NULL)) != 0) ||
            ((pcerr = pthread_mutex_lock (&gpio_start_mutex)) != 0)) {
        perror ("GPIO startup sequence mutex creation failed");
        return errno;
    }

    // Create the actual GPIO handler thread
    pcerr = pthread_create (&gpio_thread_info, NULL, gpio_thread,
                            &terminate_gpio_thread);
    if (pcerr != 0) {
        int errlen = snprintf (errs, sizeof(errs), "Error creating "
                "PiDP-8/I GPIO thread: %s\n", strerror (pcerr));
        if (errlen > 0 && errlen < sizeof(errs)) write (2, errs, errlen);
    }
    else if (must_map && !pidp8i_gpio_present) {
        int errlen = snprintf (errs, sizeof(errs), "Cannot run the %s "
                "while another PiDP-8/I program runs.\r\n", must_map);
        if (errlen > 0 && errlen < sizeof(errs)) write (2, errs, errlen);
        pcerr = EACCES;
    }
    else {
        // Don't return until GPIO thread is sufficiently initted.
        //
        // There are two possible sequences:
        //
        // 1. We get here before the GPIO thread gets to its "unlock"
        //    call, so our back-to-back locks in this thread stall this
        //    thread until the GPIO thread gets to its unlock condition,
        //    which removes the first lock taken above, and our second
        //    unlock call below removes the second lock.
        //
        // 2. The GPIO thread hits its "unlock" call before we get here,
        //    so it unlocks the lock we made above, so that these two
        //    calls happen back to back, with no real effect.  We got
        //    here too late to cause any problem that this interlock
        //    solves, so it just locks and immediately unlocks.
        pthread_mutex_lock   (&gpio_start_mutex);
        pthread_mutex_unlock (&gpio_start_mutex);
    }

    return pcerr;
}

void stop_pidp8i_gpio_thread ()
{
    terminate_gpio_thread = 1;
    if (pthread_join (gpio_thread_info, NULL)) {
        printf("\r\nError joining multiplex thread\r\n");
    }
    unmap_peripheral (&gpio);
#ifdef PCB_SERIAL_MOD_JLW
    unmap_peripheral (&gpio2);
#endif
    pthread_mutex_destroy (&gpio_start_mutex);
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/gpio-common.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * gpio-common.h: public interface for the PiDP-8/I's GPIO module
 *
 * Copyright © 2015-2017 Oscar Vermeulen and Warren Young
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the names of the authors above shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from those
 * authors.
*/

#if !defined(PIDP8I_GPIO_H)
#define PIDP8I_GPIO_H

#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>


// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x)
#define INP_GPIO(g)   *(pgpio->addr + ((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g)   *(pgpio->addr + ((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(pgpio->addr + (((g)/10))) |= (((a)<=3?(a) + 4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET  *(pgpio->addr + 7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR  *(pgpio->addr + 10) // clears bits which are 1 ignores bits which are 0

#define GPIO_READ(g)  *(pgpio->addr + 13) &= (1<<(g))

#define GPIO_PULL *(pgpio->addr + 37) // pull up/pull down
#define GPIO_PULLCLK0 *(pgpio->addr + 38) // pull up/pull down clock


// Switch masks, SSn, used against switchstatus[n]
#define SS0_SR_B11 04000
#define SS0_SR_B10 02000
#define SS0_SR_B09 01000
#define SS0_SR_B08 00400
#define SS0_SR_B07 00200
#define SS0_SR_B06 00100
#define SS0_SR_B05 00040
#define SS0_SR_B04 00020
#define SS0_SR_B03 00010
#define SS0_SR_B02 00004
#define SS0_SR_B01 00002
#define SS0_SR_B00 00001

#define SS1_DF_B2  04000
#define SS1_DF_B1  02000
#define SS1_DF_B0  01000
#define SS1_DF_ALL (SS1_DF_B2 | SS1_DF_B1 | SS1_DF_B0)

#define SS1_IF_B2  00400
#define SS1_IF_B1  00200
#define SS1_IF_B0  00100
#define SS1_IF_ALL (SS1_IF_B2 | SS1_IF_B1 | SS1_IF_B0)

#define SS2_START  04000
#define SS2_L_ADD  02000
#define SS2_DEP    01000
#define SS2_EXAM   00400
#define SS2_CONT   00200
#define SS2_STOP   00100
#define SS2_S_STEP 00040
#define SS2_S_INST 00020

// Number of LED and switch rows and columns on the PiDP-8/I PCB
#define NCOLS    12
#define NLEDROWS 8
#define NROWS    3
 
// Info for accessing the GPIO peripheral on the SoC
struct bcm2835_peripheral {
    uint32_t addr_p;
    int mem_fd;
    void *map;
    volatile unsigned int *addr;
};

typedef uint64_t   ns_time_t;
typedef useconds_t us_time_t;
typedef uint64_t   ms_time_t;

typedef struct display {
    // Counters incremented each time the LED is known to be turned on,
    // in instructions since the last display paint.
    size_t on[NLEDROWS][NCOLS];

    // Most recent state for each LED, for use by NLS full-time and by
    // ILS in STOP mode.  (One bitfield per row.)
    uint16_t curr[NLEDROWS];

    // Number of instructions executed since this display was cleared
    int inst_count;
} display;
extern display* pdis_update, *pdis_paint;

// Compatibility interface for programs like src/test.c that depend on
// being able to modify the LED values directly.
#define ledstatus (pdis_update->curr)
extern int pidp8i_simple_gpio_mode;

extern uint16_t switchstatus[];
extern uint8_t cols[];
extern uint8_t ledrows[];
extern uint8_t rows[];
extern uint8_t pidp8i_gpio_present;

extern int start_pidp8i_gpio_thread (const char* must_map);
extern void stop_pidp8i_gpio_thread ();
extern void turn_off_pidp8i_leds ();
extern void update_led_states (const us_time_t delay);

extern unsigned bcm_host_get_peripheral_address(void);
extern int map_peripheral(struct bcm2835_peripheral *p, int exclusive);
extern void unmap_peripheral(struct bcm2835_peripheral *p);

extern void read_switches (ns_time_t delay);

extern void swap_displays ();

extern void sleep_ns(ns_time_t ns);
#define sleep_us(us) usleep(us)
#define sleep_ms(ms) sleep_us(ms * 1000)
extern ms_time_t ms_time(ms_time_t* pt);
 
#endif // !defined(PIDP8I_GPIO_H)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































Deleted src/gpio-ils.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
 * gpio-ils.c: implements gpio_core () for Ian Schofield's incandescent
 *             lamp simulator
 * 
 * Copyright © 2015-2017 Oscar Vermeulen, Ian Schofield, and Warren Young
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the names of the authors above shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from those
 * authors.
 *
 * www.obsolescenceguaranteed.blogspot.com
*/

#include "gpio-common.h"

#include "sim_defs.h"

#include "PDP8/pidp8i.h"


//// CONSTANTS /////////////////////////////////////////////////////////

// Brightness range is [0, MAX_BRIGHTNESS) truncated.
#define MAX_BRIGHTNESS 32

// On each iteration, we add or subtract a proportion of the LED's "on"
// time back to it as its new brightness, so that it takes several
// iterations at that same "on" time for the LED to achieve that
// brightness level.  Because the delta is based on the prior value, we
// get nonlinear asymptotic increase/decrease behavior.
//
// We use an asymmetric function depending on whether the LED is turning
// on or off to better mimic the behavior of an incandescent lamp, which
// reaches full brightness faster than it turns fully off.
#define RISING_FACTOR 0.012
#define FALLING_FACTOR 0.005


//// gpio_core  ////////////////////////////////////////////////////////
// The GPIO module's main loop core, called from thread entry point in
// gpio-common.c.

void gpio_core (struct bcm2835_peripheral* pgpio, int* terminate)
{
    // The ILS version uses an iteration rate 60x faster than the NLS
    // version because we have to get through 32 PWM steps, each of
    // which takes roughly 2 * intervl µs.  There's a bit of extra delay
    // over intervl in the NLS version, so the while loop iteration time
    // is about the same for both versions.
    const us_time_t intervl = 20;

    // Current brightness level for each LED.  It goes from 0 to
    // MAX_BRIGHTNESS, but we keep it as a float because the decay
    // function smoothly ramps from the current value to the ever-
    // changing target value.
    float brightness[NLEDROWS][NCOLS];
    memset(brightness, 0, sizeof (brightness));

    // Brightness target for each LED, updated at the start of each PWM
    // cycle when we get fresh "on" counts from the CPU thread.
    uint8 br_targets[NLEDROWS][NCOLS];
    memset(br_targets, 0, sizeof (br_targets));

    // Current PWM brightness step
    uint8 step = MAX_BRIGHTNESS;

    while (*terminate == 0) {
        // Prepare for lighting LEDs by setting col pins to output
        for (size_t i = 0; i < NCOLS; ++i) OUT_GPIO(cols[i]);

        // Restart PWM cycle if prior one is complete
        if (step == MAX_BRIGHTNESS) {
            // Reset PWM step counter
            step = 0;
      
            // Go get the current LED "on" times, and give the SIMH
            // CPU thread a blank copy to begin updating.  Because we're
            // in control of the swap timing, we don't need to copy the
            // pdis_paint pointer: it points to the same thing between
            // these swap_displays() calls.
            swap_displays();

            // Recalculate the brightness target values based on the
            // "on" counts in *pdis_paint and the quantized brightness
            // level, which is based on the number of instructions
            // executed for this display update.
            //
            // Handle the cases where inst_count is < 32 specially
            // because we don't want all LEDs to go out when the
            // simulator is heavily throttled.
            const size_t inst_count = pdis_paint->inst_count;
            size_t br_quant = inst_count >= 32 ? (inst_count >> 5) : 1;
            for (int row = 0; row < NLEDROWS; ++row) {
                size_t *prow = pdis_paint->on[row];
                for (int col = 0; col < NCOLS; ++col) {
                    br_targets[row][col] = prow[col] / br_quant;

                }
            }

            // Hard-code the Fetch and Execute brightnesses; in running
            // mode, they're both on half the instruction time, so we
            // just set them to 50% brightness.  Execute differs in STOP
            // mode, but that's handled in update_led_states () because
            // we fall back to NLS in STOP mode.
            br_targets[5][2] = br_targets[5][3] = MAX_BRIGHTNESS / 2;
        }
        ++step;

        // Update the brightness values.
        for (int row = 0; row < NLEDROWS; ++row) {
            size_t *prow = pdis_paint->on[row];
            for (int col = 0; col < NCOLS; ++col) {
                uint8 br_target = br_targets[row][col];
                float *p = brightness[row] + col;
                if (*p <= br_target) {
                    *p += (br_target - *p) * RISING_FACTOR;
                }
                else {
                    *p -= *p * FALLING_FACTOR;
                }
            }
        }

        // Light up LEDs
        extern int swStop, swSingInst;
        if (swStop || swSingInst) {
            // The CPU is in STOP mode, so show the current LED states
            // full-brightness using the same mechanism NLS uses.
            update_led_states (intervl * 60);
        }
        else {
            // Normal case: PWM display using the on-count values
            for (size_t row = 0; row < NLEDROWS; ++row) {
                // Output 0 (CLR) for LEDs in this row which should be on
                size_t *prow = pdis_paint->on[row];
                for (size_t col = 0; col < NCOLS; ++col) {
                    if (brightness[row][col] >= step) {
                        GPIO_CLR = 1 << cols[col];
                    }
                    else {
                        GPIO_SET = 1 << cols[col];
                    }
                }

                // Toggle this LED row on
                INP_GPIO(ledrows[row]);
                GPIO_SET = 1 << ledrows[row];
                OUT_GPIO(ledrows[row]);

                sleep_us(intervl);

                // Toggle this LED row off
                GPIO_CLR = 1 << ledrows[row]; // superstition
                INP_GPIO(ledrows[row]);

                sleep_ns(5);
            }
        }

#if 0   // debugging
        static time_t last = 0, now;
        if (time(&now) != last) {
            float* p = brightness[0];
            #define B(n) (p[n] / MAX_BRIGHTNESS * 100.0)
            printf("\r\nPC:"
                    " [%3.0f%%][%3.0f%%][%3.0f%%]"
                    " [%3.0f%%][%3.0f%%][%3.0f%%]"
                    " [%3.0f%%][%3.0f%%][%3.0f%%]"
                    " [%3.0f%%][%3.0f%%][%3.0f%%]",
                    B(11), B(10), B(9),
                    B(8),  B(7),  B(6),
                    B(5),  B(4),  B(3),
                    B(2),  B(1),  B(0));
            last = now;
        }
#endif

        // 625 = * 1000 / (100 / 60) where 60 is the difference in
        // iteration rate between ILS and NLS.  See the same call
        // in gpio-nls.c.
        read_switches(intervl * 625);      
#if defined(HAVE_SCHED_YIELD)
        sched_yield();
#endif
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































































































































Deleted src/gpio-nls.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
 * gpio-nls.c: implements gpio_core () with the original simple LED driver
 *
 * This file differs from gpio.c in that it does not include the
 * incandescent lamp simulator feature by Ian Schofield.  It is
 * more directly descended from the original gpio.c by Oscar Vermeulen.
 * 
 * Copyright © 2015-2017 Oscar Vermeulen and Warren Young
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the names of the authors above shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from those
 * authors.
 *
 * www.obsolescenceguaranteed.blogspot.com
*/

#include "gpio-common.h"

#include "PDP8/pidp8i.h"


//// gpio_core  ////////////////////////////////////////////////////////
// The GPIO module's main loop core, called from thread entry point in
// gpio-common.c.

void gpio_core (struct bcm2835_peripheral* pgpio, int* terminate)
{
    // Light each row of LEDs 1.2 ms.  With 8 rows, that's an update
    // rate of ~100x per second.  Not coincidentally, this is the human
    // persistence of vision limit: changes faster than this are
    // difficult for humans to perceive visually.
    const us_time_t intervl = 1200;  

    // This is a simplified version of what's in the gpio-ils.c version
    // of this function, so if you want more comments, read them there.
    while (*terminate == 0) {
        for (size_t i = 0; i < NCOLS; ++i) OUT_GPIO(cols[i]);
        swap_displays ();
        update_led_states (intervl);
        read_switches (intervl * 1000 / 100);
#if defined(HAVE_SCHED_YIELD)
        sched_yield ();
#endif
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































Deleted src/scanswitch.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * Scan switches for PiDP-8/I front panel
 * 
 * www.obsolescenceguaranteed.blogspot.com
 *
 * Copyright (c) 2015-2016 Oscar Vermeulen
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the names of the authors above shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from those
 * authors.
 * 
*/

#include "gpio-common.h"

#define short_wait() sleep_us(100000)

#define pgpio (&gpio)


int main()
{
	int i,j,k,switchscan[2], tmp;
	struct bcm2835_peripheral gpio;
	
	// ------------ Find gpio address (different for Pi 2) -------------

	gpio.addr_p = bcm_host_get_peripheral_address() + 0x200000;

	if (gpio.addr_p== 0x20200000) printf("scanswitch - RPi Plus\n");
	else printf("scanswitch - RPi 2\n");

	if (map_peripheral(&gpio, 0) != 0)
	{	printf("Failed to map the physical GPIO registers into the virtual memory space.\n");
		return -1;
	}

	// initialise GPIO (all pins used as inputs, with pull-ups enabled on cols)
	for (i=0;i<NLEDROWS;i++)	// Define ledrows as input
		INP_GPIO(ledrows[i]);
	for (i=0;i<NCOLS;i++)		// Define cols as input
		INP_GPIO(cols[i]);
	for (i=0;i<NROWS;i++)		// Define rows as input
		INP_GPIO(rows[i]);

	// BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
	GPIO_PULL = 2;				// pull-up
	short_wait();       		// must wait 150 cycles
	GPIO_PULLCLK0 = 0x0fff0; 	// selects GPIO pins 4..15 (assumes we avoid pins 2 and 3!)
	short_wait();
	GPIO_PULL = 0;  			// reset GPPUD register
	short_wait();
	GPIO_PULLCLK0 = 0; 			// remove clock
	short_wait(); 	        	// probably unnecessary

	// BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
	GPIO_PULL = 0;				// no pull-up no pull-down just float
	short_wait();	        	// must wait 150 cycles
	GPIO_PULLCLK0 = 0x0ff00000;	// selects GPIO pins 20..27
	short_wait();
	GPIO_PULL = 0; 				// reset GPPUD register
	short_wait();
	GPIO_PULLCLK0 = 0; 			// remove clock
	short_wait();       		// probably unnecessary

	// BCM2835 ARM Peripherals PDF p 101 & elinux.org/RPi_Low-level_peripherals#Internal_Pull-Ups_.26_Pull-Downs
	GPIO_PULL = 0;				// no pull-up no pull down just float
	short_wait();	        	// must wait 150 cycles
	GPIO_PULLCLK0 = 0x070000; 	// selects GPIO pins 16..18
	short_wait();
	GPIO_PULL = 0; 				// reset GPPUD register
	short_wait();
	GPIO_PULLCLK0 = 0; 			// remove clock
	short_wait();       		// probably unnecessary
	// --------------------------------------------------


	// prepare for reading switches		

	for (uint8_t row=1;row<=2;row++)		// do rows 2 (for IF switches) and 3 (for STOP switch)
	{		
		INP_GPIO(rows[row]);
		OUT_GPIO(rows[row]);			// turn on one switch row
		GPIO_CLR = 1 << rows[row];		// and output 0V to overrule built-in pull-up from column input pin
	
		sleep_us(10);                   // unnecessarily long?
		switchscan[row-1]=0;

		for (j=0;j<NCOLS;j++)			// 12 switches in each row
		{	tmp = GPIO_READ(cols[j]);
			if (tmp==0)
				switchscan[row-1] += 1<<j;
		}
		INP_GPIO(rows[row]);			// stop sinking current from this row of switches
	}

	unmap_peripheral(&gpio);

	if ( ((switchscan[1] >> 6) & 1) == 1 )	// STOP switch enabled,
		return 8;				// 8: STOP enabled, no bootscript
	else
		return (switchscan[0] >> 6) & 07;	// 0-7: x.script to be used in PiDP-8/I
}

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































Deleted src/scp.c.

more than 10,000 changes

Deleted src/scp.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/* scp.h: simulator control program headers

   Copyright (c) 1993-2009, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not
   be used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   05-Dec-10    MP      Added macro invocation of sim_debug 
   09-Aug-06    JDB     Added assign_device and deassign_device
   14-Jul-06    RMS     Added sim_activate_abs
   06-Jan-06    RMS     Added fprint_stopped_gen
                        Changed arg type in sim_brk_test
   07-Feb-05    RMS     Added ASSERT command
   09-Sep-04    RMS     Added reset_all_p
   14-Feb-04    RMS     Added debug prototypes (from Dave Hittner)
   02-Jan-04    RMS     Split out from SCP
*/

#ifndef SIM_SCP_H_
#define SIM_SCP_H_     0

#ifdef  __cplusplus
extern "C" {
#endif

/* run_cmd parameters */

#define RU_RUN          0                               /* run */
#define RU_GO           1                               /* go */
#define RU_STEP         2                               /* step */
#define RU_NEXT         3                               /* step or step/over */
#define RU_CONT         4                               /* continue */
#define RU_BOOT         5                               /* boot */

/* exdep_cmd parameters */

#define EX_D            0                               /* deposit */
#define EX_E            1                               /* examine */
#define EX_I            2                               /* interactive */

/* brk_cmd parameters */

#define SSH_ST          0                               /* set */
#define SSH_SH          1                               /* show */
#define SSH_CL          2                               /* clear */

/* get_sim_opt parameters */

#define CMD_OPT_SW      001                             /* switches */
#define CMD_OPT_OF      002                             /* output file */
#define CMD_OPT_SCH     004                             /* search */
#define CMD_OPT_DFT     010                             /* defaults */

/* Command processors */

t_stat reset_cmd (int32 flag, CONST char *ptr);
t_stat exdep_cmd (int32 flag, CONST char *ptr);
t_stat eval_cmd (int32 flag, CONST char *ptr);
t_stat load_cmd (int32 flag, CONST char *ptr);
t_stat run_cmd (int32 flag, CONST char *ptr);
void run_cmd_message (const char *unechod_cmdline, t_stat r);
t_stat attach_cmd (int32 flag, CONST char *ptr);
t_stat detach_cmd (int32 flag, CONST char *ptr);
t_stat assign_cmd (int32 flag, CONST char *ptr);
t_stat deassign_cmd (int32 flag, CONST char *ptr);
t_stat save_cmd (int32 flag, CONST char *ptr);
t_stat restore_cmd (int32 flag, CONST char *ptr);
t_stat exit_cmd (int32 flag, CONST char *ptr);
t_stat set_cmd (int32 flag, CONST char *ptr);
t_stat show_cmd (int32 flag, CONST char *ptr);
t_stat set_default_cmd (int32 flg, CONST char *cptr);
t_stat pwd_cmd (int32 flg, CONST char *cptr);
t_stat dir_cmd (int32 flg, CONST char *cptr);
t_stat type_cmd (int32 flg, CONST char *cptr);
t_stat delete_cmd (int32 flg, CONST char *cptr);
t_stat brk_cmd (int32 flag, CONST char *ptr);
t_stat do_cmd (int32 flag, CONST char *ptr);
t_stat goto_cmd (int32 flag, CONST char *ptr);
t_stat return_cmd (int32 flag, CONST char *ptr);
t_stat shift_cmd (int32 flag, CONST char *ptr);
t_stat call_cmd (int32 flag, CONST char *ptr);
t_stat on_cmd (int32 flag, CONST char *ptr);
t_stat noop_cmd (int32 flag, CONST char *ptr);
t_stat assert_cmd (int32 flag, CONST char *ptr);
t_stat send_cmd (int32 flag, CONST char *ptr);
t_stat expect_cmd (int32 flag, CONST char *ptr);
t_stat help_cmd (int32 flag, CONST char *ptr);
t_stat screenshot_cmd (int32 flag, CONST char *ptr);
t_stat spawn_cmd (int32 flag, CONST char *ptr);
t_stat echo_cmd (int32 flag, CONST char *ptr);

/* Allow compiler to help validate printf style format arguments */
#if !defined __GNUC__
#define GCC_FMT_ATTR(n, m)
#endif
#if !defined(GCC_FMT_ATTR)
#define GCC_FMT_ATTR(n, m) __attribute__ ((format (__printf__, n, m)))
#endif

/* Utility routines */

t_stat sim_process_event (void);
t_stat sim_activate (UNIT *uptr, int32 interval);
t_stat _sim_activate (UNIT *uptr, int32 interval);
t_stat sim_activate_abs (UNIT *uptr, int32 interval);
t_stat sim_activate_notbefore (UNIT *uptr, int32 rtime);
t_stat sim_activate_after (UNIT *uptr, uint32 usecs_walltime);
t_stat sim_activate_after_d (UNIT *uptr, double usecs_walltime);
t_stat _sim_activate_after (UNIT *uptr, double usecs_walltime);
t_stat sim_activate_after_abs (UNIT *uptr, uint32 usecs_walltime);
t_stat sim_activate_after_abs_d (UNIT *uptr, double usecs_walltime);
t_stat _sim_activate_after_abs (UNIT *uptr, double usecs_walltime);
t_stat sim_cancel (UNIT *uptr);
t_bool sim_is_active (UNIT *uptr);
int32 sim_activate_time (UNIT *uptr);
int32 _sim_activate_time (UNIT *uptr);
double sim_activate_time_usecs (UNIT *uptr);
t_stat sim_run_boot_prep (int32 flag);
double sim_gtime (void);
uint32 sim_grtime (void);
int32 sim_qcount (void);
t_stat attach_unit (UNIT *uptr, CONST char *cptr);
t_stat detach_unit (UNIT *uptr);
t_stat assign_device (DEVICE *dptr, const char *cptr);
t_stat deassign_device (DEVICE *dptr);
t_stat reset_all (uint32 start_device);
t_stat reset_all_p (uint32 start_device);
const char *sim_dname (DEVICE *dptr);
const char *sim_uname (UNIT *dptr);
const char *sim_set_uname (UNIT *uptr, const char *uname);
t_stat get_yn (const char *ques, t_stat deflt);
char *sim_trim_endspc (char *cptr);
int sim_isspace (char c);
int sim_islower (char c);
int sim_isalpha (char c);
int sim_isprint (char c);
int sim_isdigit (char c);
int sim_isgraph (char c);
int sim_isalnum (char c);
int sim_strncasecmp (const char *string1, const char *string2, size_t len);
int sim_strcasecmp (const char *string1, const char *string2);
size_t sim_strlcat (char *dst, const char *src, size_t size);
size_t sim_strlcpy (char *dst, const char *src, size_t size);
CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st);
const char *put_switches (char *buf, size_t bufsize, uint32 sw);
CONST char *get_glyph (const char *iptr, char *optr, char mchar);
CONST char *get_glyph_nc (const char *iptr, char *optr, char mchar);
CONST char *get_glyph_quoted (const char *iptr, char *optr, char mchar);
CONST char *get_glyph_cmd (const char *iptr, char *optr);
t_value get_uint (const char *cptr, uint32 radix, t_value max, t_stat *status);
CONST char *get_range (DEVICE *dptr, CONST char *cptr, t_addr *lo, t_addr *hi,
    uint32 rdx, t_addr max, char term);
t_stat sim_decode_quoted_string (const char *iptr, uint8 *optr, uint32 *osize);
char *sim_encode_quoted_string (const uint8 *iptr, uint32 size);
void fprint_buffer_string (FILE *st, const uint8 *buf, uint32 size);
t_value strtotv (CONST char *cptr, CONST char **endptr, uint32 radix);
int Fprintf (FILE *f, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
/* Use scp.c provided fprintf function */
#define fprintf Fprintf
#define fputs(_s,_f) Fprintf(_f,"%s",_s)
#define fputc(_c,_f) Fprintf(_f,"%c",_c)
t_stat sim_set_memory_load_file (const unsigned char *data, size_t size);
int Fgetc (FILE *f);
t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
t_stat sprint_val (char *buf, t_value val, uint32 rdx, uint32 wid, uint32 fmt);
t_stat sim_print_val (t_value val, uint32 radix, uint32 width, uint32 format);
const char *sim_fmt_secs (double seconds);
const char *sim_fmt_numeric (double number);
const char *sprint_capac (DEVICE *dptr, UNIT *uptr);
char *read_line (char *cptr, int32 size, FILE *stream);
void fprint_reg_help (FILE *st, DEVICE *dptr);
void fprint_set_help (FILE *st, DEVICE *dptr);
void fprint_show_help (FILE *st, DEVICE *dptr);
CTAB *find_cmd (const char *gbuf);
DEVICE *find_dev (const char *ptr);
DEVICE *find_unit (const char *ptr, UNIT **uptr);
DEVICE *find_dev_from_unit (UNIT *uptr);
t_stat sim_register_internal_device (DEVICE *dptr);
void sim_sub_args (char *in_str, size_t in_str_size, char *do_arg[]);
REG *find_reg (CONST char *ptr, CONST char **optr, DEVICE *dptr);
CTAB *find_ctab (CTAB *tab, const char *gbuf);
C1TAB *find_c1tab (C1TAB *tab, const char *gbuf);
SHTAB *find_shtab (SHTAB *tab, const char *gbuf);
t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr);
t_value get_rval (REG *rptr, uint32 idx);
BRKTAB *sim_brk_fnd (t_addr loc);
uint32 sim_brk_test (t_addr bloc, uint32 btyp);
void sim_brk_clrspc (uint32 spc, uint32 btyp);
void sim_brk_npc (uint32 cnt);
void sim_brk_setact (const char *action);
const char *sim_brk_message(void);
t_stat sim_send_input (SEND *snd, uint8 *data, size_t size, uint32 after, uint32 delay);
t_stat sim_show_send_input (FILE *st, const SEND *snd);
t_bool sim_send_poll_data (SEND *snd, t_stat *stat);
t_stat sim_send_clear (SEND *snd);
t_stat sim_set_expect (EXPECT *exp, CONST char *cptr);
t_stat sim_set_noexpect (EXPECT *exp, const char *cptr);
t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act);
t_stat sim_exp_clr (EXPECT *exp, const char *match);
t_stat sim_exp_clrall (EXPECT *exp);
t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match);
t_stat sim_exp_showall (FILE *st, const EXPECT *exp);
t_stat sim_exp_check (EXPECT *exp, uint8 data);
CONST char *match_ext (CONST char *fnam, const char *ext);
t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
const char *sim_error_text (t_stat stat);
t_stat sim_string_to_stat (const char *cptr, t_stat *cond);
t_stat sim_cancel_step (void);
void sim_printf (const char *fmt, ...) GCC_FMT_ATTR(1, 2);
void sim_perror (const char *msg);
t_stat sim_messagef (t_stat stat, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
void sim_data_trace(DEVICE *dptr, UNIT *uptr, const uint8 *data, const char *position, size_t len, const char *txt, uint32 reason);
void sim_debug_bits_hdr (uint32 dbits, DEVICE* dptr, const char *header, 
    BITFIELD* bitdefs, uint32 before, uint32 after, int terminate);
void sim_debug_bits (uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs,
    uint32 before, uint32 after, int terminate);
#if defined (__DECC) && defined (__VMS) && (defined (__VAX) || (__DECC_VER < 60590001))
#define CANT_USE_MACRO_VA_ARGS 1
#endif
#if defined(__cplusplus)
#ifdef CANT_USE_MACRO_VA_ARGS
#define _sim_debug sim_debug
void sim_debug (uint32 dbits, void* dptr, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
#else
void _sim_debug (uint32 dbits, void* dptr, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
#define sim_debug(dbits, dptr, ...) do { if (sim_deb && dptr && ((dptr)->dctrl & dbits)) _sim_debug (dbits, dptr, __VA_ARGS__);} while (0)
#endif
#else
#ifdef CANT_USE_MACRO_VA_ARGS
#define _sim_debug sim_debug
void sim_debug (uint32 dbits, DEVICE* dptr, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
#else
void _sim_debug (uint32 dbits, DEVICE* dptr, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
#define sim_debug(dbits, dptr, ...) do { if (sim_deb && dptr && ((dptr)->dctrl & dbits)) _sim_debug (dbits, dptr, __VA_ARGS__);} while (0)
#endif
#endif
void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr);
#define SCP_HELP_FLAT   (1u << 31)       /* Force flat help when prompting is not possible */
#define SCP_HELP_ONECMD (1u << 30)       /* Display one topic, do not prompt */
#define SCP_HELP_ATTACH (1u << 29)       /* Top level topic is ATTACH help */
t_stat scp_help (FILE *st, DEVICE *dptr,
                 UNIT *uptr, int32 flag, const char *help, const char *cptr, ...);
t_stat scp_vhelp (FILE *st, DEVICE *dptr,
                  UNIT *uptr, int32 flag, const char *help, const char *cptr, va_list ap);
t_stat scp_helpFromFile (FILE *st, DEVICE *dptr,
                         UNIT *uptr, int32 flag, const char *help, const char *cptr, ...);
t_stat scp_vhelpFromFile (FILE *st, DEVICE *dptr,
                          UNIT *uptr, int32 flag, const char *help, const char *cptr, va_list ap);

/* Global data */

extern DEVICE *sim_dflt_dev;
extern DEVICE *sim_dfdev;
extern UNIT *sim_dfunit;
extern int32 sim_interval;
extern int32 sim_switches;
extern int32 sim_quiet;
extern int32 sim_step;
extern t_stat sim_last_cmd_stat;                        /* Command Status */
extern FILE *sim_log;                                   /* log file */
extern FILEREF *sim_log_ref;                            /* log file file reference */
extern FILE *sim_deb;                                   /* debug file */
extern FILEREF *sim_deb_ref;                            /* debug file file reference */
extern int32 sim_deb_switches;                          /* debug display flags */
extern struct timespec sim_deb_basetime;                /* debug base time for relative time output */
extern DEVICE **sim_internal_devices;
extern uint32 sim_internal_device_count;
extern UNIT *sim_clock_queue;
extern int32 sim_is_running;
extern t_bool sim_processing_event;                     /* Called from sim_process_event */
extern char *sim_prompt;                                /* prompt string */
extern const char *sim_savename;                        /* Simulator Name used in Save/Restore files */
extern t_value *sim_eval;
extern volatile int32 stop_cpu;
extern uint32 sim_brk_types;                            /* breakpoint info */
extern uint32 sim_brk_dflt;
extern uint32 sim_brk_summ;
extern uint32 sim_brk_match_type;
extern t_addr sim_brk_match_addr;
extern BRKTYPTAB *sim_brk_type_desc;                      /* type descriptions */
extern FILE *stdnul;
extern t_bool sim_asynch_enabled;
#if defined(SIM_ASYNCH_IO)
int sim_aio_update_queue (void);
void sim_aio_activate (ACTIVATE_API caller, UNIT *uptr, int32 event_time);
#endif

/* VM interface */

extern char sim_name[64];
extern DEVICE *sim_devices[];
extern REG *sim_PC;
extern const char *sim_stop_messages[SCPE_BASE];
extern t_stat sim_instr (void);
extern t_stat sim_load (FILE *ptr, CONST char *cptr, CONST char *fnam, int flag);
extern int32 sim_emax;
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val,
    UNIT *uptr, int32 sw);
extern t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val,
    int32 sw);

/* The per-simulator init routine is a weak global that defaults to NULL
   The other per-simulator pointers can be overrriden by the init routine */

WEAK extern void (*sim_vm_init) (void);
extern char *(*sim_vm_read) (char *ptr, int32 size, FILE *stream);
extern void (*sim_vm_post) (t_bool from_scp);
extern CTAB *sim_vm_cmd;
extern void (*sim_vm_sprint_addr) (char *buf, DEVICE *dptr, t_addr addr);
extern void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr);
extern t_addr (*sim_vm_parse_addr) (DEVICE *dptr, CONST char *cptr, CONST char **tptr);
extern t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason);
extern t_value (*sim_vm_pc_value) (void);
extern t_bool (*sim_vm_is_subroutine_call) (t_addr **ret_addrs);

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_console.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
/* sim_console.c: simulator console I/O library

   Copyright (c) 1993-2014, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   02-Jan-14    RMS     Added tab stop routines
   18-Mar-12    RMS     Removed unused reference to sim_switches (Dave Bryan)
   07-Dec-11    MP      Added sim_ttisatty to support reasonable behaviour (i.e. 
                        avoid in infinite loop) in the main command input
                        loop when EOF is detected and input is coming from 
                        a file (or a null device: /dev/null or NUL:) This may
                        happen when a simulator is running in a background 
                        process.
   17-Apr-11    MP      Cleaned up to support running in a background/detached
                        process
   20-Jan-11    MP      Fixed support for BREAK key on Windows to account 
                        for/ignore other keyboard Meta characters.
   18-Jan-11    MP      Added log file reference count support
   17-Jan-11    MP      Added support for a "Buffered" behaviors which include:
                        - If Buffering is enabled and Telnet is enabled, a
                          telnet connection is not required for simulator 
                          operation (instruction execution).
                        - If Buffering is enabled, all console output is 
                          written to the buffer at all times (deleting the
                          oldest buffer contents on overflow).
                        - when a connection is established on the console 
                          telnet port, the whole contents of the Buffer is
                          presented on the telnet session and connection 
                          will then proceed as if the connection had always
                          been there.
                        This concept allows a simulator to run in the background
                        and when needed a console session to be established.  
                        The "when needed" case usually will be interested in 
                        what already happened before looking to address what 
                        to do, hence the buffer contents being presented.
   28-Dec-10    MP      Added support for BREAK key on Windows
   30-Sep-06    RMS     Fixed non-printable characters in KSR mode
   22-Jun-06    RMS     Implemented SET/SHOW PCHAR
   31-May-06    JDB     Fixed bug if SET CONSOLE DEBUG with no argument
   22-Nov-05    RMS     Added central input/output conversion support
   05-Nov-04    RMS     Moved SET/SHOW DEBUG under CONSOLE hierarchy
   28-Oct-04    JDB     Fixed SET CONSOLE to allow comma-separated parameters
   20-Aug-04    RMS     Added OS/2 EMX fixes (Holger Veit)
   14-Jul-04    RMS     Revised Windows console code (Dave Bryan)
   28-May-04    RMS     Added SET/SHOW CONSOLE
                RMS     Added break, delete character maps
   02-Jan-04    RMS     Removed timer routines, added Telnet console routines
                RMS     Moved console logging to OS-independent code
   25-Apr-03    RMS     Added long seek support (Mark Pizzolato)
                        Added Unix priority control (Mark Pizzolato)
   24-Sep-02    RMS     Removed VT support, added Telnet console support
                        Added CGI support (Brian Knittel)
                        Added MacOS sleep (Peter Schorn)
   14-Jul-02    RMS     Added Windows priority control (Mark Pizzolato)
   20-May-02    RMS     Added Windows VT support (Fischer Franz)
   01-Feb-02    RMS     Added VAX fix (Robert Alan Byer)
   19-Sep-01    RMS     More MacOS changes
   31-Aug-01    RMS     Changed int64 to t_int64 for Windoze
   20-Jul-01    RMS     Added MacOS support (Louis Chretien, Peter Schorn, Ben Supnik)
   15-May-01    RMS     Added logging support
   05-Mar-01    RMS     Added clock calibration support
   08-Dec-00    BKR     Added OS/2 support (Bruce Ray)
   18-Aug-98    RMS     Added BeOS support
   13-Oct-97    RMS     Added NetBSD terminal support
   25-Jan-97    RMS     Added POSIX terminal I/O support
   02-Jan-97    RMS     Fixed bug in sim_poll_kbd

   This module implements the following routines to support terminal and 
   Remote Console I/O:

   sim_poll_kbd                 poll for keyboard input
   sim_putchar                  output character to console
   sim_putchar_s                output character to console, stall if congested
   sim_set_console              set console parameters
   sim_show_console             show console parameters
   sim_set_remote_console       set remote console parameters
   sim_show_remote_console      show remote console parameters
   sim_set_cons_buff            set console buffered
   sim_set_cons_unbuff          set console unbuffered
   sim_set_cons_log             set console log
   sim_set_cons_nolog           set console nolog
   sim_show_cons_buff           show console buffered
   sim_show_cons_log            show console log
   sim_tt_inpcvt                convert input character per mode
   sim_tt_outcvt                convert output character per mode
   sim_cons_get_send            get console send structure address
   sim_cons_get_expect          get console expect structure address
   sim_show_cons_send_input     show pending input data
   sim_show_cons_expect         show expect rules and state
   sim_ttinit                   called once to get initial terminal state
   sim_ttrun                    called to put terminal into run state
   sim_ttcmd                    called to return terminal to command state
   sim_ttclose                  called once before the simulator exits
   sim_ttisatty                 called to determine if running interactively
   sim_os_poll_kbd              poll for keyboard input
   sim_os_putchar               output character to console
   sim_set_noconsole_port       Enable automatic WRU console polling
   sim_set_stable_registers_state Declare that all registers are always stable


   The first group is OS-independent; the second group is OS-dependent.

   The following routines are exposed but deprecated:

   sim_set_telnet               set console to Telnet port
   sim_set_notelnet             close console Telnet port
   sim_show_telnet              show console status
*/

#include "sim_defs.h"
#include "sim_tmxr.h"
#include "sim_serial.h"
#include "sim_timer.h"
#include <ctype.h>
#include <math.h>

#ifdef __HAIKU__
#define nice(n) ({})
#endif

/* Forward Declaraations of Platform specific routines */

static t_stat sim_os_poll_kbd (void);
static t_bool sim_os_poll_kbd_ready (int ms_timeout);
static t_stat sim_os_putchar (int32 out);
static t_stat sim_os_ttinit (void);
static t_stat sim_os_ttrun (void);
static t_stat sim_os_ttcmd (void);
static t_stat sim_os_ttclose (void);
static t_bool sim_os_ttisatty (void);

static t_stat sim_set_rem_telnet (int32 flag, CONST char *cptr);
static t_stat sim_set_rem_bufsize (int32 flag, CONST char *cptr);
static t_stat sim_set_rem_connections (int32 flag, CONST char *cptr);
static t_stat sim_set_rem_timeout (int32 flag, CONST char *cptr);
static t_stat sim_set_rem_master (int32 flag, CONST char *cptr);

/* Deprecated CONSOLE HALT, CONSOLE RESPONSE and CONSOLE DELAY support */
static t_stat sim_set_halt (int32 flag, CONST char *cptr);
static t_stat sim_set_response (int32 flag, CONST char *cptr);
static t_stat sim_set_delay (int32 flag, CONST char *cptr);


#define KMAP_WRU        0
#define KMAP_BRK        1
#define KMAP_DEL        2
#define KMAP_MASK       0377
#define KMAP_NZ         0400

int32 sim_int_char = 005;                               /* interrupt character */
int32 sim_brk_char = 000;                               /* break character */
int32 sim_tt_pchar = 0x00002780;
#if defined (_WIN32) || defined (__OS2__) || (defined (__MWERKS__) && defined (macintosh))
int32 sim_del_char = '\b';                              /* delete character */
#else
int32 sim_del_char = 0177;
#endif
extern TMLN *sim_oline;                                 /* global output socket */

static t_stat sim_con_poll_svc (UNIT *uptr);                /* console connection poll routine */
static t_stat sim_con_reset (DEVICE *dptr);                 /* console reset routine */
static t_stat sim_con_attach (UNIT *uptr, CONST char *ptr); /* console attach routine (save,restore) */
static t_stat sim_con_detach (UNIT *uptr);                  /* console detach routine (save,restore) */

UNIT sim_con_units[2] = {{ UDATA (&sim_con_poll_svc, UNIT_ATTABLE, 0)}}; /* console connection unit */
#define sim_con_unit sim_con_units[0]

/* debugging bitmaps */
#define DBG_TRC  TMXR_DBG_TRC                           /* trace routine calls */
#define DBG_XMT  TMXR_DBG_XMT                           /* display Transmitted Data */
#define DBG_RCV  TMXR_DBG_RCV                           /* display Received Data */
#define DBG_RET  TMXR_DBG_RET                           /* display Returned Received Data */
#define DBG_ASY  TMXR_DBG_ASY                           /* asynchronous thread activity */
#define DBG_CON  TMXR_DBG_CON                           /* display connection activity */
#define DBG_EXP  0x00000001                             /* Expect match activity */
#define DBG_SND  0x00000002                             /* Send (Inject) data activity */

static DEBTAB sim_con_debug[] = {
  {"TRC",    DBG_TRC, "routine calls"},
  {"XMT",    DBG_XMT, "Transmitted Data"},
  {"RCV",    DBG_RCV, "Received Data"},
  {"RET",    DBG_RET, "Returned Received Data"},
  {"ASY",    DBG_ASY, "asynchronous activity"},
  {"CON",    DBG_CON, "connection activity"},
  {"EXP",    DBG_EXP, "Expect match activity"},
  {"SND",    DBG_SND, "Send (Inject) data activity"},
  {0}
};

static REG sim_con_reg[] = {
    { ORDATAD (WRU,   sim_int_char,  8, "interrupt character") },
    { ORDATAD (BRK,   sim_brk_char,  8, "break character") },
    { ORDATAD (DEL,   sim_del_char,  8, "delete character ") },
    { ORDATAD (PCHAR, sim_tt_pchar, 32, "printable character mask") },
  { 0 },
};

static MTAB sim_con_mod[] = {
  { 0 },
};

static const char *sim_con_telnet_description (DEVICE *dptr)
{
return "Console telnet support";
}

DEVICE sim_con_telnet = {
    "CON-TELNET", sim_con_units, sim_con_reg, sim_con_mod, 
    2, 0, 0, 0, 0, 0, 
    NULL, NULL, sim_con_reset, NULL, sim_con_attach, sim_con_detach, 
    NULL, DEV_DEBUG, 0, sim_con_debug,
    NULL, NULL, NULL, NULL, NULL, sim_con_telnet_description};
TMLN sim_con_ldsc = { 0 };                                          /* console line descr */
TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc, NULL, &sim_con_telnet };/* console line mux */


SEND sim_con_send = {SEND_DEFAULT_DELAY, &sim_con_telnet, DBG_SND};
EXPECT sim_con_expect = {&sim_con_telnet, DBG_EXP};

static t_bool sim_con_console_port = TRUE;

/* Enable automatic WRU console polling */

t_stat sim_set_noconsole_port (void)
{
sim_con_console_port = FALSE;
return SCPE_OK;
}

static t_bool sim_con_stable_registers = FALSE;

/* Enable automatic WRU console polling */

t_stat sim_set_stable_registers_state (void)
{
sim_con_stable_registers = TRUE;
return SCPE_OK;
}

/* Unit service for console connection polling */

static t_stat sim_con_poll_svc (UNIT *uptr)
{
if ((sim_con_tmxr.master == 0) &&                       /* not Telnet and not serial and not WRU polling? */
    (sim_con_ldsc.serport == 0) &&
    (sim_con_console_port))
    return SCPE_OK;                                     /* done */
if (tmxr_poll_conn (&sim_con_tmxr) >= 0)                /* poll connect */
    sim_con_ldsc.rcve = 1;                              /* rcv enabled */
sim_activate_after(uptr, 1000000);                      /* check again in 1 second */
if (!sim_con_console_port)                              /* WRU poll needed */
    sim_poll_kbd();                                     /* sets global stop_cpu when WRU received */
if (sim_con_ldsc.conn)
    tmxr_send_buffered_data (&sim_con_ldsc);            /* try to flush any buffered data */
return SCPE_OK;
}

static t_stat sim_con_reset (DEVICE *dptr)
{
dptr->units[1].flags = UNIT_DIS;
return sim_con_poll_svc (&dptr->units[0]);              /* establish polling as needed */
}

/* Console Attach/Detach - only used indirectly in restore */

static t_stat sim_con_attach (UNIT *uptr, CONST char *ptr)
{
return tmxr_attach (&sim_con_tmxr, &sim_con_unit, ptr);
}

static t_stat sim_con_detach (UNIT *uptr)
{
return sim_set_notelnet (0, NULL);
}

/* Set/show data structures */

static CTAB set_con_tab[] = {
    { "WRU", &sim_set_kmap, KMAP_WRU | KMAP_NZ },
    { "BRK", &sim_set_kmap, KMAP_BRK },
    { "DEL", &sim_set_kmap, KMAP_DEL |KMAP_NZ },
    { "PCHAR", &sim_set_pchar, 0 },
    { "SPEED", &sim_set_cons_speed, 0 },
    { "TELNET", &sim_set_telnet, 0 },
    { "NOTELNET", &sim_set_notelnet, 0 },
    { "SERIAL", &sim_set_serial, 0 },
    { "NOSERIAL", &sim_set_noserial, 0 },
    { "LOG", &sim_set_logon, 0 },
    { "NOLOG", &sim_set_logoff, 0 },
    { "DEBUG", &sim_set_debon, 0 },
    { "NODEBUG", &sim_set_deboff, 0 },
#define CMD_WANTSTR     0100000
    { "HALT", &sim_set_halt, 1 | CMD_WANTSTR },
    { "NOHALT", &sim_set_halt, 0 },
    { "DELAY", &sim_set_delay, 0 },
    { "RESPONSE", &sim_set_response, 1 | CMD_WANTSTR },
    { "NORESPONSE", &sim_set_response, 0 },
    { NULL, NULL, 0 }
    };

static CTAB set_rem_con_tab[] = {
    { "CONNECTIONS", &sim_set_rem_connections, 0 },
    { "TELNET", &sim_set_rem_telnet, 1 },
    { "BUFFERSIZE", &sim_set_rem_bufsize, 1 },
    { "NOTELNET", &sim_set_rem_telnet, 0 },
    { "TIMEOUT", &sim_set_rem_timeout, 0 },
    { "MASTER", &sim_set_rem_master, 1 },
    { "NOMASTER", &sim_set_rem_master, 0 },
    { NULL, NULL, 0 }
    };

static SHTAB show_con_tab[] = {
    { "WRU", &sim_show_kmap, KMAP_WRU },
    { "BRK", &sim_show_kmap, KMAP_BRK },
    { "DEL", &sim_show_kmap, KMAP_DEL },
    { "PCHAR", &sim_show_pchar, 0 },
    { "SPEED", &sim_show_cons_speed, 0 },
    { "LOG", &sim_show_cons_log, 0 },
    { "TELNET", &sim_show_telnet, 0 },
    { "DEBUG", &sim_show_cons_debug, 0 },
    { "BUFFERED", &sim_show_cons_buff, 0 },
    { "EXPECT", &sim_show_cons_expect, 0 },
    { "HALT", &sim_show_cons_expect, 0 },
    { "INPUT", &sim_show_cons_send_input, 0 },
    { "RESPONSE", &sim_show_cons_send_input, 0 },
    { "DELAY", &sim_show_cons_expect, 0 },
    { NULL, NULL, 0 }
    };

static CTAB set_con_telnet_tab[] = {
    { "LOG", &sim_set_cons_log, 0 },
    { "NOLOG", &sim_set_cons_nolog, 0 },
    { "BUFFERED", &sim_set_cons_buff, 0 },
    { "NOBUFFERED", &sim_set_cons_unbuff, 0 },
    { "UNBUFFERED", &sim_set_cons_unbuff, 0 },
    { NULL, NULL, 0 }
    };

static CTAB set_con_serial_tab[] = {
    { "LOG", &sim_set_cons_log, 0 },
    { "NOLOG", &sim_set_cons_nolog, 0 },
    { NULL, NULL, 0 }
    };

static int32 *cons_kmap[] = {
    &sim_int_char,
    &sim_brk_char,
    &sim_del_char
    };

/* Console I/O package.

   The console terminal can be attached to the controlling window
   or to a Telnet connection.  If attached to a Telnet connection,
   the console is described by internal terminal multiplexor
   sim_con_tmxr and internal terminal line description sim_con_ldsc.
*/

/* SET CONSOLE command */

t_stat sim_set_console (int32 flag, CONST char *cptr)
{
char *cvptr, gbuf[CBUFSIZE];
CTAB *ctptr;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_2FARG;
while (*cptr != 0) {                                    /* do all mods */
    cptr = get_glyph_nc (cptr, gbuf, ',');              /* get modifier */
    if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
        *cvptr++ = 0;
    get_glyph (gbuf, gbuf, 0);                          /* modifier to UC */
    if ((ctptr = find_ctab (set_con_tab, gbuf))) {      /* match? */
        r = ctptr->action (ctptr->arg, cvptr);          /* do the rest */
        if (r != SCPE_OK)
            return r;
        }
    else return SCPE_NOPARAM;
    }
return SCPE_OK;
}

/* SHOW CONSOLE command */

t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
char gbuf[CBUFSIZE];
SHTAB *shptr;
int32 i;

if (*cptr == 0) {                                       /* show all */
    for (i = 0; show_con_tab[i].name; i++)
        show_con_tab[i].action (st, dptr, uptr, show_con_tab[i].arg, cptr);
    return SCPE_OK;
    }
while (*cptr != 0) {
    cptr = get_glyph (cptr, gbuf, ',');                 /* get modifier */
    if ((shptr = find_shtab (show_con_tab, gbuf)))
        shptr->action (st, dptr, uptr, shptr->arg, cptr);
    else return SCPE_NOPARAM;
    }
return SCPE_OK;
}

#define MAX_REMOTE_SESSIONS 40                          /* Arbitrary Session Limit */

t_stat sim_rem_con_poll_svc (UNIT *uptr);               /* remote console connection poll routine */
t_stat sim_rem_con_data_svc (UNIT *uptr);               /* remote console connection data routine */
t_stat sim_rem_con_repeat_svc (UNIT *uptr);             /* remote auto repeat command console timing routine */
t_stat sim_rem_con_smp_collect_svc (UNIT *uptr);        /* remote remote register data sampling routine */
t_stat sim_rem_con_reset (DEVICE *dptr);                /* remote console reset routine */
#define rem_con_poll_unit (&sim_remote_console.units[0])
#define rem_con_data_unit (&sim_remote_console.units[1])
#define REM_CON_BASE_UNITS 2
#define rem_con_repeat_units (&sim_remote_console.units[REM_CON_BASE_UNITS])
#define rem_con_smp_smpl_units (&sim_remote_console.units[REM_CON_BASE_UNITS+sim_rem_con_tmxr.lines])

#define DBG_MOD  0x00000004                             /* Remote Console Mode activities */
#define DBG_REP  0x00000008                             /* Remote Console Repeat activities */
#define DBG_SAM  0x00000010                             /* Remote Console Sample activities */
#define DBG_CMD  0x00000020                             /* Remote Console Command activities */

DEBTAB sim_rem_con_debug[] = {
  {"TRC",    DBG_TRC, "routine calls"},
  {"XMT",    DBG_XMT, "Transmitted Data"},
  {"RCV",    DBG_RCV, "Received Data"},
  {"CON",    DBG_CON, "connection activity"},
  {"CMD",    DBG_CMD, "Remote Console Command activity"},
  {"MODE",   DBG_MOD, "Remote Console Mode activity"},
  {"REPEAT", DBG_REP, "Remote Console Repeat activity"},
  {"SAMPLE", DBG_SAM, "Remote Console Sample activity"},
  {0}
};

MTAB sim_rem_con_mod[] = {
  { 0 },
};

static const char *sim_rem_con_description (DEVICE *dptr)
{
return "Remote Console Facility";
}

DEVICE sim_remote_console = {
    "REM-CON", NULL, NULL, sim_rem_con_mod, 
    0, 0, 0, 0, 0, 0, 
    NULL, NULL, sim_rem_con_reset, NULL, NULL, NULL, 
    NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_rem_con_debug,
    NULL, NULL, NULL, NULL, NULL, sim_rem_con_description};

typedef struct BITSAMPLE BITSAMPLE;
struct BITSAMPLE {
    int             tot;            /* total of all values */
    int             ptr;            /* pointer to next value cell */
    int             depth;          /* number of values */
    int             *vals;          /* values */
    };
typedef struct BITSAMPLE_REG BITSAMPLE_REG;
struct BITSAMPLE_REG {
    REG             *reg;           /* Register to be sampled */
    t_bool          indirect;       /* Register value points at memory */
    DEVICE          *dptr;          /* Device register is part of */
    UNIT            *uptr;          /* Unit Register is related to */
    uint32          width;          /* number of bits to sample */
    BITSAMPLE       *bits;
    };
typedef struct REMOTE REMOTE;
struct REMOTE {
    int32           buf_size;
    int32           buf_ptr;
    char            *buf;
    char            *act_buf;
    size_t          act_buf_size;
    char            *act;
    t_bool          single_mode;
    uint32          read_timeout;
    int             line;                   /* remote console line number */
    TMLN            *lp;                    /* mux line/socket for remote session */
    UNIT            *uptr;                  /* remote console unit */
    uint32          repeat_interval;        /* usecs between repeat execution */
    t_bool          repeat_pending;         /* repeat delivery pending */
    char            *repeat_action;         /* command(s) to repeatedly execute */
    int             smp_sample_interval;    /* cycles between samples */
    uint32          smp_reg_count;          /* sample register count */
    BITSAMPLE_REG   *smp_regs;              /* registers being sampled */
    };
REMOTE *sim_rem_consoles = NULL;

static TMXR sim_rem_con_tmxr = { 0, 0, 0, NULL, NULL, &sim_remote_console };/* remote console line mux */
static uint32 sim_rem_read_timeout = 30;    /* seconds before automatic continue */
static uint32 *sim_rem_read_timeouts = NULL;/* per line read timeout (default from sim_rem_read_timeout) */
static int32 sim_rem_active_number = -1;    /* -1 - not active, >= 0 is index of active console */
int32 sim_rem_cmd_active_line = -1;         /* step in progress on line # */
static CTAB *sim_rem_active_command = NULL; /* active command */
static char *sim_rem_command_buf;           /* active command buffer */
static t_bool sim_log_temp = FALSE;         /* temporary log file active */
static char sim_rem_con_temp_name[PATH_MAX+1];
static t_bool sim_rem_master_mode = FALSE;  /* Master Mode Enabled Flag */
static t_bool sim_rem_master_was_enabled = FALSE; /* Master was Enabled */
static t_bool sim_rem_master_was_connected = FALSE; /* Master Mode has been connected */
static t_offset sim_rem_cmd_log_start = 0;  /* Log File saved position */

static t_stat sim_rem_sample_output (FILE *st, int32 line)
{
REMOTE *rem = &sim_rem_consoles[line];
uint32 reg;

if (rem->smp_reg_count == 0) {
    fprintf (st, "Samples are not being collected\n");
    return SCPE_OK;
    }
for (reg = 0; reg < rem->smp_reg_count; reg++) {
    uint32 bit;

    fprintf (st, "}%s %s%s %d:", rem->smp_regs[reg].dptr->name, rem->smp_regs[reg].reg->name, rem->smp_regs[reg].indirect ? " -I" : "", rem->smp_regs[reg].bits[0].depth);
    for (bit = 0; bit < rem->smp_regs[reg].width; bit++)
        fprintf (st, "%s%d", (bit != 0) ? "," : "", rem->smp_regs[reg].bits[bit].tot);
    fprintf (st, "\n");
    }
return SCPE_OK;
}


/* SET REMOTE CONSOLE command */

t_stat sim_set_remote_console (int32 flag, CONST char *cptr)
{
char *cvptr, gbuf[CBUFSIZE];
CTAB *ctptr;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_2FARG;
while (*cptr != 0) {                                    /* do all mods */
    cptr = get_glyph_nc (cptr, gbuf, ',');              /* get modifier */
    if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
        *cvptr++ = 0;
    get_glyph (gbuf, gbuf, 0);                          /* modifier to UC */
    if ((ctptr = find_ctab (set_rem_con_tab, gbuf))) {  /* match? */
        r = ctptr->action (ctptr->arg, cvptr);          /* do the rest */
        if (r != SCPE_OK)
            return r;
        }
    else return SCPE_NOPARAM;
    }
return SCPE_OK;
}

/* SHOW REMOTE CONSOLE command */

t_stat sim_show_remote_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
int32 i, connections;
REMOTE *rem;

if (*cptr != 0)
    return SCPE_NOPARAM;
if (sim_rem_active_number >= 0) {
    if (sim_rem_master_mode && (sim_rem_active_number == 0))
        fprintf (st, "Running from Master Mode Remote Console Connection\n");
    else
        fprintf (st, "Running from Remote Console Connection %d\n", sim_rem_active_number);
    }
if (sim_rem_con_tmxr.lines > 1)
    fprintf (st, "Remote Console Input Connections from %d sources are supported concurrently\n", sim_rem_con_tmxr.lines);
if (sim_rem_read_timeout)
    fprintf (st, "Remote Console Input automatically continues after %d seconds\n", sim_rem_read_timeout);
if (!sim_rem_con_tmxr.master)
    fprintf (st, "Remote Console Command input is disabled\n");
else {
    fprintf (st, "Remote Console Command Input listening on TCP port: %s\n", rem_con_poll_unit->filename);
    fprintf (st, "Remote Console Per Command Output buffer size:      %d bytes\n", sim_rem_con_tmxr.buffered);
    }
for (i=connections=0; i<sim_rem_con_tmxr.lines; i++) {
    rem = &sim_rem_consoles[i];
    if (!rem->lp->conn)
        continue;
    ++connections;
    if (connections == 1)
        fprintf (st, "Remote Console Connections:\n");
    tmxr_fconns (st, rem->lp, i);
    if (rem->read_timeout != sim_rem_read_timeout) {
        if (rem->read_timeout)
            fprintf (st, "Remote Console Input on connection %d automatically continues after %d seconds\n", i, rem->read_timeout);
        else
            fprintf (st, "Remote Console Input on connection %d does not continue automatically\n", i);
        }
    if (rem->repeat_action) {
        fprintf (st, "The Command: %s\n", rem->repeat_action);
        fprintf (st, "    is repeated every %s\n", sim_fmt_secs (rem->repeat_interval / 1000000.0));
        }
    if (rem->smp_reg_count) {
        uint32 reg;
        DEVICE *dptr = NULL;

        fprintf (st, "Register Bit Sampling is occurring every %d cycles\n", rem->smp_sample_interval);
        fprintf (st, " Registers being sampled are: ");
        for (reg = 0; reg < rem->smp_reg_count; reg++) {
            if (rem->smp_regs[reg].indirect)
                fprintf (st, " indirect ");
            if (dptr != rem->smp_regs[reg].dptr)
                fprintf (st, "%s ", rem->smp_regs[reg].dptr->name);
            fprintf (st, "%s%s", rem->smp_regs[reg].reg->name, ((reg + 1) < rem->smp_reg_count) ? ", " : "");
            dptr = rem->smp_regs[reg].dptr;
            }
        fprintf (st, "\n");
        if (sim_switches & SWMASK ('D'))
            sim_rem_sample_output (st, rem->line);
        }
    }
return SCPE_OK;
}

/* Unit service for remote console connection polling */

t_stat sim_rem_con_poll_svc (UNIT *uptr)
{
int32 c;

c = tmxr_poll_conn (&sim_rem_con_tmxr);
if (c >= 0) {                                           /* poll connect */
    REMOTE *rem = &sim_rem_consoles[c];
    TMLN *lp = rem->lp;
    char wru_name[8];

    sim_activate_after(uptr+1, 1000000);                /* start data poll after 1 second */
    lp->rcve = 1;                                       /* rcv enabled */
    rem->buf_ptr = 0;                                   /* start with empty command buffer */
    rem->single_mode = TRUE;                            /* start in single command mode */
    rem->read_timeout = sim_rem_read_timeout;           /* Start with default timeout */
    if (isprint(sim_int_char&0xFF))
        sprintf(wru_name, "'%c'", sim_int_char&0xFF);
    else
        if (sim_int_char <= 26)
            sprintf(wru_name, "^%c", '@' + (sim_int_char&0xFF));
        else
            sprintf(wru_name, "'\\%03o'", sim_int_char&0xFF);
    tmxr_linemsgf (lp, "%s Remote Console\r\n"
                       "Enter single commands or to enter multiple command mode enter the %s character\r"
                       "%s",
                       sim_name, wru_name, 
                       ((sim_rem_master_mode && (c == 0)) ? "" : "\nSimulator Running..."));
    if (sim_rem_master_mode && (c == 0))                /* Master Mode session? */
        rem->single_mode = FALSE;                       /*  start in multi-command mode */
    tmxr_send_buffered_data (lp);                       /* flush buffered data */
    }
sim_activate_after(uptr, 1000000);                      /* check again in 1 second */
if (sim_con_ldsc.conn)
    tmxr_send_buffered_data (&sim_con_ldsc);            /* try to flush any buffered data */
return SCPE_OK;
}

static t_stat x_continue_cmd (int32 flag, CONST char *cptr)
{
return 1+SCPE_IERR;         /* This routine should never be called */
}

static t_stat x_repeat_cmd (int32 flag, CONST char *cptr)
{
return 2+SCPE_IERR;         /* This routine should never be called */
}

static t_stat x_collect_cmd (int32 flag, CONST char *cptr)
{
return 3+SCPE_IERR;         /* This routine should never be called */
}

static t_stat x_sampleout_cmd (int32 flag, CONST char *cptr)
{
return 4+SCPE_IERR;         /* This routine should never be called */
}

static t_stat x_step_cmd (int32 flag, CONST char *cptr)
{
return 5+SCPE_IERR;         /* This routine should never be called */
}

static t_stat x_run_cmd (int32 flag, CONST char *cptr)
{
return 6+SCPE_IERR;         /* This routine should never be called */
}

static t_stat x_help_cmd (int32 flag, CONST char *cptr);

static CTAB allowed_remote_cmds[] = {
    { "EXAMINE",  &exdep_cmd,      EX_E },
    { "DEPOSIT",  &exdep_cmd,      EX_D },
    { "EVALUATE", &eval_cmd,          0 },
    { "ATTACH",   &attach_cmd,        0 },
    { "DETACH",   &detach_cmd,        0 },
    { "ASSIGN",   &assign_cmd,        0 },
    { "DEASSIGN", &deassign_cmd,      0 },
    { "CONTINUE", &x_continue_cmd,    0 },
    { "REPEAT",   &x_repeat_cmd,      0 },
    { "COLLECT",  &x_collect_cmd,     0 },
    { "SAMPLEOUT",&x_sampleout_cmd,   0 },
    { "STEP",     &x_step_cmd,        0 },
    { "PWD",      &pwd_cmd,           0 },
    { "SAVE",     &save_cmd,          0 },
    { "DIR",      &dir_cmd,           0 },
    { "LS",       &dir_cmd,           0 },
    { "ECHO",     &echo_cmd,          0 },
    { "SET",      &set_cmd,           0 },
    { "SHOW",     &show_cmd,          0 },
    { "HELP",     &x_help_cmd,        0 },
    { NULL,       NULL }
    };

static CTAB allowed_master_remote_cmds[] = {
    { "EXAMINE",  &exdep_cmd,      EX_E },
    { "DEPOSIT",  &exdep_cmd,      EX_D },
    { "EVALUATE", &eval_cmd,          0 },
    { "ATTACH",   &attach_cmd,        0 },
    { "DETACH",   &detach_cmd,        0 },
    { "ASSIGN",   &assign_cmd,        0 },
    { "DEASSIGN", &deassign_cmd,      0 },
    { "CONTINUE", &x_continue_cmd,    0 },
    { "REPEAT",   &x_repeat_cmd,      0 },
    { "COLLECT",  &x_collect_cmd,     0 },
    { "SAMPLEOUT",&x_sampleout_cmd,   0 },
    { "STEP",     &x_step_cmd,        0 },
    { "PWD",      &pwd_cmd,           0 },
    { "SAVE",     &save_cmd,          0 },
    { "CD",       &set_default_cmd,   0 },
    { "DIR",      &dir_cmd,           0 },
    { "LS",       &dir_cmd,           0 },
    { "ECHO",     &echo_cmd,          0 },
    { "SET",      &set_cmd,           0 },
    { "SHOW",     &show_cmd,          0 },
    { "HELP",     &x_help_cmd,        0 },
    { "EXIT",     &exit_cmd,          0 },
    { "QUIT",     &exit_cmd,          0 },
    { "RUN",      &x_run_cmd,    RU_RUN },
    { "GO",       &x_run_cmd,     RU_GO },
    { "BOOT",     &x_run_cmd,   RU_BOOT },
    { "BREAK",    &brk_cmd,      SSH_ST },
    { "NOBREAK",  &brk_cmd,      SSH_CL },
    { "EXPECT",   &expect_cmd,        1 },
    { "NOEXPECT", &expect_cmd,        0 },
    { "SEND",     &send_cmd,          0 },
    { NULL,       NULL }
    };

static CTAB allowed_single_remote_cmds[] = {
    { "ATTACH",   &attach_cmd,        0 },
    { "DETACH",   &detach_cmd,        0 },
    { "EXAMINE",  &exdep_cmd,      EX_E },
    { "EVALUATE", &eval_cmd,          0 },
    { "REPEAT",   &x_repeat_cmd,      0 },
    { "COLLECT",  &x_collect_cmd,     0 },
    { "SAMPLEOUT",&x_sampleout_cmd,   0 },
    { "PWD",      &pwd_cmd,           0 },
    { "DIR",      &dir_cmd,           0 },
    { "LS",       &dir_cmd,           0 },
    { "ECHO",     &echo_cmd,          0 },
    { "SHOW",     &show_cmd,          0 },
    { "HELP",     &x_help_cmd,        0 },
    { NULL,       NULL }
    };

static CTAB remote_only_cmds[] = {
    { "REPEAT",   &x_repeat_cmd,      0 },
    { "COLLECT",  &x_collect_cmd,     0 },
    { "SAMPLEOUT",&x_sampleout_cmd,   0 },
    { NULL,       NULL }
    };

static t_stat x_help_cmd (int32 flag, CONST char *cptr)
{
CTAB *cmdp, *cmdph;

if (*cptr) {
    int32 saved_switches = sim_switches;
    t_stat r;

    sim_switches |= SWMASK ('F');
    r = help_cmd (flag, cptr);
    sim_switches = saved_switches;
    return r;
    }
sim_printf ("Help is available for the following Remote Console commands:\r\n");
for (cmdp=allowed_remote_cmds; cmdp->name != NULL; ++cmdp) {
    cmdph = find_cmd (cmdp->name);
    if (cmdph && cmdph->help)
        sim_printf ("    %s\r\n", cmdp->name);
    }
sim_printf ("Enter \"HELP cmd\" for detailed help on a command\r\n");
return SCPE_OK;
}

static t_stat _sim_rem_message (const char *cmd, t_stat stat)
{
CTAB *cmdp = NULL;
t_stat stat_nomessage = stat & SCPE_NOMESSAGE;  /* extract possible message supression flag */

cmdp = find_cmd (cmd);
stat = SCPE_BARE_STATUS(stat);                  /* remove possible flag */
if (!stat_nomessage) {
    if (cmdp && (cmdp->message))                /* special message handler? */
        cmdp->message (NULL, stat);             /* let it deal with display */
    else {
        if (stat >= SCPE_BASE)                  /* error? */
            sim_printf ("%s\r\n", sim_error_text (stat));
        }
    }
return stat;
}

static void _sim_rem_log_out (TMLN *lp)
{
char cbuf[4*CBUFSIZE];
REMOTE *rem = &sim_rem_consoles[(int)(lp - sim_rem_con_tmxr.ldsc)];
int line = rem->line;

if ((!sim_oline) && (sim_log)) {
    fflush (sim_log);
    sim_fseeko (sim_log, sim_rem_cmd_log_start, SEEK_SET);
    cbuf[sizeof(cbuf)-1] = '\0';
    while (fgets (cbuf, sizeof(cbuf)-1, sim_log))
        tmxr_linemsgf (lp, "%s", cbuf);
    }
sim_oline = NULL;
if ((rem->act == NULL) && 
    (!tmxr_input_pending_ln (lp))) {
    int32 unwritten;

    do {
        unwritten = tmxr_send_buffered_data (lp);
        if (unwritten == lp->txbsz)
            sim_os_ms_sleep (100);
        } while (unwritten == lp->txbsz);
    }

}

void sim_remote_process_command (void)
{
char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], *argv[1] = {NULL};
CONST char *cptr;
int32 saved_switches = sim_switches;
t_stat stat;

sim_strlcpy (cbuf, sim_rem_command_buf, sizeof (cbuf));
while (isspace(cbuf[0]))
    memmove (cbuf, cbuf+1, strlen(cbuf+1)+1);   /* skip leading whitespace */
sim_sub_args (cbuf, sizeof(cbuf), argv);
cptr = cbuf;
cptr = get_glyph (cptr, gbuf, 0);               /* get command glyph */
sim_rem_active_command = find_cmd (gbuf);       /* find command */

if (!sim_processing_event)
    sim_ttcmd ();                               /* restore console */
stat = sim_rem_active_command->action (sim_rem_active_command->arg, cptr);/* execute command */
if (stat != SCPE_OK)
    stat = _sim_rem_message (gbuf, stat);       /* display results */
sim_last_cmd_stat = SCPE_BARE_STATUS(stat);
if (!sim_processing_event) {
    sim_ttrun ();                               /* set console mode */
    sim_cancel (rem_con_data_unit);             /* force immediate activation of sim_rem_con_data_svc */
    sim_activate (rem_con_data_unit, -1);
    }
sim_switches = saved_switches;                  /* restore original switches */
}

/* Clear pending actions */

static char *sim_rem_clract (int32 line)
{
REMOTE *rem = &sim_rem_consoles[line];

tmxr_send_buffered_data (rem->lp);              /* flush any buffered data */
return rem->act = NULL;
}

/* Set up pending actions */

static void sim_rem_setact (int32 line, const char *action)
{
if (action) {
    size_t act_size = strlen (action) + 1;
    REMOTE *rem = &sim_rem_consoles[line];

    if (act_size > rem->act_buf_size) {         /* expand buffer if necessary */
        rem->act_buf = (char *)realloc (rem->act_buf, act_size);
        rem->act_buf_size = act_size;
        }
    strcpy (rem->act_buf, action);              /* populate buffer */
    rem->act = rem->act_buf;                    /* start at beginning of buffer */
    }
else
    sim_rem_clract (line);
}

/* Get next pending action, if any */

static char *sim_rem_getact (int32 line, char *buf, int32 size)
{
char *ep;
size_t lnt;
REMOTE *rem = &sim_rem_consoles[line];

if (rem->act == NULL)                           /* any action? */
    return NULL;
while (sim_isspace (*rem->act))                 /* skip spaces */
    rem->act++;
if (*rem->act == 0)                             /* now empty? */
    return sim_rem_clract (line);
if ((ep = strchr (rem->act, ';'))) {            /* cmd delimiter? */
    lnt = ep - rem->act;                        /* cmd length */
    memcpy (buf, rem->act, lnt + 1);            /* copy with ; */
    buf[lnt] = 0;                               /* erase ; */
    rem->act += lnt + 1;                        /* adv ptr */
    }
else {
    strncpy (buf, rem->act, size);              /* copy action */
    rem->act += strlen (rem->act);              /* adv ptr to end */
    }
return buf;
}

/* 
    Parse and setup Remote Console REPEAT command:
       REPEAT EVERY nnn USECS Command {; command...}
 */
static t_stat sim_rem_repeat_cmd_setup (int32 line, CONST char **iptr)
{
char gbuf[CBUFSIZE];
int32 val;
t_bool all_stop = FALSE;
t_stat stat = SCPE_OK;
CONST char *cptr = *iptr;
REMOTE *rem = &sim_rem_consoles[line];

sim_debug (DBG_REP, &sim_remote_console, "Repeat Setup: %s\n", cptr);
if (*cptr == 0)         /* required argument? */
    stat = SCPE_2FARG;
else {
    cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
    if (MATCH_CMD (gbuf, "EVERY") == 0) {
        cptr = get_glyph (cptr, gbuf, 0);           /* get next glyph */
        val = (int32) get_uint (gbuf, 10, INT_MAX, &stat);
        if ((stat != SCPE_OK) || (val <= 0))        /* error? */
            stat = SCPE_ARG;
        else {
            cptr = get_glyph (cptr, gbuf, 0);       /* get next glyph */
            if ((MATCH_CMD (gbuf, "USECS") != 0) || (*cptr == 0))
                stat = SCPE_ARG;
            else
                rem->repeat_interval = val;
            }
        }
    else {
        if (MATCH_CMD (gbuf, "STOP") == 0) {
            if (*cptr) {                            /* more command arguments? */
                cptr = get_glyph (cptr, gbuf, 0);   /* get next glyph */
                if ((MATCH_CMD (gbuf, "ALL") != 0) ||   /*  */
                    (*cptr != 0)                   ||   /*  */
                    (line != 0))                        /* master line? */
                    stat = SCPE_ARG;
                else
                    all_stop = TRUE;
                }
            else
                rem->repeat_interval = 0;
            }
        else
            stat = SCPE_ARG;
        }
    }
if (stat == SCPE_OK) {
    if (all_stop) {
        for (line = 0; line < sim_rem_con_tmxr.lines; line++) {
            rem = &sim_rem_consoles[line];
            free (rem->repeat_action);
            rem->repeat_action = NULL;
            sim_cancel (rem->uptr);
            rem->repeat_pending = FALSE;
            sim_rem_clract (line);
            }
        }
    else {
        if (rem->repeat_interval != 0) {
            rem->repeat_action = (char *)realloc (rem->repeat_action, 1 + strlen (cptr));
            strcpy (rem->repeat_action, cptr);
            cptr += strlen (cptr);
            stat = sim_activate_after (rem->uptr, rem->repeat_interval);
            }
        else {
            free (rem->repeat_action);
            rem->repeat_action = NULL;
            sim_cancel (rem->uptr);
            }
        rem->repeat_pending = FALSE;
        sim_rem_clract (line);
        }
    }
*iptr = cptr;
return stat;
}


/* 
    Parse and setup Remote Console REPEAT command:
       COLLECT nnn SAMPLES EVERY nnn CYCLES reg{,reg...}
 */
static t_stat sim_rem_collect_cmd_setup (int32 line, CONST char **iptr)
{
char gbuf[CBUFSIZE];
int32 samples, cycles;
t_bool all_stop = FALSE;
t_stat stat = SCPE_OK;
CONST char *cptr = *iptr;
REMOTE *rem = &sim_rem_consoles[line];

sim_debug (DBG_SAM, &sim_remote_console, "Collect Setup: %s\n", cptr);
if (*cptr == 0)         /* required argument? */
    return SCPE_2FARG;
cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
samples = (int32) get_uint (gbuf, 10, INT_MAX, &stat);
if ((stat != SCPE_OK) || (samples <= 0)) {      /* error? */
    if (MATCH_CMD (gbuf, "STOP") == 0) {
        stat = SCPE_OK;
        if (*cptr) {                            /* more command arguments? */
            cptr = get_glyph (cptr, gbuf, 0);   /* get next glyph */
            if ((MATCH_CMD (gbuf, "ALL") != 0) ||   /*  */
                (*cptr != 0)                   ||   /*  */
                (line != 0))                        /* master line? */
                stat = SCPE_ARG;
            else
                all_stop = TRUE;
            }
        if (stat == SCPE_OK) {
            for (line = all_stop ? 0 : rem->line; line < (all_stop ? sim_rem_con_tmxr.lines : (rem->line + 1)); line++) {
                uint32 i, j;

                rem = &sim_rem_consoles[line];
                for (i = 0; i< rem->smp_reg_count; i++) {
                    for (j = 0; j < rem->smp_regs[i].width; j++)
                        free (rem->smp_regs[i].bits[j].vals);
                    free (rem->smp_regs[i].bits);
                    }
                free (rem->smp_regs);
                rem->smp_regs = NULL;
                rem->smp_reg_count = 0;
                sim_cancel (&rem_con_smp_smpl_units[rem->line]);
                rem->smp_sample_interval = 0;
                }
            }
        }
    else
        stat = sim_messagef (SCPE_ARG, "Expected value or STOP found: %s\n", gbuf);
    }
else {
    const char *tptr;

    cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
    if (MATCH_CMD (gbuf, "SAMPLES") != 0) {
        *iptr = cptr;
        return sim_messagef (SCPE_ARG, "Expected SAMPLES found: %s\n", gbuf);
        }
    cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
    if (MATCH_CMD (gbuf, "EVERY") != 0) {
        *iptr = cptr;
        return sim_messagef (SCPE_ARG, "Expected EVERY found: %s\n", gbuf);
        }
    cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
    cycles = (int32) get_uint (gbuf, 10, INT_MAX, &stat);
    if ((stat != SCPE_OK) || (cycles <= 0)) {       /* error? */
        *iptr = cptr;
        return sim_messagef (SCPE_ARG, "Expected value found: %s\n", gbuf);
        }
    cptr = get_glyph (cptr, gbuf, 0);               /* get next glyph */
    if ((MATCH_CMD (gbuf, "CYCLES") != 0) || (*cptr == 0)) {
        *iptr = cptr;
        return sim_messagef (SCPE_ARG, "Expected CYCLES found: %s\n", gbuf);
        }
    tptr = strcpy (gbuf, "STOP");                   /* Start from a clean slate */
    sim_rem_collect_cmd_setup (rem->line, &tptr);
    rem->smp_sample_interval = cycles;
    rem->smp_reg_count = 0;
    while (cptr && *cptr) {
        const char *comma = strchr (cptr, ',');
        char tbuf[2*CBUFSIZE];
        uint32 bit, width;
        REG *reg;
        int32 saved_switches = sim_switches;
        t_bool indirect = FALSE;
        BITSAMPLE_REG *smp_regs;

        if (comma) {
            strncpy (tbuf, cptr, comma - cptr);
            tbuf[comma - cptr] = '\0';
            cptr = comma + 1;
            }
        else {
            strcpy (tbuf, cptr);
            cptr += strlen (cptr);
            }
        tptr = tbuf;
        if (strchr (tbuf, ' ')) {
            sim_switches = 0;
            tptr = get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, tbuf, &stat); /* get switches and device */
            indirect = ((sim_switches & SWMASK('I')) != 0);
            sim_switches = saved_switches;
            }
        if (stat != SCPE_OK)
            break;
        tptr = get_glyph (tptr, gbuf, 0);     /* get next glyph */
        reg = find_reg (gbuf, &tptr, sim_dfdev);
        if (reg == NULL) {
            stat = sim_messagef (SCPE_NXREG, "Nonexistent Register: %s\n", gbuf);
            break;
            }
        smp_regs = (BITSAMPLE_REG *)realloc (rem->smp_regs, (rem->smp_reg_count + 1) * sizeof(*smp_regs));
        if (smp_regs == NULL) {
            stat = SCPE_MEM;
            break;
            }
        rem->smp_regs = smp_regs;
        smp_regs[rem->smp_reg_count].reg = reg;
        smp_regs[rem->smp_reg_count].dptr = sim_dfdev;
        smp_regs[rem->smp_reg_count].uptr = sim_dfunit;
        smp_regs[rem->smp_reg_count].indirect = indirect;
        width = indirect ? sim_dfdev->dwidth : reg->width;
        smp_regs[rem->smp_reg_count].width = width;
        smp_regs[rem->smp_reg_count].bits = (BITSAMPLE *)calloc (width, sizeof (*smp_regs[rem->smp_reg_count - 1].bits));
        if (smp_regs[rem->smp_reg_count].bits == NULL) {
            stat = SCPE_MEM;
            break;
            }
        rem->smp_reg_count += 1;
        for (bit = 0; bit < width; bit++) {
            smp_regs[rem->smp_reg_count - 1].bits[bit].depth = samples;
            smp_regs[rem->smp_reg_count - 1].bits[bit].vals = (int *)calloc (samples, sizeof (int));
            if (smp_regs[rem->smp_reg_count - 1].bits[bit].vals == NULL) {
                stat = SCPE_MEM;
                break;
                }
            }
        if (stat != SCPE_OK)
            break;
        }
    if (stat != SCPE_OK) {                      /* Error? */
        *iptr = cptr;
        cptr = strcpy (gbuf, "STOP");
        sim_rem_collect_cmd_setup (line, &cptr);/* Cleanup mess */
        return stat;
        }
    sim_activate (&rem_con_smp_smpl_units[rem->line], rem->smp_sample_interval);
    }
*iptr = cptr;
return stat;
}

t_stat sim_rem_con_repeat_svc (UNIT *uptr)
{
int line = uptr - rem_con_repeat_units;
REMOTE *rem = &sim_rem_consoles[line];

sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_repeat_svc(line=%d) - interval=%d\n", line, rem->repeat_interval);
if (rem->repeat_interval) {
    rem->repeat_pending = TRUE;
    sim_activate_after (uptr, rem->repeat_interval);        /* reschedule */
    sim_activate_abs (rem_con_data_unit, -1);               /* wake up to process */
    }
return SCPE_OK;
}

static void sim_rem_record_reg_bit (BITSAMPLE *bit, int val)
{
bit->tot -= bit->vals[bit->ptr];    /* remove retired value */
bit->tot += val;                    /* accumulate new value */
bit->vals[bit->ptr] = val;          /* save new value */
++bit->ptr;                         /* increment next pointer */
if (bit->ptr >= bit->depth)         /* if too big */
    bit->ptr = 0;                   /* wrap around */
}

static void sim_rem_set_reg_bit (BITSAMPLE *bit, int val)
{
int i;

bit->tot = bit->depth * val;        /* compute total */
for (i = 0; i < bit->depth; i++)    /* set all value bits */
    bit->vals[i] = val;
}

static void sim_rem_collect_reg_bits (BITSAMPLE_REG *reg)
{
uint32 i;
t_value val = get_rval (reg->reg, 0);

if (reg->indirect)
    val = get_aval ((t_addr)val, reg->dptr, reg->uptr);
val = val >> reg->reg->offset;
for (i = 0; i < reg->width; i++) {
    if (sim_is_running)
        sim_rem_record_reg_bit (&reg->bits[i], val&1);
    else
        sim_rem_set_reg_bit (&reg->bits[i], val&1);
    val = val >> 1;
    }
}

static void sim_rem_collect_registers (REMOTE *rem)
{
uint32 i;

for (i = 0; i < rem->smp_reg_count; i++)
    sim_rem_collect_reg_bits (&rem->smp_regs[i]);
}

static void sim_rem_collect_all_registers (void)
{
int32 line;

for (line = 0; line < sim_rem_con_tmxr.lines; line++)
    sim_rem_collect_registers (&sim_rem_consoles[line]);
}

t_stat sim_rem_con_smp_collect_svc (UNIT *uptr)
{
int line = uptr - rem_con_smp_smpl_units;
REMOTE *rem = &sim_rem_consoles[line];

sim_debug (DBG_SAM, &sim_remote_console, "sim_rem_con_smp_collect_svc(line=%d) - interval=%d\n", line, rem->smp_sample_interval);
if (rem->smp_sample_interval && (rem->smp_reg_count != 0)) {
    sim_rem_collect_registers (rem);
    sim_activate (uptr, rem->smp_sample_interval);        /* reschedule */
    }
return SCPE_OK;
}

/* Unit service for remote console data polling */

t_stat sim_rem_con_data_svc (UNIT *uptr)
{
int32 i, j, c = 0;
t_stat stat = SCPE_OK;
t_bool active_command = FALSE;
int32 steps = 0;
t_bool was_active_command = (sim_rem_cmd_active_line != -1);
t_bool got_command;
t_bool close_session = FALSE;
TMLN *lp;
char cbuf[4*CBUFSIZE], gbuf[CBUFSIZE], *argv[1] = {NULL};
CONST char *cptr;
CTAB *cmdp = NULL;
CTAB *basecmdp = NULL;
uint32 read_start_time = 0;

tmxr_poll_rx (&sim_rem_con_tmxr);                      /* poll input */
for (i=(was_active_command ? sim_rem_cmd_active_line : 0); 
     (i < sim_rem_con_tmxr.lines) && (!active_command); 
     i++) {
    REMOTE *rem = &sim_rem_consoles[i];
    t_bool master_session = (sim_rem_master_mode && (i == 0));

    lp = rem->lp;
    if (!lp->conn) {
        if (rem->repeat_interval) {                 /* was repeated enabled? */
            cptr = strcpy (gbuf, "STOP");
            sim_rem_repeat_cmd_setup (i, &cptr);    /* make sure it is now disabled */
            }
        if (rem->smp_reg_count) {                   /* were bit samples being collected? */
            cptr = strcpy (gbuf, "STOP");
            sim_rem_collect_cmd_setup (i, &cptr);   /* make sure it is now disabled */
            }
        continue;
        }
    if (master_session && !sim_rem_master_was_connected) {
        tmxr_linemsgf (lp, "\nMaster Mode Session\r\n");
        tmxr_send_buffered_data (lp);               /* flush any buffered data */
        }
    sim_rem_master_was_connected |= master_session; /* Remember if master ever connected */
    stat = SCPE_OK;
    if ((was_active_command) ||
        (master_session && !rem->single_mode)) {
        sim_debug (DBG_MOD, &sim_remote_console, "Session: %d %s %s\n", i, was_active_command ? "Was Active" : "", (master_session && !rem->single_mode) ? "master_session && !single_mode" : "");
        if (was_active_command) {
            sim_rem_cmd_active_line = -1;           /* Done with active command */
            if (!sim_rem_active_command) {          /* STEP command? */
                stat = SCPE_STEP;
                _sim_rem_message ("STEP", stat);    /* produce a STEP complete message */
                }
            _sim_rem_log_out (lp);
            sim_rem_active_command = NULL;          /* Restart loop to process available input */
            was_active_command = FALSE;
            i = -1;
            continue;
            }
        else {
            sim_is_running = 0;
            sim_rem_collect_all_registers ();
            sim_stop_timer_services ();
            for (j=0; j < sim_rem_con_tmxr.lines; j++) {
                TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
                if ((i == j) || (!lpj->conn))
                    continue;
                tmxr_linemsgf (lpj, "\nRemote Master Console(%s) Entering Commands\n", lp->ipad);
                tmxr_send_buffered_data (lpj);     /* flush any buffered data */
                }
            }
        }
    else {
        if ((!rem->repeat_pending) || (rem->buf_ptr != 0)) {
            c = tmxr_getc_ln (lp);
            if (!(TMXR_VALID & c))
                continue;
            c = c & ~TMXR_VALID;
            if (rem->single_mode) {
                if (c == sim_int_char) {            /* ^E (the interrupt character) must start continue mode console interaction */
                    rem->single_mode = FALSE;       /* enter multi command mode */
                    sim_is_running = 0;
                    sim_rem_collect_all_registers ();
                    sim_stop_timer_services ();
                    stat = SCPE_STOP;
                    _sim_rem_message ("RUN", stat);
                    _sim_rem_log_out (lp);
                    for (j=0; j < sim_rem_con_tmxr.lines; j++) {
                        TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
                        if ((i == j) || (!lpj->conn))
                            continue;
                        tmxr_linemsgf (lpj, "\nRemote Console %d(%s) Entering Commands\n", i, lp->ipad);
                        tmxr_send_buffered_data (lpj);  /* flush any buffered data */
                        }
                    lp = &sim_rem_con_tmxr.ldsc[i];
                    if (!master_session)
                        tmxr_linemsg (lp, "\r\nSimulator paused.\r\n");
                    if (!master_session && rem->read_timeout) {
                        tmxr_linemsgf (lp, "Simulation will resume automatically if input is not received in %d seconds\n", sim_rem_read_timeouts[i]);
                        tmxr_linemsgf (lp, "\r\n");
                        tmxr_send_buffered_data (lp);   /* flush any buffered data */
                        }
                    }
                else {
                    if ((rem->buf_ptr == 0) &&          /* At beginning of input line */
                        ((c == '\n') ||                 /* Ignore bare LF between commands (Microsoft Telnet bug) */
                         (c == '\r')))                  /* Ignore empty commands */
                        continue;
                    if ((c == '\004') || (c == '\032')) {/* EOF character (^D or ^Z) ? */
                        tmxr_linemsgf (lp, "\r\nGoodbye\r\n");
                        tmxr_send_buffered_data (lp);   /* flush any buffered data */
                        tmxr_reset_ln (lp);
                        continue;
                        }
                    if (rem->buf_ptr == 0) {
                        /* we just picked up the first character on a command line */
                        if (!master_session)
                            tmxr_linemsgf (lp, "\r\n%s", sim_prompt);
                        else
                            tmxr_linemsgf (lp, "\r\n%s", sim_is_running ? "SIM> " : "sim> ");
                        sim_debug (DBG_XMT, &sim_remote_console, "Prompt Written: %s\n", sim_is_running ? "SIM> " : "sim> ");
                        if ((rem->act == NULL) && (!tmxr_input_pending_ln (lp)))
                            tmxr_send_buffered_data (lp);/* flush any buffered data */
                        }
                    }
                }
            }
        }
    got_command = FALSE;
    while (1) {
        if (stat == SCPE_EXIT)
            return stat|SCPE_NOMESSAGE;
        if (!rem->single_mode) {
            read_start_time = sim_os_msec();
            if (master_session)
                tmxr_linemsg (lp, "sim> ");
            else
                tmxr_linemsg (lp, sim_prompt);
            tmxr_send_buffered_data (lp);               /* flush any buffered data */
            }
        do {
            if (rem->buf_ptr == 0) {
                if (sim_rem_getact (i, rem->buf, rem->buf_size)) {
                    if (!master_session)
                        tmxr_linemsgf (lp, "%s%s\n", sim_prompt, rem->buf);
                    else
                        tmxr_linemsgf (lp, "%s%s\n", sim_is_running ? "SIM> " : "sim> ", rem->buf);
                    rem->buf_ptr = strlen (rem->repeat_action);
                    got_command = TRUE;
                    break;
                    }
                else {
                    if (rem->repeat_pending) {
                        rem->repeat_pending = FALSE;
                        sim_rem_setact (i, rem->repeat_action);
                        sim_rem_getact (i, rem->buf, rem->buf_size);
                        if (!master_session)
                            tmxr_linemsgf (lp, "%s%s\n", sim_prompt, rem->buf);
                        else
                            tmxr_linemsgf (lp, "%s%s\n", sim_is_running ? "SIM> " : "sim> ", rem->buf);
                        rem->buf_ptr = strlen (rem->repeat_action);
                        got_command = TRUE;
                        break;
                        }
                    }
                }
            if (!rem->single_mode) {
                c = tmxr_getc_ln (lp);
                if (!(TMXR_VALID & c)) {
                    tmxr_send_buffered_data (lp);       /* flush any buffered data */
                    if (!master_session && 
                        rem->read_timeout &&
                        ((sim_os_msec() - read_start_time)/1000 >= rem->read_timeout)) {
                        while (rem->buf_ptr > 0) {      /* Erase current input line */
                            tmxr_linemsg (lp, "\b \b");
                            --rem->buf_ptr;
                            }
                        if (rem->buf_ptr+80 >= rem->buf_size) {
                            rem->buf_size += 1024;
                            rem->buf = (char *)realloc (rem->buf, rem->buf_size);
                            }
                        strcpy (rem->buf, "CONTINUE         ! Automatic continue due to timeout");
                        tmxr_linemsgf (lp, "%s\n", rem->buf);
                        got_command = TRUE;
                        break;
                        }
                    sim_os_ms_sleep (50);
                    tmxr_poll_rx (&sim_rem_con_tmxr);   /* poll input */
                    if (!lp->conn) {                    /* if connection lost? */
                        rem->single_mode = TRUE;        /* No longer multi-command more */
                        break;                          /* done waiting */
                        }
                    continue;
                    }
                read_start_time = sim_os_msec();
                c = c & ~TMXR_VALID;
                }
            switch (c) {
                case 0:     /* no data */
                    break;
                case '\b':  /* Backspace */
                case 127:   /* Rubout */
                    if (rem->buf_ptr > 0) {
                        tmxr_linemsg (lp, "\b \b");
                        --rem->buf_ptr;
                        }
                    break;
                case 27:   /* escape */
                case 21:   /* ^U */
                    while (rem->buf_ptr > 0) {
                        tmxr_linemsg (lp, "\b \b");
                        --rem->buf_ptr;
                        }
                    break;
                case '\n':
                    if (rem->buf_ptr == 0)
                        break;
                case '\r':
                    tmxr_linemsg (lp, "\r\n");
                    if (rem->buf_ptr+1 >= rem->buf_size) {
                        rem->buf_size += 1024;
                        rem->buf = (char *)realloc (rem->buf, rem->buf_size);
                        }
                    rem->buf[rem->buf_ptr++] = '\0';
                    sim_debug (DBG_RCV, &sim_remote_console, "Got Command (%d bytes still in buffer): %s\n", tmxr_input_pending_ln (lp), rem->buf);
                    got_command = TRUE;
                    break;
                case '\004': /* EOF (^D) */
                case '\032': /* EOF (^Z) */
                    while (rem->buf_ptr > 0) {          /* Erase current input line */
                        tmxr_linemsg (lp, "\b \b");
                        --rem->buf_ptr;
                        }
                    if (!rem->single_mode) {
                        if (rem->buf_ptr+80 >= rem->buf_size) {
                            rem->buf_size += 1024;
                            rem->buf = (char *)realloc (rem->buf, rem->buf_size);
                            }
                        strcpy (rem->buf, "CONTINUE         ! Automatic continue before close");
                        tmxr_linemsgf (lp, "%s\n", rem->buf);
                        got_command = TRUE;
                        }
                    close_session = TRUE;
                    break;
                default:
                    tmxr_putc_ln (lp, c);
                    if (rem->buf_ptr+2 >= rem->buf_size) {
                        rem->buf_size += 1024;
                        rem->buf = (char *)realloc (rem->buf, rem->buf_size);
                        }
                    rem->buf[rem->buf_ptr++] = (char)c;
                    rem->buf[rem->buf_ptr] = '\0';
                    if (((size_t)rem->buf_ptr) >= sizeof(cbuf))
                        got_command = TRUE;             /* command too long */
                    break;
                }
            c = 0;
            if ((!got_command) && (rem->single_mode) && (tmxr_input_pending_ln (lp))) {
                c = tmxr_getc_ln (lp);
                c = c & ~TMXR_VALID;
                }
            } while ((!got_command) && ((!rem->single_mode) || c));
        if ((rem->act == NULL) && (!tmxr_input_pending_ln (lp)))
            tmxr_send_buffered_data (lp);               /* flush any buffered data */
        if ((rem->single_mode) && !got_command) {
            break;
            }
        if (!sim_rem_master_mode)
            sim_printf ("Remote Console Command from %s> %s\r\n", lp->ipad, rem->buf);
        got_command = FALSE;
        if (strlen(rem->buf) >= sizeof(cbuf)) {
            sim_printf ("\r\nLine too long. Ignored.  Continuing Simulator execution\r\n");
            tmxr_linemsgf (lp, "\nLine too long. Ignored.  Continuing Simulator execution\n");
            tmxr_send_buffered_data (lp);               /* try to flush any buffered data */
            break;
            }
        strcpy (cbuf, rem->buf);
        rem->buf_ptr = 0;
        rem->buf[rem->buf_ptr] = '\0';
        while (isspace(cbuf[0]))
            memmove (cbuf, cbuf+1, strlen(cbuf+1)+1);   /* skip leading whitespace */
        if (cbuf[0] == '\0') {
            if (rem->single_mode) {
                rem->single_mode = FALSE;
                break;
                }
            else
                continue;
            }
        strcpy (sim_rem_command_buf, cbuf);
        sim_sub_args (cbuf, sizeof(cbuf), argv);
        cptr = cbuf;
        cptr = get_glyph (cptr, gbuf, 0);               /* get command glyph */
        sim_switches = 0;                               /* init switches */
        sim_rem_active_number = i;
        if (!sim_log) {                                 /* Not currently logging? */
            int32 save_quiet = sim_quiet;

            sim_quiet = 1;
            sprintf (sim_rem_con_temp_name, "sim_remote_console_%d.temporary_log", (int)getpid());
            sim_set_logon (0, sim_rem_con_temp_name);
            sim_quiet = save_quiet;
            sim_log_temp = TRUE;
            }
        sim_rem_cmd_log_start = sim_ftell (sim_log);
        basecmdp = find_cmd (gbuf);                     /* validate basic command */
        if (basecmdp == NULL)
            basecmdp = find_ctab (remote_only_cmds, gbuf);/* validate basic command */
        if (basecmdp == NULL) {
            if ((gbuf[0] == ';') || (gbuf[0] == '#')) { /* ignore comment */
                sim_rem_cmd_active_line = i;
                was_active_command = TRUE;
                sim_rem_active_command = &allowed_single_remote_cmds[0];/* Dummy */
                i = i - 1;
                break;
                }
            else
                stat = SCPE_UNK;
            }
        else {
            if ((cmdp = find_ctab (rem->single_mode ? allowed_single_remote_cmds : (master_session ? allowed_master_remote_cmds : allowed_remote_cmds), gbuf))) {/* lookup command */
                sim_debug (DBG_CMD, &sim_remote_console, "gbuf='%s', basecmd='%s', cmd='%s'\n", gbuf, basecmdp->name, cmdp->name);
                if (cmdp->action == &x_continue_cmd) {
                    sim_debug (DBG_CMD, &sim_remote_console, "continue_cmd executing\n");
                    stat = SCPE_OK;
                    }
                else {
                    if (cmdp->action == &exit_cmd)
                        return SCPE_EXIT;
                    if (cmdp->action == &x_step_cmd) {
                        sim_debug (DBG_CMD, &sim_remote_console, "step_cmd executing\n");
                        steps = 1;                      /* default of 1 instruction */
                        stat = SCPE_OK;
                        if (*cptr != 0) {               /* argument? */
                            cptr = get_glyph (cptr, gbuf, 0);/* get next glyph */
                            if (*cptr != 0)            /* should be end */
                                stat = SCPE_2MARG;
                            else {
                                steps = (int32) get_uint (gbuf, 10, INT_MAX, &stat);
                                if ((stat != SCPE_OK) || (steps <= 0)) /* error? */
                                    stat = SCPE_ARG;
                                }
                            }
                        if (stat != SCPE_OK)
                            cmdp = NULL;
                        }
                    else {
                        if (cmdp->action == &x_run_cmd) {
                            sim_debug (DBG_CMD, &sim_remote_console, "run_cmd executing\n");
                            if (sim_con_stable_registers && /* can we process command now? */
                                sim_rem_master_mode)
                                sim_oline = lp;             /* specify output socket */
                            sim_switches |= SIM_SW_HIDE;    /* Request Setup only */
                            stat = basecmdp->action (cmdp->arg, cptr);
                            sim_switches &= ~SIM_SW_HIDE;   /* Done with Setup only mode */
                            if (stat == SCPE_OK) {
                                /* switch to CONTINUE after x_run_cmd() did RUN setup */
                                cmdp = find_ctab (allowed_master_remote_cmds, "CONTINUE");
                                }
                            }
                        else {
                            if (cmdp->action == &x_sampleout_cmd) {
                                sim_debug (DBG_CMD, &sim_remote_console, "sampleout_cmd executing\n");
                                sim_oline = lp;                     /* specify output socket */
                                stat = sim_rem_sample_output (NULL, i);
                                }
                            else {
                                if (cmdp->action == &x_repeat_cmd) {
                                    sim_debug (DBG_CMD, &sim_remote_console, "repeat_cmd executing\n");
                                    stat = sim_rem_repeat_cmd_setup (i, &cptr);
                                    }
                                else {
                                    if (cmdp->action == &x_collect_cmd) {
                                        sim_debug (DBG_CMD, &sim_remote_console, "sample_cmd executing\n");
                                        stat = sim_rem_collect_cmd_setup (i, &cptr);
                                        }
                                    else {
                                        if (sim_con_stable_registers && 
                                            sim_rem_master_mode) {  /* can we process command now? */
                                            sim_debug (DBG_CMD, &sim_remote_console, "Processing Command directly\n");
                                            sim_oline = lp;         /* specify output socket */
                                            sim_remote_process_command ();
                                            stat = SCPE_OK;         /* any message has already been emitted */
                                            }
                                        else {
                                            sim_debug (DBG_CMD, &sim_remote_console, "Processing Command via SCPE_REMOTE\n");
                                            stat = SCPE_REMOTE;     /* force processing outside of sim_instr() */
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            else
                stat = SCPE_INVREM;
            }
        sim_rem_active_number = -1;
        if ((stat != SCPE_OK) && (stat != SCPE_REMOTE))
            stat = _sim_rem_message (gbuf, stat);
        _sim_rem_log_out (lp);
        if (master_session && !sim_rem_master_mode) {
            rem->single_mode = TRUE;
            return SCPE_STOP;
            }
        if (cmdp && (cmdp->action == &x_continue_cmd)) {
            sim_rem_cmd_active_line = -1;                   /* Not active_command */
            if (sim_log_temp &&                             /* If we setup a temporary log, clean it now  */
                (!sim_rem_master_mode)) {
                int32 save_quiet = sim_quiet;

                sim_quiet = 1;
                sim_set_logoff (0, NULL);
                sim_quiet = save_quiet;
                (void)remove (sim_rem_con_temp_name);
                sim_log_temp = FALSE;
                }
            else {
                fflush (sim_log);
                sim_rem_cmd_log_start = sim_ftell (sim_log);
                }
            if (!rem->single_mode) {
                tmxr_linemsg (lp, "Simulator Running...");
                tmxr_send_buffered_data (lp);
                for (j=0; j < sim_rem_con_tmxr.lines; j++) {
                    TMLN *lpj = &sim_rem_con_tmxr.ldsc[j];
                    if ((i == j) || (!lpj->conn))
                        continue;
                    tmxr_linemsg (lpj, "Simulator Running...");
                    tmxr_send_buffered_data (lpj);
                    }
                sim_is_running = 1;
                sim_start_timer_services ();
                }
            if (cmdp && (cmdp->action == &x_continue_cmd))
                rem->single_mode = TRUE;
            else {
                if (!rem->single_mode) {
                    if (master_session)
                        tmxr_linemsgf (lp, "%s", "sim> ");
                    else
                        tmxr_linemsgf (lp, "%s", sim_prompt);
                    tmxr_send_buffered_data (lp);
                    }
                }
            break;
            }
        if ((cmdp && (cmdp->action == &x_step_cmd)) ||
            (stat == SCPE_REMOTE)) {
            sim_rem_cmd_active_line = i;
            break;
            }
        }
    if (close_session) {
        tmxr_linemsgf (lp, "\r\nGoodbye\r\n");
        tmxr_send_buffered_data (lp);                       /* flush any buffered data */
        tmxr_reset_ln (lp);
        rem->single_mode = FALSE;
        }
    }
if (sim_rem_master_was_connected &&                         /* Master mode ever connected? */
    !sim_rem_con_tmxr.ldsc[0].sock)                         /* Master Connection lost? */
    return SCPE_EXIT;                                       /* simulator has been 'unplugged' */
if (sim_rem_cmd_active_line != -1) {
    if (steps)
        sim_activate(uptr, steps);                          /* check again after 'steps' instructions */
    else
        return SCPE_REMOTE;                                 /* force sim_instr() to exit to process command */
    }
else
    sim_activate_after(uptr, 100000);                       /* check again in 100 milliaeconds */
if (sim_rem_master_was_enabled && !sim_rem_master_mode) {   /* Transitioning out of master mode? */
    lp = &sim_rem_con_tmxr.ldsc[0];
    tmxr_linemsgf (lp, "Non Master Mode Session...");       /* report transition */
    tmxr_send_buffered_data (lp);                           /* flush any buffered data */
    return SCPE_STOP|SCPE_NOMESSAGE;                        /* Unwind to the normal input path */
    }
else
    return SCPE_OK;                                         /* keep going */
}

t_stat sim_rem_con_reset (DEVICE *dptr)
{
if (sim_rem_con_tmxr.lines) {
    int32 i;

    sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_reset(lines=%d)\n", sim_rem_con_tmxr.lines);
    for (i=0; i<sim_rem_con_tmxr.lines; i++) {
        REMOTE *rem = &sim_rem_consoles[i];

        if (!sim_rem_con_tmxr.ldsc[i].conn)
            continue;
        sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_reset(line=%d, usecs=%d)\n", i, rem->repeat_interval);
        if (rem->repeat_interval)
            sim_activate_after (&rem_con_repeat_units[rem->line], rem->repeat_interval);    /* schedule */
        if (rem->smp_reg_count)
            sim_activate (&rem_con_smp_smpl_units[rem->line], rem->smp_sample_interval);    /* schedule */
        }
    if (i != sim_rem_con_tmxr.lines)
        sim_activate_after (rem_con_data_unit, 100000);     /* continue polling for open sessions */
    return sim_rem_con_poll_svc (rem_con_poll_unit);        /* establish polling for new sessions */
    }
return SCPE_OK;
}

static t_stat sim_set_rem_telnet (int32 flag, CONST char *cptr)
{
t_stat r;

if (flag) {
    r = sim_parse_addr (cptr, NULL, 0, NULL, NULL, 0, NULL, NULL);
    if (r == SCPE_OK) {
        if (sim_rem_con_tmxr.master)                        /* already open? */
            sim_set_rem_telnet (0, NULL);                   /* close first */
        if (sim_rem_con_tmxr.lines == 0)                    /* Ir no connection limit set */
            sim_set_rem_connections (0, "1");               /* use 1 */
        sim_rem_con_tmxr.buffered = 8192;                   /* Use big enough buffers */
        sim_register_internal_device (&sim_remote_console);
        r = tmxr_attach (&sim_rem_con_tmxr, rem_con_poll_unit, cptr);/* open master socket */
        if (r == SCPE_OK)
            sim_activate_after(rem_con_poll_unit, 1000000);/* check for connection in 1 second */
        return r;
        }
    return SCPE_NOPARAM;
    }
else {
    if (sim_rem_con_tmxr.master) {
        int32 i;

        tmxr_detach (&sim_rem_con_tmxr, rem_con_poll_unit);
        for (i=0; i<sim_rem_con_tmxr.lines; i++) {
            REMOTE *rem = &sim_rem_consoles[i];
            free (rem->buf);
            rem->buf = NULL;
            rem->buf_size = 0;
            rem->buf_ptr = 0;
            rem->single_mode = TRUE;
            }
        }
    }
return SCPE_OK;
}

static t_stat sim_set_rem_connections (int32 flag, CONST char *cptr)
{
int32 lines;
REMOTE *rem;
t_stat r;
int32 i;

if (cptr == NULL)
    return SCPE_ARG;
lines = (int32) get_uint (cptr, 10, MAX_REMOTE_SESSIONS, &r);
if (r != SCPE_OK)
    return r;
if (sim_rem_con_tmxr.master)
    return SCPE_ALATT;
if (sim_rem_con_tmxr.lines) {
    sim_cancel (rem_con_poll_unit);
    sim_cancel (rem_con_data_unit);
    }
for (i=0; i<sim_rem_con_tmxr.lines; i++) {
    rem = &sim_rem_consoles[i];
    free (rem->buf);
    free (rem->act_buf);
    free (rem->act);
    free (rem->repeat_action);
    sim_cancel (&rem_con_repeat_units[i]);
    sim_cancel (&rem_con_smp_smpl_units[i]);
    }
sim_rem_con_tmxr.lines = lines;
sim_rem_con_tmxr.ldsc = (TMLN *)realloc (sim_rem_con_tmxr.ldsc, sizeof(*sim_rem_con_tmxr.ldsc)*lines);
memset (sim_rem_con_tmxr.ldsc, 0, sizeof(*sim_rem_con_tmxr.ldsc)*lines);
sim_remote_console.units = (UNIT *)realloc (sim_remote_console.units, sizeof(*sim_remote_console.units)*((2 * lines) + REM_CON_BASE_UNITS));
memset (sim_remote_console.units, 0, sizeof(*sim_remote_console.units)*((2 * lines) + REM_CON_BASE_UNITS));
sim_remote_console.numunits = (2 * lines) + REM_CON_BASE_UNITS;
rem_con_poll_unit->action = &sim_rem_con_poll_svc;/* remote console connection polling unit */
rem_con_poll_unit->flags |= UNIT_IDLE;
rem_con_data_unit->action = &sim_rem_con_data_svc;/* console data handling unit */
rem_con_data_unit->flags |= UNIT_IDLE|UNIT_DIS;
sim_rem_consoles = (REMOTE *)realloc (sim_rem_consoles, sizeof(*sim_rem_consoles)*lines);
memset (sim_rem_consoles, 0, sizeof(*sim_rem_consoles)*lines);
sim_rem_command_buf = (char *)realloc (sim_rem_command_buf, 4*CBUFSIZE+1);
memset (sim_rem_command_buf, 0, 4*CBUFSIZE+1);
for (i=0; i<lines; i++) {
    rem_con_repeat_units[i].flags = UNIT_DIS;
    rem_con_repeat_units[i].action = &sim_rem_con_repeat_svc;
    rem_con_smp_smpl_units[i].flags = UNIT_DIS;
    rem_con_smp_smpl_units[i].action = &sim_rem_con_smp_collect_svc;
    rem = &sim_rem_consoles[i];
    rem->line = i;
    rem->lp = &sim_rem_con_tmxr.ldsc[i];
    rem->uptr = &rem_con_repeat_units[i];
    }
return SCPE_OK;
}

static t_stat sim_set_rem_timeout (int32 flag, CONST char *cptr)
{
int32 timeout;
t_stat r;

if (cptr == NULL)
    return SCPE_ARG;
timeout = (int32) get_uint (cptr, 10, 3600, &r);
if (r != SCPE_OK)
    return r;
if (sim_rem_active_number >= 0)
    sim_rem_consoles[sim_rem_active_number].read_timeout = timeout;
else
    sim_rem_read_timeout = timeout;
return SCPE_OK;
}

static t_stat sim_set_rem_bufsize (int32 flag, CONST char *cptr)
{
char cmdbuf[CBUFSIZE];
int32 bufsize;
t_stat r;

if (cptr == NULL)
    return SCPE_ARG;
bufsize = (int32) get_uint (cptr, 10, 32768, &r);
if (r != SCPE_OK)
    return r;
if (bufsize < 1400)
    return sim_messagef (SCPE_ARG, "%d is too small.  Minimum size is 1400\n", bufsize);
sprintf(cmdbuf, "BUFFERED=%d", bufsize);
return tmxr_open_master (&sim_rem_con_tmxr, cmdbuf);        /* open master socket */
}

/* Enable or disable Remote Console master mode */

/* In master mode, commands are subsequently processed from the
   primary/initial (master mode) remote console session.  Commands
   are processed from that source until that source disables master
   mode or the simulator exits 
 */

static t_stat sim_set_rem_master (int32 flag, CONST char *cptr)
{
t_stat stat = SCPE_OK;

if (cptr && *cptr)
    return SCPE_2MARG;

if (sim_rem_active_number > 0) {
    sim_printf ("Can't change Remote Console mode from Remote Console\n");
    return SCPE_INVREM;
    }

if (sim_rem_con_tmxr.master || (!flag))                     /* Remote Console Enabled? */
    sim_rem_master_mode = flag;
else {
    sim_printf ("Can't enable Remote Console Master mode with Remote Console disabled\n");
    return SCPE_INVREM;
    }

if (sim_rem_master_mode) {
    t_stat stat_nomessage;

    sim_printf ("Command input starting on Master Remote Console Session\n");
    stat = sim_run_boot_prep (0);
    sim_rem_master_was_enabled = TRUE;
    while (sim_rem_master_mode) {
        sim_rem_consoles[0].single_mode = FALSE;
        sim_cancel (rem_con_data_unit);
        sim_activate (rem_con_data_unit, -1);
        stat = run_cmd (RU_GO, "");
        if (stat != SCPE_TTMO) {
            stat_nomessage = stat & SCPE_NOMESSAGE;         /* extract possible message supression flag */
            stat = _sim_rem_message ("RUN", stat);
            }
        if (stat == SCPE_EXIT)
            sim_rem_master_mode = FALSE;
        }
    sim_rem_master_was_enabled = FALSE;
    sim_rem_master_was_connected = FALSE;
    if (sim_log_temp) {                                     /* If we setup a temporary log, clean it now  */
        int32 save_quiet = sim_quiet;

        sim_quiet = 1;
        sim_set_logoff (0, NULL);
        sim_quiet = save_quiet;
        (void)remove (sim_rem_con_temp_name);
        sim_log_temp = FALSE;
        }
    stat |= stat_nomessage;
    }
else {
    sim_rem_consoles[0].single_mode = TRUE;                 /* Force remote session into single command mode */
    }
return stat;
}

/* Set keyboard map */

t_stat sim_set_kmap (int32 flag, CONST char *cptr)
{
DEVICE *dptr = sim_devices[0];
int32 val, rdx;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_2FARG;
if (dptr->dradix == 16) rdx = 16;
else rdx = 8;
val = (int32) get_uint (cptr, rdx, 0177, &r);
if ((r != SCPE_OK) ||
    ((val == 0) && (flag & KMAP_NZ)))
    return SCPE_ARG;
*(cons_kmap[flag & KMAP_MASK]) = val;
return SCPE_OK;
}

/* Show keyboard map */

t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
if (sim_devices[0]->dradix == 16)
    fprintf (st, "%s = %X\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK]));
else
    fprintf (st, "%s = %o\n", show_con_tab[flag].name, *(cons_kmap[flag & KMAP_MASK]));
return SCPE_OK;
}

/* Set printable characters */

t_stat sim_set_pchar (int32 flag, CONST char *cptr)
{
DEVICE *dptr = sim_devices[0];
uint32 val, rdx;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_2FARG;
if (dptr->dradix == 16) rdx = 16;
else rdx = 8;
val = (uint32) get_uint (cptr, rdx, 0xFFFFFFFF, &r);
if ((r != SCPE_OK) ||
    ((val & 0x00002400) == 0))
    return SCPE_ARG;
sim_tt_pchar = val;
return SCPE_OK;
}

/* Show printable characters */

t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
if (sim_devices[0]->dradix == 16)
    fprintf (st, "pchar mask = %X", sim_tt_pchar);
else
    fprintf (st, "pchar mask = %o", sim_tt_pchar);
if (sim_tt_pchar) {
    static const char *pchars[] = {"NUL(^@)", "SOH(^A)", "STX(^B)", "ETX(^C)", "EOT(^D)", "ENQ(^E)", "ACK(^F)", "BEL(^G)", 
                                   "BS(^H)" , "HT(^I)",  "LF(^J)",  "VT(^K)",  "FF(^L)",  "CR(^M)",  "SO(^N)",  "SI(^O)",
                                   "DLE(^P)", "DC1(^Q)", "DC2(^R)", "DC3(^S)", "DC4(^T)", "NAK(^U)", "SYN(^V)", "ETB(^W)",
                                   "CAN(^X)", "EM(^Y)",  "SUB(^Z)", "ESC",     "FS",      "GS",      "RS",      "US"};
    int i;
    t_bool found = FALSE;

    fprintf (st, " {");
    for (i=31; i>=0; i--)
        if (sim_tt_pchar & (1 << i)) {
            fprintf (st, "%s%s", found ? "," : "", pchars[i]);
            found = TRUE;
            }
    fprintf (st, "}");
    }
fprintf (st, "\n");
return SCPE_OK;
}

/* Set input speed (bps) */

t_stat sim_set_cons_speed (int32 flag, CONST char *cptr)
{
return tmxr_set_line_speed (&sim_con_ldsc, cptr);
}

t_stat sim_show_cons_speed (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
if (sim_con_ldsc.rxbps) {
    fprintf (st, "Speed = %d", sim_con_ldsc.rxbps);
    if (sim_con_ldsc.rxbpsfactor != TMXR_RX_BPS_UNIT_SCALE)
        fprintf (st, "*%.0f", sim_con_ldsc.rxbpsfactor/TMXR_RX_BPS_UNIT_SCALE);
    fprintf (st, " bps\n");
    }
return SCPE_OK;
}

/* Set log routine */

t_stat sim_set_logon (int32 flag, CONST char *cptr)
{
char gbuf[CBUFSIZE];
t_stat r;
time_t now;

if ((cptr == NULL) || (*cptr == 0))                     /* need arg */
    return SCPE_2FARG;
cptr = get_glyph_nc (cptr, gbuf, 0);                    /* get file name */
if (*cptr != 0)                                         /* now eol? */
    return SCPE_2MARG;
sim_set_logoff (0, NULL);                               /* close cur log */
r = sim_open_logfile (gbuf, FALSE, &sim_log, &sim_log_ref); /* open log */
if (r != SCPE_OK)                                       /* error? */
    return r;
if (!sim_quiet)
    fprintf (stdout, "Logging to file \"%s\"\n", 
             sim_logfile_name (sim_log, sim_log_ref));
fprintf (sim_log, "Logging to file \"%s\"\n", 
             sim_logfile_name (sim_log, sim_log_ref));  /* start of log */
time(&now);
fprintf (sim_log, "Logging to file \"%s\" at %s", sim_logfile_name (sim_log, sim_log_ref), ctime(&now));
return SCPE_OK;
}

/* Set nolog routine */

t_stat sim_set_logoff (int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))                               /* now eol? */
    return SCPE_2MARG;
if (sim_log == NULL)                                    /* no log? */
    return SCPE_OK;
if (!sim_quiet)
    fprintf (stdout, "Log file closed\n");
fprintf (sim_log, "Log file closed\n");
sim_close_logfile (&sim_log_ref);                       /* close log */
sim_log = NULL;
return SCPE_OK;
}

/* Show log status */

t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))
    return SCPE_2MARG;
if (sim_log)
    fprintf (st, "Logging enabled to \"%s\"\n", 
                 sim_logfile_name (sim_log, sim_log_ref));
else
    fprintf (st, "Logging disabled\n");
return SCPE_OK;
}

/* Set debug routine */

t_stat sim_set_debon (int32 flag, CONST char *cptr)
{
char gbuf[CBUFSIZE];
t_stat r;
time_t now;

sim_deb_switches = sim_switches;                        /* save debug switches */
if ((cptr == NULL) || (*cptr == 0))                     /* need arg */
    return SCPE_2FARG;
cptr = get_glyph_nc (cptr, gbuf, 0);                    /* get file name */
if (*cptr != 0)                                         /* now eol? */
    return SCPE_2MARG;
r = sim_open_logfile (gbuf, FALSE, &sim_deb, &sim_deb_ref);

if (r != SCPE_OK)
    return r;

if (sim_deb_switches & SWMASK ('R')) {
    clock_gettime(CLOCK_REALTIME, &sim_deb_basetime);
    if (!(sim_deb_switches & (SWMASK ('A') | SWMASK ('T'))))
        sim_deb_switches |= SWMASK ('T');
    }
if (!sim_quiet) {
    sim_printf ("Debug output to \"%s\"\n", sim_logfile_name (sim_deb, sim_deb_ref));
    if (sim_deb_switches & SWMASK ('P'))
        sim_printf ("   Debug messages contain current PC value\n");
    if (sim_deb_switches & SWMASK ('T'))
        sim_printf ("   Debug messages display time of day as hh:mm:ss.msec%s\n", sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
    if (sim_deb_switches & SWMASK ('A'))
        sim_printf ("   Debug messages display time of day as seconds.msec%s\n", sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
    time(&now);
    fprintf (sim_deb, "Debug output to \"%s\" at %s", sim_logfile_name (sim_deb, sim_deb_ref), ctime(&now));
    show_version (sim_deb, NULL, NULL, 0, NULL);
    }
if (sim_deb_switches & SWMASK ('N'))
    sim_deb_switches &= ~SWMASK ('N');          /* Only process the -N flag initially */

return SCPE_OK;
}

t_stat sim_debug_flush (void)
{
int32 saved_quiet = sim_quiet;
int32 saved_sim_switches = sim_switches;
int32 saved_deb_switches = sim_deb_switches;
struct timespec saved_deb_basetime = sim_deb_basetime;
char saved_debug_filename[CBUFSIZE];

if (sim_deb == NULL)                                    /* no debug? */
    return SCPE_OK;

if (sim_deb == sim_log) {                               /* debug is log */
    fflush (sim_deb);                                   /* fflush is the best we can do */
    return SCPE_OK;
    }

strcpy (saved_debug_filename, sim_logfile_name (sim_deb, sim_deb_ref));

sim_quiet = 1;
sim_set_deboff (0, NULL);
sim_switches = saved_deb_switches;
sim_set_debon (0, saved_debug_filename);
sim_deb_basetime = saved_deb_basetime;
sim_switches = saved_sim_switches;
sim_quiet = saved_quiet;
return SCPE_OK;
}

/* Set nodebug routine */

t_stat sim_set_deboff (int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))                               /* now eol? */
    return SCPE_2MARG;
if (sim_deb == NULL)                                    /* no debug? */
    return SCPE_OK;
sim_close_logfile (&sim_deb_ref);
sim_deb = NULL;
sim_deb_switches = 0;
if (!sim_quiet)
    sim_printf ("Debug output disabled\n");
return SCPE_OK;
}

/* Show debug routine */

t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
int32 i;

if (cptr && (*cptr != 0))
    return SCPE_2MARG;
if (sim_deb) {
    fprintf (st, "Debug output enabled to \"%s\"\n", 
                 sim_logfile_name (sim_deb, sim_deb_ref));
    if (sim_deb_switches & SWMASK ('P'))
        fprintf (st, "   Debug messages contain current PC value\n");
    if (sim_deb_switches & SWMASK ('T'))
        fprintf (st, "   Debug messages display time of day as hh:mm:ss.msec%s\n", sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
    if (sim_deb_switches & SWMASK ('A'))
        fprintf (st, "   Debug messages display time of day as seconds.msec%s\n", sim_deb_switches & SWMASK ('R') ? " relative to the start of debugging" : "");
    for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
        if (!(dptr->flags & DEV_DIS) &&
            (dptr->flags & DEV_DEBUG) &&
            (dptr->dctrl)) {
            fprintf (st, "Device: %-6s ", dptr->name);
            show_dev_debug (st, dptr, NULL, 0, NULL);
            }
        }
    for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) {
        if (!(dptr->flags & DEV_DIS) &&
            (dptr->flags & DEV_DEBUG) &&
            (dptr->dctrl)) {
            fprintf (st, "Device: %-6s ", dptr->name);
            show_dev_debug (st, dptr, NULL, 0, NULL);
            }
        }
    }
else
    fprintf (st, "Debug output disabled\n");
return SCPE_OK;
}

/* SET CONSOLE command */

/* Set console to Telnet port (and parameters) */

t_stat sim_set_telnet (int32 flag, CONST char *cptr)
{
char *cvptr, gbuf[CBUFSIZE];
CTAB *ctptr;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_2FARG;
while (*cptr != 0) {                                    /* do all mods */
    cptr = get_glyph_nc (cptr, gbuf, ',');              /* get modifier */
    if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
        *cvptr++ = 0;
    get_glyph (gbuf, gbuf, 0);                          /* modifier to UC */
    if ((ctptr = find_ctab (set_con_telnet_tab, gbuf))) { /* match? */
        r = ctptr->action (ctptr->arg, cvptr);          /* do the rest */
        if (r != SCPE_OK)
            return r;
        }
    else {
        if (sim_con_tmxr.master)                        /* already open? */
            sim_set_notelnet (0, NULL);                 /* close first */
        r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, gbuf);/* open master socket */
        if (r == SCPE_OK)
            sim_activate_after(&sim_con_unit, 1000000); /* check for connection in 1 second */
        else
            return r;
        }
    }
return SCPE_OK;
}

/* Close console Telnet port */

t_stat sim_set_notelnet (int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))                               /* too many arguments? */
    return SCPE_2MARG;
if (sim_con_tmxr.master == 0)                           /* ignore if already closed */
    return SCPE_OK;
return tmxr_close_master (&sim_con_tmxr);               /* close master socket */
}

/* Show console Telnet status */

t_stat sim_show_telnet (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))
    return SCPE_2MARG;
if ((sim_con_tmxr.master == 0) && 
    (sim_con_ldsc.serport == 0))
    fprintf (st, "Connected to console window\n");
else {
    if (sim_con_ldsc.serport) {
        fprintf (st, "Connected to ");
        tmxr_fconns (st, &sim_con_ldsc, -1);
        }
    else 
        if (sim_con_ldsc.sock == 0)
            fprintf (st, "Listening on port %s\n", sim_con_tmxr.port);
        else {
            fprintf (st, "Listening on port %s, connection from %s\n",
                sim_con_tmxr.port, sim_con_ldsc.ipad);
            tmxr_fconns (st, &sim_con_ldsc, -1);
            }
    tmxr_fstats (st, &sim_con_ldsc, -1);
    }
return SCPE_OK;
}

/* Set console to Buffering  */

t_stat sim_set_cons_buff (int32 flg, CONST char *cptr)
{
char cmdbuf[CBUFSIZE];

sprintf(cmdbuf, "BUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf);      /* open master socket */
}

/* Set console to NoBuffering */

t_stat sim_set_cons_unbuff (int32 flg, CONST char *cptr)
{
char cmdbuf[CBUFSIZE];

sprintf(cmdbuf, "UNBUFFERED%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf);      /* open master socket */
}

/* Set console to Logging */

t_stat sim_set_cons_log (int32 flg, CONST char *cptr)
{
char cmdbuf[CBUFSIZE];

sprintf(cmdbuf, "LOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf);      /* open master socket */
}

/* Set console to NoLogging */

t_stat sim_set_cons_nolog (int32 flg, CONST char *cptr)
{
char cmdbuf[CBUFSIZE];

sprintf(cmdbuf, "NOLOG%c%s", cptr ? '=' : '\0', cptr ? cptr : "");
return tmxr_open_master (&sim_con_tmxr, cmdbuf);      /* open master socket */
}

t_stat sim_show_cons_log (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))
    return SCPE_2MARG;
if (sim_con_tmxr.ldsc->txlog)
    fprintf (st, "Log File being written to %s\n", sim_con_tmxr.ldsc->txlogname);
else
    fprintf (st, "No Logging\n");
return SCPE_OK;
}

t_stat sim_show_cons_buff (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))
    return SCPE_2MARG;
if (!sim_con_tmxr.ldsc->txbfd)
    fprintf (st, "Unbuffered\n");
else
    fprintf (st, "Buffer Size = %d\n", sim_con_tmxr.ldsc->txbsz);
return SCPE_OK;
}

/* Set console Debug Mode */

t_stat sim_set_cons_debug (int32 flg, CONST char *cptr)
{
return set_dev_debug (&sim_con_telnet, &sim_con_unit, flg, cptr);
}

t_stat sim_show_cons_debug (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))
    return SCPE_2MARG;
return show_dev_debug (st, &sim_con_telnet, &sim_con_unit, flag, cptr);
}

/* Set console to Serial port (and parameters) */

t_stat sim_set_serial (int32 flag, CONST char *cptr)
{
char *cvptr, gbuf[CBUFSIZE], ubuf[CBUFSIZE];
CTAB *ctptr;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_2FARG;
while (*cptr != 0) {                                    /* do all mods */
    cptr = get_glyph_nc (cptr, gbuf, ',');              /* get modifier */
    if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
        *cvptr++ = 0;
    get_glyph (gbuf, ubuf, 0);                          /* modifier to UC */
    if ((ctptr = find_ctab (set_con_serial_tab, ubuf))) { /* match? */
        r = ctptr->action (ctptr->arg, cvptr);          /* do the rest */
        if (r != SCPE_OK)
            return r;
        }
    else {
        SERHANDLE serport = sim_open_serial (gbuf, NULL, &r);
        if (serport != INVALID_HANDLE) {
            sim_close_serial (serport);
            if (r == SCPE_OK) {
                char cbuf[CBUFSIZE];
                if ((sim_con_tmxr.master) ||            /* already open? */
                    (sim_con_ldsc.serport))
                    sim_set_noserial (0, NULL);         /* close first */
                sprintf(cbuf, "Connect=%s", gbuf);
                r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, cbuf);/* open master socket */
                sim_con_ldsc.rcve = 1;                  /* rcv enabled */
                if (r == SCPE_OK)
                    sim_activate_after(&sim_con_unit, 1000000); /* check for connection in 1 second */
                return r;
                }
            }
        return SCPE_ARG;
        }
    }
return SCPE_OK;
}

/* Close console Serial port */

t_stat sim_set_noserial (int32 flag, CONST char *cptr)
{
if (cptr && (*cptr != 0))                               /* too many arguments? */
    return SCPE_2MARG;
if (sim_con_ldsc.serport == 0)                          /* ignore if already closed */
    return SCPE_OK;
return tmxr_close_master (&sim_con_tmxr);               /* close master socket */
}

/* Show the console expect rules and state */

t_stat sim_show_cons_expect (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, CONST char *cptr)
{
return sim_exp_show (st, &sim_con_expect, cptr);
}

/* Log File Open/Close/Show Support */

/* Open log file */

t_stat sim_open_logfile (const char *filename, t_bool binary, FILE **pf, FILEREF **pref)
{
char gbuf[CBUFSIZE];
const char *tptr;

if ((filename == NULL) || (*filename == 0))             /* too few arguments? */
    return SCPE_2FARG;
tptr = get_glyph (filename, gbuf, 0);
if (*tptr != 0)                                         /* now eol? */
    return SCPE_2MARG;
sim_close_logfile (pref);
*pf = NULL;
if (strcmp (gbuf, "LOG") == 0) {                        /* output to log? */
    if (sim_log == NULL)                                /* any log? */
        return SCPE_ARG;
    *pf = sim_log;
    *pref = sim_log_ref;
    if (*pref)
        ++(*pref)->refcount;
    }
else if (strcmp (gbuf, "DEBUG") == 0) {                 /* output to debug? */
    if (sim_deb == NULL)                                /* any debug? */
        return SCPE_ARG;
    *pf = sim_deb;
    *pref = sim_deb_ref;
    if (*pref)
        ++(*pref)->refcount;
    }
else if (strcmp (gbuf, "STDOUT") == 0) {                /* output to stdout? */
    *pf = stdout;
    *pref = NULL;
    }
else if (strcmp (gbuf, "STDERR") == 0) {                /* output to stderr? */
    *pf = stderr;
    *pref = NULL;
    }
else {
    *pref = (FILEREF *)calloc (1, sizeof(**pref));
    if (!*pref)
        return SCPE_MEM;
    get_glyph_nc (filename, gbuf, 0);                   /* reparse */
    strncpy ((*pref)->name, gbuf, sizeof((*pref)->name)-1);
    if (sim_switches & SWMASK ('N'))                    /* if a new log file is requested */
        *pf = sim_fopen (gbuf, (binary ? "w+b" : "w+"));/*   then open an empty file */
    else                                                /* otherwise */
        *pf = sim_fopen (gbuf, (binary ? "a+b" : "a+"));/*   append to an existing file */
    if (*pf == NULL) {                                  /* error? */
        free (*pref);
        *pref = NULL;
        return SCPE_OPENERR;
        }
    setvbuf (*pf, NULL, _IOFBF, 65536);
    (*pref)->file = *pf;
    (*pref)->refcount = 1;                               /* need close */
    }
return SCPE_OK;
}

/* Close log file */

t_stat sim_close_logfile (FILEREF **pref)
{
if (NULL == *pref)
    return SCPE_OK;
(*pref)->refcount = (*pref)->refcount  - 1;
if ((*pref)->refcount > 0) {
    *pref = NULL;
    return SCPE_OK;
    }
fclose ((*pref)->file);
free (*pref);
*pref = NULL;
return SCPE_OK;
}

/* Show logfile support routine */

const char *sim_logfile_name (FILE *st, FILEREF *ref)
{
if (!st)
    return "";
if (st == stdout)
    return "STDOUT";
if (st == stderr)
    return "STDERR";
if (!ref)
    return "";
return ref->name;
}

/* Check connection before executing 
   (including a remote console which may be required in master mode) */

t_stat sim_check_console (int32 sec)
{
int32 c, trys = 0;

if (sim_rem_master_mode) {
    for (;trys < sec; ++trys) {
        sim_rem_con_poll_svc (rem_con_poll_unit);
        if (sim_rem_con_tmxr.ldsc[0].conn)
            break;
        if ((trys % 10) == 0) {                         /* Status every 10 sec */
            sim_printf ("Waiting for Remote Console connection\r\n");
            fflush (stdout);
            if (sim_log)                                /* log file? */
                fflush (sim_log);
            }
        sim_os_sleep (1);                               /* wait 1 second */
        }
    if ((sim_rem_con_tmxr.ldsc[0].conn) &&
        (!sim_con_ldsc.serport) &&
        (sim_con_tmxr.master == 0) &&
        (sim_con_console_port)) {
        tmxr_linemsgf (&sim_rem_con_tmxr.ldsc[0], "\r\nConsole port must be Telnet or Serial with Master Remote Console\r\n");
        tmxr_linemsgf (&sim_rem_con_tmxr.ldsc[0], "Goodbye\r\n");
        while (tmxr_send_buffered_data (&sim_rem_con_tmxr.ldsc[0]))
            sim_os_ms_sleep (100);
        sim_os_ms_sleep (100);
        tmxr_reset_ln (&sim_rem_con_tmxr.ldsc[0]);
        sim_printf ("Console port must be Telnet or Serial with Master Remote Console\r\n");
        return SCPE_EXIT;
        }
    }
if (trys == sec) {
    return SCPE_TTMO;                                   /* timed out */
    }
if (sim_con_ldsc.serport)
    if (tmxr_poll_conn (&sim_con_tmxr) >= 0) 
        sim_con_ldsc.rcve = 1;                          /* rcv enabled */
if ((sim_con_tmxr.master == 0) ||                       /* serial console or not Telnet? done */
    (sim_con_ldsc.serport))
    return SCPE_OK;
if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) {          /* connected or buffered ? */
    tmxr_poll_rx (&sim_con_tmxr);                       /* poll (check disconn) */
    if (sim_con_ldsc.conn || sim_con_ldsc.txbfd) {      /* still connected? */
        if (!sim_con_ldsc.conn) {
            sim_printf ("Running with Buffered Console\r\n"); /* print transition */
            fflush (stdout);
            if (sim_log)                                /* log file? */
                fflush (sim_log);
            }
        return SCPE_OK;
        }
    }
for (; trys < sec; trys++) {                            /* loop */
    if (tmxr_poll_conn (&sim_con_tmxr) >= 0) {          /* poll connect */
        sim_con_ldsc.rcve = 1;                          /* rcv enabled */
        if (trys) {                                     /* if delayed */
            sim_printf ("Running\r\n");                 /* print transition */
            fflush (stdout);
            if (sim_log)                                /* log file? */
                fflush (sim_log);
            }
        return SCPE_OK;                                 /* ready to proceed */
        }
    c = sim_os_poll_kbd ();                             /* check for stop char */
    if ((c == SCPE_STOP) || stop_cpu)
        return SCPE_STOP;
    if ((trys % 10) == 0) {                             /* Status every 10 sec */
        sim_printf ("Waiting for console Telnet connection\r\n");
        fflush (stdout);
        if (sim_log)                                    /* log file? */
            fflush (sim_log);
        }
    sim_os_sleep (1);                                   /* wait 1 second */
    }
return SCPE_TTMO;                                       /* timed out */
}

/* Get Send object address for console */

SEND *sim_cons_get_send (void)
{
return &sim_con_send;
}

/* Get Expect object address for console */

EXPECT *sim_cons_get_expect (void)
{
return &sim_con_expect;
}

/* Display console Queued input data status */

t_stat sim_show_cons_send_input (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
return sim_show_send_input (st, &sim_con_send);
}

/* Poll for character */

t_stat sim_poll_kbd (void)
{
t_stat c;

if (sim_send_poll_data (&sim_con_send, &c))                 /* injected input characters available? */
    return c;
if (!sim_rem_master_mode) {
    if ((sim_con_ldsc.rxbps) &&                             /* rate limiting && */
        (sim_gtime () < sim_con_ldsc.rxnexttime))           /* too soon? */
        return SCPE_OK;                                     /* not yet */
    c = sim_os_poll_kbd ();                                 /* get character */
    if (c == SCPE_STOP) {                                   /* ^E */
        stop_cpu = 1;                                       /* Force a stop (which is picked up by sim_process_event */
        return SCPE_OK;
        }
    if ((sim_con_tmxr.master == 0) &&                       /* not Telnet? */
        (sim_con_ldsc.serport == 0)) {                      /* and not serial? */
        if (c && sim_con_ldsc.rxbps)                        /* got something && rate limiting? */
            sim_con_ldsc.rxnexttime =                       /* compute next input time */
                floor (sim_gtime () + ((sim_con_ldsc.rxdelta * sim_timer_inst_per_sec ())/sim_con_ldsc.rxbpsfactor));
        if (c)
            sim_debug (DBG_RCV, &sim_con_telnet, "sim_poll_kbd() returning: '%c' (0x%02X)\n", sim_isprint (c & 0xFF) ? c & 0xFF : '.', c);
        return c;                                           /* in-window */
        }
    if (!sim_con_ldsc.conn) {                               /* no telnet or serial connection? */
        if (!sim_con_ldsc.txbfd)                            /* unbuffered? */
            return SCPE_LOST;                               /* connection lost */
        if (tmxr_poll_conn (&sim_con_tmxr) >= 0)            /* poll connect */
            sim_con_ldsc.rcve = 1;                          /* rcv enabled */
        else                                                /* fall through to poll reception */
            return SCPE_OK;                                 /* unconnected and buffered - nothing to receive */
        }
    }
tmxr_poll_rx (&sim_con_tmxr);                               /* poll for input */
if ((c = (t_stat)tmxr_getc_ln (&sim_con_ldsc)))             /* any char? */ 
    return (c & (SCPE_BREAK | 0377)) | SCPE_KFLAG;
return SCPE_OK;
}

/* Output character */

t_stat sim_putchar (int32 c)
{
sim_exp_check (&sim_con_expect, c);
if ((sim_con_tmxr.master == 0) &&                       /* not Telnet? */
    (sim_con_ldsc.serport == 0)) {                      /* and not serial port */
    if (sim_log)                                        /* log file? */
        fputc (c, sim_log);
    sim_debug (DBG_XMT, &sim_con_telnet, "sim_putchar('%c' (0x%02X)\n", sim_isprint (c) ? c : '.', c);
    return sim_os_putchar (c);                          /* in-window version */
    }
if (!sim_con_ldsc.conn) {                               /* no Telnet or serial connection? */
    if (!sim_con_ldsc.txbfd)                            /* unbuffered? */
        return SCPE_LOST;                               /* connection lost */
    if (tmxr_poll_conn (&sim_con_tmxr) >= 0)            /* poll connect */
        sim_con_ldsc.rcve = 1;                          /* rcv enabled */
    }
tmxr_putc_ln (&sim_con_ldsc, c);                        /* output char */
tmxr_poll_tx (&sim_con_tmxr);                           /* poll xmt */
return SCPE_OK;
}

t_stat sim_putchar_s (int32 c)
{
t_stat r;

sim_exp_check (&sim_con_expect, c);
if ((sim_con_tmxr.master == 0) &&                       /* not Telnet? */
    (sim_con_ldsc.serport == 0)) {                      /* and not serial port */
    if (sim_log)                                        /* log file? */
        fputc (c, sim_log);
    sim_debug (DBG_XMT, &sim_con_telnet, "sim_putchar('%c' (0x%02X)\n", sim_isprint (c) ? c : '.', c);
    return sim_os_putchar (c);                          /* in-window version */
    }
if (!sim_con_ldsc.conn) {                               /* no Telnet or serial connection? */
    if (!sim_con_ldsc.txbfd)                            /* non-buffered Telnet connection? */
        return SCPE_LOST;                               /* lost */
    if (tmxr_poll_conn (&sim_con_tmxr) >= 0)            /* poll connect */
        sim_con_ldsc.rcve = 1;                          /* rcv enabled */
    }
if (sim_con_ldsc.xmte == 0)                             /* xmt disabled? */
    r = SCPE_STALL;
else r = tmxr_putc_ln (&sim_con_ldsc, c);               /* no, Telnet output */
tmxr_poll_tx (&sim_con_tmxr);                           /* poll xmt */
return r;                                               /* return status */
}

/* Input character processing */

int32 sim_tt_inpcvt (int32 c, uint32 mode)
{
uint32 md = mode & TTUF_M_MODE;

if (md != TTUF_MODE_8B) {
    uint32 par_mode = (mode >> TTUF_W_MODE) & TTUF_M_PAR;
    static int32 nibble_even_parity = 0x699600;   /* bit array indicating the even parity for each index (offset by 8) */

    c = c & 0177;
    if (md == TTUF_MODE_UC) {
        if (islower (c))
            c = toupper (c);
        if (mode & TTUF_KSR)
            c = c | 0200;
        }
    switch (par_mode) {
        case TTUF_PAR_EVEN:
            c |= (((nibble_even_parity >> ((c & 0xF) + 1)) ^ (nibble_even_parity >> (((c >> 4) & 0xF) + 1))) & 0x80);
            break;
        case TTUF_PAR_ODD:
            c |= ((~((nibble_even_parity >> ((c & 0xF) + 1)) ^ (nibble_even_parity >> (((c >> 4) & 0xF) + 1)))) & 0x80);
            break;
        case TTUF_PAR_MARK:
            c = c | 0x80;
            break;
        }
    }
else c = c & 0377;
return c;
}

/* Output character processing */

int32 sim_tt_outcvt (int32 c, uint32 mode)
{
uint32 md = mode & TTUF_M_MODE;

if (md != TTUF_MODE_8B) {
    c = c & 0177;
    if (md == TTUF_MODE_UC) {
        if (islower (c))
            c = toupper (c);
        if ((mode & TTUF_KSR) && (c >= 0140))
            return -1;
        }
    if (((md == TTUF_MODE_UC) || (md == TTUF_MODE_7P)) &&
        ((c == 0177) ||
         ((c < 040) && !((sim_tt_pchar >> c) & 1))))
        return -1;
    }
else c = c & 0377;
return c;
}

/* Tab stop array handling

   *desc points to a uint8 array of length val

   Columns with tabs set are non-zero; columns without tabs are 0 */

t_stat sim_tt_settabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint8 *temptabs, *tabs = (uint8 *) desc;
int32 i, d;
t_stat r;
char gbuf[CBUFSIZE];

if ((cptr == NULL) || (tabs == NULL) || (val <= 1))
    return SCPE_IERR;
if (*cptr == 0)
    return SCPE_2FARG;
if ((temptabs = (uint8 *)malloc (val)) == NULL)
    return SCPE_MEM;
for (i = 0; i < val; i++)
    temptabs[i] = 0;
do {
    cptr = get_glyph (cptr, gbuf, ';');
    d = (int32)get_uint (gbuf, 10, val, &r);
    if ((r != SCPE_OK) || (d == 0)) {
        free (temptabs);
        return SCPE_ARG;
        }
    temptabs[d - 1] = 1;
    } while (*cptr != 0);
for (i = 0; i < val; i++)
    tabs[i] = temptabs[i];
free (temptabs);
return SCPE_OK;
}

t_stat sim_tt_showtabs (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
const uint8 *tabs = (const uint8 *) desc;
int32 i, any;

if ((st == NULL) || (val == 0) || (desc == NULL))
    return SCPE_IERR;
for (i = any = 0; i < val; i++) {
    if (tabs[i] != 0) {
        fprintf (st, (any? ";%d": "%d"), i + 1);
        any = 1;
        }
    }
fprintf (st, (any? "\n": "no tabs set\n"));
return SCPE_OK;
}


#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
extern pthread_mutex_t     sim_tmxr_poll_lock;
extern pthread_cond_t      sim_tmxr_poll_cond;
extern int32               sim_tmxr_poll_count;
extern t_bool              sim_tmxr_poll_running;
extern int32 sim_is_running;

pthread_t           sim_console_poll_thread;       /* Keyboard Polling Thread Id */
t_bool              sim_console_poll_running = FALSE;
pthread_cond_t      sim_console_startup_cond;

static void *
_console_poll(void *arg)
{
int wait_count = 0;
DEVICE *d;

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which, in general, won't be readily yielding the processor when 
   this thread needs to run */
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - starting\n");

pthread_mutex_lock (&sim_tmxr_poll_lock);
pthread_cond_signal (&sim_console_startup_cond);   /* Signal we're ready to go */
while (sim_asynch_enabled) {

    if (!sim_is_running) {
        if (wait_count) {
            sim_debug (DBG_ASY, d, "_console_poll() - Removing interest in %s. Other interest: %d\n", d->name, sim_con_ldsc.uptr->a_poll_waiter_count);
            --sim_con_ldsc.uptr->a_poll_waiter_count;
            --sim_tmxr_poll_count;
            }
        break;
        }

    /* If we started something, let it finish before polling again */
    if (wait_count) {
        sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - waiting for %d units\n", wait_count);
        pthread_cond_wait (&sim_tmxr_poll_cond, &sim_tmxr_poll_lock);
        sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - continuing with after wait\n");
        }

    pthread_mutex_unlock (&sim_tmxr_poll_lock);
    wait_count = 0;
    if (sim_os_poll_kbd_ready (1000)) {
        sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - Keyboard Data available\n");
        pthread_mutex_lock (&sim_tmxr_poll_lock);
        ++wait_count;
        if (!sim_con_ldsc.uptr->a_polling_now) {
            sim_con_ldsc.uptr->a_polling_now = TRUE;
            sim_con_ldsc.uptr->a_poll_waiter_count = 1;
            d = find_dev_from_unit(sim_con_ldsc.uptr);
            sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - Activating %s\n", d->name);
            pthread_mutex_unlock (&sim_tmxr_poll_lock);
            _sim_activate (sim_con_ldsc.uptr, 0);
            pthread_mutex_lock (&sim_tmxr_poll_lock);
            }
        else {
            d = find_dev_from_unit(sim_con_ldsc.uptr);
            sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - Already Activated %s %d times\n", d->name, sim_con_ldsc.uptr->a_poll_waiter_count);
            ++sim_con_ldsc.uptr->a_poll_waiter_count;
            }
        }
    else
        pthread_mutex_lock (&sim_tmxr_poll_lock);

    sim_tmxr_poll_count += wait_count;
    }
pthread_mutex_unlock (&sim_tmxr_poll_lock);

sim_debug (DBG_ASY, &sim_con_telnet, "_console_poll() - exiting\n");

return NULL;
}


#endif /* defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) */


t_stat sim_ttinit (void)
{
sim_con_tmxr.ldsc->mp = &sim_con_tmxr;
sim_register_internal_device (&sim_con_telnet);
tmxr_startup ();
return sim_os_ttinit ();
}

t_stat sim_ttrun (void)
{
if (!sim_con_tmxr.ldsc->uptr) {                         /* If simulator didn't declare its input polling unit */
    sim_con_unit.dynflags &= ~UNIT_TM_POLL;             /* we can't poll asynchronously */
    sim_con_unit.dynflags |= TMUF_NOASYNCH;             /* disable asynchronous behavior */
    }
else {
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
    if (sim_asynch_enabled) {
        sim_con_tmxr.ldsc->uptr->dynflags |= UNIT_TM_POLL;/* flag console input device as a polling unit */
        sim_con_unit.dynflags |= UNIT_TM_POLL;         /* flag as polling unit */
        }
#endif
    }
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
pthread_mutex_lock (&sim_tmxr_poll_lock);
if (sim_asynch_enabled) {
    pthread_attr_t attr;

    pthread_cond_init (&sim_console_startup_cond, NULL);
    pthread_attr_init (&attr);
    pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_create (&sim_console_poll_thread, &attr, _console_poll, NULL);
    pthread_attr_destroy( &attr);
    pthread_cond_wait (&sim_console_startup_cond, &sim_tmxr_poll_lock); /* Wait for thread to stabilize */
    pthread_cond_destroy (&sim_console_startup_cond);
    sim_console_poll_running = TRUE;
    }
pthread_mutex_unlock (&sim_tmxr_poll_lock);
#endif
tmxr_start_poll ();
return sim_os_ttrun ();
}

t_stat sim_ttcmd (void)
{
#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX)
pthread_mutex_lock (&sim_tmxr_poll_lock);
if (sim_console_poll_running) {
    pthread_cond_signal (&sim_tmxr_poll_cond);
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
    pthread_join (sim_console_poll_thread, NULL);
    sim_console_poll_running = FALSE;
    }
else
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
#endif
tmxr_stop_poll ();
return sim_os_ttcmd ();
}

t_stat sim_ttclose (void)
{
t_stat r1 = tmxr_shutdown ();
t_stat r2 = sim_os_ttclose ();

if (r1 != SCPE_OK)
    return r1;
return r2;
}

t_bool sim_ttisatty (void)
{
return sim_os_ttisatty ();
}


/* Platform specific routine definitions */

/* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */

#if defined (VMS)

#if defined(__VAX)
#define sys$assign SYS$ASSIGN
#define sys$qiow SYS$QIOW
#define sys$dassgn SYS$DASSGN
#endif

#include <descrip.h>
#include <ttdef.h>
#include <tt2def.h>
#include <iodef.h>
#include <ssdef.h>
#include <starlet.h>
#include <unistd.h>

#define EFN 0
uint32 tty_chan = 0;
int buffered_character = 0;

typedef struct {
    unsigned short sense_count;
    unsigned char sense_first_char;
    unsigned char sense_reserved;
    unsigned int stat;
    unsigned int stat2; } SENSE_BUF;

typedef struct {
    unsigned short status;
    unsigned short count;
    unsigned int dev_status; } IOSB;

SENSE_BUF cmd_mode = { 0 };
SENSE_BUF run_mode = { 0 };

static t_stat sim_os_ttinit (void)
{
unsigned int status;
IOSB iosb;
$DESCRIPTOR (terminal_device, "tt");

status = sys$assign (&terminal_device, &tty_chan, 0, 0);
if (status != SS$_NORMAL)
    return SCPE_TTIERR;
status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE, &iosb, 0, 0,
    &cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
    return SCPE_TTIERR;
run_mode = cmd_mode;
run_mode.stat = cmd_mode.stat | TT$M_NOECHO & ~(TT$M_HOSTSYNC | TT$M_TTSYNC);
run_mode.stat2 = cmd_mode.stat2 | TT2$M_PASTHRU;
return SCPE_OK;
}

static t_stat sim_os_ttrun (void)
{
unsigned int status;
IOSB iosb;

status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0,
    &run_mode, sizeof (run_mode), 0, 0, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
    return SCPE_TTIERR;
return SCPE_OK;
}

static t_stat sim_os_ttcmd (void)
{
unsigned int status;
IOSB iosb;

status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0,
    &cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
    return SCPE_TTIERR;
return SCPE_OK;
}

static t_stat sim_os_ttclose (void)
{
sim_ttcmd ();
sys$dassgn (tty_chan);
return SCPE_OK;
}

static t_bool sim_os_ttisatty (void)
{
return isatty (fileno (stdin));
}

static t_stat sim_os_poll_kbd_data (void)
{
unsigned int status, term[2];
unsigned char buf[4];
IOSB iosb;
SENSE_BUF sense;

term[0] = 0; term[1] = 0;
status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb,
    0, 0, &sense, 8, 0, term, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
    return SCPE_TTIERR;
if (sense.sense_count == 0) return SCPE_OK;
term[0] = 0; term[1] = 0;
status = sys$qiow (EFN, tty_chan,
    IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO,
    &iosb, 0, 0, buf, 1, 0, term, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
    return SCPE_OK;
if (buf[0] == sim_int_char) return SCPE_STOP;
if (sim_brk_char && (buf[0] == sim_brk_char))
    return SCPE_BREAK;
return (buf[0] | SCPE_KFLAG);
}

static t_stat sim_os_poll_kbd (void)
{
t_stat response;

if (response = buffered_character) {
    buffered_character = 0;
    return response;
    }
return sim_os_poll_kbd_data ();
}

static t_bool sim_os_poll_kbd_ready (int ms_timeout)
{
unsigned int status, term[2];
unsigned char buf[4];
IOSB iosb;

term[0] = 0; term[1] = 0;
status = sys$qiow (EFN, tty_chan,
    IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO,
    &iosb, 0, 0, buf, 1, (ms_timeout+999)/1000, term, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
    return FALSE;
if (buf[0] == sim_int_char)
    buffered_character = SCPE_STOP;
else
    if (sim_brk_char && (buf[0] == sim_brk_char))
        buffered_character = SCPE_BREAK;
    else
        buffered_character = (buf[0] | SCPE_KFLAG);
return TRUE;
}


static t_stat sim_os_putchar (int32 out)
{
unsigned int status;
char c;
IOSB iosb;

c = out;
status = sys$qiow (EFN, tty_chan, IO$_WRITELBLK | IO$M_NOFORMAT,
    &iosb, 0, 0, &c, 1, 0, 0, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL))
    return SCPE_TTOERR;
return SCPE_OK;
}

/* Win32 routines */

#elif defined (_WIN32)

#include <fcntl.h>
#include <io.h>
#include <windows.h>
#define RAW_MODE 0
static HANDLE std_input;
static HANDLE std_output;
static DWORD saved_input_mode;
static DWORD saved_output_mode;
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
#endif
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif

/* Note: This routine catches all the potential events which some aspect 
         of the windows system can generate.  The CTRL_C_EVENT won't be 
         generated by a  user typing in a console session since that 
         session is in RAW mode.  In general, Ctrl-C on a simulator's
         console terminal is a useful character to be passed to the 
         simulator.  This code does nothing to disable or affect that. */

static BOOL WINAPI
ControlHandler(DWORD dwCtrlType)
    {
    DWORD Mode;
    extern void int_handler (int sig);

    switch (dwCtrlType)
        {
        case CTRL_BREAK_EVENT:      // Use CTRL-Break or CTRL-C to simulate 
        case CTRL_C_EVENT:          // SERVICE_CONTROL_STOP in debug mode
            int_handler(0);
            return TRUE;
        case CTRL_CLOSE_EVENT:      // Window is Closing
        case CTRL_LOGOFF_EVENT:     // User is logging off
            if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &Mode))
                return TRUE;        // Not our User, so ignore
        case CTRL_SHUTDOWN_EVENT:   // System is shutting down
            int_handler(0);
            return TRUE;
        }
    return FALSE;
    }

static t_stat sim_os_ttinit (void)
{
SetConsoleCtrlHandler( ControlHandler, TRUE );
std_input = GetStdHandle (STD_INPUT_HANDLE);
std_output = GetStdHandle (STD_OUTPUT_HANDLE);
if ((std_input) &&                                      /* Not Background process? */
    (std_input != INVALID_HANDLE_VALUE))
    GetConsoleMode (std_input, &saved_input_mode);      /* Save Input Mode */
if ((std_output) &&                                     /* Not Background process? */
    (std_output != INVALID_HANDLE_VALUE))
    GetConsoleMode (std_output, &saved_output_mode);    /* Save Output Mode */
return SCPE_OK;
}

static t_stat sim_os_ttrun (void)
{
if ((std_input) &&                                      /* If Not Background process? */
    (std_input != INVALID_HANDLE_VALUE)) {
    if (!GetConsoleMode(std_input, &saved_input_mode))
        return SCPE_TTYERR;
    if ((!SetConsoleMode(std_input, ENABLE_VIRTUAL_TERMINAL_INPUT)) &&
        (!SetConsoleMode(std_input, RAW_MODE)))
        return SCPE_TTYERR;
    }
if ((std_output) &&                                     /* If Not Background process? */
    (std_output != INVALID_HANDLE_VALUE)) {
    if (GetConsoleMode(std_output, &saved_output_mode))
        SetConsoleMode(std_output, ENABLE_VIRTUAL_TERMINAL_PROCESSING|ENABLE_PROCESSED_OUTPUT);
    }
if (sim_log) {
    fflush (sim_log);
    _setmode (_fileno (sim_log), _O_BINARY);
    }
sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL);
return SCPE_OK;
}

static t_stat sim_os_ttcmd (void)
{
if (sim_log) {
    fflush (sim_log);
    _setmode (_fileno (sim_log), _O_TEXT);
    }
sim_os_set_thread_priority (PRIORITY_NORMAL);
if ((std_input) &&                                      /* If Not Background process? */
    (std_input != INVALID_HANDLE_VALUE) &&
    (!SetConsoleMode(std_input, saved_input_mode)))     /* Restore Normal mode */
    return SCPE_TTYERR;
if ((std_output) &&                                     /* If Not Background process? */
    (std_output != INVALID_HANDLE_VALUE) &&
    (!SetConsoleMode(std_output, saved_output_mode)))   /* Restore Normal mode */
    return SCPE_TTYERR;
return SCPE_OK;
}

static t_stat sim_os_ttclose (void)
{
return SCPE_OK;
}

static t_bool sim_os_ttisatty (void)
{
DWORD Mode;

return (std_input) && (std_input != INVALID_HANDLE_VALUE) && GetConsoleMode (std_input, &Mode);
}

static t_stat sim_os_poll_kbd (void)
{
int c = -1;
DWORD nkbevents, nkbevent;
INPUT_RECORD rec;

sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd()\n");

if ((std_input == NULL) ||                              /* No keyboard for */
    (std_input == INVALID_HANDLE_VALUE))                /* background processes */
    return SCPE_OK;
if (!GetNumberOfConsoleInputEvents(std_input, &nkbevents))
    return SCPE_TTYERR;
while (c == -1) {
    if (0 == nkbevents)
        return SCPE_OK;
    if (!ReadConsoleInput(std_input, &rec, 1, &nkbevent))
        return SCPE_TTYERR;
    if (0 == nkbevent)
        return SCPE_OK;
    --nkbevents;
    if (rec.EventType == KEY_EVENT) {
        if (rec.Event.KeyEvent.bKeyDown) {
            if (0 == rec.Event.KeyEvent.uChar.UnicodeChar) {     /* Special Character/Keys? */
                if (rec.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) /* Pause/Break Key */
                    c = sim_brk_char | SCPE_BREAK;
                else
                    if (rec.Event.KeyEvent.wVirtualKeyCode == '2')  /* ^@ */
                        c = 0;                                      /* return NUL */
            } else
                c = rec.Event.KeyEvent.uChar.AsciiChar;
            }
      }
    }
if ((c & 0177) == sim_del_char)
    c = 0177;
if ((c & 0177) == sim_int_char)
    return SCPE_STOP;
if ((sim_brk_char && ((c & 0177) == sim_brk_char)) || (c & SCPE_BREAK))
    return SCPE_BREAK;
return c | SCPE_KFLAG;
}

static t_bool sim_os_poll_kbd_ready (int ms_timeout)
{
sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd_ready()\n");
if ((std_input == NULL) ||                              /* No keyboard for */
    (std_input == INVALID_HANDLE_VALUE)) {              /* background processes */
    Sleep (ms_timeout);
    return FALSE;
    }
return (WAIT_OBJECT_0 == WaitForSingleObject (std_input, ms_timeout));
}


#define BELL_CHAR           7       /* Bell Character */
#define BELL_INTERVAL_MS    500     /* No more than 2 Bell Characters Per Second */
#define ESC_CHAR            033     /* Escape Character */
#define CSI_CHAR            0233    /* Control Sequence Introducer */
#define NUL_CHAR            0000    /* NUL character */
#define ESC_HOLD_USEC_DELAY 8000    /* Escape hold interval */
#define ESC_HOLD_MAX        32      /* Maximum Escape hold buffer */

static uint8 out_buf[ESC_HOLD_MAX]; /* Buffered characters pending output */
static int32 out_ptr = 0;

static t_stat sim_out_hold_svc (UNIT *uptr)
{
DWORD unused;

WriteConsoleA(std_output, out_buf, out_ptr, &unused, NULL);
out_ptr = 0;
return SCPE_OK;
}

#define out_hold_unit sim_con_units[1]

static t_stat sim_os_putchar (int32 c)
{
DWORD unused;
uint32 now;
static uint32 last_bell_time;

if (c != 0177) {
    switch (c) {
        case BELL_CHAR:
            now = sim_os_msec ();
            if ((now - last_bell_time) > BELL_INTERVAL_MS) {
                WriteConsoleA(std_output, &c, 1, &unused, NULL);
                last_bell_time = now;
                }
            break;
        case NUL_CHAR:
            break;
        case CSI_CHAR:
        case ESC_CHAR:
            if (out_ptr) {
                WriteConsoleA(std_output, out_buf, out_ptr, &unused, NULL);
                out_ptr = 0;
                sim_cancel (&out_hold_unit);
                }
            out_buf[out_ptr++] = (uint8)c;
            sim_activate_after (&out_hold_unit, ESC_HOLD_USEC_DELAY);
            out_hold_unit.action = &sim_out_hold_svc;
            break;
        default:
            if (out_ptr) {
                if (out_ptr >= ESC_HOLD_MAX) {              /* Stop buffering if full */
                    WriteConsoleA(std_output, out_buf, out_ptr, &unused, NULL);
                    out_ptr = 0;
                    WriteConsoleA(std_output, &c, 1, &unused, NULL);
                    }
                else
                    out_buf[out_ptr++] = (uint8)c;
                }
            else
                WriteConsoleA(std_output, &c, 1, &unused, NULL);
        }
    }
return SCPE_OK;
}

/* OS/2 routines, from Bruce Ray and Holger Veit */

#elif defined (__OS2__)

#include <conio.h>

static t_stat sim_os_ttinit (void)
{
return SCPE_OK;
}

static t_stat sim_os_ttrun (void)
{
return SCPE_OK;
}

static t_stat sim_os_ttcmd (void)
{
return SCPE_OK;
}

static t_stat sim_os_ttclose (void)
{
return SCPE_OK;
}

static t_bool sim_os_ttisatty (void)
{
return 1;
}

static t_stat sim_os_poll_kbd (void)
{
int c;

#if defined (__EMX__)
switch (c = _read_kbd(0,0,0)) {                         /* EMX has _read_kbd */

    case -1:                                            /* no char*/
        return SCPE_OK;

    case 0:                                             /* char pending */
        c = _read_kbd(0,1,0);
        break;

    default:                                            /* got char */
        break;
        }
#else
if (!kbhit ())
    return SCPE_OK;
c = getch();
#endif
if ((c & 0177) == sim_del_char)
    c = 0177;
if ((c & 0177) == sim_int_char)
    return SCPE_STOP;
if (sim_brk_char && ((c & 0177) == sim_brk_char))
    return SCPE_BREAK;
return c | SCPE_KFLAG;
}

static t_bool sim_os_poll_kbd_ready (int ms_timeout)   /* Don't know how to do this on this platform */
{
sim_os_ms_sleep (MIN(20,ms_timeout));           /* Wait a little */
return TRUE;                                    /* force a poll */
}

static t_stat sim_os_putchar (int32 c)
{
if (c != 0177) {
#if defined (__EMX__)
    putchar (c);
#else
    putch (c);
#endif
    fflush (stdout);
    }
return SCPE_OK;
}

/* Metrowerks CodeWarrior Macintosh routines, from Louis Chretien and
   Peter Schorn */

#elif defined (__MWERKS__) && defined (macintosh)

#include <console.h>
#include <Mactypes.h>
#include <string.h>
#include <sioux.h>
#include <unistd.h>
#include <siouxglobals.h>
#include <Traps.h>
#include <LowMem.h>

/* function prototypes */

Boolean SIOUXIsAppWindow(WindowPtr window);
void SIOUXDoMenuChoice(long menuValue);
void SIOUXUpdateMenuItems(void);
void SIOUXUpdateScrollbar(void);
int ps_kbhit(void);
int ps_getch(void);

extern pSIOUXWin SIOUXTextWindow;
static CursHandle iBeamCursorH = NULL;                  /* contains the iBeamCursor */

static void updateCursor(void) {
    WindowPtr window;
    window = FrontWindow();
    if (SIOUXIsAppWindow(window)) {
        GrafPtr savePort;
        Point localMouse;
        GetPort(&savePort);
        SetPort(window);
#if TARGET_API_MAC_CARBON
        GetGlobalMouse(&localMouse);
#else
        localMouse = LMGetMouseLocation();
#endif
        GlobalToLocal(&localMouse);
        if (PtInRect(localMouse, &(*SIOUXTextWindow->edit)->viewRect) && iBeamCursorH) {
            SetCursor(*iBeamCursorH);
        }
        else {
            SetCursor(&qd.arrow);
        }
        TEIdle(SIOUXTextWindow->edit);
        SetPort(savePort);
    }
    else {
        SetCursor(&qd.arrow);
        TEIdle(SIOUXTextWindow->edit);
    }
    return;
}

int ps_kbhit(void) {
    EventRecord event;
    int c;
    updateCursor();
    SIOUXUpdateScrollbar();
    while (GetNextEvent(updateMask | osMask | mDownMask | mUpMask | activMask |
             highLevelEventMask | diskEvt, &event)) {
        SIOUXHandleOneEvent(&event);
    }
    if (SIOUXQuitting) {
        exit(1);
    }
    if (EventAvail(keyDownMask,&event)) {
        c = event.message&charCodeMask;
        if ((event.modifiers & cmdKey) && (c > 0x20)) {
            GetNextEvent(keyDownMask, &event);
            SIOUXHandleOneEvent(&event);
            if (SIOUXQuitting) {
                exit(1);
            }
            return false;
        }
        return true;
    }
    else {
        return false;
    }
}

int ps_getch(void) {
    int c;
    EventRecord event;
    fflush(stdout);
    updateCursor();
    while(!GetNextEvent(keyDownMask,&event)) {
        if (GetNextEvent(updateMask | osMask | mDownMask | mUpMask | activMask |
             highLevelEventMask | diskEvt, &event)) {
            SIOUXUpdateScrollbar();
            SIOUXHandleOneEvent(&event);
        }
    }
    if (SIOUXQuitting) {
        exit(1);
    }
    c = event.message&charCodeMask;
    if ((event.modifiers & cmdKey) && (c > 0x20)) {
        SIOUXUpdateMenuItems();
        SIOUXDoMenuChoice(MenuKey(c));
    }
    if (SIOUXQuitting) {
        exit(1);
    }
   return c;
}

/* Note that this only works if the call to sim_ttinit comes before any output to the console */

static t_stat sim_os_ttinit (void) {
    int i;
    /* this blank will later be replaced by the number of characters */
    char title[50] = " ";
    unsigned char ptitle[50];
    SIOUXSettings.autocloseonquit       = TRUE;
    SIOUXSettings.asktosaveonclose = FALSE;
    SIOUXSettings.showstatusline = FALSE;
    SIOUXSettings.columns = 80;
    SIOUXSettings.rows = 40;
    SIOUXSettings.toppixel = 42;
    SIOUXSettings.leftpixel     = 6;
    iBeamCursorH = GetCursor(iBeamCursor);
    sim_strlcat(title, sim_name, sizeof(title));
    sim_strlcat(title, " Simulator", sizeof(title));
    title[0] = strlen(title) - 1;                       /* Pascal string done */
    for (i = 0; i <= title[0]; i++) {                   /* copy to unsigned char */
        ptitle[i] = title[i];
    }
    SIOUXSetTitle(ptitle);
    return SCPE_OK;
}

static t_stat sim_os_ttrun (void)
{
return SCPE_OK;
}

static t_stat sim_os_ttcmd (void)
{
return SCPE_OK;
}

static t_stat sim_os_ttclose (void)
{
return SCPE_OK;
}

static t_bool sim_os_ttisatty (void)
{
return 1;
}

static t_stat sim_os_poll_kbd (void)
{
int c;

if (!ps_kbhit ())
    return SCPE_OK;
c = ps_getch();
if ((c & 0177) == sim_del_char)
    c = 0177;
if ((c & 0177) == sim_int_char) return SCPE_STOP;
if (sim_brk_char && ((c & 0177) == sim_brk_char))
    return SCPE_BREAK;
return c | SCPE_KFLAG;
}

static t_bool sim_os_poll_kbd_ready (int ms_timeout)   /* Don't know how to do this on this platform */
{
sim_os_ms_sleep (MIN(20,ms_timeout));           /* Wait a little */
return TRUE;                                    /* force a poll */
}

static t_stat sim_os_putchar (int32 c)
{
if (c != 0177) {
    putchar (c);
    fflush (stdout);
    }
return SCPE_OK;
}

/* BSD UNIX routines */

#elif defined (BSDTTY)

#include <sgtty.h>
#include <fcntl.h>
#include <unistd.h>

struct sgttyb cmdtty,runtty;                            /* V6/V7 stty data */
struct tchars cmdtchars,runtchars;                      /* V7 editing */
struct ltchars cmdltchars,runltchars;                   /* 4.2 BSD editing */
int cmdfl,runfl;                                        /* TTY flags */

static t_stat sim_os_ttinit (void)
{
cmdfl = fcntl (0, F_GETFL, 0);                          /* get old flags  and status */
runfl = cmdfl | FNDELAY;
if (ioctl (0, TIOCGETP, &cmdtty) < 0)
    return SCPE_TTIERR;
if (ioctl (0, TIOCGETC, &cmdtchars) < 0)
    return SCPE_TTIERR;
if (ioctl (0, TIOCGLTC, &cmdltchars) < 0)
    return SCPE_TTIERR;
runtty = cmdtty;                                        /* initial run state */
runtty.sg_flags = cmdtty.sg_flags & ~(ECHO|CRMOD) | CBREAK;
runtchars.t_intrc = sim_int_char;                       /* interrupt */
runtchars.t_quitc = 0xFF;                               /* no quit */
runtchars.t_startc = 0xFF;                              /* no host sync */
runtchars.t_stopc = 0xFF;
runtchars.t_eofc = 0xFF;
runtchars.t_brkc = 0xFF;
runltchars.t_suspc = 0xFF;                              /* no specials of any kind */
runltchars.t_dsuspc = 0xFF;
runltchars.t_rprntc = 0xFF;
runltchars.t_flushc = 0xFF;
runltchars.t_werasc = 0xFF;
runltchars.t_lnextc = 0xFF;
return SCPE_OK;                                         /* return success */
}

static t_stat sim_os_ttrun (void)
{
runtchars.t_intrc = sim_int_char;                       /* in case changed */
fcntl (0, F_SETFL, runfl);                              /* non-block mode */
if (ioctl (0, TIOCSETP, &runtty) < 0)
    return SCPE_TTIERR;
if (ioctl (0, TIOCSETC, &runtchars) < 0)
    return SCPE_TTIERR;
if (ioctl (0, TIOCSLTC, &runltchars) < 0)
    return SCPE_TTIERR;
sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL)l     /* lower priority */
return SCPE_OK;
}

static t_stat sim_os_ttcmd (void)
{
sim_os_set_thread_priority (PRIORITY_NORMAL);           /* restore priority */
fcntl (0, F_SETFL, cmdfl);                              /* block mode */
if (ioctl (0, TIOCSETP, &cmdtty) < 0)
    return SCPE_TTIERR;
if (ioctl (0, TIOCSETC, &cmdtchars) < 0)
    return SCPE_TTIERR;
if (ioctl (0, TIOCSLTC, &cmdltchars) < 0)
    return SCPE_TTIERR;
return SCPE_OK;
}

static t_stat sim_os_ttclose (void)
{
return sim_ttcmd ();
}

static t_bool sim_os_ttisatty (void)
{
return isatty (fileno (stdin));
}

static t_stat sim_os_poll_kbd (void)
{
int status;
unsigned char buf[1];

status = read (0, buf, 1);
if (status != 1) return SCPE_OK;
if (sim_brk_char && (buf[0] == sim_brk_char))
    return SCPE_BREAK;
if (sim_int_char && (buf[0] == sim_int_char))
    return SCPE_STOP;
return (buf[0] | SCPE_KFLAG);
}

static t_bool sim_os_poll_kbd_ready (int ms_timeout)
{
fd_set readfds;
struct timeval timeout;

if (!isatty (0)) {                           /* skip if !tty */
    sim_os_ms_sleep (ms_timeout);
    return FALSE;
    }
FD_ZERO (&readfds);
FD_SET (0, &readfds);
timeout.tv_sec = (ms_timeout*1000)/1000000;
timeout.tv_usec = (ms_timeout*1000)%1000000;
return (1 == select (1, &readfds, NULL, NULL, &timeout));
}

static t_stat sim_os_putchar (int32 out)
{
char c;

c = out;
write (1, &c, 1);
return SCPE_OK;
}

/* POSIX UNIX routines, from Leendert Van Doorn */

#else

#include <termios.h>
#include <unistd.h>

struct termios cmdtty, runtty;

static t_stat sim_os_ttinit (void)
{
if (!isatty (fileno (stdin)))                           /* skip if !tty */
    return SCPE_OK;
if (tcgetattr (0, &cmdtty) < 0)                         /* get old flags */
    return SCPE_TTIERR;
runtty = cmdtty;
runtty.c_lflag = runtty.c_lflag & ~(ECHO | ICANON);     /* no echo or edit */
runtty.c_oflag = runtty.c_oflag & ~OPOST;               /* no output edit */
runtty.c_iflag = runtty.c_iflag & ~ICRNL;               /* no cr conversion */
#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)
runtty.c_cc[VINTR] = 0;                                 /* OS X doesn't deliver SIGINT to main thread when enabled */
#else
runtty.c_cc[VINTR] = sim_int_char;                      /* interrupt */
#endif
runtty.c_cc[VQUIT] = 0;                                 /* no quit */
runtty.c_cc[VERASE] = 0;
runtty.c_cc[VKILL] = 0;
runtty.c_cc[VEOF] = 0;
runtty.c_cc[VEOL] = 0;
runtty.c_cc[VSTART] = 0;                                /* no host sync */
runtty.c_cc[VSUSP] = 0;
runtty.c_cc[VSTOP] = 0;
#if defined (VREPRINT)
runtty.c_cc[VREPRINT] = 0;                              /* no specials */
#endif
#if defined (VDISCARD)
runtty.c_cc[VDISCARD] = 0;
#endif
#if defined (VWERASE)
runtty.c_cc[VWERASE] = 0;
#endif
#if defined (VLNEXT)
runtty.c_cc[VLNEXT] = 0;
#endif
runtty.c_cc[VMIN] = 0;                                  /* no waiting */
runtty.c_cc[VTIME] = 0;
#if defined (VDSUSP)
runtty.c_cc[VDSUSP] = 0;
#endif
#if defined (VSTATUS)
runtty.c_cc[VSTATUS] = 0;
#endif
return SCPE_OK;
}

static t_stat sim_os_ttrun (void)
{
if (!isatty (fileno (stdin)))                           /* skip if !tty */
    return SCPE_OK;
#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)
runtty.c_cc[VINTR] = 0;                                 /* OS X doesn't deliver SIGINT to main thread when enabled */
#else
runtty.c_cc[VINTR] = sim_int_char;                      /* in case changed */
#endif
if (tcsetattr (0, TCSAFLUSH, &runtty) < 0)
    return SCPE_TTIERR;
sim_os_set_thread_priority (PRIORITY_BELOW_NORMAL);     /* try to lower pri */
return SCPE_OK;
}

static t_stat sim_os_ttcmd (void)
{
if (!isatty (fileno (stdin)))                           /* skip if !tty */
    return SCPE_OK;
sim_os_set_thread_priority (PRIORITY_NORMAL);           /* try to raise pri */
if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0)
    return SCPE_TTIERR;
return SCPE_OK;
}

static t_stat sim_os_ttclose (void)
{
return sim_ttcmd ();
}

static t_bool sim_os_ttisatty (void)
{
return isatty (fileno (stdin));
}

static t_stat sim_os_poll_kbd (void)
{
int status;
unsigned char buf[1];

status = read (0, buf, 1);
if (status != 1) return SCPE_OK;
if (sim_brk_char && (buf[0] == sim_brk_char))
    return SCPE_BREAK;
if (sim_int_char && (buf[0] == sim_int_char))
    return SCPE_STOP;
return (buf[0] | SCPE_KFLAG);
}

static t_bool sim_os_poll_kbd_ready (int ms_timeout)
{
fd_set readfds;
struct timeval timeout;

if (!sim_os_ttisatty()) {                   /* skip if !tty */
    sim_os_ms_sleep (ms_timeout);
    return FALSE;
    }
FD_ZERO (&readfds);
FD_SET (0, &readfds);
timeout.tv_sec = (ms_timeout*1000)/1000000;
timeout.tv_usec = (ms_timeout*1000)%1000000;
return (1 == select (1, &readfds, NULL, NULL, &timeout));
}

static t_stat sim_os_putchar (int32 out)
{
char c;

c = out;
(void)write (1, &c, 1);
return SCPE_OK;
}

#endif

/* Decode a string.

   A string containing encoded control characters is decoded into the equivalent
   character string.  Escape targets @, A-Z, and [\]^_ form control characters
   000-037.
*/
#define ESCAPE_CHAR '~'

static void decode (char *decoded, const char *encoded)
{
char c;

while ((c = *decoded++ = *encoded++))                   /* copy the character */
    if (c == ESCAPE_CHAR) {                             /* does it start an escape? */
        if ((isalpha (*encoded)) ||                     /* is next character "A-Z" or "a-z"? */
            (*encoded == '@') ||                        /*   or "@"? */
            ((*encoded >= '[') && (*encoded <= '_')))   /*   or "[\]^_"? */

            *(decoded - 1) = *encoded++ & 037;          /* convert back to control character */
        else {
            if ((*encoded == '\0') ||                   /* single escape character at EOL? */
                 (*encoded++ != ESCAPE_CHAR))           /*   or not followed by another escape? */
                decoded--;                              /* drop the encoding */
            }
        }
return;
}

/* Set console halt */

static t_stat sim_set_halt (int32 flag, CONST char *cptr)
{
if (flag == 0)                                              /* no halt? */
    sim_exp_clrall (&sim_con_expect);                       /* disable halt checks */
else {
    char *mbuf;
    char *mbuf2;

    if (cptr == NULL || *cptr == 0)                         /* no match string? */
        return SCPE_2FARG;                                  /* need an argument */

    sim_exp_clrall (&sim_con_expect);                       /* make sure that none currently exist */

    mbuf = (char *)malloc (1 + strlen (cptr));
    decode (mbuf, cptr);                                    /* save decoded match string */

    mbuf2 = (char *)malloc (3 + strlen(cptr));
    sprintf (mbuf2, "%s%s%s", (sim_switches & SWMASK ('A')) ? "\n" : "",
                              mbuf, 
                              (sim_switches & SWMASK ('I')) ? "" : "\n");
    free (mbuf);
    mbuf = sim_encode_quoted_string ((uint8 *)mbuf2, strlen (mbuf2));
    sim_exp_set (&sim_con_expect, mbuf, 0, sim_con_expect.after, EXP_TYP_PERSIST, NULL);
    free (mbuf);
    free (mbuf2);
    }

return SCPE_OK;
}


/* Set console response */

static t_stat sim_set_response (int32 flag, CONST char *cptr)
{
if (flag == 0)                                          /* no response? */
    sim_send_clear (&sim_con_send);
else {
    uint8 *rbuf;

    if (cptr == NULL || *cptr == 0)
        return SCPE_2FARG;                              /* need arg */

    rbuf = (uint8 *)malloc (1 + strlen(cptr));

    decode ((char *)rbuf, cptr);                        /* decod string */
    sim_send_input (&sim_con_send, rbuf, strlen((char *)rbuf), 0, 0); /* queue it for output */
    free (rbuf);
    }

return SCPE_OK;
}

/* Set console delay */

static t_stat sim_set_delay (int32 flag, CONST char *cptr)
{
int32 val;
t_stat r;

if (cptr == NULL || *cptr == 0)                         /* no argument string? */
    return SCPE_2FARG;                                  /* need an argument */

val = (int32) get_uint (cptr, 10, INT_MAX, &r);         /* parse the argument */

if (r == SCPE_OK)                                       /* parse OK? */
    sim_con_expect.after = val;                         /* save the delay value */

return r;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_console.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* sim_console.h: simulator console I/O library headers

   Copyright (c) 1993-2014, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   02-Jan-14    RMS     Added tab stop routines
   17-Jan-11    MP      Added buffered line capabilities
   22-Jun-06    RMS     Implemented SET/SHOW PCHAR
   22-Nov-05    RMS     Added central input/output conversion support
   05-Nov-04    RMS     Moved SET/SHOW DEBUG under CONSOLE hierarchy
   28-May-04    RMS     Added SET/SHOW CONSOLE
   02-Jan-04    RMS     Removed timer routines, added Telnet console routines
*/

#ifndef SIM_CONSOLE_H_
#define SIM_CONSOLE_H_ 0

#ifdef  __cplusplus
extern "C" {
#endif

#define TTUF_V_MODE     (UNIT_V_UF + 0)
#define TTUF_W_MODE     2
#define  TTUF_MODE_7B   0
#define  TTUF_MODE_8B   1
#define  TTUF_MODE_UC   2
#define  TTUF_MODE_7P   3
#define TTUF_M_MODE     ((1u << TTUF_W_MODE) - 1)
#define TTUF_V_PAR      (TTUF_V_MODE + TTUF_W_MODE)
#define TTUF_W_PAR      2
#define  TTUF_PAR_SPACE 0
#define  TTUF_PAR_MARK  1
#define  TTUF_PAR_EVEN  2
#define  TTUF_PAR_ODD   3
#define TTUF_M_PAR      ((1u << TTUF_W_PAR) - 1)
#define  TTUF_KSR       (1u << (TTUF_W_MODE + TTUF_W_PAR))
#define TTUF_V_UF       (TTUF_V_MODE + TTUF_W_MODE + TTUF_W_PAR)
#define TT_MODE         (TTUF_M_MODE << TTUF_V_MODE)
#define  TT_MODE_7B     (TTUF_MODE_7B << TTUF_V_MODE)
#define  TT_MODE_8B     (TTUF_MODE_8B << TTUF_V_MODE)
#define  TT_MODE_UC     (TTUF_MODE_UC << TTUF_V_MODE)
#define  TT_MODE_7P     (TTUF_MODE_7P << TTUF_V_MODE)
#define  TT_MODE_KSR    (TT_MODE_UC)
/* 7 bit modes allow for an 8th bit parity mode */
#define TT_PAR          (TTUF_M_PAR << TTUF_V_PAR)
#define  TT_PAR_SPACE   (TTUF_PAR_SPACE << TTUF_V_PAR)
#define  TT_PAR_MARK    (TTUF_PAR_MARK  << TTUF_V_PAR)
#define  TT_PAR_EVEN    (TTUF_PAR_EVEN  << TTUF_V_PAR)
#define  TT_PAR_ODD     (TTUF_PAR_ODD   << TTUF_V_PAR)
/* TT_GET_MODE returns both the TT_MODE and TT_PAR fields 
   since they together are passed into sim_tt_inpcvt() */
#define TT_GET_MODE(x)  (((x) >> TTUF_V_MODE) & (TTUF_M_MODE | (TTUF_M_PAR << TTUF_W_MODE)))

t_stat sim_set_console (int32 flag, CONST char *cptr);
t_stat sim_set_remote_console (int32 flag, CONST char *cptr);
void sim_remote_process_command (void);
t_stat sim_set_kmap (int32 flag, CONST char *cptr);
t_stat sim_set_telnet (int32 flag, CONST char *cptr);
t_stat sim_set_notelnet (int32 flag, CONST char *cptr);
t_stat sim_set_serial (int32 flag, CONST char *cptr);
t_stat sim_set_noserial (int32 flag, CONST char *cptr);
t_stat sim_set_logon (int32 flag, CONST char *cptr);
t_stat sim_set_logoff (int32 flag, CONST char *cptr);
t_stat sim_set_debon (int32 flag, CONST char *cptr);
t_stat sim_set_cons_debug (int32 flg, CONST char *cptr);
t_stat sim_set_cons_buff (int32 flg, CONST char *cptr);
t_stat sim_set_cons_unbuff (int32 flg, CONST char *cptr);
t_stat sim_set_cons_log (int32 flg, CONST char *cptr);
t_stat sim_set_cons_nolog (int32 flg, CONST char *cptr);
t_stat sim_set_deboff (int32 flag, CONST char *cptr);
t_stat sim_set_cons_expect (int32 flg, CONST char *cptr);
t_stat sim_set_cons_noexpect (int32 flg, CONST char *cptr);
t_stat sim_debug_flush (void);
t_stat sim_set_pchar (int32 flag, CONST char *cptr);
t_stat sim_set_cons_speed (int32 flag, CONST char *cptr);
t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_remote_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_telnet (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_cons_speed (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_cons_buff (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_cons_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_cons_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_show_cons_expect (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_check_console (int32 sec);
t_stat sim_open_logfile (const char *filename, t_bool binary, FILE **pf, FILEREF **pref);
t_stat sim_close_logfile (FILEREF **pref);
const char *sim_logfile_name (FILE *st, FILEREF *ref);
SEND *sim_cons_get_send (void);
EXPECT *sim_cons_get_expect (void);
t_stat sim_show_cons_send_input (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_stat sim_set_noconsole_port (void);
t_stat sim_set_stable_registers_state (void);
t_stat sim_poll_kbd (void);
t_stat sim_putchar (int32 c);
t_stat sim_putchar_s (int32 c);
t_stat sim_ttinit (void);
t_stat sim_ttrun (void);
t_stat sim_ttcmd (void);
t_stat sim_ttclose (void);
t_bool sim_ttisatty (void);
int32 sim_tt_inpcvt (int32 c, uint32 mode);
int32 sim_tt_outcvt (int32 c, uint32 mode);
t_stat sim_tt_settabs (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_tt_showtabs (FILE *st, UNIT *uptr, int32 val, CONST void *desc);

extern int32 sim_rem_cmd_active_line;                       /* command in progress on line # */

extern int32 sim_int_char;                                  /* interrupt character */
extern int32 sim_brk_char;                                  /* break character */
extern int32 sim_tt_pchar;                                  /* printable character mask */
extern int32 sim_del_char;                                  /* delete character */

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































Deleted src/sim_defs.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
/* sim_defs.h: simulator definitions

   Copyright (c) 1993-2016, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   25-Sep-16    RMS     Removed KBD_WAIT and friends
   08-Mar-16    RMS     Added shutdown invisible switch
   24-Dec-14    JDB     Added T_ADDR_FMT
   05-Jan-11    MP      Added Asynch I/O support
   18-Jan-11    MP      Added log file reference count support
   21-Jul-08    RMS     Removed inlining support
   28-May-08    RMS     Added inlining support
   28-Jun-07    RMS     Added IA64 VMS support (from Norm Lastovica)
   18-Jun-07    RMS     Added UNIT_IDLE flag
   18-Mar-07    RMS     Added UNIT_TEXT flag
   07-Mar-07    JDB     Added DEBUG_PRJ macro
   18-Oct-06    RMS     Added limit check for clock synchronized keyboard waits
   13-Jul-06    RMS     Guarantee CBUFSIZE is at least 256
   07-Jan-06    RMS     Added support for breakpoint spaces
                        Added REG_FIT flag
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   11-Mar-05    RMS     Moved 64b data type definitions outside USE_INT64
   07-Feb-05    RMS     Added assertion fail stop
   05-Nov-04    RMS     Added support for SHOW opt=val
   20-Oct-04    RMS     Converted all base types to typedefs
   21-Sep-04    RMS     Added switch to flag stop message printout
   06-Feb-04    RMS     Moved device and unit user flags fields (V3.2)
                RMS     Added REG_VMAD
   29-Dec-03    RMS     Added output stall status
   15-Jun-03    RMS     Added register flag REG_VMIO
   23-Apr-03    RMS     Revised for 32b/64b t_addr
   14-Mar-03    RMS     Lengthened default serial output wait
   31-Mar-03    RMS     Added u5, u6 fields
   18-Mar-03    RMS     Added logical name support
                        Moved magtape definitions to sim_tape.h
                        Moved breakpoint definitions from scp.c
   03-Mar-03    RMS     Added sim_fsize
   08-Feb-03    RMS     Changed sim_os_sleep to void, added match_ext
   05-Jan-03    RMS     Added hidden switch definitions, device dyn memory support,
                        parameters for function pointers, case sensitive SET support
   22-Dec-02    RMS     Added break flag
   08-Oct-02    RMS     Increased simulator error code space
                        Added Telnet errors
                        Added end of medium support
                        Added help messages to CTAB
                        Added flag and context fields to DEVICE
                        Added restore flag masks
                        Revised 64b definitions
   02-May-02    RMS     Removed log status codes
   22-Apr-02    RMS     Added magtape record length error
   30-Dec-01    RMS     Generalized timer package, added circular arrays
   07-Dec-01    RMS     Added breakpoint package
   01-Dec-01    RMS     Added read-only unit support, extended SET/SHOW features,
                        improved error messages
   24-Nov-01    RMS     Added unit-based registers
   27-Sep-01    RMS     Added queue count prototype
   17-Sep-01    RMS     Removed multiple console support
   07-Sep-01    RMS     Removed conditional externs on function prototypes
   31-Aug-01    RMS     Changed int64 to t_int64 for Windoze
   17-Jul-01    RMS     Added additional function prototypes
   27-May-01    RMS     Added multiple console support
   15-May-01    RMS     Increased string buffer size
   25-Feb-01    RMS     Revisions for V2.6
   15-Oct-00    RMS     Editorial revisions for V2.5
   11-Jul-99    RMS     Added unsigned int data types
   14-Apr-99    RMS     Converted t_addr to unsigned
   04-Oct-98    RMS     Additional definitions for V2.4

   The interface between the simulator control package (SCP) and the
   simulator consists of the following routines and data structures

        sim_name                simulator name string
        sim_devices[]           array of pointers to simulated devices
        sim_PC                  pointer to saved PC register descriptor
        sim_interval            simulator interval to next event
        sim_stop_messages[]     array of pointers to stop messages
        sim_instr()             instruction execution routine
        sim_load()              binary loader routine
        sim_emax                maximum number of words in an instruction

   In addition, the simulator must supply routines to print and parse
   architecture specific formats

        print_sym               print symbolic output
        parse_sym               parse symbolic input
*/

#ifndef SIM_DEFS_H_
#define SIM_DEFS_H_    0

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf      /* poor man's snprintf which will work most of the time but has different return value */
#endif
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <limits.h>

#ifdef _WIN32
#include <winsock2.h>
#undef PACKED                       /* avoid macro name collision */
#undef ERROR                        /* avoid macro name collision */
#undef MEM_MAPPED                   /* avoid macro name collision */
#include <process.h>
#endif

#ifdef USE_REGEX
#undef USE_REGEX
#endif
#if defined(HAVE_PCREPOSIX_H)
#include <pcreposix.h>
#define USE_REGEX 1
#elif defined(HAVE_REGEX_H)
#include <regex.h>
#define USE_REGEX 1
#endif

#ifdef  __cplusplus
extern "C" {
#endif

/* avoid macro names collisions */
#ifdef MAX
#undef MAX
#endif
#ifdef MIN
#undef MIN
#endif
#ifdef PMASK
#undef PMASK
#endif
#ifdef RS
#undef RS
#endif
#ifdef PAGESIZE
#undef PAGESIZE
#endif


#ifndef TRUE
#define TRUE            1
#define FALSE           0
#endif

/* SCP API shim.

   The SCP API for version 4.0 introduces a number of "pointer-to-const"
   parameter qualifiers that were not present in the 3.x versions.  To maintain
   compatibility with the earlier versions, the new qualifiers are expressed as
   "CONST" rather than "const".  This allows macro removal of the qualifiers
   when compiling for SIMH 3.x.
*/
#ifndef CONST
#define CONST const
#endif

/* Length specific integer declarations */

#if defined (VMS)
#include <ints.h>
#else
typedef signed char     int8;
typedef signed short    int16;
typedef signed int      int32;
typedef unsigned char   uint8;
typedef unsigned short  uint16;
typedef unsigned int    uint32;
#endif
typedef int             t_stat;                         /* status */
typedef int             t_bool;                         /* boolean */

/* 64b integers */

#if defined (__GNUC__)                                  /* GCC */
typedef signed long long        t_int64;
typedef unsigned long long      t_uint64;
#elif defined (_WIN32)                                  /* Windows */
typedef signed __int64          t_int64;
typedef unsigned __int64        t_uint64;
#elif (defined (__ALPHA) || defined (__ia64)) && defined (VMS) /* 64b VMS */
typedef signed __int64          t_int64;
typedef unsigned __int64        t_uint64;
#elif defined (__ALPHA) && defined (__unix__)           /* Alpha UNIX */
typedef signed long             t_int64;
typedef unsigned long           t_uint64;
#else                                                   /* default */
#define t_int64                 signed long long
#define t_uint64                unsigned long long
#endif                                                  /* end 64b */
#ifndef INT64_C
#define INT64_C(x)      x ## LL
#endif

#if defined (USE_INT64)                                 /* 64b data */
typedef t_int64         t_svalue;                       /* signed value */
typedef t_uint64        t_value;                        /* value */
#else                                                   /* 32b data */
typedef int32           t_svalue;
typedef uint32          t_value;
#endif                                                  /* end 64b data */

#if defined (USE_INT64) && defined (USE_ADDR64)         /* 64b address */
typedef t_uint64        t_addr;
#define T_ADDR_W        64
#define T_ADDR_FMT      LL_FMT
#else                                                   /* 32b address */
typedef uint32          t_addr;
#define T_ADDR_W        32
#define T_ADDR_FMT      ""
#endif                                                  /* end 64b address */

#if defined (_WIN32)
#define vsnprintf _vsnprintf
#endif
#if defined (__DECC) && defined (__VMS) && (defined (__VAX) || (__CRTL_VER <= 70311000))
#define NO_vsnprintf
#endif
#if defined( NO_vsnprintf)
#define STACKBUFSIZE 16384
#else
#define STACKBUFSIZE 2048
#endif

#if defined (_WIN32) /* Actually, a GCC issue */
#define LL_FMT "I64"
#define LL_TYPE long long
#else
#if defined (__VAX) /* No 64 bit ints on VAX */
#define LL_FMT "l"
#define LL_TYPE long
#else
#define LL_FMT "ll"
#define LL_TYPE long long
#endif
#endif

#if defined (VMS) && (defined (__ia64) || defined (__ALPHA))
#define HAVE_GLOB
#endif

#if defined (__linux) || defined (VMS) || defined (__APPLE__)
#define HAVE_C99_STRFTIME 1
#endif

#if defined (_WIN32)
#define NULL_DEVICE "NUL:"
#elif defined (_VMS)
#define NULL_DEVICE "NL:"
#else
#define NULL_DEVICE "/dev/null"
#endif

/* Stubs for inlining */

#if defined(_MSC_VER)
#define SIM_INLINE _inline
#define SIM_NOINLINE _declspec (noinline)
#elif defined(__GNUC__)
#define SIM_INLINE inline
#define SIM_NOINLINE  __attribute__ ((noinline))
#else
#define SIM_INLINE 
#define SIM_NOINLINE
#endif

/* Storage class modifier for weak link definition for sim_vm_init() */

#if defined(__cplusplus)
#if defined(__GNUC__)
#define WEAK __attribute__((weak))
#elif defined(_MSC_VER)
#define WEAK __declspec(selectany) 
#else
#define WEAK extern 
#endif
#else
#define WEAK 
#endif

/* System independent definitions */

#define FLIP_SIZE       (1 << 16)                       /* flip buf size */
#if !defined (PATH_MAX)                                 /* usually in limits */
#define PATH_MAX        512
#endif
#if (PATH_MAX >= 128)
#define CBUFSIZE        (128 + PATH_MAX)                /* string buf size */
#else
#define CBUFSIZE        256
#endif

/* Breakpoint spaces definitions */

#define SIM_BKPT_N_SPC  (1 << (32 - SIM_BKPT_V_SPC))    /* max number spaces */
#define SIM_BKPT_V_SPC  (BRK_TYP_MAX + 1)               /* location in arg */

/* Extended switch definitions (bits >= 26) */

#define SIM_SW_HIDE     (1u << 26)                      /* enable hiding */
#define SIM_SW_REST     (1u << 27)                      /* attach/restore */
#define SIM_SW_REG      (1u << 28)                      /* register value */
#define SIM_SW_STOP     (1u << 29)                      /* stop message */
#define SIM_SW_SHUT     (1u << 30)                      /* shutdown */

/* Simulator status codes

   0                    ok
   1 - (SCPE_BASE - 1)  simulator specific
   SCPE_BASE - n        general
*/

#define SCPE_OK         0                               /* normal return */
#define SCPE_BASE       64                              /* base for messages */
#define SCPE_NXM        (SCPE_BASE + 0)                 /* nxm */
#define SCPE_UNATT      (SCPE_BASE + 1)                 /* no file */
#define SCPE_IOERR      (SCPE_BASE + 2)                 /* I/O error */
#define SCPE_CSUM       (SCPE_BASE + 3)                 /* loader cksum */
#define SCPE_FMT        (SCPE_BASE + 4)                 /* loader format */
#define SCPE_NOATT      (SCPE_BASE + 5)                 /* not attachable */
#define SCPE_OPENERR    (SCPE_BASE + 6)                 /* open error */
#define SCPE_MEM        (SCPE_BASE + 7)                 /* alloc error */
#define SCPE_ARG        (SCPE_BASE + 8)                 /* argument error */
#define SCPE_STEP       (SCPE_BASE + 9)                 /* step expired */
#define SCPE_UNK        (SCPE_BASE + 10)                /* unknown command */
#define SCPE_RO         (SCPE_BASE + 11)                /* read only */
#define SCPE_INCOMP     (SCPE_BASE + 12)                /* incomplete */
#define SCPE_STOP       (SCPE_BASE + 13)                /* sim stopped */
#define SCPE_EXIT       (SCPE_BASE + 14)                /* sim exit */
#define SCPE_TTIERR     (SCPE_BASE + 15)                /* console tti err */
#define SCPE_TTOERR     (SCPE_BASE + 16)                /* console tto err */
#define SCPE_EOF        (SCPE_BASE + 17)                /* end of file */
#define SCPE_REL        (SCPE_BASE + 18)                /* relocation error */
#define SCPE_NOPARAM    (SCPE_BASE + 19)                /* no parameters */
#define SCPE_ALATT      (SCPE_BASE + 20)                /* already attached */
#define SCPE_TIMER      (SCPE_BASE + 21)                /* hwre timer err */
#define SCPE_SIGERR     (SCPE_BASE + 22)                /* signal err */
#define SCPE_TTYERR     (SCPE_BASE + 23)                /* tty setup err */
#define SCPE_SUB        (SCPE_BASE + 24)                /* subscript err */
#define SCPE_NOFNC      (SCPE_BASE + 25)                /* func not imp */
#define SCPE_UDIS       (SCPE_BASE + 26)                /* unit disabled */
#define SCPE_NORO       (SCPE_BASE + 27)                /* rd only not ok */
#define SCPE_INVSW      (SCPE_BASE + 28)                /* invalid switch */
#define SCPE_MISVAL     (SCPE_BASE + 29)                /* missing value */
#define SCPE_2FARG      (SCPE_BASE + 30)                /* too few arguments */
#define SCPE_2MARG      (SCPE_BASE + 31)                /* too many arguments */
#define SCPE_NXDEV      (SCPE_BASE + 32)                /* nx device */
#define SCPE_NXUN       (SCPE_BASE + 33)                /* nx unit */
#define SCPE_NXREG      (SCPE_BASE + 34)                /* nx register */
#define SCPE_NXPAR      (SCPE_BASE + 35)                /* nx parameter */
#define SCPE_NEST       (SCPE_BASE + 36)                /* nested DO */
#define SCPE_IERR       (SCPE_BASE + 37)                /* internal error */
#define SCPE_MTRLNT     (SCPE_BASE + 38)                /* tape rec lnt error */
#define SCPE_LOST       (SCPE_BASE + 39)                /* Telnet conn lost */
#define SCPE_TTMO       (SCPE_BASE + 40)                /* Telnet conn timeout */
#define SCPE_STALL      (SCPE_BASE + 41)                /* Telnet conn stall */
#define SCPE_AFAIL      (SCPE_BASE + 42)                /* assert failed */
#define SCPE_INVREM     (SCPE_BASE + 43)                /* invalid remote console command */
#define SCPE_NOTATT     (SCPE_BASE + 44)                /* not attached */
#define SCPE_EXPECT     (SCPE_BASE + 45)                /* expect matched */
#define SCPE_AMBREG     (SCPE_BASE + 46)                /* ambiguous register */
#define SCPE_REMOTE     (SCPE_BASE + 47)                /* remote console command */

#define SCPE_MAX_ERR    (SCPE_BASE + 48)                /* Maximum SCPE Error Value */
#define SCPE_KFLAG      0x1000                          /* tti data flag */
#define SCPE_BREAK      0x2000                          /* tti break flag */
#define SCPE_NOMESSAGE  0x10000000                      /* message display supression flag */
#define SCPE_BARE_STATUS(stat) ((stat) & ~(SCPE_NOMESSAGE|SCPE_KFLAG|SCPE_BREAK))

/* Print value format codes */

#define PV_RZRO         0                               /* right, zero fill */
#define PV_RSPC         1                               /* right, space fill */
#define PV_RCOMMA       2                               /* right, space fill. Comma separate every 3 */
#define PV_LEFT         3                               /* left justify */

/* Default timing parameters */

#define KBD_POLL_WAIT   5000                            /* keyboard poll */
#define SERIAL_IN_WAIT  100                             /* serial in time */
#define SERIAL_OUT_WAIT 100                             /* serial output */
#define NOQUEUE_WAIT    1000000                         /* min check time */

/* Convert switch letter to bit mask */

#define SWMASK(x) (1u << (((int) (x)) - ((int) 'A')))

/* String match - at least one character required */

#define MATCH_CMD(ptr,cmd) ((NULL == (ptr)) || (!*(ptr)) || sim_strncasecmp ((ptr), (cmd), strlen (ptr)))

/* End of Linked List/Queue value                           */
/* Chosen for 2 reasons:                                    */
/*     1 - to not be NULL, this allowing the NULL value to  */
/*         indicate inclusion on a list                     */
/* and                                                      */
/*     2 - to not be a valid/possible pointer (alignment)   */
#define QUEUE_LIST_END ((UNIT *)1)

/* Typedefs for principal structures */

typedef struct DEVICE DEVICE;
typedef struct UNIT UNIT;
typedef struct REG REG;
typedef struct CTAB CTAB;
typedef struct C1TAB C1TAB;
typedef struct SHTAB SHTAB;
typedef struct MTAB MTAB;
typedef struct SCHTAB SCHTAB;
typedef struct BRKTAB BRKTAB;
typedef struct BRKTYPTAB BRKTYPTAB;
typedef struct EXPTAB EXPTAB;
typedef struct EXPECT EXPECT;
typedef struct SEND SEND;
typedef struct DEBTAB DEBTAB;
typedef struct FILEREF FILEREF;
typedef struct MEMFILE MEMFILE;
typedef struct BITFIELD BITFIELD;

typedef t_stat (*ACTIVATE_API)(UNIT *unit, int32 interval);

/* Device data structure */

struct DEVICE {
    const char          *name;                          /* name */
    UNIT                *units;                         /* units */
    REG                 *registers;                     /* registers */
    MTAB                *modifiers;                     /* modifiers */
    uint32              numunits;                       /* #units */
    uint32              aradix;                         /* address radix */
    uint32              awidth;                         /* address width */
    uint32              aincr;                          /* addr increment */
    uint32              dradix;                         /* data radix */
    uint32              dwidth;                         /* data width */
    t_stat              (*examine)(t_value *v, t_addr a, UNIT *up,
                            int32 sw);                  /* examine routine */
    t_stat              (*deposit)(t_value v, t_addr a, UNIT *up,
                            int32 sw);                  /* deposit routine */
    t_stat              (*reset)(DEVICE *dp);           /* reset routine */
    t_stat              (*boot)(int32 u, DEVICE *dp);
                                                        /* boot routine */
    t_stat              (*attach)(UNIT *up, CONST char *cp);
                                                        /* attach routine */
    t_stat              (*detach)(UNIT *up);            /* detach routine */
    void                *ctxt;                          /* context */
    uint32              flags;                          /* flags */
    uint32              dctrl;                          /* debug control */
    DEBTAB              *debflags;                      /* debug flags */
    t_stat              (*msize)(UNIT *up, int32 v, CONST char *cp, void *dp);
                                                        /* mem size routine */
    char                *lname;                         /* logical name */
    t_stat              (*help)(FILE *st, DEVICE *dptr,
                            UNIT *uptr, int32 flag, const char *cptr); 
                                                        /* help */
    t_stat              (*attach_help)(FILE *st, DEVICE *dptr,
                            UNIT *uptr, int32 flag, const char *cptr);
                                                        /* attach help */
    void *help_ctx;                                     /* Context available to help routines */
    const char          *(*description)(DEVICE *dptr);  /* Device Description */
    BRKTYPTAB           *brk_types;                     /* Breakpoint types */
    };

/* Device flags */

#define DEV_V_DIS       0                               /* dev disabled */
#define DEV_V_DISABLE   1                               /* dev disable-able */
#define DEV_V_DYNM      2                               /* mem size dynamic */
#define DEV_V_DEBUG     3                               /* debug capability */
#define DEV_V_TYPE      4                               /* Attach type */
#define DEV_S_TYPE      3                               /* Width of Type Field */
#define DEV_V_SECTORS   7                               /* Unit Capacity is in 512byte sectors */
#define DEV_V_DONTAUTO  8                               /* Do not auto detach already attached units */
#define DEV_V_FLATHELP  9                               /* Use traditional (unstructured) help */
#define DEV_V_NOSAVE    10                              /* Don't save device state */
#define DEV_V_UF_31     12                              /* user flags, V3.1 */
#define DEV_V_UF        16                              /* user flags */
#define DEV_V_RSV       31                              /* reserved */

#define DEV_DIS         (1 << DEV_V_DIS)                /* device is currently disabled */
#define DEV_DISABLE     (1 << DEV_V_DISABLE)            /* device can be set enabled or disabled */
#define DEV_DYNM        (1 << DEV_V_DYNM)               /* device requires call on msize routine to change memory size */
#define DEV_DEBUG       (1 << DEV_V_DEBUG)              /* device supports SET DEBUG command */
#define DEV_SECTORS     (1 << DEV_V_SECTORS)            /* capacity is 512 byte sectors */
#define DEV_DONTAUTO    (1 << DEV_V_DONTAUTO)           /* Do not auto detach already attached units */
#define DEV_FLATHELP    (1 << DEV_V_FLATHELP)           /* Use traditional (unstructured) help */
#define DEV_NOSAVE      (1 << DEV_V_NOSAVE)             /* Don't save device state */
#define DEV_NET         0                               /* Deprecated - meaningless */


#define DEV_TYPEMASK    (((1 << DEV_S_TYPE) - 1) << DEV_V_TYPE)
#define DEV_DISK        (1 << DEV_V_TYPE)               /* sim_disk Attach */
#define DEV_TAPE        (2 << DEV_V_TYPE)               /* sim_tape Attach */
#define DEV_MUX         (3 << DEV_V_TYPE)               /* sim_tmxr Attach */
#define DEV_ETHER       (4 << DEV_V_TYPE)               /* Ethernet Device */
#define DEV_DISPLAY     (5 << DEV_V_TYPE)               /* Display Device */
#define DEV_TYPE(dptr)  ((dptr)->flags & DEV_TYPEMASK)

#define DEV_UFMASK_31   (((1u << DEV_V_RSV) - 1) & ~((1u << DEV_V_UF_31) - 1))
#define DEV_UFMASK      (((1u << DEV_V_RSV) - 1) & ~((1u << DEV_V_UF) - 1))
#define DEV_RFLAGS      (DEV_UFMASK|DEV_DIS)            /* restored flags */

/* Unit data structure

   Parts of the unit structure are device specific, that is, they are
   not referenced by the simulator control package and can be freely
   used by device simulators.  Fields starting with 'buf', and flags
   starting with 'UF', are device specific.  The definitions given here
   are for a typical sequential device.
*/

struct UNIT {
    UNIT                *next;                          /* next active */
    t_stat              (*action)(UNIT *up);            /* action routine */
    char                *filename;                      /* open file name */
    FILE                *fileref;                       /* file reference */
    void                *filebuf;                       /* memory buffer */
    uint32              hwmark;                         /* high water mark */
    int32               time;                           /* time out */
    uint32              flags;                          /* flags */
    uint32              dynflags;                       /* dynamic flags */
    t_addr              capac;                          /* capacity */
    t_addr              pos;                            /* file position */
    void                (*io_flush)(UNIT *up);          /* io flush routine */
    uint32              iostarttime;                    /* I/O start time */
    int32               buf;                            /* buffer */
    int32               wait;                           /* wait */
    int32               u3;                             /* device specific */
    int32               u4;                             /* device specific */
    int32               u5;                             /* device specific */
    int32               u6;                             /* device specific */
    void                *up7;                           /* device specific */
    void                *up8;                           /* device specific */
    uint16              us9;                            /* device specific */
    uint16              us10;                           /* device specific */
    void                *tmxr;                          /* TMXR linkage */
    t_bool              (*cancel)(UNIT *);
    double              usecs_remaining;                /* time balance for long delays */
    char                *uname;                         /* Unit name */
#ifdef SIM_ASYNCH_IO
    void                (*a_check_completion)(UNIT *);
    t_bool              (*a_is_active)(UNIT *);
    UNIT                *a_next;                        /* next asynch active */
    int32               a_event_time;
    ACTIVATE_API        a_activate_call;
    /* Asynchronous Polling control */
    /* These fields should only be referenced when holding the sim_tmxr_poll_lock */
    t_bool              a_polling_now;                  /* polling active flag */
    int32               a_poll_waiter_count;            /* count of polling threads */
                                                        /* waiting for this unit */
    /* Asynchronous Timer control */
    double              a_due_time;                     /* due time for timer event */
    double              a_due_gtime;                    /* due time (in instructions) for timer event */
    double              a_usec_delay;                   /* time delay for timer event */
#endif
    };

/* Unit flags */

#define UNIT_V_UF_31    12              /* dev spec, V3.1 */
#define UNIT_V_UF       16              /* device specific */
#define UNIT_V_RSV      31              /* reserved!! */

#define UNIT_ATTABLE    0000001         /* attachable */
#define UNIT_RO         0000002         /* read only */
#define UNIT_FIX        0000004         /* fixed capacity */
#define UNIT_SEQ        0000010         /* sequential */
#define UNIT_ATT        0000020         /* attached */
#define UNIT_BINK       0000040         /* K = power of 2 */
#define UNIT_BUFABLE    0000100         /* bufferable */
#define UNIT_MUSTBUF    0000200         /* must buffer */
#define UNIT_BUF        0000400         /* buffered */
#define UNIT_ROABLE     0001000         /* read only ok */
#define UNIT_DISABLE    0002000         /* disable-able */
#define UNIT_DIS        0004000         /* disabled */
#define UNIT_IDLE       0040000         /* idle eligible */

/* Unused/meaningless flags */
#define UNIT_TEXT       0000000         /* text mode - no effect */

#define UNIT_UFMASK_31  (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF_31) - 1))
#define UNIT_UFMASK     (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1))
#define UNIT_RFLAGS     (UNIT_UFMASK|UNIT_DIS)          /* restored flags */

/* Unit dynamic flags (dynflags) */

/* These flags are only set dynamically */

#define UNIT_ATTMULT    0000001         /* Allow multiple attach commands */
#define UNIT_TM_POLL    0000002         /* TMXR Polling unit */
#define UNIT_NO_FIO     0000004         /* fileref is NOT a FILE * */
#define UNIT_DISK_CHK   0000010         /* disk data debug checking (sim_disk) */
#define UNIT_TMR_UNIT   0000020         /* Unit registered as a calibrated timer */
#define UNIT_V_DF_TAPE  5               /* Bit offset for Tape Density reservation */
#define UNIT_S_DF_TAPE  3               /* Bits Reserved for Tape Density */

struct BITFIELD {
    const char      *name;                              /* field name */
    uint32          offset;                             /* starting bit */
    uint32          width;                              /* width */
    const char      **valuenames;                       /* map of values to strings */
    const char      *format;                            /* value format string */
    };

/* Register data structure */

struct REG {
    CONST char          *name;                          /* name */
    void                *loc;                           /* location */
    uint32              radix;                          /* radix */
    uint32              width;                          /* width */
    uint32              offset;                         /* starting bit */
    uint32              depth;                          /* save depth */
    const char          *desc;                          /* description */
    BITFIELD            *fields;                        /* bit fields */
    uint32              flags;                          /* flags */
    uint32              qptr;                           /* circ q ptr */
    size_t              str_size;                       /* structure size */
    };

/* Register flags */

#define REG_FMT         00003                           /* see PV_x */
#define REG_RO          00004                           /* read only */
#define REG_HIDDEN      00010                           /* hidden */
#define REG_NZ          00020                           /* must be non-zero */
#define REG_UNIT        00040                           /* in unit struct */
#define REG_STRUCT      00100                           /* in structure array */
#define REG_CIRC        00200                           /* circular array */
#define REG_VMIO        00400                           /* use VM data print/parse */
#define REG_VMAD        01000                           /* use VM addr print/parse */
#define REG_FIT         02000                           /* fit access to size */
#define REG_HRO         (REG_RO | REG_HIDDEN)           /* hidden, read only */

#define REG_V_UF        16                              /* device specific */
#define REG_UFMASK      (~((1u << REG_V_UF) - 1))       /* user flags mask */
#define REG_VMFLAGS     (REG_VMIO | REG_UFMASK)         /* call VM routine if any of these are set */

/* Command tables, base and alternate formats */

struct CTAB {
    const char          *name;                          /* name */
    t_stat              (*action)(int32 flag, CONST char *cptr);
                                                        /* action routine */
    int32               arg;                            /* argument */
    const char          *help;                          /* help string/structured locator */
    const char          *help_base;                     /* structured help base*/
    void                (*message)(const char *unechoed_cmdline, t_stat stat);
                                                        /* message printing routine */
    };

struct C1TAB {
    const char          *name;                          /* name */
    t_stat              (*action)(DEVICE *dptr, UNIT *uptr,
                            int32 flag, CONST char *cptr);/* action routine */
    int32               arg;                            /* argument */
    const char          *help;                          /* help string */
    };

struct SHTAB {
    const char          *name;                          /* name */
    t_stat              (*action)(FILE *st, DEVICE *dptr,
                            UNIT *uptr, int32 flag, CONST char *cptr);
    int32               arg;                            /* argument */
    const char          *help;                          /* help string */
    };

/* Modifier table - only extended entries have disp, reg, or flags */

struct MTAB {
    uint32              mask;                           /* mask */
    uint32              match;                          /* match */
    const char          *pstring;                       /* print string */
    const char          *mstring;                       /* match string */
    t_stat              (*valid)(UNIT *up, int32 v, CONST char *cp, void *dp);
                                                        /* validation routine */
    t_stat              (*disp)(FILE *st, UNIT *up, int32 v, CONST void *dp);
                                                        /* display routine */
    void                *desc;                          /* value descriptor */
                                                        /* REG * if MTAB_VAL */
                                                        /* int * if not */
    const char          *help;                          /* help string */
    };


/* mtab mask flag bits */
/* NOTE: MTAB_VALR and MTAB_VALO are only used to display help */
#define MTAB_XTD        (1u << UNIT_V_RSV)              /* ext entry flag */
#define MTAB_VDV        (0001 | MTAB_XTD)               /* valid for dev */
#define MTAB_VUN        (0002 | MTAB_XTD)               /* valid for unit */
#define MTAB_VALR       (0004 | MTAB_XTD)               /* takes a value (required) */
#define MTAB_VALO       (0010 | MTAB_XTD)               /* takes a value (optional) */
#define MTAB_NMO        (0020 | MTAB_XTD)               /* only if named */
#define MTAB_NC         (0040 | MTAB_XTD)               /* no UC conversion */
#define MTAB_QUOTE      (0100 | MTAB_XTD)               /* quoted string */
#define MTAB_SHP        (0200 | MTAB_XTD)               /* show takes parameter */
#define MODMASK(mptr,flag) (((mptr)->mask & (uint32)(flag)) == (uint32)(flag))/* flag mask test */

/* Search table */

struct SCHTAB {
    int32               logic;                          /* logical operator */
    int32               boolop;                         /* boolean operator */
    uint32              count;                          /* value count in mask and comp arrays */
    t_value             *mask;                          /* mask for logical */
    t_value             *comp;                          /* comparison for boolean */
    };

/* Breakpoint table */

struct BRKTAB {
    t_addr              addr;                           /* address */
    uint32              typ;                            /* mask of types */
#define BRK_TYP_USR_TYPES       ((1 << ('Z'-'A'+1)) - 1)/* all types A-Z */
#define BRK_TYP_DYN_STEPOVER    (SWMASK ('Z'+1))
#define BRK_TYP_DYN_USR         (SWMASK ('Z'+2))
#define BRK_TYP_DYN_ALL         (BRK_TYP_DYN_USR|BRK_TYP_DYN_STEPOVER) /* Mask of All Dynamic types */
#define BRK_TYP_TEMP            (SWMASK ('Z'+3))        /* Temporary (one-shot) */
#define BRK_TYP_MAX             (('Z'-'A')+3)           /* Maximum breakpoint type */
    int32               cnt;                            /* proceed count */
    char                *act;                           /* action string */
    double              time_fired[SIM_BKPT_N_SPC];     /* instruction count when match occurred */
    BRKTAB *next;                                       /* list with same address value */
    };

/* Breakpoint table */

struct BRKTYPTAB {
    uint32      btyp;                                   /* type mask */
    const char *desc;                                   /* description */
    };
#define BRKTYPE(typ,descrip) {SWMASK(typ), descrip}

/* Expect rule */

struct EXPTAB {
    uint8               *match;                         /* match string */
    uint32              size;                           /* match string size */
    char                *match_pattern;                 /* match pattern for format */
    int32               cnt;                            /* proceed count */
    int32               switches;                       /* flags */
#define EXP_TYP_PERSIST         (SWMASK ('P'))      /* rule persists after match, default is once a rule matches, it is removed */
#define EXP_TYP_CLEARALL        (SWMASK ('C'))      /* clear all rules after matching this rule, default is to once a rule matches, it is removed */
#define EXP_TYP_REGEX           (SWMASK ('R'))      /* rule pattern is a regular expression */
#define EXP_TYP_REGEX_I         (SWMASK ('I'))      /* regular expression pattern matching should be case independent */
#define EXP_TYP_TIME            (SWMASK ('T'))      /* halt delay is in microseconds instead of instructions */
#if defined(USE_REGEX)
    regex_t             regex;                          /* compiled regular expression */
#endif
    char                *act;                           /* action string */
    };

/* Expect Context */

struct EXPECT {
    DEVICE              *dptr;                          /* Device (for Debug) */
    uint32              dbit;                           /* Debugging Bit */
    EXPTAB              *rules;                         /* match rules */
    int32               size;                           /* count of match rules */
    uint32              after;                          /* delay before halting */
    uint8               *buf;                           /* buffer of output data which has produced */
    uint32              buf_ins;                        /* buffer insertion point for the next output data */
    uint32              buf_size;                       /* buffer size */
    };

/* Send Context */

struct SEND {
    uint32              delay;                          /* instruction delay between sent data */
#define SEND_DEFAULT_DELAY  1000                        /* default delay instruction count */
    DEVICE              *dptr;                          /* Device (for Debug) */
    uint32              dbit;                           /* Debugging Bit */
    uint32              after;                          /* instruction delay before sending any data */
    double              next_time;                      /* execution time when next data can be sent */
    uint8               *buffer;                        /* buffer */
    size_t              bufsize;                        /* buffer size */
    int32               insoff;                         /* insert offset */
    int32               extoff;                         /* extra offset */
    };

/* Debug table */

struct DEBTAB {
    const char          *name;                          /* control name */
    uint32              mask;                           /* control bit */
    const char          *desc;                          /* description */
    };

/* Deprecated Debug macros.  Use sim_debug() */

#define DEBUG_PRS(d)    (sim_deb && d.dctrl)
#define DEBUG_PRD(d)    (sim_deb && d->dctrl)
#define DEBUG_PRI(d,m)  (sim_deb && (d.dctrl & (m)))
#define DEBUG_PRJ(d,m)  (sim_deb && ((d)->dctrl & (m)))

#define SIM_DBG_EVENT       0x10000
#define SIM_DBG_ACTIVATE    0x20000
#define SIM_DBG_AIO_QUEUE   0x40000

/* Open File Reference */
struct FILEREF {
    char                name[CBUFSIZE];                 /* file name */
    FILE                *file;                          /* file handle */
    int32               refcount;                       /* reference count */
    };

struct MEMFILE {
    char                *buf;                           /* buffered data */
    size_t              size;                        /* size */
    size_t              pos;                         /* data used */
    };
/* 
   The following macros exist to help populate structure contents

   They are dependent on the declaration order of the fields 
   of the structures they exist to populate.

 */

#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),0,(cap),0,NULL,0,0

#if defined (__STDC__) || defined (_WIN32) /* Variants which depend on how macro arguments are convered to strings */
/* Generic Register declaration for all fields.  
   If the register structure is extended, this macro will be retained and a 
   new macro will be provided that populates the new register structure */
#define REGDATA(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \
    #nm, &(loc), (rdx), (wd), (off), (dep), (desc), (flds), (fl), (qptr), (siz)
/* Right Justified Octal Register Data */
#define ORDATA(nm,loc,wd) #nm, &(loc), 8, (wd), 0, 1, NULL, NULL
/* Right Justified Decimal Register Data */
#define DRDATA(nm,loc,wd) #nm, &(loc), 10, (wd), 0, 1, NULL, NULL
/* Right Justified Hexadecimal Register Data */
#define HRDATA(nm,loc,wd) #nm, &(loc), 16, (wd), 0, 1, NULL, NULL
/* Right Justified Binary Register Data */
#define BINRDATA(nm,loc,wd) #nm, &(loc), 2, (wd), 0, 1, NULL, NULL
/* One-bit binary flag at an arbitrary offset in a 32-bit word Register */
#define FLDATA(nm,loc,pos) #nm, &(loc), 2, 1, (pos), 1, NULL, NULL
/* Arbitrary location and Radix Register */
#define GRDATA(nm,loc,rdx,wd,pos) #nm, &(loc), (rdx), (wd), (pos), 1, NULL, NULL
/* Arrayed register whose data is kept in a standard C array Register */
#define BRDATA(nm,loc,rdx,wd,dep) #nm, (loc), (rdx), (wd), 0, (dep), NULL, NULL
/* Same as above, but with additional description initializer */
#define ORDATAD(nm,loc,wd,desc) #nm, &(loc), 8, (wd), 0, 1, (desc), NULL
#define DRDATAD(nm,loc,wd,desc) #nm, &(loc), 10, (wd), 0, 1, (desc), NULL
#define HRDATAD(nm,loc,wd,desc) #nm, &(loc), 16, (wd), 0, 1, (desc), NULL
#define BINRDATAD(nm,loc,wd,desc) #nm, &(loc), 2, (wd), 0, 1, (desc), NULL
#define FLDATAD(nm,loc,pos,desc) #nm, &(loc), 2, 1, (pos), 1, (desc), NULL
#define GRDATAD(nm,loc,rdx,wd,pos,desc) #nm, &(loc), (rdx), (wd), (pos), 1, (desc), NULL
#define BRDATAD(nm,loc,rdx,wd,dep,desc) #nm, (loc), (rdx), (wd), 0, (dep), (desc), NULL
/* Same as above, but with additional description initializer, and bitfields */
#define ORDATADF(nm,loc,wd,desc,flds) #nm, &(loc), 8, (wd), 0, 1, (desc), (flds)
#define DRDATADF(nm,loc,wd,desc,flds) #nm, &(loc), 10, (wd), 0, 1, (desc), (flds)
#define HRDATADF(nm,loc,wd,desc,flds) #nm, &(loc), 16, (wd), 0, 1, (desc), (flds)
#define BINRDATADF(nm,loc,wd) #nm, &(loc), 2, (wd), 0, 1, NULL, NULL
#define FLDATADF(nm,loc,pos,desc,flds) #nm, &(loc), 2, 1, (pos), 1, (desc), (flds)
#define GRDATADF(nm,loc,rdx,wd,pos,desc,flds) #nm, &(loc), (rdx), (wd), (pos), 1, (desc), (flds)
#define BRDATADF(nm,loc,rdx,wd,dep,desc,flds) #nm, (loc), (rdx), (wd), 0, (dep), (desc), (flds)
#define BIT(nm)              {#nm, 0xffffffff, 1}             /* Single Bit definition */
#define BITNC                {"",  0xffffffff, 1}             /* Don't care Bit definition */
#define BITF(nm,sz)          {#nm, 0xffffffff, sz}            /* Bit Field definition */
#define BITNCF(sz)           {"",  0xffffffff, sz}            /* Don't care Bit Field definition */
#define BITFFMT(nm,sz,fmt)   {#nm, 0xffffffff, sz, NULL, #fmt}/* Bit Field definition with Output format */
#define BITFNAM(nm,sz,names) {#nm, 0xffffffff, sz, names}     /* Bit Field definition with value->name map */
#else /* For non-STD-C compiler which can't stringify macro arguments with # */
#define REGDATA(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \
    "nm", &(loc), (rdx), (wd), (off), (dep), (desc), (flds), (fl), (qptr), (siz)
#define ORDATA(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1, NULL, NULL
#define DRDATA(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1, NULL, NULL
#define HRDATA(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1, NULL, NULL
#define BINRDATA(nm,loc,wd) "nm", &(loc), 2, (wd), 0, 1, NULL, NULL
#define FLDATA(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1, NULL, NULL
#define GRDATA(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1, NULL, NULL
#define BRDATA(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep), NULL, NULL
#define ORDATAD(nm,loc,wd,desc) "nm", &(loc), 8, (wd), 0, 1, (desc), NULL
#define DRDATAD(nm,loc,wd,desc) "nm", &(loc), 10, (wd), 0, 1, (desc), NULL
#define HRDATAD(nm,loc,wd,desc) "nm", &(loc), 16, (wd), 0, 1, (desc), NULL
#define BINRDATAD(nm,loc,wd,desc) "nm", &(loc), 2, (wd), 0, 1, (desc), NULL
#define FLDATAD(nm,loc,pos,desc) "nm", &(loc), 2, 1, (pos), 1, (desc), NULL
#define GRDATAD(nm,loc,rdx,wd,pos,desc) "nm", &(loc), (rdx), (wd), (pos), 1, (desc), NULL
#define BRDATAD(nm,loc,rdx,wd,dep,desc) "nm", (loc), (rdx), (wd), 0, (dep), (desc), NULL
#define ORDATADF(nm,loc,wd,desc,flds) "nm", &(loc), 8, (wd), 0, 1, (desc), (flds)
#define DRDATADF(nm,loc,wd,desc,flds) "nm", &(loc), 10, (wd), 0, 1, (desc), (flds)
#define HRDATADF(nm,loc,wd,desc,flds) "nm", &(loc), 16, (wd), 0, 1, (desc), (flds)
#define BINRDATADF(nm,loc,wd,desc,flds) "nm", &(loc), 2, (wd), 0, 1, (desc), (flds)
#define FLDATADF(nm,loc,pos,desc,flds) "nm", &(loc), 2, 1, (pos), 1, (desc), (flds)
#define GRDATADF(nm,loc,rdx,wd,pos,desc,flds) "nm", &(loc), (rdx), (wd), (pos), 1, (desc), (flds)
#define BRDATADF(nm,loc,rdx,wd,dep,desc,flds) "nm", (loc), (rdx), (wd), 0, (dep), (desc), (flds)
#define BIT(nm)              {"nm", 0xffffffff, 1}              /* Single Bit definition */
#define BITNC                {"",   0xffffffff, 1}              /* Don't care Bit definition */
#define BITF(nm,sz)          {"nm", 0xffffffff, sz}             /* Bit Field definition */
#define BITNCF(sz)           {"",   0xffffffff, sz}             /* Don't care Bit Field definition */
#define BITFFMT(nm,sz,fmt)   {"nm", 0xffffffff, sz, NULL, "fmt"}/* Bit Field definition with Output format */
#define BITFNAM(nm,sz,names) {"nm", 0xffffffff, sz, names}      /* Bit Field definition with value->name map */
#endif
#define ENDBITS {NULL}  /* end of bitfield list */

/* Arrayed register whose data is part of the UNIT structure */
#define URDATA(nm,loc,rdx,wd,off,dep,fl) \
    REGDATA(nm,(loc),(rdx),(wd),(off),(dep),NULL,NULL,((fl) | REG_UNIT),0,0)
/* Arrayed register whose data is part of an arbitrary structure */
#define STRDATA(nm,loc,rdx,wd,off,dep,siz,fl) \
    REGDATA(nm,(loc),(rdx),(wd),(off),(dep),NULL,NULL,((fl) | REG_STRUCT),0,(siz))
/* Same as above, but with additional description initializer */
#define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) \
    REGDATA(nm,(loc),(rdx),(wd),(off),(dep),(desc),NULL,((fl) | REG_UNIT),0,0)
#define STRDATAD(nm,loc,rdx,wd,off,dep,siz,fl,desc) \
    REGDATA(nm,(loc),(rdx),(wd),(off),(dep),(desc),NULL,((fl) | REG_STRUCT),0,(siz))
/* Same as above, but with additional description initializer, and bitfields */
#define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc,flds) \
    REGDATA(nm,(loc),(rdx),(wd),(off),(dep),(desc),(flds),((fl) | REG_UNIT),0,0)
#define STRDATADF(nm,loc,rdx,wd,off,dep,siz,fl,desc,flds) \
    REGDATA(nm,(loc),(rdx),(wd),(off),(dep),(desc),(flds),((fl) | REG_STRUCT),0,(siz))

/* Function prototypes */

#include "scp.h"
#include "sim_console.h"
#include "sim_timer.h"
#include "sim_fio.h"

/* Macro to ALWAYS execute the specified expression and fail if it evaluates to false. */
/* This replaces any references to "assert()" which should never be invoked */
/* with an expression which causes side effects (i.e. must be executed for */
/* the program to work correctly) */
#define ASSURE(_Expression) while (!(_Expression)) {fprintf(stderr, "%s failed at %s line %d\n", #_Expression, __FILE__, __LINE__);  \
                                                    sim_printf("%s failed at %s line %d\n", #_Expression, __FILE__, __LINE__);       \
                                                    abort();}

/* Asynch/Threaded I/O support */

#if defined (SIM_ASYNCH_IO)
#include <pthread.h>

#define SIM_ASYNCH_CLOCKS 1

extern pthread_mutex_t sim_asynch_lock;
extern pthread_cond_t sim_asynch_wake;
extern pthread_mutex_t sim_timer_lock;
extern pthread_cond_t sim_timer_wake;
extern t_bool sim_timer_event_canceled;
extern int32 sim_tmxr_poll_count;
extern pthread_cond_t sim_tmxr_poll_cond;
extern pthread_mutex_t sim_tmxr_poll_lock;
extern pthread_t sim_asynch_main_threadid;
extern UNIT * volatile sim_asynch_queue;
extern volatile t_bool sim_idle_wait;
extern int32 sim_asynch_check;
extern int32 sim_asynch_latency;
extern int32 sim_asynch_inst_latency;

/* Thread local storage */
#if defined(__GNUC__) && !defined(__APPLE__) && !defined(__hpux) && !defined(__OpenBSD__) && !defined(_AIX)
#define AIO_TLS __thread
#elif defined(_MSC_VER)
#define AIO_TLS __declspec(thread)
#else
/* Other compiler environment, then don't worry about thread local storage. */
/* It is primarily used only used in debugging messages */
#define AIO_TLS
#endif
#define AIO_QUEUE_CHECK(que, lock)                              \
    do {                                                        \
        UNIT *_cptr;                                            \
        if (lock)                                               \
            pthread_mutex_lock (lock);                          \
        for (_cptr = que;                                       \
            (_cptr != QUEUE_LIST_END);                          \
            _cptr = _cptr->next)                                \
            if (!_cptr->next) {                                 \
                if (sim_deb) {                                  \
                    sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Queue Corruption detected\n");\
                    fclose(sim_deb);                            \
                    }                                           \
                sim_printf("Queue Corruption detected\n");      \
                abort();                                        \
                }                                               \
        if (lock)                                               \
            pthread_mutex_unlock (lock);                        \
        } while (0)
#define AIO_MAIN_THREAD (pthread_equal ( pthread_self(), sim_asynch_main_threadid ))
#define AIO_LOCK                                                  \
    pthread_mutex_lock(&sim_asynch_lock)
#define AIO_UNLOCK                                                \
    pthread_mutex_unlock(&sim_asynch_lock)
#define AIO_IS_ACTIVE(uptr) (((uptr)->a_is_active ? (uptr)->a_is_active (uptr) : FALSE) || ((uptr)->a_next))
#if defined(SIM_ASYNCH_MUX)
#define AIO_CANCEL(uptr)                                      \
    if (((uptr)->dynflags & UNIT_TM_POLL) &&                  \
        !((uptr)->next) && !((uptr)->a_next)) {               \
        (uptr)->a_polling_now = FALSE;                        \
        sim_tmxr_poll_count -= (uptr)->a_poll_waiter_count;   \
        (uptr)->a_poll_waiter_count = 0;                      \
        }
#endif /* defined(SIM_ASYNCH_MUX) */
#if !defined(AIO_CANCEL)
#define AIO_CANCEL(uptr)
#endif /* !defined(AIO_CANCEL) */
#define AIO_EVENT_BEGIN(uptr)                                     \
    do {                                                          \
        int __was_poll = uptr->dynflags & UNIT_TM_POLL
#define AIO_EVENT_COMPLETE(uptr, reason)                          \
        if (__was_poll) {                                         \
            pthread_mutex_lock (&sim_tmxr_poll_lock);             \
            uptr->a_polling_now = FALSE;                          \
            if (uptr->a_poll_waiter_count) {                      \
                sim_tmxr_poll_count -= uptr->a_poll_waiter_count; \
                uptr->a_poll_waiter_count = 0;                    \
                if (0 == sim_tmxr_poll_count)                     \
                    pthread_cond_broadcast (&sim_tmxr_poll_cond); \
                }                                                 \
            pthread_mutex_unlock (&sim_tmxr_poll_lock);           \
            }                                                     \
        AIO_UPDATE_QUEUE;                                         \
        } while (0)

#if defined(__DECC_VER)
#include <builtins>
#if defined(__IA64)
#define USE_AIO_INTRINSICS 1
#endif
#endif
#if defined(_WIN32) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#define USE_AIO_INTRINSICS 1
#endif
/* Provide a way to test both Intrinsic and Lock based queue manipulations  */
/* when both are available on a particular platform                         */
#if defined(DONT_USE_AIO_INTRINSICS) && defined(USE_AIO_INTRINSICS)
#undef USE_AIO_INTRINSICS
#endif
#ifdef USE_AIO_INTRINSICS
/* This approach uses intrinsics to manage access to the link list head     */
/* sim_asynch_queue.  This implementation is a completely lock free design  */
/* which avoids the potential ABA issues.                                   */
#define AIO_QUEUE_MODE "Lock free asynchronous event queue"
#define AIO_INIT                                                  \
    do {                                                          \
      int tmr;                                                    \
      sim_asynch_main_threadid = pthread_self();                  \
      /* Empty list/list end uses the point value (void *)1.      \
         This allows NULL in an entry's a_next pointer to         \
         indicate that the entry is not currently in any list */  \
      sim_asynch_queue = QUEUE_LIST_END;                          \
      for (tmr=0; tmr<SIM_NTIMERS; tmr++)                         \
          sim_clock_cosched_queue[tmr] = QUEUE_LIST_END;          \
      } while (0)
#define AIO_CLEANUP                                               \
    do {                                                          \
      pthread_mutex_destroy(&sim_asynch_lock);                    \
      pthread_cond_destroy(&sim_asynch_wake);                     \
      pthread_mutex_destroy(&sim_timer_lock);                     \
      pthread_cond_destroy(&sim_timer_wake);                      \
      pthread_mutex_destroy(&sim_tmxr_poll_lock);                 \
      pthread_cond_destroy(&sim_tmxr_poll_cond);                  \
      } while (0)
#ifdef _WIN32
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)
#define InterlockedCompareExchangePointer(Destination, Exchange, Comparand) __sync_val_compare_and_swap(Destination, Comparand, Exchange)
#elif defined(__DECC_VER)
#define InterlockedCompareExchangePointer(Destination, Exchange, Comparand) (void *)((int32)_InterlockedCompareExchange64(Destination, Exchange, Comparand))
#else
#error "Implementation of function InterlockedCompareExchangePointer() is needed to build with USE_AIO_INTRINSICS"
#endif
#define AIO_ILOCK AIO_LOCK
#define AIO_IUNLOCK AIO_UNLOCK
#define AIO_QUEUE_VAL (UNIT *)(InterlockedCompareExchangePointer((void * volatile *)&sim_asynch_queue, (void *)sim_asynch_queue, NULL))
#define AIO_QUEUE_SET(newval, oldval) (UNIT *)(InterlockedCompareExchangePointer((void * volatile *)&sim_asynch_queue, (void *)newval, oldval))
#define AIO_UPDATE_QUEUE sim_aio_update_queue ()
#define AIO_ACTIVATE(caller, uptr, event_time)                                   \
    if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) {           \
      sim_aio_activate ((ACTIVATE_API)caller, uptr, event_time);                 \
      return SCPE_OK;                                                            \
    } else (void)0
#else /* !USE_AIO_INTRINSICS */
/* This approach uses a pthread mutex to manage access to the link list     */
/* head sim_asynch_queue.  It will always work, but may be slower than the  */
/* lock free approach when using USE_AIO_INTRINSICS                         */
#define AIO_QUEUE_MODE "Lock based asynchronous event queue"
#define AIO_INIT                                                  \
    do {                                                          \
      int tmr;                                                    \
      pthread_mutexattr_t attr;                                   \
                                                                  \
      pthread_mutexattr_init (&attr);                             \
      pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);  \
      pthread_mutex_init (&sim_asynch_lock, &attr);               \
      pthread_mutexattr_destroy (&attr);                          \
      sim_asynch_main_threadid = pthread_self();                  \
      /* Empty list/list end uses the point value (void *)1.      \
         This allows NULL in an entry's a_next pointer to         \
         indicate that the entry is not currently in any list */  \
      sim_asynch_queue = QUEUE_LIST_END;                          \
      for (tmr=0; tmr<SIM_NTIMERS; tmr++)                         \
          sim_clock_cosched_queue[tmr] = QUEUE_LIST_END;          \
      } while (0)
#define AIO_CLEANUP                                               \
    do {                                                          \
      pthread_mutex_destroy(&sim_asynch_lock);                    \
      pthread_cond_destroy(&sim_asynch_wake);                     \
      pthread_mutex_destroy(&sim_timer_lock);                     \
      pthread_cond_destroy(&sim_timer_wake);                      \
      pthread_mutex_destroy(&sim_tmxr_poll_lock);                 \
      pthread_cond_destroy(&sim_tmxr_poll_cond);                  \
      } while (0)
#define AIO_ILOCK AIO_LOCK
#define AIO_IUNLOCK AIO_UNLOCK
#define AIO_QUEUE_VAL sim_asynch_queue
#define AIO_QUEUE_SET(newval, oldval) ((sim_asynch_queue = newval),oldval)
#define AIO_UPDATE_QUEUE sim_aio_update_queue ()
#define AIO_ACTIVATE(caller, uptr, event_time)                         \
    if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
      sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch event for %s after %d instructions\n", sim_uname(uptr), event_time);\
      AIO_LOCK;                                                        \
      if (uptr->a_next) {                       /* already queued? */  \
        uptr->a_activate_call = sim_activate_abs;                      \
      } else {                                                         \
        uptr->a_next = sim_asynch_queue;                               \
        uptr->a_event_time = event_time;                               \
        uptr->a_activate_call = (ACTIVATE_API)&caller;                 \
        sim_asynch_queue = uptr;                                       \
      }                                                                \
      if (sim_idle_wait) {                                             \
        sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(uptr), event_time);\
        pthread_cond_signal (&sim_asynch_wake);                        \
        }                                                              \
      AIO_UNLOCK;                                                      \
      sim_asynch_check = 0;                                            \
      return SCPE_OK;                                                  \
    } else (void)0
#endif /* USE_AIO_INTRINSICS */
#define AIO_VALIDATE if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) {sim_printf("Improper thread context for operation\n"); abort();}
#define AIO_CHECK_EVENT                                                \
    if (0 > --sim_asynch_check) {                                      \
      AIO_UPDATE_QUEUE;                                                \
      sim_asynch_check = sim_asynch_inst_latency;                      \
      } else (void)0
#define AIO_SET_INTERRUPT_LATENCY(instpersec)                                                   \
    do {                                                                                        \
      sim_asynch_inst_latency = (int32)((((double)(instpersec))*sim_asynch_latency)/1000000000);\
      if (sim_asynch_inst_latency == 0)                                                         \
        sim_asynch_inst_latency = 1;                                                            \
      } while (0)
#else /* !SIM_ASYNCH_IO */
#define AIO_QUEUE_MODE "Asynchronous I/O is not available"
#define AIO_UPDATE_QUEUE
#define AIO_ACTIVATE(caller, uptr, event_time)
#define AIO_VALIDATE
#define AIO_CHECK_EVENT
#define AIO_INIT
#define AIO_MAIN_THREAD TRUE
#define AIO_LOCK
#define AIO_UNLOCK
#define AIO_CLEANUP
#define AIO_EVENT_BEGIN(uptr)
#define AIO_EVENT_COMPLETE(uptr, reason)
#define AIO_IS_ACTIVE(uptr) FALSE
#define AIO_CANCEL(uptr)
#define AIO_SET_INTERRUPT_LATENCY(instpersec)
#define AIO_TLS
#endif /* SIM_ASYNCH_IO */

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_disk.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
/* sim_disk.c: simulator disk support library

   Copyright (c) 2011, Mark Pizzolato

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the names of Mark Pizzolato shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Mark Pizzolato.



   This is the place which hides processing of various disk formats,
   as well as OS-specific direct hardware access.

   25-Jan-11    MP      Initial Implemementation

Public routines:

   sim_disk_attach           attach disk unit
   sim_disk_detach           detach disk unit
   sim_disk_attach_help      help routine for attaching disks
   sim_disk_rdsect           read disk sectors
   sim_disk_rdsect_a         read disk sectors asynchronously
   sim_disk_wrsect           write disk sectors
   sim_disk_wrsect_a         write disk sectors asynchronously
   sim_disk_unload           unload or detach a disk as needed
   sim_disk_reset            reset unit
   sim_disk_wrp              TRUE if write protected
   sim_disk_isavailable      TRUE if available for I/O
   sim_disk_size             get disk size
   sim_disk_set_fmt          set disk format
   sim_disk_show_fmt         show disk format
   sim_disk_set_capac        set disk capacity
   sim_disk_show_capac       show disk capacity
   sim_disk_set_async        enable asynchronous operation
   sim_disk_clr_async        disable asynchronous operation
   sim_disk_data_trace       debug support

Internal routines:

   sim_os_disk_open_raw      platform specific open raw device
   sim_os_disk_close_raw     platform specific close raw device
   sim_os_disk_size_raw      platform specific raw device size
   sim_os_disk_unload_raw    platform specific disk unload/eject
   sim_os_disk_rdsect        platform specific read sectors
   sim_os_disk_wrsect        platform specific write sectors

   sim_vhd_disk_open         platform independent open virtual disk file
   sim_vhd_disk_create       platform independent create virtual disk file
   sim_vhd_disk_create_diff  platform independent create differencing virtual disk file
   sim_vhd_disk_close        platform independent close virtual disk file
   sim_vhd_disk_size         platform independent virtual disk size
   sim_vhd_disk_rdsect       platform independent read virtual disk sectors
   sim_vhd_disk_wrsect       platform independent write virtual disk sectors


*/

#define _FILE_OFFSET_BITS 64    /* 64 bit file offset for raw I/O operations  */

#include "sim_defs.h"
#include "sim_disk.h"
#include "sim_ether.h"
#include <ctype.h>
#include <sys/stat.h>

#ifdef _WIN32
#include <windows.h>
#endif
#if defined SIM_ASYNCH_IO
#include <pthread.h>
#endif

struct disk_context {
    DEVICE              *dptr;              /* Device for unit (access to debug flags) */
    uint32              dbit;               /* debugging bit */
    uint32              sector_size;        /* Disk Sector Size (of the pseudo disk) */
    uint32              capac_factor;       /* Units of Capacity (2 = word, 1 = byte) */
    uint32              xfer_element_size;  /* Disk Bus Transfer size (1 - byte, 2 - word, 4 - longword) */
    uint32              storage_sector_size;/* Sector size of the containing storage */
    uint32              removable;          /* Removable device flag */
    uint32              auto_format;        /* Format determined dynamically */
#if defined _WIN32
    HANDLE              disk_handle;        /* OS specific Raw device handle */
#endif
#if defined SIM_ASYNCH_IO
    int                 asynch_io;          /* Asynchronous Interrupt scheduling enabled */
    int                 asynch_io_latency;  /* instructions to delay pending interrupt */
    pthread_mutex_t     lock;
    pthread_t           io_thread;          /* I/O Thread Id */
    pthread_mutex_t     io_lock;
    pthread_cond_t      io_cond;
    pthread_cond_t      io_done;
    pthread_cond_t      startup_cond;
    int                 io_dop;
    uint8               *buf;
    t_seccnt            *rsects;
    t_seccnt            sects;
    t_lba               lba;
    DISK_PCALLBACK      callback;
    t_stat              io_status;
#endif
    };

#define disk_ctx up8                        /* Field in Unit structure which points to the disk_context */

#if defined SIM_ASYNCH_IO
#define AIO_CALLSETUP                                               \
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;   \
                                                                    \
if ((!callback) || !ctx->asynch_io)

#define AIO_CALL(op, _lba, _buf, _rsects, _sects,  _callback)   \
    if (ctx->asynch_io) {                                       \
        struct disk_context *ctx =                              \
                      (struct disk_context *)uptr->disk_ctx;    \
                                                                \
        pthread_mutex_lock (&ctx->io_lock);                     \
                                                                \
        sim_debug (ctx->dbit, ctx->dptr,                        \
      "sim_disk AIO_CALL(op=%d, unit=%d, lba=0x%X, sects=%d)\n",\
                op, (int)(uptr-ctx->dptr->units), _lba, _sects);\
                                                                \
        if (ctx->callback)                                      \
            abort(); /* horrible mistake, stop */               \
        ctx->io_dop = op;                                       \
        ctx->lba = _lba;                                        \
        ctx->buf = _buf;                                        \
        ctx->sects = _sects;                                    \
        ctx->rsects = _rsects;                                  \
        ctx->callback = _callback;                              \
        pthread_cond_signal (&ctx->io_cond);                    \
        pthread_mutex_unlock (&ctx->io_lock);                   \
        }                                                       \
    else                                                        \
        if (_callback)                                          \
            (_callback) (uptr, r);


#define DOP_DONE  0             /* close */
#define DOP_RSEC  1             /* sim_disk_rdsect_a */
#define DOP_WSEC  2             /* sim_disk_wrsect_a */
#define DOP_IAVL  3             /* sim_disk_isavailable_a */

static void *
_disk_io(void *arg)
{
UNIT* volatile uptr = (UNIT*)arg;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

/* Boost Priority for this I/O thread vs the CPU instruction execution
   thread which in general won't be readily yielding the processor when
   this thread needs to run */
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) starting\n", (int)(uptr-ctx->dptr->units));

pthread_mutex_lock (&ctx->io_lock);
pthread_cond_signal (&ctx->startup_cond);   /* Signal we're ready to go */
while (ctx->asynch_io) {
    pthread_cond_wait (&ctx->io_cond, &ctx->io_lock);
    if (ctx->io_dop == DOP_DONE)
        break;
    pthread_mutex_unlock (&ctx->io_lock);
    switch (ctx->io_dop) {
        case DOP_RSEC:
            ctx->io_status = sim_disk_rdsect (uptr, ctx->lba, ctx->buf, ctx->rsects, ctx->sects);
            break;
        case DOP_WSEC:
            ctx->io_status = sim_disk_wrsect (uptr, ctx->lba, ctx->buf, ctx->rsects, ctx->sects);
            break;
        case DOP_IAVL:
            ctx->io_status = sim_disk_isavailable (uptr);
            break;
        }
    pthread_mutex_lock (&ctx->io_lock);
    ctx->io_dop = DOP_DONE;
    pthread_cond_signal (&ctx->io_done);
    sim_activate (uptr, ctx->asynch_io_latency);
    }
pthread_mutex_unlock (&ctx->io_lock);

sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) exiting\n", (int)(uptr-ctx->dptr->units));

return NULL;
}

/* This routine is called in the context of the main simulator thread before
   processing events for any unit. It is only called when an asynchronous
   thread has called sim_activate() to activate a unit.  The job of this
   routine is to put the unit in proper condition to digest what may have
   occurred in the asynchrconous thread.
  
   Since disk processing only handles a single I/O at a time to a
   particular disk device (due to using stdio for the SimH Disk format
   and stdio doesn't have an atomic seek+(read|write) operation),
   we have the opportunity to possibly detect improper attempts to
   issue multiple concurrent I/O requests. */
static void _disk_completion_dispatch (UNIT *uptr)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
DISK_PCALLBACK callback = ctx->callback;

sim_debug (ctx->dbit, ctx->dptr, "_disk_completion_dispatch(unit=%d, dop=%d, callback=%p)\n", (int)(uptr-ctx->dptr->units), ctx->io_dop, ctx->callback);

if (ctx->io_dop != DOP_DONE)
    abort();                                            /* horribly wrong, stop */

if (ctx->callback && ctx->io_dop == DOP_DONE) {
    ctx->callback = NULL;
    callback (uptr, ctx->io_status);
    }
}

static t_bool _disk_is_active (UNIT *uptr)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

if (ctx) {
    sim_debug (ctx->dbit, ctx->dptr, "_disk_is_active(unit=%d, dop=%d)\n", (int)(uptr-ctx->dptr->units), ctx->io_dop);
    return (ctx->io_dop != DOP_DONE);
    }
return FALSE;
}

static t_bool _disk_cancel (UNIT *uptr)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

if (ctx) {
    sim_debug (ctx->dbit, ctx->dptr, "_disk_cancel(unit=%d, dop=%d)\n", (int)(uptr-ctx->dptr->units), ctx->io_dop);
    if (ctx->asynch_io) {
        pthread_mutex_lock (&ctx->io_lock);
        while (ctx->io_dop != DOP_DONE)
            pthread_cond_wait (&ctx->io_done, &ctx->io_lock);
        pthread_mutex_unlock (&ctx->io_lock);
        }
    }
return FALSE;
}
#else
#define AIO_CALLSETUP
#define AIO_CALL(op, _lba, _buf, _rsects, _sects,  _callback)   \
    if (_callback)                                              \
        (_callback) (uptr, r);
#endif

/* Forward declarations */

static t_stat sim_vhd_disk_implemented (void);
static FILE *sim_vhd_disk_open (const char *rawdevicename, const char *openmode);
static FILE *sim_vhd_disk_create (const char *szVHDPath, t_offset desiredsize);
static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szParentVHDPath);
static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD);
static int sim_vhd_disk_close (FILE *f);
static void sim_vhd_disk_flush (FILE *f);
static t_offset sim_vhd_disk_size (FILE *f);
static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
static t_stat sim_vhd_disk_clearerr (UNIT *uptr);
static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype);
static const char *sim_vhd_disk_get_dtype (FILE *f);
static t_stat sim_os_disk_implemented_raw (void);
static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode);
static int sim_os_disk_close_raw (FILE *f);
static void sim_os_disk_flush_raw (FILE *f);
static t_offset sim_os_disk_size_raw (FILE *f);
static t_stat sim_os_disk_unload_raw (FILE *f);
static t_bool sim_os_disk_isavailable_raw (FILE *f);
static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable);
static char *HostPathToVhdPath (const char *szHostPath, char *szVhdPath, size_t VhdPathSize);
static char *VhdPathToHostPath (const char *szVhdPath, char *szHostPath, size_t HostPathSize);
static t_offset get_filesystem_size (UNIT *uptr);

struct sim_disk_fmt {
    const char          *name;                          /* name */
    int32               uflags;                         /* unit flags */
    int32               fmtval;                         /* Format type value */
    t_stat              (*impl_fnc)(void);              /* Implemented Test Function */
    };

static struct sim_disk_fmt fmts[DKUF_N_FMT] = {
    { "SIMH", 0, DKUF_F_STD, NULL},
    { "RAW",  0, DKUF_F_RAW, sim_os_disk_implemented_raw},
    { "VHD",  0, DKUF_F_VHD, sim_vhd_disk_implemented},
    { NULL,   0, 0}
    };

/* Set disk format */

t_stat sim_disk_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 f;

if (uptr == NULL)
    return SCPE_IERR;
if (cptr == NULL)
    return SCPE_ARG;
for (f = 0; f < DKUF_N_FMT && fmts[f].name; f++) {
    if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) {
        if ((fmts[f].impl_fnc) && (fmts[f].impl_fnc() != SCPE_OK))
            return SCPE_NOFNC;
        uptr->flags = (uptr->flags & ~DKUF_FMT) |
            (fmts[f].fmtval << DKUF_V_FMT) | fmts[f].uflags;
        return SCPE_OK;
        }
    }
return SCPE_ARG;
}

/* Show disk format */

t_stat sim_disk_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 f = DK_GET_FMT (uptr);
size_t i;

for (i = 0; i < DKUF_N_FMT; i++)
    if (fmts[i].fmtval == f) {
        fprintf (st, "%s format", fmts[i].name);
        return SCPE_OK;
        }
fprintf (st, "invalid format");
return SCPE_OK;
}

/* Set disk capacity */

t_stat sim_disk_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_offset cap;
t_stat r;
DEVICE *dptr = find_dev_from_unit (uptr);

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_ARG;
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;
cap = (t_offset) get_uint (cptr, 10, sim_taddr_64? 2000000: 2000, &r);
if (r != SCPE_OK)
    return SCPE_ARG;
uptr->capac = (t_addr)((cap * ((t_offset) 1000000))/((dptr->flags & DEV_SECTORS) ? 512 : 1));
return SCPE_OK;
}

/* Show disk capacity */

t_stat sim_disk_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
const char *cap_units = "B";
DEVICE *dptr = find_dev_from_unit (uptr);
t_offset capac = ((t_offset)uptr->capac)*((dptr->flags & DEV_SECTORS) ? 512 : 1);

if ((dptr->dwidth / dptr->aincr) == 16)
    cap_units = "W";
if (capac) {
    if (capac >= (t_offset) 1000000)
        fprintf (st, "capacity=%dM%s", (uint32) (capac / ((t_offset) 1000000)), cap_units);
    else if (uptr->capac >= (t_addr) 1000)
        fprintf (st, "capacity=%dK%s", (uint32) (capac / ((t_offset) 1000)), cap_units);
    else fprintf (st, "capacity=%d%s", (uint32) capac, cap_units);
    }
else fprintf (st, "undefined capacity");
return SCPE_OK;
}

/* Test for available */

t_bool sim_disk_isavailable (UNIT *uptr)
{
if (!(uptr->flags & UNIT_ATT))                          /* attached? */
    return FALSE;
switch (DK_GET_FMT (uptr)) {                            /* case on format */
    case DKUF_F_STD:                                    /* SIMH format */
        return TRUE;
    case DKUF_F_VHD:                                    /* VHD format */
        return TRUE;
        break;
    case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
        return sim_os_disk_isavailable_raw (uptr->fileref);
        break;
    default:
        return FALSE;
    }
}

t_bool sim_disk_isavailable_a (UNIT *uptr, DISK_PCALLBACK callback)
{
t_bool r = FALSE;
AIO_CALLSETUP
    r = sim_disk_isavailable (uptr);
AIO_CALL(DOP_IAVL, 0, NULL, NULL, 0, callback);
return r;
}

/* Test for write protect */

t_bool sim_disk_wrp (UNIT *uptr)
{
return (uptr->flags & DKUF_WRP)? TRUE: FALSE;
}

/* Get Disk size */

t_offset sim_disk_size (UNIT *uptr)
{
t_offset physical_size, filesystem_size;
t_bool saved_quiet = sim_quiet;

switch (DK_GET_FMT (uptr)) {                            /* case on format */
    case DKUF_F_STD:                                    /* SIMH format */
        physical_size = sim_fsize_ex (uptr->fileref);
        break;
    case DKUF_F_VHD:                                    /* VHD format */
        physical_size = sim_vhd_disk_size (uptr->fileref);
        break;
    case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
        physical_size = sim_os_disk_size_raw (uptr->fileref);
        break;
    default:
        return (t_offset)-1;
    }
sim_quiet = TRUE;
filesystem_size = get_filesystem_size (uptr);
sim_quiet = saved_quiet;
if ((filesystem_size == (t_offset)-1) ||
    (filesystem_size < physical_size))
    return physical_size;
return filesystem_size;
}

/* Enable asynchronous operation */

t_stat sim_disk_set_async (UNIT *uptr, int latency)
{
#if !defined(SIM_ASYNCH_IO)
char *msg = "Disk: can't operate asynchronously\r\n";
sim_printf ("%s", msg);
return SCPE_NOFNC;
#else
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
pthread_attr_t attr;

sim_debug (ctx->dbit, ctx->dptr, "sim_disk_set_async(unit=%d)\n", (int)(uptr-ctx->dptr->units));

ctx->asynch_io = sim_asynch_enabled;
ctx->asynch_io_latency = latency;
if (ctx->asynch_io) {
    pthread_mutex_init (&ctx->io_lock, NULL);
    pthread_cond_init (&ctx->io_cond, NULL);
    pthread_cond_init (&ctx->io_done, NULL);
    pthread_cond_init (&ctx->startup_cond, NULL);
    pthread_attr_init(&attr);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_mutex_lock (&ctx->io_lock);
    pthread_create (&ctx->io_thread, &attr, _disk_io, (void *)uptr);
    pthread_attr_destroy(&attr);
    pthread_cond_wait (&ctx->startup_cond, &ctx->io_lock); /* Wait for thread to stabilize */
    pthread_mutex_unlock (&ctx->io_lock);
    pthread_cond_destroy (&ctx->startup_cond);
    }
uptr->a_check_completion = _disk_completion_dispatch;
uptr->a_is_active = _disk_is_active;
uptr->cancel = _disk_cancel;
return SCPE_OK;
#endif
}

/* Disable asynchronous operation */

t_stat sim_disk_clr_async (UNIT *uptr)
{
#if !defined(SIM_ASYNCH_IO)
return SCPE_NOFNC;
#else
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

/* make sure device exists */
if (!ctx) return SCPE_UNATT;

sim_debug (ctx->dbit, ctx->dptr, "sim_disk_clr_async(unit=%d)\n", (int)(uptr-ctx->dptr->units));

if (ctx->asynch_io) {
    pthread_mutex_lock (&ctx->io_lock);
    ctx->asynch_io = 0;
    pthread_cond_signal (&ctx->io_cond);
    pthread_mutex_unlock (&ctx->io_lock);
    pthread_join (ctx->io_thread, NULL);
    pthread_mutex_destroy (&ctx->io_lock);
    pthread_cond_destroy (&ctx->io_cond);
    pthread_cond_destroy (&ctx->io_done);
    }
return SCPE_OK;
#endif
}

/* Read Sectors */

static t_stat _sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
t_offset da;
uint32 err, tbc;
size_t i;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

da = ((t_offset)lba) * ctx->sector_size;
tbc = sects * ctx->sector_size;
if (sectsread)
    *sectsread = 0;
err = sim_fseeko (uptr->fileref, da, SEEK_SET);          /* set pos */
if (!err) {
    i = sim_fread (buf, ctx->xfer_element_size, tbc/ctx->xfer_element_size, uptr->fileref);
    if (i < tbc/ctx->xfer_element_size)                 /* fill */
        memset (&buf[i*ctx->xfer_element_size], 0, tbc-(i*ctx->xfer_element_size));
    err = ferror (uptr->fileref);
    if ((!err) && (sectsread))
        *sectsread = (t_seccnt)((i*ctx->xfer_element_size+ctx->sector_size-1)/ctx->sector_size);
    }
return err;
}

t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
t_stat r;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_seccnt sread = 0;

sim_debug (ctx->dbit, ctx->dptr, "sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

if ((sects == 1) &&                                     /* Single sector reads */
    (lba >= (uptr->capac*ctx->capac_factor)/(ctx->sector_size/((ctx->dptr->flags & DEV_SECTORS) ? 512 : 1)))) {/* beyond the end of the disk */
    memset (buf, '\0', ctx->sector_size);               /* are bad block management efforts - zero buffer */
    if (sectsread)
        *sectsread = 1;
    return SCPE_OK;                                     /* return success */
    }

if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) ||   /* Sector Aligned & whole sector transfers */
    ((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) &&
     (0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) {
    switch (DK_GET_FMT (uptr)) {                        /* case on format */
        case DKUF_F_STD:                                /* SIMH format */
            return _sim_disk_rdsect (uptr, lba, buf, sectsread, sects);
        case DKUF_F_VHD:                                /* VHD format */
            r = sim_vhd_disk_rdsect (uptr, lba, buf, &sread, sects);
            break;
        case DKUF_F_RAW:                                /* Raw Physical Disk Access */
            r = sim_os_disk_rdsect (uptr, lba, buf, &sread, sects);
            break;
        default:
            return SCPE_NOFNC;
        }
    if (sectsread)
        *sectsread = sread;
    if (r != SCPE_OK)
        return r;
    sim_buf_swap_data (buf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size);
    return r;
    }
else { /* Unaligned and/or partial sector transfers */
    uint8 *tbuf = (uint8*) malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size);
    t_lba sspsts = ctx->storage_sector_size/ctx->sector_size; /* sim sectors in a storage sector */
    t_lba tlba = lba & ~(sspsts - 1);
    t_seccnt tsects = sects + (lba - tlba);

    tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1);
    if (sectsread)
        *sectsread = 0;
    if (tbuf == NULL)
        return SCPE_MEM;
    switch (DK_GET_FMT (uptr)) {                        /* case on format */
        case DKUF_F_STD:                                /* SIMH format */
            r = _sim_disk_rdsect (uptr, tlba, tbuf, &sread, tsects);
            break;
        case DKUF_F_VHD:                                /* VHD format */
            r = sim_vhd_disk_rdsect (uptr, tlba, tbuf, &sread, tsects);
            if (r == SCPE_OK)
                sim_buf_swap_data (tbuf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size);
            break;
        case DKUF_F_RAW:                                /* Raw Physical Disk Access */
            r = sim_os_disk_rdsect (uptr, tlba, tbuf, &sread, tsects);
            if (r == SCPE_OK)
                sim_buf_swap_data (tbuf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size);
            break;
        default:
            free (tbuf);
            return SCPE_NOFNC;
        }
    if (r == SCPE_OK) {
        memcpy (buf, tbuf + ((lba - tlba) * ctx->sector_size), sects * ctx->sector_size);
        if (sectsread) {
            *sectsread = sread - (lba - tlba);
            if (*sectsread > sects)
                *sectsread = sects;
            }
        }
    free (tbuf);
    return r;
    }
}

t_stat sim_disk_rdsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects, DISK_PCALLBACK callback)
{
t_stat r = SCPE_OK;
AIO_CALLSETUP
    r = sim_disk_rdsect (uptr, lba, buf, sectsread, sects);
AIO_CALL(DOP_RSEC, lba, buf, sectsread, sects, callback);
return r;
}

/* Write Sectors */

static t_stat _sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{
t_offset da;
uint32 err, tbc;
size_t i;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

da = ((t_offset)lba) * ctx->sector_size;
tbc = sects * ctx->sector_size;
if (sectswritten)
    *sectswritten = 0;
err = sim_fseeko (uptr->fileref, da, SEEK_SET);          /* set pos */
if (!err) {
    i = sim_fwrite (buf, ctx->xfer_element_size, tbc/ctx->xfer_element_size, uptr->fileref);
    err = ferror (uptr->fileref);
    if ((!err) && (sectswritten))
        *sectswritten = (t_seccnt)((i*ctx->xfer_element_size+ctx->sector_size-1)/ctx->sector_size);
    }
return err;
}

t_stat sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
uint32 f = DK_GET_FMT (uptr);
t_stat r;
uint8 *tbuf = NULL;

sim_debug (ctx->dbit, ctx->dptr, "sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

if (uptr->dynflags & UNIT_DISK_CHK) {
    DEVICE *dptr = find_dev_from_unit (uptr);
    uint32 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 1) */
    t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/(ctx->sector_size/((dptr->flags & DEV_SECTORS) ? 512 : 1)));
    t_lba sect;

    for (sect = 0; sect < sects; sect++) {
        t_lba offset;
        t_bool sect_error = FALSE;

        for (offset = 0; offset < ctx->sector_size; offset += sizeof(uint32)) {
            if (*((uint32 *)&buf[sect*ctx->sector_size + offset]) != (uint32)(lba + sect)) {
                sect_error = TRUE;
                break;
                }
            }
        if (sect_error) {
            uint32 save_dctrl = dptr->dctrl;
            FILE *save_sim_deb = sim_deb;

            sim_printf ("\n%s%d: Write Address Verification Error on lbn %d(0x%X) of %d(0x%X).\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)(lba+sect), (int)(lba+sect), (int)total_sectors, (int)total_sectors);
            dptr->dctrl = 0xFFFFFFFF;
            sim_deb = save_sim_deb ? save_sim_deb : stdout;
            sim_disk_data_trace (uptr, buf+sect*ctx->sector_size, lba+sect, ctx->sector_size,    "Found", TRUE, 1);
            dptr->dctrl = save_dctrl;
            sim_deb = save_sim_deb;
            }
        }
    }
if (f == DKUF_F_STD)
    return _sim_disk_wrsect (uptr, lba, buf, sectswritten, sects);
if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) ||   /* Sector Aligned & whole sector transfers */
    ((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) &&
     (0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) {

    if (sim_end || (ctx->xfer_element_size == sizeof (char)))
        switch (DK_GET_FMT (uptr)) {                            /* case on format */
            case DKUF_F_VHD:                                    /* VHD format */
                return sim_vhd_disk_wrsect  (uptr, lba, buf, sectswritten, sects);
            case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
                return sim_os_disk_wrsect  (uptr, lba, buf, sectswritten, sects);
            default:
                return SCPE_NOFNC;
            }

    tbuf = (uint8*) malloc (sects * ctx->sector_size);
    if (NULL == tbuf)
        return SCPE_MEM;
    sim_buf_copy_swapped (tbuf, buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);

    switch (DK_GET_FMT (uptr)) {                            /* case on format */
        case DKUF_F_VHD:                                    /* VHD format */
            r = sim_vhd_disk_wrsect (uptr, lba, tbuf, sectswritten, sects);
            break;
        case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
            r = sim_os_disk_wrsect (uptr, lba, tbuf, sectswritten, sects);
            break;
        default:
            r = SCPE_NOFNC;
            break;
        }
    }
else { /* Unaligned and/or partial sector transfers */
    t_lba sspsts = ctx->storage_sector_size/ctx->sector_size; /* sim sectors in a storage sector */
    t_lba tlba = lba & ~(sspsts - 1);
    t_seccnt tsects = sects + (lba - tlba);

    tbuf = (uint8*) malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size);
    tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1);
    if (sectswritten)
        *sectswritten = 0;
    if (tbuf == NULL)
        return SCPE_MEM;
    /* Partial Sector writes require a read-modify-write sequence for the partial sectors */
    if ((lba & (sspsts - 1)) ||
        (sects < sspsts))
        switch (DK_GET_FMT (uptr)) {                            /* case on format */
            case DKUF_F_VHD:                                    /* VHD format */
                sim_vhd_disk_rdsect (uptr, tlba, tbuf, NULL, sspsts);
                break;
            case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
                sim_os_disk_rdsect (uptr, tlba, tbuf, NULL, sspsts);
                break;
            default:
                r = SCPE_NOFNC;
                break;
            }
    if ((tsects > sspsts) &&
        ((sects + lba - tlba) & (sspsts - 1)))
        switch (DK_GET_FMT (uptr)) {                            /* case on format */
            case DKUF_F_VHD:                                    /* VHD format */
                sim_vhd_disk_rdsect (uptr, tlba + tsects - sspsts,
                                     tbuf + (tsects - sspsts) * ctx->sector_size,
                                     NULL, sspsts);
                break;
            case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
                sim_os_disk_rdsect (uptr, tlba + tsects - sspsts,
                                    tbuf + (tsects - sspsts) * ctx->sector_size,
                                    NULL, sspsts);
                break;
            default:
                r = SCPE_NOFNC;
                break;
            }
    sim_buf_copy_swapped (tbuf + (lba & (sspsts - 1)) * ctx->sector_size,
                          buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);
    switch (DK_GET_FMT (uptr)) {                            /* case on format */
        case DKUF_F_VHD:                                    /* VHD format */
            r = sim_vhd_disk_wrsect (uptr, tlba, tbuf, sectswritten, tsects);
            break;
        case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
            r = sim_os_disk_wrsect (uptr, tlba, tbuf, sectswritten, tsects);
            break;
        default:
            r = SCPE_NOFNC;
            break;
        }
    if ((r == SCPE_OK) && sectswritten) {
        *sectswritten -= (lba - tlba);
        if (*sectswritten > sects)
            *sectswritten = sects;
        }
    }
free (tbuf);
return r;
}

t_stat sim_disk_wrsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects, DISK_PCALLBACK callback)
{
t_stat r = SCPE_OK;
AIO_CALLSETUP
    r =  sim_disk_wrsect (uptr, lba, buf, sectswritten, sects);
AIO_CALL(DOP_WSEC, lba, buf, sectswritten, sects, callback);
return r;
}

t_stat sim_disk_unload (UNIT *uptr)
{
switch (DK_GET_FMT (uptr)) {                            /* case on format */
    case DKUF_F_STD:                                    /* Simh */
    case DKUF_F_VHD:                                    /* VHD format */
        return sim_disk_detach (uptr);
    case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
        return sim_os_disk_unload_raw (uptr->fileref);  /* remove/eject disk */
        break;
    default:
        return SCPE_NOFNC;
    }
}

/*
   This routine is called when the simulator stops and any time
   the asynch mode is changed (enabled or disabled)
*/
static void _sim_disk_io_flush (UNIT *uptr)
{
uint32 f = DK_GET_FMT (uptr);

#if defined (SIM_ASYNCH_IO)
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

sim_disk_clr_async (uptr);
if (sim_asynch_enabled)
    sim_disk_set_async (uptr, ctx->asynch_io_latency);
#endif
switch (f) {                                            /* case on format */
    case DKUF_F_STD:                                    /* Simh */
        fflush (uptr->fileref);
        break;
    case DKUF_F_VHD:                                    /* Virtual Disk */
        sim_vhd_disk_flush (uptr->fileref);
        break;
    case DKUF_F_RAW:                                    /* Physical */
        sim_os_disk_flush_raw (uptr->fileref);
        break;
        }
}

static t_stat _err_return (UNIT *uptr, t_stat stat)
{
free (uptr->filename);
uptr->filename = NULL;
free (uptr->disk_ctx);
uptr->disk_ctx = NULL;
return stat;
}

#pragma pack(push,1)
typedef struct _ODS1_HomeBlock
    {
    uint16  hm1_w_ibmapsize;
    uint32  hm1_l_ibmaplbn;
    uint16  hm1_w_maxfiles;
    uint16  hm1_w_cluster;
    uint16  hm1_w_devtype;
    uint16  hm1_w_structlev;
#define HM1_C_LEVEL1    0401
#define HM1_C_LEVEL2    0402
    uint8   hm1_t_volname[12];
    uint8   hm1_b_fill_1[4];
    uint16  hm1_w_volowner;
    uint16  hm1_w_protect;
    uint16  hm1_w_volchar;
    uint16  hm1_w_fileprot;
    uint8   hm1_b_fill_2[6];
    uint8   hm1_b_window;
    uint8   hm1_b_extend;
    uint8   hm1_b_lru_lim;
    uint8   hm1_b_fill_3[11];
    uint16  hm1_w_checksum1;
    uint8   hm1_t_credate[14];
    uint8   hm1_b_fill_4[382];
    uint32  hm1_l_serialnum;
    uint8   hm1_b_fill_5[12];
    uint8   hm1_t_volname2[12];
    uint8   hm1_t_ownername[12];
    uint8   hm1_t_format[12];
    uint8   hm1_t_fill_6[2];
    uint16  hm1_w_checksum2;
    } ODS1_HomeBlock;

    typedef struct _ODS2_HomeBlock
    {
    uint32 hm2_l_homelbn;
    uint32 hm2_l_alhomelbn;
    uint32 hm2_l_altidxlbn;
    uint8  hm2_b_strucver;
    uint8  hm2_b_struclev;
    uint16 hm2_w_cluster;
    uint16 hm2_w_homevbn;
    uint16 hm2_w_alhomevbn;
    uint16 hm2_w_altidxvbn;
    uint16 hm2_w_ibmapvbn;
    uint32 hm2_l_ibmaplbn;
    uint32 hm2_l_maxfiles;
    uint16 hm2_w_ibmapsize;
    uint16 hm2_w_resfiles;
    uint16 hm2_w_devtype;
    uint16 hm2_w_rvn;
    uint16 hm2_w_setcount;
    uint16 hm2_w_volchar;
    uint32 hm2_l_volowner;
    uint32 hm2_l_reserved;
    uint16 hm2_w_protect;
    uint16 hm2_w_fileprot;
    uint16 hm2_w_reserved;
    uint16 hm2_w_checksum1;
    uint32 hm2_q_credate[2];
    uint8  hm2_b_window;
    uint8  hm2_b_lru_lim;
    uint16 hm2_w_extend;
    uint32 hm2_q_retainmin[2];
    uint32 hm2_q_retainmax[2];
    uint32 hm2_q_revdate[2];
    uint8  hm2_r_min_class[20];
    uint8  hm2_r_max_class[20];
    uint8  hm2_r_reserved[320];
    uint32 hm2_l_serialnum;
    uint8  hm2_t_strucname[12];
    uint8  hm2_t_volname[12];
    uint8  hm2_t_ownername[12];
    uint8  hm2_t_format[12];
    uint16 hm2_w_reserved2;
    uint16 hm2_w_checksum2;
    } ODS2_HomeBlock;

typedef struct _ODS1_FileHeader
    {
    uint8   fh1_b_idoffset;
    uint8   fh1_b_mpoffset;
    uint16  fh1_w_fid_num;
    uint16  fh1_w_fid_seq;
    uint16  fh1_w_struclev;
    uint16  fh1_w_fileowner;
    uint16  fh1_w_fileprot;
    uint16  fh1_w_filechar;
    uint16  fh1_w_recattr;
    uint8   fh1_b_fill_1[494];
    uint16  fh1_w_checksum;
    } ODS1_FileHeader;

typedef struct _ODS2_FileHeader
    {
    uint8  fh2_b_idoffset;
    uint8  fh2_b_mpoffset;
    uint8  fh2_b_acoffset;
    uint8  fh2_b_rsoffset;
    uint16 fh2_w_seg_num;
    uint16 fh2_w_structlev;
    uint16 fh2_w_fid[3];
    uint16 fh2_w_ext_fid[3];
    uint16 fh2_w_recattr[16];
    uint32 fh2_l_filechar;
    uint16 fh2_w_remaining[228];
    } ODS2_FileHeader;

typedef union _ODS2_Retreval
    {
        struct 
            {
            unsigned fm2___fill   : 14;       /* type specific data               */
            unsigned fm2_v_format : 2;        /* format type code                 */
            } fm2_r_word0_bits;
        struct
            {
            unsigned fm2_v_exact    : 1;      /* exact placement specified        */
            unsigned fm2_v_oncyl    : 1;      /* on cylinder allocation desired   */
            unsigned fm2___fill     : 10;
            unsigned fm2_v_lbn      : 1;      /* use LBN of next map pointer      */
            unsigned fm2_v_rvn      : 1;      /* place on specified RVN           */
            unsigned fm2_v_format0  : 2;
            } fm2_r_map_bits0;
        struct
            {
            unsigned fm2_b_count1   : 8;      /* low byte described below         */
            unsigned fm2_v_highlbn1 : 6;      /* high order LBN                   */
            unsigned fm2_v_format1  : 2;
            unsigned fm2_w_lowlbn1  : 16;     /* low order LBN                    */
            } fm2_r_map_bits1;
        struct
            {
            struct
                {
                unsigned fm2_v_count2   : 14; /* count field                      */
                unsigned fm2_v_format2  : 2;
                unsigned fm2_l_lowlbn2  : 16; /* low order LBN                    */
                } fm2_r_map2_long0;
            uint16 fm2_l_highlbn2;            /* high order LBN                   */
            } fm2_r_map_bits2;
        struct
            {
            struct
                {
                unsigned fm2_v_highcount3 : 14; /* low order count field          */
                unsigned fm2_v_format3  : 2;
                unsigned fm2_w_lowcount3 : 16;  /* high order count field         */
                } fm2_r_map3_long0;
            uint32 fm2_l_lbn3;
            } fm2_r_map_bits3;
    } ODS2_Retreval;

typedef struct _ODS1_Retreval
    {
    uint8   fm1_b_ex_segnum;
    uint8   fm1_b_ex_rvn;
    uint16  fm1_w_ex_filnum;
    uint16  fm1_w_ex_filseq;
    uint8   fm1_b_countsize;
    uint8   fm1_b_lbnsize;
    uint8   fm1_b_inuse;
    uint8   fm1_b_avail;
    union {
        struct {
            uint8 fm1_b_highlbn;
            uint8 fm1_b_count;
            uint16 fm1_w_lowlbn;
            } fm1_s_fm1def1;
        struct {
            uint8 fm1_b_highlbn;
            uint8 fm1_b_count;
            uint16 fm1_w_lowlbn;
            } fm1_s_fm1def2;
        } fm1_pointers[4];
    } ODS1_Retreval;

typedef struct _ODS1_StorageControlBlock
    {
    uint8  scb_b_unused[3];
    uint8  scb_b_bitmapblks;
    struct _bitmapblk {
        uint16 scb_w_freeblks;
        uint16 scb_w_freeptr;
        } scb_r_blocks[1];
    } ODS1_SCB;


typedef struct _ODS2_StorageControlBlock
    {
    uint8  scb_b_strucver;   /* 1 */
    uint8  scb_b_struclev;   /* 2 */
    uint16 scb_w_cluster;
    uint32 scb_l_volsize;
    uint32 scb_l_blksize;
    uint32 scb_l_sectors;
    uint32 scb_l_tracks;
    uint32 scb_l_cylinder;
    uint32 scb_l_status;
    uint32 scb_l_status2;
    uint16 scb_w_writecnt;
    uint8  scb_t_volockname[12];
    uint32 scb_q_mounttime[2];
    uint16 scb_w_backrev;
    uint32 scb_q_genernum[2];
    uint8  scb_b_reserved[446];
    uint16 scb_w_checksum;
    } ODS2_SCB;
#pragma pack(pop)

static uint16
ODSChecksum (void *Buffer, uint16 WordCount)
    {
    int i;
    uint16 Sum = 0;
    uint16 CheckSum = 0;
    uint16 *Buf = (uint16 *)Buffer;

    for (i=0; i<WordCount; i++)
        CheckSum += Buf[i];
    return CheckSum;
    }


static t_offset get_ods2_filesystem_size (UNIT *uptr)
{
DEVICE *dptr;
t_addr saved_capac;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu;  /* Make sure we can access the largest sector */
uint32 capac_factor;
ODS2_HomeBlock Home;
ODS2_FileHeader Header;
ODS2_Retreval *Retr;
ODS2_SCB Scb;
uint16 CheckSum1, CheckSum2;
uint32 ScbLbn = 0;
t_offset ret_val = (t_offset)-1;

if ((dptr = find_dev_from_unit (uptr)) == NULL)
    return ret_val;
capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
saved_capac = uptr->capac;
uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
if (sim_disk_rdsect (uptr, 512 / ctx->sector_size, (uint8 *)&Home, NULL, sizeof (Home) / ctx->sector_size))
    goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm2_w_checksum1)-((char *)&Home.hm2_l_homelbn))/2));
CheckSum2 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm2_w_checksum2)-((char *)&Home.hm2_l_homelbn))/2));
if ((Home.hm2_l_homelbn == 0) || 
    (Home.hm2_l_alhomelbn == 0) || 
    (Home.hm2_l_altidxlbn == 0) || 
    ((Home.hm2_b_struclev != 2) && (Home.hm2_b_struclev != 5)) || 
    (Home.hm2_b_strucver == 0) || 
    (Home.hm2_w_cluster == 0) || 
    (Home.hm2_w_homevbn == 0) || 
    (Home.hm2_w_alhomevbn == 0) || 
    (Home.hm2_w_ibmapvbn == 0) || 
    (Home.hm2_l_ibmaplbn == 0) || 
    (Home.hm2_w_resfiles >= Home.hm2_l_maxfiles) || 
    (Home.hm2_w_ibmapsize == 0) || 
    (Home.hm2_w_resfiles < 5) || 
    (Home.hm2_w_checksum1 != CheckSum1) ||
    (Home.hm2_w_checksum2 != CheckSum2))
    goto Return_Cleanup;
if (sim_disk_rdsect (uptr, (Home.hm2_l_ibmaplbn+Home.hm2_w_ibmapsize+1) * (512 / ctx->sector_size), 
                           (uint8 *)&Header, NULL, sizeof (Header) / ctx->sector_size))
    goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Header, 255);
if (CheckSum1 != *(((uint16 *)&Header)+255)) /* Verify Checksum on BITMAP.SYS file header */
    goto Return_Cleanup;
Retr = (ODS2_Retreval *)(((uint16*)(&Header))+Header.fh2_b_mpoffset);
/* The BitMap File has a single extent, which may be preceeded by a placement descriptor */
if (Retr->fm2_r_word0_bits.fm2_v_format == 0)
    Retr = (ODS2_Retreval *)(((uint16 *)Retr)+1); /* skip placement descriptor */
switch (Retr->fm2_r_word0_bits.fm2_v_format)
    {
    case 1:
        ScbLbn = (Retr->fm2_r_map_bits1.fm2_v_highlbn1<<16)+Retr->fm2_r_map_bits1.fm2_w_lowlbn1;
        break;
    case 2:
        ScbLbn = (Retr->fm2_r_map_bits2.fm2_l_highlbn2<<16)+Retr->fm2_r_map_bits2.fm2_r_map2_long0.fm2_l_lowlbn2;
        break;
    case 3:
        ScbLbn = Retr->fm2_r_map_bits3.fm2_l_lbn3;
        break;
    }
Retr = (ODS2_Retreval *)(((uint16 *)Retr)+Retr->fm2_r_word0_bits.fm2_v_format+1);
if (sim_disk_rdsect (uptr, ScbLbn * (512 / ctx->sector_size), (uint8 *)&Scb, NULL, sizeof (Scb) / ctx->sector_size))
    goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Scb, 255);
if (CheckSum1 != *(((uint16 *)&Scb)+255)) /* Verify Checksum on Storage Control Block */
    goto Return_Cleanup;
if ((Scb.scb_w_cluster != Home.hm2_w_cluster) || 
    (Scb.scb_b_strucver != Home.hm2_b_strucver) ||
    (Scb.scb_b_struclev != Home.hm2_b_struclev))
    goto Return_Cleanup;
if (!sim_quiet) {
    sim_printf ("%s%d: '%s' Contains ODS%d File system\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename, Home.hm2_b_struclev);
    sim_printf ("%s%d: Volume Name: %12.12s ", sim_dname (dptr), (int)(uptr-dptr->units), Home.hm2_t_volname);
    sim_printf ("Format: %12.12s ", Home.hm2_t_format);
    sim_printf ("Sectors In Volume: %u\n", Scb.scb_l_volsize);
    }
ret_val = ((t_offset)Scb.scb_l_volsize) * 512;

Return_Cleanup:
uptr->capac = saved_capac;
return ret_val;
}

static t_offset get_ods1_filesystem_size (UNIT *uptr)
{
DEVICE *dptr;
t_addr saved_capac;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu;  /* Make sure we can access the largest sector */
uint32 capac_factor;
ODS1_HomeBlock Home;
ODS1_FileHeader Header;
ODS1_Retreval *Retr;
uint8 scb_buf[512];
ODS1_SCB *Scb = (ODS1_SCB *)scb_buf;
uint16 CheckSum1, CheckSum2;
uint32 ScbLbn;
t_offset ret_val = (t_offset)-1;

if ((dptr = find_dev_from_unit (uptr)) == NULL)
    return ret_val;
capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
saved_capac = uptr->capac;
uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
if (sim_disk_rdsect (uptr, 512 / ctx->sector_size, (uint8 *)&Home, NULL, sizeof (Home) / ctx->sector_size))
    goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm1_w_checksum1)-((char *)&Home.hm1_w_ibmapsize))/2));
CheckSum2 = ODSChecksum (&Home, (uint16)((((char *)&Home.hm1_w_checksum2)-((char *)&Home.hm1_w_ibmapsize))/2));
if ((Home.hm1_w_ibmapsize == 0) || 
    (Home.hm1_l_ibmaplbn == 0) || 
    (Home.hm1_w_maxfiles == 0) || 
    (Home.hm1_w_cluster != 1) || 
    ((Home.hm1_w_structlev != HM1_C_LEVEL1) && (Home.hm1_w_structlev != HM1_C_LEVEL2)) || 
    (Home.hm1_l_ibmaplbn == 0) || 
    (Home.hm1_w_checksum1 != CheckSum1) ||
    (Home.hm1_w_checksum2 != CheckSum2))
    goto Return_Cleanup;
if (sim_disk_rdsect (uptr, (((Home.hm1_l_ibmaplbn << 16) + ((Home.hm1_l_ibmaplbn >> 16) & 0xFFFF)) + Home.hm1_w_ibmapsize + 1) * (512 / ctx->sector_size),
                           (uint8 *)&Header, NULL, sizeof (Header) / ctx->sector_size))
    goto Return_Cleanup;
CheckSum1 = ODSChecksum (&Header, 255);
if (CheckSum1 != *(((uint16 *)&Header)+255)) /* Verify Checksum on BITMAP.SYS file header */
    goto Return_Cleanup;

Retr = (ODS1_Retreval *)(((uint16*)(&Header))+Header.fh1_b_mpoffset);
ScbLbn = (Retr->fm1_pointers[0].fm1_s_fm1def1.fm1_b_highlbn<<16)+Retr->fm1_pointers[0].fm1_s_fm1def1.fm1_w_lowlbn;
if (sim_disk_rdsect (uptr, ScbLbn * (512 / ctx->sector_size), (uint8 *)Scb, NULL, 512 / ctx->sector_size))
    goto Return_Cleanup;
if (Scb->scb_b_bitmapblks < 127)
    ret_val = (((t_offset)Scb->scb_r_blocks[Scb->scb_b_bitmapblks].scb_w_freeblks << 16) + Scb->scb_r_blocks[Scb->scb_b_bitmapblks].scb_w_freeptr) * 512;
else
    ret_val = (((t_offset)Scb->scb_r_blocks[0].scb_w_freeblks << 16) + Scb->scb_r_blocks[0].scb_w_freeptr) * 512;
if (!sim_quiet) {
    sim_printf ("%s%d: '%s' Contains an ODS1 File system\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
    sim_printf ("%s%d: Volume Name: %12.12s ", sim_dname (dptr), (int)(uptr-dptr->units), Home.hm1_t_volname);
    sim_printf ("Format: %12.12s ", Home.hm1_t_format);
    sim_printf ("Sectors In Volume: %u\n", (uint32)(ret_val / 512));
    }

Return_Cleanup:
uptr->capac = saved_capac;
return ret_val;
}

typedef struct ultrix_disklabel {
    uint32  pt_magic;       /* magic no. indicating part. info exits */
    uint32  pt_valid;       /* set by driver if pt is current */
    struct  pt_info {
        uint32  pi_nblocks; /* no. of sectors */
        uint32  pi_blkoff;  /* block offset for start */
        } pt_part[8];
    } ultrix_disklabel;

#define PT_MAGIC        0x032957        /* Partition magic number */
#define PT_VALID        1               /* Indicates if struct is valid */

static t_offset get_ultrix_filesystem_size (UNIT *uptr)
{
DEVICE *dptr;
t_addr saved_capac;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu;  /* Make sure we can access the largest sector */
uint32 capac_factor;
uint8 sector_buf[512];
ultrix_disklabel *Label = (ultrix_disklabel *)(sector_buf + sizeof (sector_buf) - sizeof (ultrix_disklabel));
t_offset ret_val = (t_offset)-1;
int i;
uint32 max_lbn = 0, max_lbn_partnum = 0;

if ((dptr = find_dev_from_unit (uptr)) == NULL)
    return ret_val;
capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
saved_capac = uptr->capac;
uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
if (sim_disk_rdsect (uptr, 31 * (512 / ctx->sector_size), sector_buf, NULL, 512 / ctx->sector_size))
    goto Return_Cleanup;

if ((Label->pt_magic != PT_MAGIC) || 
    (Label->pt_valid != PT_VALID))
    goto Return_Cleanup;

for (i = 0; i < 8; i++) {
    uint32 end_lbn = Label->pt_part[i].pi_blkoff + Label->pt_part[i].pi_nblocks;
    if (end_lbn > max_lbn) {
        max_lbn = end_lbn;
        max_lbn_partnum = i;
        }
    }
if (!sim_quiet) {
    sim_printf ("%s%d: '%s' Contains Ultrix partitions\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
    sim_printf ("Partition with highest sector: %c, Sectors On Disk: %u\n", 'a' + max_lbn_partnum, max_lbn);
    }
ret_val = ((t_offset)max_lbn) * 512;

Return_Cleanup:
uptr->capac = saved_capac;
return ret_val;
}

typedef t_offset (*FILESYSTEM_CHECK)(UNIT *uptr);

static t_offset get_filesystem_size (UNIT *uptr)
{
static FILESYSTEM_CHECK checks[] = {
    &get_ods2_filesystem_size,
    &get_ods1_filesystem_size,
    &get_ultrix_filesystem_size,
    NULL
    };
t_offset ret_val;
int i;

for (i = 0; checks[i] != NULL; i++) {
    ret_val = checks[i] (uptr);
    if (ret_val != (t_offset)-1)
        break;
    }
return ret_val;
}

t_stat sim_disk_attach (UNIT *uptr, const char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize,
                        uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay)
{
struct disk_context *ctx;
DEVICE *dptr;
char tbuf[4*CBUFSIZE];
FILE *(*open_function)(const char *filename, const char *mode) = sim_fopen;
FILE *(*create_function)(const char *filename, t_offset desiredsize) = NULL;
t_offset (*size_function)(FILE *file);
t_stat (*storage_function)(FILE *file, uint32 *sector_size, uint32 *removable) = NULL;
t_bool created = FALSE, copied = FALSE;
t_bool auto_format = FALSE;
t_offset capac, filesystem_capac;

if (uptr->flags & UNIT_DIS)                             /* disabled? */
    return SCPE_UDIS;
if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
    return SCPE_NOATT;
if ((dptr = find_dev_from_unit (uptr)) == NULL)
    return SCPE_NOATT;
if (sim_switches & SWMASK ('F')) {                      /* format spec? */
    char gbuf[CBUFSIZE];
    cptr = get_glyph (cptr, gbuf, 0);                   /* get spec */
    if (*cptr == 0)                                     /* must be more */
        return SCPE_2FARG;
    if (sim_disk_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK)
        return sim_messagef (SCPE_ARG, "Invalid Disk Format: %s\n", gbuf);
    sim_switches = sim_switches & ~(SWMASK ('F'));      /* Record Format specifier already processed */
    auto_format = TRUE;
    }
if (sim_switches & SWMASK ('D')) {                      /* create difference disk? */
    char gbuf[CBUFSIZE];
    FILE *vhd;

    sim_switches = sim_switches & ~(SWMASK ('D'));
    cptr = get_glyph_nc (cptr, gbuf, 0);                /* get spec */
    if (*cptr == 0)                                     /* must be more */
        return SCPE_2FARG;
    vhd = sim_vhd_disk_create_diff (gbuf, cptr);
    if (vhd) {
        sim_vhd_disk_close (vhd);
        return sim_disk_attach (uptr, gbuf, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay);
        }
    return sim_messagef (SCPE_ARG, "Unable to create differencing VHD: %s\n", gbuf);
    }
if (sim_switches & SWMASK ('C')) {                      /* create vhd disk & copy contents? */
    char gbuf[CBUFSIZE];
    FILE *vhd;
    int saved_sim_switches = sim_switches;
    int32 saved_sim_quiet = sim_quiet;
    uint32 capac_factor;
    t_stat r;

    sim_switches = sim_switches & ~(SWMASK ('C'));
    cptr = get_glyph_nc (cptr, gbuf, 0);                /* get spec */
    if (*cptr == 0)                                     /* must be more */
        return SCPE_2FARG;
    sim_switches |= SWMASK ('R') | SWMASK ('E');
    sim_quiet = TRUE;
    /* First open the source of the copy operation */
    r = sim_disk_attach (uptr, cptr, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay);
    sim_quiet = saved_sim_quiet;
    if (r != SCPE_OK) {
        sim_switches = saved_sim_switches;
        return sim_messagef (r, "Can't open source VHD: %s\n", cptr);
        }
    if (!sim_quiet) {
        sim_printf ("%s%d: creating new virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf);
        }
    capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 1) */
    vhd = sim_vhd_disk_create (gbuf, ((t_offset)uptr->capac)*capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1));
    if (!vhd) {
        return sim_messagef (r, "%s%d: can't create virtual disk '%s'\n", sim_dname (dptr), (int)(uptr-dptr->units), gbuf);
        }
    else {
        uint8 *copy_buf = (uint8*) malloc (1024*1024);
        t_lba lba;
        t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size);
        t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/(sector_size/((dptr->flags & DEV_SECTORS) ? 512 : 1)));
        t_seccnt sects = sectors_per_buffer;

        if (!copy_buf) {
            sim_vhd_disk_close(vhd);
            (void)remove (gbuf);
            return SCPE_MEM;
            }
        for (lba = 0; (lba < total_sectors) && (r == SCPE_OK); lba += sects) {
            if (!sim_quiet)
                sim_printf ("%s%d: Copied %dMB.  %d%% complete.\r", sim_dname (dptr), (int)(uptr-dptr->units), (int)((((float)lba)*sector_size)/1000000), (int)((((float)lba)*100)/total_sectors));
            sects = sectors_per_buffer;
            if (lba + sects > total_sectors)
                sects = total_sectors - lba;
            r = sim_disk_rdsect (uptr, lba, copy_buf, NULL, sects);
            if (r == SCPE_OK) {
                uint32 saved_unit_flags = uptr->flags;
                FILE *save_unit_fileref = uptr->fileref;

                sim_disk_set_fmt (uptr, 0, "VHD", NULL);
                uptr->fileref = vhd;
                r = sim_disk_wrsect (uptr, lba, copy_buf, NULL, sects);
                uptr->fileref = save_unit_fileref;
                uptr->flags = saved_unit_flags;
                }
            }
        if (!sim_quiet) {
            if (r == SCPE_OK)
                sim_printf ("\n%s%d: Copied %dMB. Done.\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)(((t_offset)lba*sector_size)/1000000));
            else
                sim_printf ("\n%s%d: Error copying: %s.\n", sim_dname (dptr), (int)(uptr-dptr->units), sim_error_text (r));
            }
        if ((r == SCPE_OK) && (sim_switches & SWMASK ('V'))) {
            uint8 *verify_buf = (uint8*) malloc (1024*1024);

            if (!verify_buf) {
                sim_vhd_disk_close(vhd);
                (void)remove (gbuf);
                free (copy_buf);
                return SCPE_MEM;
                }
            for (lba = 0; (lba < total_sectors) && (r == SCPE_OK); lba += sects) {
                if (!sim_quiet)
                    sim_printf ("%s%d: Verified %dMB.  %d%% complete.\r", sim_dname (dptr), (int)(uptr-dptr->units), (int)((((float)lba)*sector_size)/1000000), (int)((((float)lba)*100)/total_sectors));
                sects = sectors_per_buffer;
                if (lba + sects > total_sectors)
                    sects = total_sectors - lba;
                r = sim_disk_rdsect (uptr, lba, copy_buf, NULL, sects);
                if (r == SCPE_OK) {
                    uint32 saved_unit_flags = uptr->flags;
                    FILE *save_unit_fileref = uptr->fileref;

                    sim_disk_set_fmt (uptr, 0, "VHD", NULL);
                    uptr->fileref = vhd;
                    r = sim_disk_rdsect (uptr, lba, verify_buf, NULL, sects);
                    uptr->fileref = save_unit_fileref;
                    uptr->flags = saved_unit_flags;
                    if (r == SCPE_OK) {
                        if (0 != memcmp (copy_buf, verify_buf, 1024*1024))
                            r = SCPE_IOERR;
                        }
                    }
                }
            if (!sim_quiet) {
                if (r == SCPE_OK)
                    sim_printf ("\n%s%d: Verified %dMB. Done.\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)(((t_offset)lba*sector_size)/1000000));
                else {
                    t_lba i;
                    uint32 save_dctrl = dptr->dctrl;
                    FILE *save_sim_deb = sim_deb;

                    for (i = 0; i < (1024*1024/sector_size); ++i)
                        if (0 != memcmp (copy_buf+i*sector_size, verify_buf+i*sector_size, sector_size))
                            break;
                    sim_printf ("\n%s%d: Verification Error on lbn %d.\n", sim_dname (dptr), (int)(uptr-dptr->units), lba+i);
                    dptr->dctrl = 0xFFFFFFFF;
                    sim_deb = stdout;
                    sim_disk_data_trace (uptr,   copy_buf+i*sector_size, lba+i, sector_size, "Expected", TRUE, 1);
                    sim_disk_data_trace (uptr, verify_buf+i*sector_size, lba+i, sector_size,    "Found", TRUE, 1);
                    dptr->dctrl = save_dctrl;
                    sim_deb = save_sim_deb;
                    }
                }
            free (verify_buf);
            }
        free (copy_buf);
        sim_vhd_disk_close (vhd);
        sim_disk_detach (uptr);
        if (r == SCPE_OK) {
            created = TRUE;
            copied = TRUE;
            tbuf[sizeof(tbuf)-1] = '\0';
            strncpy (tbuf, gbuf, sizeof(tbuf)-1);
            cptr = tbuf;
            sim_disk_set_fmt (uptr, 0, "VHD", NULL);
            sim_switches = saved_sim_switches;
            }
        else
            return r;
        /* fall through and open/return the newly created & copied vhd */
        }
    }
else
    if (sim_switches & SWMASK ('M')) {                 /* merge difference disk? */
        char gbuf[CBUFSIZE], *Parent = NULL;
        FILE *vhd;

        sim_switches = sim_switches & ~(SWMASK ('M'));
        get_glyph_nc (cptr, gbuf, 0);                  /* get spec */
        vhd = sim_vhd_disk_merge (gbuf, &Parent);
        if (vhd) {
            t_stat r;

            sim_vhd_disk_close (vhd);
            r = sim_disk_attach (uptr, Parent, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay);
            free (Parent);
            return r;
            }
        return SCPE_ARG;
        }

switch (DK_GET_FMT (uptr)) {                            /* case on format */
    case DKUF_F_STD:                                    /* SIMH format */
        if (NULL == (uptr->fileref = sim_vhd_disk_open (cptr, "rb"))) {
            if (errno == EBADF)                        /* VHD but broken */
                return SCPE_OPENERR;
            open_function = sim_fopen;
            size_function = sim_fsize_ex;
            break;
            }
        sim_disk_set_fmt (uptr, 0, "VHD", NULL);        /* set file format to VHD */
        sim_vhd_disk_close (uptr->fileref);             /* close vhd file*/
        auto_format = TRUE;
        uptr->fileref = NULL;
        /* Fall through to normal VHD processing */
    case DKUF_F_VHD:                                    /* VHD format */
        open_function = sim_vhd_disk_open;
        create_function = sim_vhd_disk_create;
        size_function = sim_vhd_disk_size;
        break;
    case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
        open_function = sim_os_disk_open_raw;
        size_function = sim_os_disk_size_raw;
        storage_function = sim_os_disk_info_raw;
        break;
    default:
        return SCPE_IERR;
    }
uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));/* alloc name buf */
uptr->disk_ctx = ctx = (struct disk_context *)calloc(1, sizeof(struct disk_context));
if ((uptr->filename == NULL) || (uptr->disk_ctx == NULL))
    return _err_return (uptr, SCPE_MEM);
strncpy (uptr->filename, cptr, CBUFSIZE);               /* save name */
ctx->sector_size = (uint32)sector_size;                 /* save sector_size */
ctx->capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
ctx->xfer_element_size = (uint32)xfer_element_size;     /* save xfer_element_size */
ctx->dptr = dptr;                                       /* save DEVICE pointer */
ctx->dbit = dbit;                                       /* save debug bit */
sim_debug (ctx->dbit, ctx->dptr, "sim_disk_attach(unit=%d,filename='%s')\n", (int)(uptr-ctx->dptr->units), uptr->filename);
ctx->auto_format = auto_format;                         /* save that we auto selected format */
ctx->storage_sector_size = (uint32)sector_size;         /* Default */
if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
    ((uptr->flags & UNIT_RO) != 0)) {
    if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
        ((uptr->flags & UNIT_RO) == 0))
        return _err_return (uptr, SCPE_NORO);           /* no, error */
    uptr->fileref = open_function (cptr, "rb");         /* open rd only */
    if (uptr->fileref == NULL)                          /* open fail? */
        return _err_return (uptr, SCPE_OPENERR);        /* yes, error */
    uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
    if (!sim_quiet) {
        sim_printf ("%s%d: unit is read only\n", sim_dname (dptr), (int)(uptr-dptr->units));
        }
    }
else {                                                  /* normal */
    uptr->fileref = open_function (cptr, "rb+");        /* open r/w */
    if (uptr->fileref == NULL) {                        /* open fail? */
        if ((errno == EROFS) || (errno == EACCES)) {    /* read only? */
            if ((uptr->flags & UNIT_ROABLE) == 0)       /* allowed? */
                return _err_return (uptr, SCPE_NORO);   /* no error */
            uptr->fileref = open_function (cptr, "rb"); /* open rd only */
            if (uptr->fileref == NULL)                  /* open fail? */
                return _err_return (uptr, SCPE_OPENERR);/* yes, error */
            uptr->flags = uptr->flags | UNIT_RO;        /* set rd only */
            if (!sim_quiet)
                sim_printf ("%s%d: unit is read only\n", sim_dname (dptr), (int)(uptr-dptr->units));
            }
        else {                                          /* doesn't exist */
            if (sim_switches & SWMASK ('E'))            /* must exist? */
                return _err_return (uptr, SCPE_OPENERR); /* yes, error */
            if (create_function)
                uptr->fileref = create_function (cptr, ((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1));/* create new file */
            else
                uptr->fileref = open_function (cptr, "wb+");/* open new file */
            if (uptr->fileref == NULL)                  /* open fail? */
                return _err_return (uptr, SCPE_OPENERR);/* yes, error */
            if (!sim_quiet)
                sim_printf ("%s%d: creating new file\n", sim_dname (dptr), (int)(uptr-dptr->units));
            created = TRUE;
            }
        }                                               /* end if null */
    }                                                   /* end else */
if (DK_GET_FMT (uptr) == DKUF_F_VHD) {
    if ((created) && dtype)
        sim_vhd_disk_set_dtype (uptr->fileref, dtype);
    if (dtype && strcmp (dtype, sim_vhd_disk_get_dtype (uptr->fileref))) {
        char cmd[32];

        sprintf (cmd, "%s%d %s", dptr->name, (int)(uptr-dptr->units), sim_vhd_disk_get_dtype (uptr->fileref));
        set_cmd (0, cmd);
        }
    }
uptr->flags = uptr->flags | UNIT_ATT;
uptr->pos = 0;

/* Get Device attributes if they are available */
if (storage_function)
    storage_function (uptr->fileref, &ctx->storage_sector_size, &ctx->removable);

if ((created) && (!copied)) {
    t_stat r = SCPE_OK;
    uint8 *secbuf = (uint8 *)calloc (128, ctx->sector_size);     /* alloc temp sector buf */

    /*
       On a newly created disk, we write a zero sector to the last and the
       first sectors.  This serves 3 purposes:
         1) it avoids strange allocation delays writing newly allocated
            storage at the end of the disk during simulator operation
         2) it allocates storage for the whole disk at creation time to
            avoid strange failures which may happen during simulator execution
            if the containing disk is full
         3) it leaves a Sinh Format disk at the intended size so it may
            subsequently be autosized with the correct size.
    */
    if (secbuf == NULL)
        r = SCPE_MEM;
    if (r == SCPE_OK) { /* Write all blocks */
        t_lba lba;
        t_lba total_lbas = (t_lba)((((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))/ctx->sector_size);

        for (lba = 0; (r == SCPE_OK) && (lba < total_lbas); lba += 128) { 
            t_seccnt sectors = ((lba + 128) <= total_lbas) ? 128 : total_lbas - lba;

            r = sim_disk_wrsect (uptr, lba, secbuf, NULL, sectors);
            }
        }
    free (secbuf);
    if (r != SCPE_OK) {
        sim_disk_detach (uptr);                         /* report error now */
        (void)remove (cptr);                            /* remove the created file */
        return SCPE_OPENERR;
        }
    if (sim_switches & SWMASK ('I')) {                  /* Initialize To Sector Address */
        uint8 *init_buf = (uint8*) malloc (1024*1024);
        t_lba lba, sect;
        uint32 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 1) */
        t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size);
        t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/(sector_size/((dptr->flags & DEV_SECTORS) ? 512 : 1)));
        t_seccnt sects = sectors_per_buffer;

        if (!init_buf) {
            sim_disk_detach (uptr);                         /* report error now */
            (void)remove (cptr);
            return SCPE_MEM;
            }
        for (lba = 0; (lba < total_sectors) && (r == SCPE_OK); lba += sects) {
            sects = sectors_per_buffer;
            if (lba + sects > total_sectors)
                sects = total_sectors - lba;
            for (sect = 0; sect < sects; sect++) {
                t_lba offset;
                for (offset = 0; offset < sector_size; offset += sizeof(uint32))
                    *((uint32 *)&init_buf[sect*sector_size + offset]) = (uint32)(lba + sect);
                }
            r = sim_disk_wrsect (uptr, lba, init_buf, NULL, sects);
            if (r != SCPE_OK) {
                free (init_buf);
                sim_disk_detach (uptr);                         /* report error now */
                (void)remove (cptr);                            /* remove the created file */
                return SCPE_OPENERR;
                }
            if (!sim_quiet)
                sim_printf ("%s%d: Initialized To Sector Address %dMB.  %d%% complete.\r", sim_dname (dptr), (int)(uptr-dptr->units), (int)((((float)lba)*sector_size)/1000000), (int)((((float)lba)*100)/total_sectors));
            }
        if (!sim_quiet)
            sim_printf ("%s%d: Initialized To Sector Address %dMB.  100%% complete.\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)((((float)lba)*sector_size)/1000000));
        free (init_buf);
        }
    if (pdp11tracksize)
        sim_disk_pdp11_bad_block (uptr, pdp11tracksize, sector_size/sizeof(uint16));
    }

if (sim_switches & SWMASK ('K')) {
    t_stat r = SCPE_OK;
    t_lba lba, sect;
    uint32 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 1) */
    t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size);
    t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/(sector_size/((dptr->flags & DEV_SECTORS) ? 512 : 1)));
    t_seccnt sects = sectors_per_buffer;
    uint8 *verify_buf = (uint8*) malloc (1024*1024);

    if (!verify_buf) {
        sim_disk_detach (uptr);                         /* report error now */
        return SCPE_MEM;
        }
    for (lba = 0; (lba < total_sectors) && (r == SCPE_OK); lba += sects) {
        sects = sectors_per_buffer;
        if (lba + sects > total_sectors)
            sects = total_sectors - lba;
        r = sim_disk_rdsect (uptr, lba, verify_buf, NULL, sects);
        if (r == SCPE_OK) {
            for (sect = 0; sect < sects; sect++) {
                t_lba offset;
                t_bool sect_error = FALSE;

                for (offset = 0; offset < sector_size; offset += sizeof(uint32)) {
                    if (*((uint32 *)&verify_buf[sect*sector_size + offset]) != (uint32)(lba + sect)) {
                        sect_error = TRUE;
                        break;
                        }
                    }
                if (sect_error) {
                    uint32 save_dctrl = dptr->dctrl;
                    FILE *save_sim_deb = sim_deb;

                    sim_printf ("\n%s%d: Verification Error on lbn %d(0x%X) of %d(0x%X).\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)(lba+sect), (int)(lba+sect), (int)total_sectors, (int)total_sectors);
                    dptr->dctrl = 0xFFFFFFFF;
                    sim_deb = stdout;
                    sim_disk_data_trace (uptr, verify_buf+sect*sector_size, lba+sect, sector_size,    "Found", TRUE, 1);
                    dptr->dctrl = save_dctrl;
                    sim_deb = save_sim_deb;
                    }
                }
            }
        if (!sim_quiet)
            sim_printf ("%s%d: Verified containing Sector Address %dMB.  %d%% complete.\r", sim_dname (dptr), (int)(uptr-dptr->units), (int)((((float)lba)*sector_size)/1000000), (int)((((float)lba)*100)/total_sectors));
        }
    if (!sim_quiet)
        sim_printf ("%s%d: Verified containing Sector Address %dMB.  100%% complete.\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)((((float)lba)*sector_size)/1000000));
    free (verify_buf);
    uptr->dynflags |= UNIT_DISK_CHK;
    }

filesystem_capac = get_filesystem_size (uptr);
capac = size_function (uptr->fileref);
if (capac && (capac != (t_offset)-1)) {
    if (dontautosize) {
        t_addr saved_capac = uptr->capac;

        if ((filesystem_capac != (t_offset)-1) &&
            (filesystem_capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)))) {
            if (!sim_quiet) {
                uptr->capac = (t_addr)(filesystem_capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
                sim_printf ("%s%d: The file system on the disk %s is larger than simulated device (%s > ", sim_dname (dptr), (int)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr));
                uptr->capac = saved_capac;
                sim_printf ("%s)\n", sprint_capac (dptr, uptr));
                }
            sim_disk_detach (uptr);
            return SCPE_OPENERR;
            }
        if ((capac < (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) && (DKUF_F_STD != DK_GET_FMT (uptr))) {
            if (!sim_quiet) {
                uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
                sim_printf ("%s%d: non expandable disk %s is smaller than simulated device (%s < ", sim_dname (dptr), (int)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr));
                uptr->capac = saved_capac;
                sim_printf ("%s)\n", sprint_capac (dptr, uptr));
                }
            sim_disk_detach (uptr);
            return SCPE_OPENERR;
            }
        }
    else {
        if ((filesystem_capac != (t_offset)-1) &&
            (filesystem_capac > capac))
            capac = filesystem_capac;
        if ((capac != (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) || 
            (DKUF_F_STD != DK_GET_FMT (uptr)))
            uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
        }
    }

#if defined (SIM_ASYNCH_IO)
sim_disk_set_async (uptr, completion_delay);
#endif
uptr->io_flush = _sim_disk_io_flush;

return SCPE_OK;
}

t_stat sim_disk_detach (UNIT *uptr)
{
struct disk_context *ctx;
int (*close_function)(FILE *f);
FILE *fileref;
t_bool auto_format;

if ((uptr == NULL) || !(uptr->flags & UNIT_ATT))
    return SCPE_NOTATT;

ctx = (struct disk_context *)uptr->disk_ctx;
fileref = uptr->fileref;

sim_debug (ctx->dbit, ctx->dptr, "sim_disk_detach(unit=%d,filename='%s')\n", (int)(uptr-ctx->dptr->units), uptr->filename);

switch (DK_GET_FMT (uptr)) {                            /* case on format */
    case DKUF_F_STD:                                    /* Simh */
        close_function = fclose;
        break;
    case DKUF_F_VHD:                                    /* Virtual Disk */
        close_function = sim_vhd_disk_close;
        break;
    case DKUF_F_RAW:                                    /* Physical */
        close_function = sim_os_disk_close_raw;
        break;
    default:
        return SCPE_IERR;
        }
if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
    return SCPE_NOATT;
if (!(uptr->flags & UNIT_ATT))                          /* attached? */
    return SCPE_OK;
if (NULL == find_dev_from_unit (uptr))
    return SCPE_OK;
auto_format = ctx->auto_format;

if (uptr->io_flush)
    uptr->io_flush (uptr);                              /* flush buffered data */

sim_disk_clr_async (uptr);

uptr->flags &= ~(UNIT_ATT | UNIT_RO);
uptr->dynflags &= ~(UNIT_NO_FIO | UNIT_DISK_CHK);
free (uptr->filename);
uptr->filename = NULL;
uptr->fileref = NULL;
free (uptr->disk_ctx);
uptr->disk_ctx = NULL;
uptr->io_flush = NULL;
if (auto_format)
    sim_disk_set_fmt (uptr, 0, "SIMH", NULL);           /* restore file format */
if (close_function (fileref) == EOF)
    return SCPE_IOERR;
return SCPE_OK;
}

t_stat sim_disk_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "%s Disk Attach Help\n\n", dptr->name);

fprintf (st, "Disk container files can be one of 3 different types:\n\n");
fprintf (st, "    SIMH   A disk is an unstructured binary file of the size appropriate\n");
fprintf (st, "           for the disk drive being simulated\n");
fprintf (st, "    VHD    Virtual Disk format which is described in the \"Microsoft\n");
fprintf (st, "           Virtual Hard Disk (VHD) Image Format Specification\".  The\n");
fprintf (st, "           VHD implementation includes support for 1) Fixed (Preallocated)\n");
fprintf (st, "           disks, 2) Dynamically Expanding disks, and 3) Differencing disks.\n");
fprintf (st, "    RAW    platform specific access to physical disk or CDROM drives\n\n");
fprintf (st, "Virtual (VHD) Disks  supported conform to \"Virtual Hard Disk Image Format\n");
fprintf (st, "Specification\", Version 1.0 October 11, 2006.\n");
fprintf (st, "Dynamically expanding disks never change their \"Virtual Size\", but they don't\n");
fprintf (st, "consume disk space on the containing storage until the virtual sectors in the\n");
fprintf (st, "disk are actually written to (i.e. a 2GB Dynamic disk container file with only\n");
fprintf (st, "30MB of data will initially be about 30MB in size and this size will grow up to\n");
fprintf (st, "2GB as different sectors are written to.  The VHD format contains metadata\n");
fprintf (st, "which describes the drive size and the simh device type in use when the VHD\n");
fprintf (st, "was created.  This metadata is therefore available whenever that VHD is\n");
fprintf (st, "attached to an emulated disk device in the future so the device type and\n");
fprintf (st, "size can be automatically be configured.\n\n");

if (0 == (uptr-dptr->units)) {
    if (dptr->numunits > 1) {
        uint32 i;

        for (i=0; i < dptr->numunits; ++i)
            if (dptr->units[i].flags & UNIT_ATTABLE)
                fprintf (st, "  sim> ATTACH {switches} %s%d diskfile\n", dptr->name, i);
        }
    else
        fprintf (st, "  sim> ATTACH {switches} %s diskfile\n", dptr->name);
    }
else
    fprintf (st, "  sim> ATTACH {switches} %s diskfile\n\n", dptr->name);
fprintf (st, "\n%s attach command switches\n", dptr->name);
fprintf (st, "    -R          Attach Read Only.\n");
fprintf (st, "    -E          Must Exist (if not specified an attempt to create the indicated\n");
fprintf (st, "                disk container will be attempted).\n");
fprintf (st, "    -F          Open the indicated disk container in a specific format (default\n");
fprintf (st, "                is to autodetect VHD defaulting to simh if the indicated\n");
fprintf (st, "                container is not a VHD).\n");
fprintf (st, "    -I          Initialize newly created disk so that each sector contains its\n");
fprintf (st, "                sector address\n");
fprintf (st, "    -K          Verify that the disk contents contain the sector address in each\n");
fprintf (st, "                sector.  Whole disk checked at attach time and each sector is\n");
fprintf (st, "                checked when written.\n");
fprintf (st, "    -C          Create a VHD and copy its contents from another disk (simh, VHD,\n");
fprintf (st, "                or RAW format). Add a -V switch to verify a copy operation.\n");
fprintf (st, "    -V          Perform a verification pass to confirm successful data copy\n");
fprintf (st, "                operation.\n");
fprintf (st, "    -X          When creating a VHD, create a fixed sized VHD (vs a Dynamically\n");
fprintf (st, "                expanding one).\n");
fprintf (st, "    -D          Create a Differencing VHD (relative to an already existing VHD\n");
fprintf (st, "                disk)\n");
fprintf (st, "    -M          Merge a Differencing VHD into its parent VHD disk\n");
fprintf (st, "    -O          Override consistency checks when attaching differencing disks\n");
fprintf (st, "                which have unexpected parent disk GUID or timestamps\n\n");
fprintf (st, "    -U          Fix inconsistencies which are overridden by the -O switch\n");
fprintf (st, "    -Y          Answer Yes to prompt to overwrite last track (on disk create)\n");
fprintf (st, "    -N          Answer No to prompt to overwrite last track (on disk create)\n");
fprintf (st, "Examples:\n");
fprintf (st, "  sim> show rq\n");
fprintf (st, "    RQ, address=20001468-2000146B*, no vector, 4 units\n");
fprintf (st, "    RQ0, 159MB, not attached, write enabled, RD54, autosize, SIMH format\n");
fprintf (st, "    RQ1, 159MB, not attached, write enabled, RD54, autosize, SIMH format\n");
fprintf (st, "    RQ2, 159MB, not attached, write enabled, RD54, autosize, SIMH format\n");
fprintf (st, "    RQ3, 409KB, not attached, write enabled, RX50, autosize, SIMH format\n");
fprintf (st, "  sim> atta rq0 RA81.vhd\n");
fprintf (st, "  sim> show rq0\n");
fprintf (st, "  RQ0, 456MB, attached to RA81.vhd, write enabled, RA81, autosize, VHD format\n");
fprintf (st, "  sim> set rq2 ra92\n");
fprintf (st, "  sim> att rq2 -f vhd RA92.vhd\n");
fprintf (st, "  RQ2: creating new file\n");
fprintf (st, "  sim> sho rq2\n");
fprintf (st, "  RQ2, 1505MB, attached to RA92.vhd, write enabled, RA92, autosize, VHD format\n");
fprintf (st, "  sim> ! dir RA92.vhd\n");
fprintf (st, "   Volume in drive H is New Volume\n");
fprintf (st, "   Volume Serial Number is F8DE-510C\n\n");
fprintf (st, "   Directory of H:\\Data\n\n");
fprintf (st, "  04/14/2011  12:57 PM             5,120 RA92.vhd\n");
fprintf (st, "                 1 File(s)          5,120 bytes\n");
fprintf (st, "  sim> atta rq3 -d RA92-1-Diff.vhd RA92.vhd\n");
fprintf (st, "  sim> atta rq3 -c RA92-1.vhd RA92.vhd\n");
fprintf (st, "  RQ3: creating new virtual disk 'RA92-1.vhd'\n");
fprintf (st, "  RQ3: Copied 1505MB.  99%% complete.\n");
fprintf (st, "  RQ3: Copied 1505MB. Done.\n");
fprintf (st, "  sim> sh rq3\n");
fprintf (st, "  RQ3, 1505MB, attached to RA92-1.vhd, write enabled, RA92, autosize, VHD format\n");
fprintf (st, "  sim>  ! dir RA92*\n");
fprintf (st, "   Volume in drive H is New Volume\n");
fprintf (st, "   Volume Serial Number is F8DE-510C\n\n");
fprintf (st, "   Directory of H:\\Data\n\n");
fprintf (st, "  04/14/2011  01:12 PM             5,120 RA92-1.vhd\n");
fprintf (st, "  04/14/2011  12:58 PM             5,120 RA92.vhd\n");
fprintf (st, "                 2 File(s)         10,240 bytes\n");
fprintf (st, "  sim> sho rq2\n");
fprintf (st, "  RQ2, 1505MB, not attached, write enabled, RA92, autosize, VHD format\n");
fprintf (st, "  sim> set rq2 ra81\n");
fprintf (st, "  sim> set rq2 noauto\n");
fprintf (st, "  sim> sho rq2\n");
fprintf (st, "  RQ2, 456MB, not attached, write enabled, RA81, noautosize, VHD format\n");
fprintf (st, "  sim> set rq2 format=simh\n");
fprintf (st, "  sim> sho rq2\n");
fprintf (st, "  RQ2, 456MB, not attached, write enabled, RA81, noautosize, SIMH format\n");
fprintf (st, "  sim> atta rq2 -c RA81-Copy.vhd VMS055.dsk\n");
fprintf (st, "  RQ2: creating new virtual disk 'RA81-Copy.vhd'\n");
fprintf (st, "  RQ2: Copied 456MB.  99%% complete.\n");
fprintf (st, "  RQ2: Copied 456MB. Done.\n");
fprintf (st, "  sim> sho rq2\n");
fprintf (st, "  RQ2, 456MB, attached to RA81-Copy.vhd, write enabled, RA81, noautosize, VHD format\n");
return SCPE_OK;
}

t_bool sim_disk_vhd_support (void)
{
return SCPE_OK == sim_vhd_disk_implemented ();
}

t_bool sim_disk_raw_support (void)
{
return SCPE_OK == sim_os_disk_implemented_raw ();
}

t_stat sim_disk_reset (UNIT *uptr)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

if (!(uptr->flags & UNIT_ATT))                          /* attached? */
    return SCPE_OK;

sim_debug (ctx->dbit, ctx->dptr, "sim_disk_reset(unit=%d)\n", (int)(uptr-ctx->dptr->units));

_sim_disk_io_flush(uptr);
AIO_VALIDATE;
AIO_UPDATE_QUEUE;
return SCPE_OK;
}

t_stat sim_disk_perror (UNIT *uptr, const char *msg)
{
int saved_errno = errno;

if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
    return SCPE_NOATT;
switch (DK_GET_FMT (uptr)) {                            /* case on format */
    case DKUF_F_STD:                                    /* SIMH format */
    case DKUF_F_VHD:                                    /* VHD format */
    case DKUF_F_RAW:                                    /* Raw Physical Disk Access */
        perror (msg);
        sim_printf ("%s %s: %s\n", sim_uname(uptr), msg, strerror(saved_errno));
    default:
        ;
    }
return SCPE_OK;
}

t_stat sim_disk_clearerr (UNIT *uptr)
{
if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
    return SCPE_NOATT;
switch (DK_GET_FMT (uptr)) {                            /* case on format */
    case DKUF_F_STD:                                    /* SIMH format */
        clearerr (uptr->fileref);
        break;
    case DKUF_F_VHD:                                    /* VHD format */
        sim_vhd_disk_clearerr (uptr);
        break;
    default:
        ;
    }
return SCPE_OK;
}


/* Factory bad block table creation routine

   This routine writes a DEC standard 144 compliant bad block table on the
   last track of the specified unit as described in: 
      EL-00144_B_DEC_STD_144_Disk_Standard_for_Recording_and_Handling_Bad_Sectors_Nov76.pdf
   The bad block table consists of 10 repetitions of the same table, 
   formatted as follows:

        words 0-1       pack id number
        words 2-3       cylinder/sector/surface specifications
         :
        words n-n+1     end of table (-1,-1)

   Inputs:
        uptr    =       pointer to unit
        sec     =       number of sectors per surface
        wds     =       number of words per sector
   Outputs:
        sta     =       status code
*/

t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
int32 i;
t_addr da;
uint16 *buf;
DEVICE *dptr;
char *namebuf, *c;
uint32 packid;
t_stat stat = SCPE_OK;

if ((sec < 2) || (wds < 16))
    return SCPE_ARG;
if ((uptr->flags & UNIT_ATT) == 0)
    return SCPE_UNATT;
if ((dptr = find_dev_from_unit (uptr)) == NULL)
    return SCPE_NOATT;
if (uptr->flags & UNIT_RO)
    return SCPE_RO;
if (!get_yn ("Overwrite last track? [N]", FALSE))
    return SCPE_OK;
if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL)
    return SCPE_MEM;
namebuf = uptr->filename;
if ((c = strrchr (namebuf, '/')))
    namebuf = c+1;
if ((c = strrchr (namebuf, '\\')))
    namebuf = c+1;
if ((c = strrchr (namebuf, ']')))
    namebuf = c+1;
packid = eth_crc32(0, namebuf, strlen (namebuf));
buf[0] = (uint16)packid;
buf[1] = (uint16)(packid >> 16) & 0x7FFF;   /* Make sure MSB is clear */
buf[2] = buf[3] = 0;
for (i = 4; i < wds; i++)
    buf[i] = 0177777u;
da = (uptr->capac*((dptr->flags & DEV_SECTORS) ? 512 : 1)) - (sec * wds);
for (i = 0; (stat == SCPE_OK) && (i < sec) && (i < 10); i++, da += wds)
    if (ctx)
        stat = sim_disk_wrsect (uptr, (t_lba)(da/wds), (uint8 *)buf, NULL, 1);
    else {
        if (sim_fseek (uptr->fileref, da, SEEK_SET)) {
            stat = SCPE_IOERR;
            break;
            }
        if (wds != sim_fwrite (buf, sizeof (uint16), wds, uptr->fileref))
            stat = SCPE_IOERR;
        }
free (buf);
return stat;
}

void sim_disk_data_trace(UNIT *uptr, const uint8 *data, size_t lba, size_t len, const char* txt, int detail, uint32 reason)
{
DEVICE *dptr = find_dev_from_unit (uptr);

if (sim_deb && (dptr->dctrl & reason)) {
    char pos[32];

    sprintf (pos, "lbn: %08X ", (unsigned int)lba);
    sim_data_trace(dptr, uptr, (detail ? data : NULL), pos, len, txt, reason);
    }
}


/* OS Specific RAW Disk I/O support */

#if defined _WIN32

static void _set_errno_from_status (DWORD dwStatus)
{
switch (dwStatus) {
    case ERROR_FILE_NOT_FOUND:    case ERROR_PATH_NOT_FOUND:
    case ERROR_INVALID_DRIVE:     case ERROR_NO_MORE_FILES:
    case ERROR_BAD_NET_NAME:      case ERROR_BAD_NETPATH:
    case ERROR_BAD_PATHNAME:      case ERROR_FILENAME_EXCED_RANGE:
        errno = ENOENT;
        return;
    case ERROR_INVALID_ACCESS:    case ERROR_INVALID_DATA:
    case ERROR_INVALID_FUNCTION:  case ERROR_INVALID_PARAMETER:
    case ERROR_NEGATIVE_SEEK:
        errno = EINVAL;
        return;
    case ERROR_ARENA_TRASHED:     case ERROR_NOT_ENOUGH_MEMORY:
    case ERROR_INVALID_BLOCK:     case ERROR_NOT_ENOUGH_QUOTA:
        errno = ENOMEM;
        return;
    case ERROR_TOO_MANY_OPEN_FILES:
        errno = EMFILE;
        return;
    case ERROR_ACCESS_DENIED:     case ERROR_CURRENT_DIRECTORY:
    case ERROR_LOCK_VIOLATION:    case ERROR_NETWORK_ACCESS_DENIED:
    case ERROR_CANNOT_MAKE:       case ERROR_FAIL_I24:
    case ERROR_DRIVE_LOCKED:      case ERROR_SEEK_ON_DEVICE:
    case ERROR_NOT_LOCKED:        case ERROR_LOCK_FAILED:
        errno = EACCES;
        return;
    case ERROR_ALREADY_EXISTS:    case ERROR_FILE_EXISTS:
        errno = EEXIST;
        return;
    case ERROR_INVALID_HANDLE:    case ERROR_INVALID_TARGET_HANDLE:
    case ERROR_DIRECT_ACCESS_HANDLE:
        errno = EBADF;
        return;
    case ERROR_DIR_NOT_EMPTY:
        errno = ENOTEMPTY;
        return;
    case ERROR_BAD_ENVIRONMENT:
        errno = E2BIG;
        return;
    case ERROR_BAD_FORMAT:
        errno = ENOEXEC;
        return;
    case ERROR_NOT_SAME_DEVICE:
        errno = EXDEV;
        return;
    case ERROR_BROKEN_PIPE:
        errno = EPIPE;
        return;
    case ERROR_DISK_FULL:
        errno = ENOSPC;
        return;
    case ERROR_WAIT_NO_CHILDREN:  case ERROR_CHILD_NOT_COMPLETE:
        errno = ECHILD;
        return;
    case ERROR_NO_PROC_SLOTS:     case ERROR_MAX_THRDS_REACHED:
    case ERROR_NESTING_NOT_ALLOWED:
        errno = EAGAIN;
        return;
    }
if ((dwStatus >= ERROR_WRITE_PROTECT) && (dwStatus <= ERROR_SHARING_BUFFER_EXCEEDED)) {
    errno = EACCES;
    return;
    }
if ((dwStatus >= ERROR_INVALID_STARTING_CODESEG) && (dwStatus <= ERROR_INFLOOP_IN_RELOC_CHAIN)) {
    errno = ENOEXEC;
    return;
    }
errno = EINVAL;
}
#if defined(__GNUC__)
#include <ddk/ntddstor.h>
#include <ddk/ntdddisk.h>
#else
#include <winioctl.h>
#endif

#if defined(__cplusplus)
extern "C" {
#endif
WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize);
#if defined(__cplusplus)
    }
#endif

struct _device_type {
    int32 Type;
    const char *desc;
    } DeviceTypes[] = {
        {FILE_DEVICE_8042_PORT,             "8042_PORT"},
        {FILE_DEVICE_ACPI,                  "ACPI"},
        {FILE_DEVICE_BATTERY,               "BATTERY"},
        {FILE_DEVICE_BEEP,                  "BEEP"},
#ifdef FILE_DEVICE_BLUETOOTH
        {FILE_DEVICE_BLUETOOTH,             "BLUETOOTH"},
#endif
        {FILE_DEVICE_BUS_EXTENDER,          "BUS_EXTENDER"},
        {FILE_DEVICE_CD_ROM,                "CD_ROM"},
        {FILE_DEVICE_CD_ROM_FILE_SYSTEM,    "CD_ROM_FILE_SYSTEM"},
        {FILE_DEVICE_CHANGER,               "CHANGER"},
        {FILE_DEVICE_CONTROLLER,            "CONTROLLER"},
#ifdef FILE_DEVICE_CRYPT_PROVIDER
        {FILE_DEVICE_CRYPT_PROVIDER,        "CRYPT_PROVIDER"},
#endif
        {FILE_DEVICE_DATALINK,              "DATALINK"},
        {FILE_DEVICE_DFS,                   "DFS"},
        {FILE_DEVICE_DFS_FILE_SYSTEM,       "DFS_FILE_SYSTEM"},
        {FILE_DEVICE_DFS_VOLUME,            "DFS_VOLUME"},
        {FILE_DEVICE_DISK,                  "DISK"},
        {FILE_DEVICE_DISK_FILE_SYSTEM,      "DISK_FILE_SYSTEM"},
        {FILE_DEVICE_DVD,                   "DVD"},
        {FILE_DEVICE_FILE_SYSTEM,           "FILE_SYSTEM"},
#ifdef FILE_DEVICE_FIPS
        {FILE_DEVICE_FIPS,                  "FIPS"},
#endif
        {FILE_DEVICE_FULLSCREEN_VIDEO,      "FULLSCREEN_VIDEO"},
#ifdef FILE_DEVICE_INFINIBAND
        {FILE_DEVICE_INFINIBAND,            "INFINIBAND"},
#endif
        {FILE_DEVICE_INPORT_PORT,           "INPORT_PORT"},
        {FILE_DEVICE_KEYBOARD,              "KEYBOARD"},
        {FILE_DEVICE_KS,                    "KS"},
        {FILE_DEVICE_KSEC,                  "KSEC"},
        {FILE_DEVICE_MAILSLOT,              "MAILSLOT"},
        {FILE_DEVICE_MASS_STORAGE,          "MASS_STORAGE"},
        {FILE_DEVICE_MIDI_IN,               "MIDI_IN"},
        {FILE_DEVICE_MIDI_OUT,              "MIDI_OUT"},
        {FILE_DEVICE_MODEM,                 "MODEM"},
        {FILE_DEVICE_MOUSE,                 "MOUSE"},
        {FILE_DEVICE_MULTI_UNC_PROVIDER,    "MULTI_UNC_PROVIDER"},
        {FILE_DEVICE_NAMED_PIPE,            "NAMED_PIPE"},
        {FILE_DEVICE_NETWORK,               "NETWORK"},
        {FILE_DEVICE_NETWORK_BROWSER,       "NETWORK_BROWSER"},
        {FILE_DEVICE_NETWORK_FILE_SYSTEM,   "NETWORK_FILE_SYSTEM"},
        {FILE_DEVICE_NETWORK_REDIRECTOR,    "NETWORK_REDIRECTOR"},
        {FILE_DEVICE_NULL,                  "NULL"},
        {FILE_DEVICE_PARALLEL_PORT,         "PARALLEL_PORT"},
        {FILE_DEVICE_PHYSICAL_NETCARD,      "PHYSICAL_NETCARD"},
        {FILE_DEVICE_PRINTER,               "PRINTER"},
        {FILE_DEVICE_SCANNER,               "SCANNER"},
        {FILE_DEVICE_SCREEN,                "SCREEN"},
        {FILE_DEVICE_SERENUM,               "SERENUM"},
        {FILE_DEVICE_SERIAL_MOUSE_PORT,     "SERIAL_MOUSE_PORT"},
        {FILE_DEVICE_SERIAL_PORT,           "SERIAL_PORT"},
        {FILE_DEVICE_SMARTCARD,             "SMARTCARD"},
        {FILE_DEVICE_SMB,                   "SMB"},
        {FILE_DEVICE_SOUND,                 "SOUND"},
        {FILE_DEVICE_STREAMS,               "STREAMS"},
        {FILE_DEVICE_TAPE,                  "TAPE"},
        {FILE_DEVICE_TAPE_FILE_SYSTEM,      "TAPE_FILE_SYSTEM"},
        {FILE_DEVICE_TERMSRV,               "TERMSRV"},
        {FILE_DEVICE_TRANSPORT,             "TRANSPORT"},
        {FILE_DEVICE_UNKNOWN,               "UNKNOWN"},
        {FILE_DEVICE_VDM,                   "VDM"},
        {FILE_DEVICE_VIDEO,                 "VIDEO"},
        {FILE_DEVICE_VIRTUAL_DISK,          "VIRTUAL_DISK"},
#ifdef FILE_DEVICE_VMBUS
        {FILE_DEVICE_VMBUS,                 "VMBUS"},
#endif
        {FILE_DEVICE_WAVE_IN,               "WAVE_IN"},
        {FILE_DEVICE_WAVE_OUT,              "WAVE_OUT"},
#ifdef FILE_DEVICE_WPD
        {FILE_DEVICE_WPD,                   "WPD"},
#endif
        {0,                                 NULL}};

static const char *_device_type_name (int DeviceType)
{
int i;

for (i=0; DeviceTypes[i].desc; i++)
    if (DeviceTypes[i].Type == DeviceType)
        return DeviceTypes[i].desc;
return "Unknown";
}

static t_stat sim_os_disk_implemented_raw (void)
{
return sim_toffset_64 ? SCPE_OK : SCPE_NOFNC;
}

static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode)
{
HANDLE Handle;
DWORD DesiredAccess = 0;

if (strchr (openmode, 'r'))
    DesiredAccess |= GENERIC_READ;
if (strchr (openmode, 'w') || strchr (openmode, '+'))
    DesiredAccess |= GENERIC_WRITE;
/* SCP Command Line parsing replaces \\ with \ presuming this is an 
   escape sequence.  This only affecdts RAW device names and UNC paths.
   We handle the RAW device name case here by prepending paths beginning 
   with \.\ with an extra \. */
if (!memcmp ("\\.\\", rawdevicename, 3)) {
    char *tmpname = (char *)malloc (2 + strlen (rawdevicename));

    if (tmpname == NULL)
        return NULL;
    *tmpname = '\\';
    strcpy (tmpname + 1, rawdevicename);
    Handle = CreateFileA (tmpname, DesiredAccess, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS|FILE_FLAG_WRITE_THROUGH, NULL);
    free (tmpname);
    if (Handle != INVALID_HANDLE_VALUE)
        return (FILE *)Handle;
    }
Handle = CreateFileA (rawdevicename, DesiredAccess, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS|FILE_FLAG_WRITE_THROUGH, NULL);
if (Handle == INVALID_HANDLE_VALUE) {
    _set_errno_from_status (GetLastError ());
    return NULL;
    }
return (FILE *)Handle;
}

static int sim_os_disk_close_raw (FILE *f)
{
if (!CloseHandle ((HANDLE)f)) {
    _set_errno_from_status (GetLastError ());
    return EOF;
    }
return 0;
}

static void sim_os_disk_flush_raw (FILE *f)
{
FlushFileBuffers ((HANDLE)f);
}

static t_offset sim_os_disk_size_raw (FILE *Disk)
{
DWORD IoctlReturnSize;
LARGE_INTEGER Size;

if (GetFileSizeEx((HANDLE)Disk, &Size))
    return (t_offset)(Size.QuadPart);
#ifdef IOCTL_STORAGE_READ_CAPACITY
if (1) {
    STORAGE_READ_CAPACITY S;

    ZeroMemory (&S, sizeof (S));
    S.Version = sizeof (STORAGE_READ_CAPACITY);
    if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                         IOCTL_STORAGE_READ_CAPACITY,      /* dwIoControlCode */
                         NULL,                             /* lpInBuffer */
                         0,                                /* nInBufferSize */
                         (LPVOID) &S,                      /* output buffer */
                         (DWORD) sizeof(S),                /* size of output buffer */
                         (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                         (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
        return (t_offset)(S.DiskLength.QuadPart);
    }
#endif
#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
if (1) {
    DISK_GEOMETRY_EX G;

    ZeroMemory (&G, sizeof (G));
    if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                         IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, /* dwIoControlCode */
                         NULL,                             /* lpInBuffer */
                         0,                                /* nInBufferSize */
                         (LPVOID) &G,                      /* output buffer */
                         (DWORD) sizeof(G),                /* size of output buffer */
                         (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                         (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
        return (t_offset)(G.DiskSize.QuadPart);
    }
#endif
#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY
if (1) {
    DISK_GEOMETRY G;

    if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                         IOCTL_DISK_GET_DRIVE_GEOMETRY,    /* dwIoControlCode */
                         NULL,                             /* lpInBuffer */
                         0,                                /* nInBufferSize */
                         (LPVOID) &G,                      /* output buffer */
                         (DWORD) sizeof(G),                /* size of output buffer */
                         (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                         (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
        return (t_offset)(G.Cylinders.QuadPart*G.TracksPerCylinder*G.SectorsPerTrack*G.BytesPerSector);
    }
#endif
_set_errno_from_status (GetLastError ());
return (t_offset)-1;
}

static t_stat sim_os_disk_unload_raw (FILE *Disk)
{
#ifdef IOCTL_STORAGE_EJECT_MEDIA
DWORD BytesReturned;
uint32 Removable = FALSE;

sim_os_disk_info_raw (Disk, NULL, &Removable);
if (Removable) {
    if (!DeviceIoControl((HANDLE)Disk,                  /* handle to disk */
                         IOCTL_STORAGE_EJECT_MEDIA,     /* dwIoControlCode */
                         NULL,                          /* lpInBuffer */
                         0,                             /* nInBufferSize */
                         NULL,                          /* lpOutBuffer */
                         0,                             /* nOutBufferSize */
                         (LPDWORD) &BytesReturned,      /* number of bytes returned */
                         (LPOVERLAPPED) NULL)) {        /* OVERLAPPED structure */
        _set_errno_from_status (GetLastError ());
        return SCPE_IOERR;
        }
    }
return SCPE_OK;
#else
return SCPE_NOFNC;
#endif
}

static t_bool sim_os_disk_isavailable_raw (FILE *Disk)
{
#ifdef IOCTL_STORAGE_EJECT_MEDIA
DWORD BytesReturned;
uint32 Removable = FALSE;

sim_os_disk_info_raw (Disk, NULL, &Removable);
if (Removable) {
    if (!DeviceIoControl((HANDLE)Disk,                  /* handle to disk */
                         IOCTL_STORAGE_CHECK_VERIFY,    /* dwIoControlCode */
                         NULL,                          /* lpInBuffer */
                         0,                             /* nInBufferSize */
                         NULL,                          /* lpOutBuffer */
                         0,                             /* nOutBufferSize */
                         (LPDWORD) &BytesReturned,      /* number of bytes returned */
                         (LPOVERLAPPED) NULL)) {        /* OVERLAPPED structure */
        _set_errno_from_status (GetLastError ());
        return FALSE;
        }
    }
#endif
return TRUE;
}

static t_stat sim_os_disk_info_raw (FILE *Disk, uint32 *sector_size, uint32 *removable)
{
DWORD IoctlReturnSize;
STORAGE_DEVICE_NUMBER Device;

ZeroMemory (&Device, sizeof (Device));
if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                     IOCTL_STORAGE_GET_DEVICE_NUMBER,  /* dwIoControlCode */
                     NULL,                             /* lpInBuffer */
                     0,                                /* nInBufferSize */
                     (LPVOID) &Device,                 /* output buffer */
                     (DWORD) sizeof(Device),           /* size of output buffer */
                     (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                     (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
     sim_printf ("Device OK - Type: %s, Number: %d\n", _device_type_name (Device.DeviceType), (int)Device.DeviceNumber);

if (sector_size)
    *sector_size = 512;
if (removable)
    *removable = 0;
#ifdef IOCTL_STORAGE_READ_CAPACITY
if (1) {
    STORAGE_READ_CAPACITY S;

    ZeroMemory (&S, sizeof (S));
    S.Version = sizeof (STORAGE_READ_CAPACITY);
    if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                         IOCTL_STORAGE_READ_CAPACITY,      /* dwIoControlCode */
                         NULL,                             /* lpInBuffer */
                         0,                                /* nInBufferSize */
                         (LPVOID) &S,                      /* output buffer */
                         (DWORD) sizeof(S),                /* size of output buffer */
                         (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                         (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
        if (sector_size)
            *sector_size = S.BlockLength;
    }
#endif
#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
if (1) {
    DISK_GEOMETRY_EX G;

    ZeroMemory (&G, sizeof (G));
    if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                         IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, /* dwIoControlCode */
                         NULL,                             /* lpInBuffer */
                         0,                                /* nInBufferSize */
                         (LPVOID) &G,                      /* output buffer */
                         (DWORD) sizeof(G),                /* size of output buffer */
                         (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                         (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
        if (sector_size)
            *sector_size = G.Geometry.BytesPerSector;
    }
#endif
#ifdef IOCTL_DISK_GET_DRIVE_GEOMETRY
if (1) {
    DISK_GEOMETRY G;

    if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                         IOCTL_DISK_GET_DRIVE_GEOMETRY,    /* dwIoControlCode */
                         NULL,                             /* lpInBuffer */
                         0,                                /* nInBufferSize */
                         (LPVOID) &G,                      /* output buffer */
                         (DWORD) sizeof(G),                /* size of output buffer */
                         (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                         (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
        if (sector_size)
            *sector_size = G.BytesPerSector;
    }
#endif
#ifdef IOCTL_STORAGE_GET_HOTPLUG_INFO
if (1) {
    STORAGE_HOTPLUG_INFO H;

    ZeroMemory (&H, sizeof (H));
    if (DeviceIoControl((HANDLE)Disk,                      /* handle to volume */
                         IOCTL_STORAGE_GET_HOTPLUG_INFO,   /* dwIoControlCode */
                         NULL,                             /* lpInBuffer */
                         0,                                /* nInBufferSize */
                         (LPVOID) &H,                      /* output buffer */
                         (DWORD) sizeof(H),                /* size of output buffer */
                         (LPDWORD) &IoctlReturnSize,       /* number of bytes returned */
                         (LPOVERLAPPED) NULL))             /* OVERLAPPED structure */
        if (removable)
            *removable = H.MediaRemovable;
    }
#endif
if (removable && *removable)
    sim_printf ("Removable Device\n");
return SCPE_OK;
}

static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
OVERLAPPED pos;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
long long addr;

sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

addr = ((long long)lba) * ctx->sector_size;
memset (&pos, 0, sizeof (pos));
pos.Offset = (DWORD)addr;
pos.OffsetHigh = (DWORD)(addr >> 32);
if (ReadFile ((HANDLE)(uptr->fileref), buf, sects * ctx->sector_size, (LPDWORD)sectsread, &pos)) {
    if (sectsread)
        *sectsread /= ctx->sector_size;
    return SCPE_OK;
    }
_set_errno_from_status (GetLastError ());
return SCPE_IOERR;
}

static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{
OVERLAPPED pos;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
long long addr;

sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

addr = ((long long)lba) * ctx->sector_size;
memset (&pos, 0, sizeof (pos));
pos.Offset = (DWORD)addr;
pos.OffsetHigh = (DWORD)(addr >> 32);
if (WriteFile ((HANDLE)(uptr->fileref), buf, sects * ctx->sector_size, (LPDWORD)sectswritten, &pos)) {
    if (sectswritten)
        *sectswritten /= ctx->sector_size;
    return SCPE_OK;
    }
_set_errno_from_status (GetLastError ());
return SCPE_IOERR;
}

#elif defined (__linux) || defined (__linux__) || defined (__sun) || defined (__sun__) || defined (__hpux) || defined (_AIX)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

static t_stat sim_os_disk_implemented_raw (void)
{
return sim_toffset_64 ? SCPE_OK : SCPE_NOFNC;
}

static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode)
{
int mode = 0;

if (strchr (openmode, 'r') && (strchr (openmode, '+') || strchr (openmode, 'w')))
    mode = O_RDWR;
else
    if (strchr (openmode, 'r'))
        mode = O_RDONLY;
#ifdef O_LARGEFILE
mode |= O_LARGEFILE;
#endif
#ifdef O_DSYNC
mode |= O_DSYNC;
#endif
return (FILE *)((long)open (rawdevicename, mode, 0));
}

static int sim_os_disk_close_raw (FILE *f)
{
return close ((int)((long)f));
}

static void sim_os_disk_flush_raw (FILE *f)
{
fsync ((int)((long)f));
}

static t_offset sim_os_disk_size_raw (FILE *f)
{
t_offset pos, size;

pos = (t_offset)lseek ((int)((long)f), (off_t)0, SEEK_CUR);
size = (t_offset)lseek ((int)((long)f), (off_t)0, SEEK_END);
if (pos != (t_offset)-1)
    (void)lseek ((int)((long)f), (off_t)pos, SEEK_SET);
return size;
}

static t_stat sim_os_disk_unload_raw (FILE *f)
{
return SCPE_IOERR;
}

static t_bool sim_os_disk_isavailable_raw (FILE *Disk)
{
return TRUE;
}

static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
off_t addr;
ssize_t bytesread;

sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

addr = ((off_t)lba) * ctx->sector_size;
bytesread = pread((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr);
if (bytesread < 0) {
    if (sectsread)
        *sectsread = 0;
    return SCPE_IOERR;
    }
if (sectsread)
    *sectsread = bytesread / ctx->sector_size;
return SCPE_OK;
}

static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
off_t addr;
ssize_t byteswritten;

sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects);

addr = ((off_t)lba) * ctx->sector_size;
byteswritten = pwrite((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr);
if (byteswritten < 0) {
    if (sectswritten)
        *sectswritten = 0;
    return SCPE_IOERR;
    }
if (sectswritten)
    *sectswritten = byteswritten / ctx->sector_size;
return SCPE_OK;
}

static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable)
{
if (sector_size)
    *sector_size = 512;
if (removable)
    *removable = 0;
return SCPE_OK;
}

#else
/*============================================================================*/
/*                        Non-implemented versions                            */
/*============================================================================*/

static t_stat sim_os_disk_implemented_raw (void)
{
return SCPE_NOFNC;
}

static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode)
{
return NULL;
}

static int sim_os_disk_close_raw (FILE *f)
{
return EOF;
}

static void sim_os_disk_flush_raw (FILE *f)
{
}

static t_offset sim_os_disk_size_raw (FILE *f)
{
return (t_offset)-1;
}

static t_stat sim_os_disk_unload_raw (FILE *f)
{
return SCPE_NOFNC;
}

static t_bool sim_os_disk_isavailable_raw (FILE *Disk)
{
return FALSE;
}

static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
return SCPE_NOFNC;
}

static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{
return SCPE_NOFNC;
}

static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable)
{
return SCPE_NOFNC;
}

#endif

/* OS Independent Disk Virtual Disk (VHD) I/O support */

#if (defined (VMS) && !(defined (__ALPHA) || defined (__ia64)))
#define DONT_DO_VHD_SUPPORT  /* VAX/VMS compilers don't have 64 bit integers */
#endif

#if defined (DONT_DO_VHD_SUPPORT)

/*============================================================================*/
/*                        Non-implemented version                             */
/*   This is only for hody systems which don't have 64 bit integer types      */
/*============================================================================*/

static t_stat sim_vhd_disk_implemented (void)
{
return SCPE_NOFNC;
}

static FILE *sim_vhd_disk_open (const char *vhdfilename, const char *openmode)
{
return NULL;
}

static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD)
{
return NULL;
}

static FILE *sim_vhd_disk_create (const char *szVHDPath, t_offset desiredsize)
{
return NULL;
}

static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szParentVHDPath)
{
return NULL;
}

static int sim_vhd_disk_close (FILE *f)
{
return -1;
}

static void sim_vhd_disk_flush (FILE *f)
{
}

static t_offset sim_vhd_disk_size (FILE *f)
{
return (t_offset)-1;
}

static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
return SCPE_IOERR;
}

static t_stat sim_vhd_disk_clearerr (UNIT *uptr)
{
return SCPE_IOERR;
}

static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{
return SCPE_IOERR;
}

static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype)
{
return SCPE_NOFNC;
}

static const char *sim_vhd_disk_get_dtype (FILE *f)
{
return NULL;
}

#else

/*++
    This code follows the details specified in the "Virtual Hard Disk Image
    Format Specification", Version 1.0 October 11, 2006.  This format
    specification is available for anyone to implement under the
    "Microsoft Open Specification Promise" described at:
        http://www.microsoft.com/interop/osp/default.mspx.
--*/

typedef t_uint64    uint64;
typedef t_int64     int64;

typedef struct _VHD_Footer {
    /*
    Cookies are used to uniquely identify the original creator of the hard disk
    image. The values are case-sensitive.  Microsoft uses the "conectix" string
    to identify this file as a hard disk image created by Microsoft Virtual
    Server, Virtual PC, and predecessor products. The cookie is stored as an
    eight-character ASCII string with the "c" in the first byte, the "o" in
    the second byte, and so on.
    */
    char Cookie[8];
    /*
    This is a bit field used to indicate specific feature support. The following
    table displays the list of features.
    Any fields not listed are reserved.

    Feature Value:
       No features enabled     0x00000000
       Temporary               0x00000001
       Reserved                0x00000002

       No features enabled.
              The hard disk image has no special features enabled in it.
       Temporary.
              This bit is set if the current disk is a temporary disk. A
              temporary disk designation indicates to an application that
              this disk is a candidate for deletion on shutdown.
       Reserved.
              This bit must always be set to 1.
       All other bits are also reserved and should be set to 0.
    */
    uint32 Features;
    /*
    This field is divided into a major/minor version and matches the version of
    the specification used in creating the file. The most-significant two bytes
    are for the major version. The least-significant two bytes are the minor
    version.  This must match the file format specification. For the current
    specification, this field must be initialized to 0x00010000.
    The major version will be incremented only when the file format is modified
    in such a way that it is no longer compatible with older versions of the
    file format.
    */
    uint32 FileFormatVersion;
    /*
    This field holds the absolute byte offset, from the beginning of the file,
    to the next structure. This field is used for dynamic disks and differencing
    disks, but not fixed disks. For fixed disks, this field should be set to
    0xFFFFFFFF.
    */
    uint64 DataOffset;
    /*
    This field stores the creation time of a hard disk image. This is the number
    of seconds since January 1, 2000 12:00:00 AM in UTC/GMT.
    */
    uint32 TimeStamp;
    /*
    This field is used to document which application created the hard disk. The
    field is a left-justified text field. It uses a single-byte character set.
    If the hard disk is created by Microsoft Virtual PC, "vpc " is written in
    this field. If the hard disk image is created by Microsoft Virtual Server,
    then "vs  " is written in this field.
    Other applications should use their own unique identifiers.
    */
    char CreatorApplication[4];
    /*
    This field holds the major/minor version of the application that created
    the hard disk image.  Virtual Server 2004 sets this value to 0x00010000 and
    Virtual PC 2004 sets this to 0x00050000.
    */
    uint32 CreatorVersion;
    /*
    This field stores the type of host operating system this disk image is
    created on.
       Host OS type    Value
       Windows         0x5769326B (Wi2k)
       Macintosh       0x4D616320 (Mac )
    */
    uint8 CreatorHostOS[4];
    /*
    This field stores the size of the hard disk in bytes, from the perspective
    of the virtual machine, at creation time. This field is for informational
    purposes.
    */
    uint64 OriginalSize;
    /*
    This field stores the current size of the hard disk, in bytes, from the
    perspective of the virtual machine.
    This value is same as the original size when the hard disk is created.
    This value can change depending on whether the hard disk is expanded.
    */
    uint64 CurrentSize;
    /*
    This field stores the cylinder, heads, and sectors per track value for the
    hard disk.
       Disk Geometry field          Size (bytes)
       Cylinder                     2
       Heads                        1
       Sectors per track/cylinder   1

    When a hard disk is configured as an ATA hard disk, the CHS values (that is,
    Cylinder, Heads, Sectors per track) are used by the ATA controller to
    determine the size of the disk. When the user creates a hard disk of a
    certain size, the size of the hard disk image in the virtual machine is
    smaller than that created by the user. This is because CHS value calculated
    from the hard disk size is rounded down. The pseudo-code for the algorithm
    used to determine the CHS values can be found in the appendix of this
    document.
    */
    uint32 DiskGeometry;
    /*
       Disk Type field              Value
       None                         0
       Reserved (deprecated)        1
       Fixed hard disk              2
       Dynamic hard disk            3
       Differencing hard disk       4
       Reserved (deprecated)        5
       Reserved (deprecated)        6
    */
    uint32 DiskType;
    /*
    This field holds a basic checksum of the hard disk footer. It is just a
    one's complement of the sum of all the bytes in the footer without the
    checksum field.
    If the checksum verification fails, the Virtual PC and Virtual Server
    products will instead use the header. If the checksum in the header also
    fails, the file should be assumed to be corrupt. The pseudo-code for the
    algorithm used to determine the checksum can be found in the appendix of
    this document.
    */
    uint32 Checksum;
    /*
    Every hard disk has a unique ID stored in the hard disk. This is used to
    identify the hard disk. This is a 128-bit universally unique identifier
    (UUID). This field is used to associate a parent hard disk image with its
    differencing hard disk image(s).
    */
    uint8 UniqueID[16];
    /*
    This field holds a one-byte flag that describes whether the system is in
    saved state. If the hard disk is in the saved state the value is set to 1.
    Operations such as compaction and expansion cannot be performed on a hard
    disk in a saved state.
    */
    uint8 SavedState;
    /*
    This field contains zeroes. It is 427 bytes in size.
    */
    uint8 Reserved1[11];
    /*
    This field is an extension to the VHD spec and includes a simh drive type
    name as a nul terminated string.
    */
    uint8 DriveType[16];
    /*
    This field contains zeroes. It is 400 bytes in size.
    */
    uint8 Reserved[400];
    } VHD_Footer;

/*
For dynamic and differencing disk images, the "Data Offset" field within
the image footer points to a secondary structure that provides additional
information about the disk image. The dynamic disk header should appear on
a sector (512-byte) boundary.
*/
typedef struct _VHD_DynamicDiskHeader {
    /*
    This field holds the value "cxsparse". This field identifies the header.
    */
    char Cookie[8];
    /*
    This field contains the absolute byte offset to the next structure in the
    hard disk image. It is currently unused by existing formats and should be
    set to 0xFFFFFFFF.
    */
    uint64 DataOffset;
    /*
    This field stores the absolute byte offset of the Block Allocation Table
    (BAT) in the file.
    */
    uint64 TableOffset;
    /*
    This field stores the version of the dynamic disk header. The field is
    divided into Major/Minor version. The least-significant two bytes represent
    the minor version, and the most-significant two bytes represent the major
    version. This must match with the file format specification. For this
    specification, this field must be initialized to 0x00010000.
    The major version will be incremented only when the header format is
    modified in such a way that it is no longer compatible with older versions
    of the product.
    */
    uint32 HeaderVersion;
    /*
    This field holds the maximum entries present in the BAT. This should be
    equal to the number of blocks in the disk (that is, the disk size divided
    by the block size).
    */
    uint32 MaxTableEntries;
    /*
    A block is a unit of expansion for dynamic and differencing hard disks. It
    is stored in bytes. This size does not include the size of the block bitmap.
    It is only the size of the data section of the block. The sectors per block
    must always be a power of two. The default value is 0x00200000 (indicating a
    block size of 2 MB).
    */
    uint32 BlockSize;
    /*
    This field holds a basic checksum of the dynamic header. It is a one's
    complement of the sum of all the bytes in the header without the checksum
    field.
    If the checksum verification fails the file should be assumed to be corrupt.
    */
    uint32 Checksum;
    /*
    This field is used for differencing hard disks. A differencing hard disk
    stores a 128-bit UUID of the parent hard disk. For more information, see
    "Creating Differencing Hard Disk Images" later in this paper.
    */
    uint8 ParentUniqueID[16];
    /*
    This field stores the modification time stamp of the parent hard disk. This
    is the number of seconds since January 1, 2000 12:00:00 AM in UTC/GMT.
    */
    uint32 ParentTimeStamp;
    /*
    This field should be set to zero.
    */
    uint32 Reserved0;
    /*
    This field contains a Unicode string (UTF-16) of the parent hard disk
    filename.
    */
    char ParentUnicodeName[512];
    /*
    These entries store an absolute byte offset in the file where the parent
    locator for a differencing hard disk is stored. This field is used only for
    differencing disks and should be set to zero for dynamic disks.
    */
    struct VHD_ParentLocator {
        /*
        The platform code describes which platform-specific format is used for the
        file locator. For Windows, a file locator is stored as a path (for example.
        "c:\disksimages\ParentDisk.vhd"). On a Macintosh system, the file locator
        is a binary large object (blob) that contains an "alias." The parent locator
        table is used to support moving hard disk images across platforms.
        Some current platform codes include the following:
           Platform Code        Description
           None (0x0)
           Wi2r (0x57693272)    [deprecated]
           Wi2k (0x5769326B)    [deprecated]
           W2ru (0x57327275)    Unicode pathname (UTF-16) on Windows relative to the differencing disk pathname.
           W2ku (0x57326B75)    Absolute Unicode (UTF-16) pathname on Windows.
           Mac (0x4D616320)     (Mac OS alias stored as a blob)
           MacX(0x4D616358)     A file URL with UTF-8 encoding conforming to RFC 2396.
        */
        uint8 PlatformCode[4];
        /*
        This field stores the number of 512-byte sectors needed to store the parent
        hard disk locator.
        */
        uint32 PlatformDataSpace;
        /*
        This field stores the actual length of the parent hard disk locator in bytes.
        */
        uint32 PlatformDataLength;
        /*
        This field must be set to zero.
        */
        uint32 Reserved;
        /*
        This field stores the absolute file offset in bytes where the platform
        specific file locator data is stored.
        */
        uint64 PlatformDataOffset;
        /*
        This field stores the absolute file offset in bytes where the platform
        specific file locator data is stored.
        */
        } ParentLocatorEntries[8];
    /*
    This must be initialized to zeroes.
    */
    char Reserved[256];
    } VHD_DynamicDiskHeader;

#define VHD_BAT_FREE_ENTRY (0xFFFFFFFF)
#define VHD_DATA_BLOCK_ALIGNMENT ((uint64)4096)    /* Optimum when underlying storage has 4k sectors */

#define VHD_DT_Fixed                 2  /* Fixed hard disk */
#define VHD_DT_Dynamic               3  /* Dynamic hard disk */
#define VHD_DT_Differencing          4  /* Differencing hard disk */

static uint32 NtoHl(uint32 value);

static uint64 NtoHll(uint64 value);

typedef struct VHD_IOData *VHDHANDLE;

static t_stat ReadFilePosition(FILE *File, void *buf, size_t bufsize, size_t *bytesread, uint64 position)
{
uint32 err = sim_fseeko (File, (t_offset)position, SEEK_SET);
size_t i;

if (bytesread)
    *bytesread = 0;
if (!err) {
    i = fread (buf, 1, bufsize, File);
    err = ferror (File);
    if ((!err) && bytesread)
        *bytesread = i;
    }
return (err ? SCPE_IOERR : SCPE_OK);
}

static t_stat WriteFilePosition(FILE *File, void *buf, size_t bufsize, size_t *byteswritten, uint64 position)
{
uint32 err = sim_fseeko (File, (t_offset)position, SEEK_SET);
size_t i;

if (byteswritten)
    *byteswritten = 0;
if (!err) {
    i = fwrite (buf, 1, bufsize, File);
    err = ferror (File);
    if ((!err) && byteswritten)
        *byteswritten = i;
    }
return (err ? SCPE_IOERR : SCPE_OK);
}

static uint32
CalculateVhdFooterChecksum(void *data,
                           size_t size)
{
uint32 sum = 0;
uint8 *c = (uint8 *)data;

while (size--)
    sum += *c++;
return ~sum;
}

#if defined(_WIN32) || defined (__ALPHA) || defined (__ia64) || defined (VMS)
#ifndef __BYTE_ORDER__
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#endif
#endif
#ifndef __BYTE_ORDER__
#define __BYTE_ORDER__ UNKNOWN
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static uint32
NtoHl(uint32 value)
{
uint8 *l = (uint8 *)&value;
return (uint32)l[3] | ((uint32)l[2]<<8) | ((uint32)l[1]<<16) | ((uint32)l[0]<<24);
}

static uint64
NtoHll(uint64 value)
{
uint8 *l = (uint8 *)&value;
uint64 highresult = (uint64)l[3] | ((uint64)l[2]<<8) | ((uint64)l[1]<<16) | ((uint64)l[0]<<24);
uint32 lowresult = (uint64)l[7] | ((uint64)l[6]<<8) | ((uint64)l[5]<<16) | ((uint64)l[4]<<24);
return (highresult << 32) | lowresult;
}
#elif  __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
static uint32
NtoHl(uint32 value)
{
return value;
}

static uint64
NtoHll(uint64 value)
{
return value;
}
#else
static uint32
NtoHl(uint32 value)
{
uint8 *l = (uint8 *)&value;

if (sim_end)
    return l[3] | (l[2]<<8) | (l[1]<<16) | (l[0]<<24);
return value;
}

static uint64
NtoHll(uint64 value)
{
uint8 *l = (uint8 *)&value;

if (sim_end) {
    uint64 highresult = l[3] | (l[2]<<8) | (l[1]<<16) | (l[0]<<24);
    uint32 lowresult = l[7] | (l[6]<<8) | (l[5]<<16) | (l[4]<<24);
    return (highresult << 32) | lowresult;
    }
return value;
}
#endif

static
int
GetVHDFooter(const char *szVHDPath,
             VHD_Footer *sFooter,
             VHD_DynamicDiskHeader *sDynamic,
             uint32 **aBAT,
             uint32 *ModifiedTimeStamp,
             char *szParentVHDPath,
             size_t ParentVHDPathSize)
{
FILE *File = NULL;
uint64 position;
uint32 sum, saved_sum;
int Return = 0;
VHD_Footer sHeader;
struct stat statb;

memset(sFooter, '\0', sizeof(*sFooter));
if (sDynamic)
    memset(sDynamic, '\0', sizeof(*sDynamic));
if (aBAT)
    *aBAT = NULL;
File = sim_fopen (szVHDPath, "rb");
if (!File) {
    Return = errno;
    goto Return_Cleanup;
    }
if (ModifiedTimeStamp) {
    if (fstat (fileno (File), &statb)) {
        Return = errno;
        goto Return_Cleanup;
        }
    else
        *ModifiedTimeStamp = NtoHl ((uint32)(statb.st_mtime-946684800));
    }
position = sim_fsize_ex (File);
if (((int64)position) == -1) {
    Return = errno;
    goto Return_Cleanup;
    }
position -= sizeof(*sFooter);
if (ReadFilePosition(File,
                     sFooter,
                     sizeof(*sFooter),
                     NULL,
                     position)) {
    Return = errno;
    goto Return_Cleanup;
    }
saved_sum = NtoHl(sFooter->Checksum);
sFooter->Checksum = 0;
sum = CalculateVhdFooterChecksum(sFooter, sizeof(*sFooter));
sFooter->Checksum = NtoHl(saved_sum);
if ((sum != saved_sum) || (memcmp("conectix", sFooter->Cookie, sizeof(sFooter->Cookie)))) {
    Return = EINVAL;                                    /* File Corrupt */
    goto Return_Cleanup;
    }
if (ReadFilePosition(File,
                     &sHeader,
                     sizeof(sHeader),
                     NULL,
                     (uint64)0)) {
    Return = errno;
    goto Return_Cleanup;
    }
if ((NtoHl(sFooter->DiskType) != VHD_DT_Dynamic) &&
    (NtoHl(sFooter->DiskType) != VHD_DT_Differencing) &&
    (NtoHl(sFooter->DiskType) != VHD_DT_Fixed)) {
    Return = EINVAL;                                    /* File Corrupt */
    goto Return_Cleanup;
    }
if (((NtoHl(sFooter->DiskType) == VHD_DT_Dynamic) ||
     (NtoHl(sFooter->DiskType) == VHD_DT_Differencing)) &&
     memcmp(sFooter, &sHeader, sizeof(sHeader))) {
    Return = EINVAL;                                    /* File Corrupt */
    goto Return_Cleanup;
    }
if ((sDynamic) &&
    ((NtoHl(sFooter->DiskType) == VHD_DT_Dynamic) ||
     (NtoHl(sFooter->DiskType) == VHD_DT_Differencing))) {
    if (ReadFilePosition(File,
                         sDynamic,
                         sizeof (*sDynamic),
                         NULL,
                         NtoHll (sFooter->DataOffset))) {
        Return = errno;
        goto Return_Cleanup;
        }
    saved_sum = NtoHl (sDynamic->Checksum);
    sDynamic->Checksum = 0;
    sum = CalculateVhdFooterChecksum (sDynamic, sizeof(*sDynamic));
    sDynamic->Checksum = NtoHl (saved_sum);
    if ((sum != saved_sum) || (memcmp ("cxsparse", sDynamic->Cookie, sizeof (sDynamic->Cookie)))) {
        Return = errno;
        goto Return_Cleanup;
        }
    if (aBAT) {
        *aBAT = (uint32*) malloc(512*((sizeof(**aBAT)*NtoHl(sDynamic->MaxTableEntries)+511)/512));
        if (ReadFilePosition(File,
                             *aBAT,
                             sizeof (**aBAT)*NtoHl(sDynamic->MaxTableEntries),
                             NULL,
                             NtoHll (sDynamic->TableOffset))) {
            Return = EINVAL;                            /* File Corrupt */
            goto Return_Cleanup;
            }
        }
    if (szParentVHDPath && ParentVHDPathSize) {
        VHD_Footer sParentFooter;

        memset (szParentVHDPath, '\0', ParentVHDPathSize);
        if (NtoHl (sFooter->DiskType) == VHD_DT_Differencing) {
            size_t i, j;

            for (j=0; j<8; ++j) {
                uint8 *Pdata;
                uint32 PdataSize;
                char ParentName[512];
                char CheckPath[512];
                uint32 ParentModificationTime;

                if ('\0' == sDynamic->ParentLocatorEntries[j].PlatformCode[0])
                    continue;
                memset (ParentName, '\0', sizeof(ParentName));
                memset (CheckPath, '\0', sizeof(CheckPath));
                PdataSize = NtoHl(sDynamic->ParentLocatorEntries[j].PlatformDataSpace);
                Pdata = (uint8*) calloc (1, PdataSize+2);
                if (!Pdata)
                    continue;
                if (ReadFilePosition(File,
                                     Pdata,
                                     PdataSize,
                                     NULL,
                                     NtoHll (sDynamic->ParentLocatorEntries[j].PlatformDataOffset))) {
                    free (Pdata);
                    continue;
                    }
                for (i=0; i<NtoHl(sDynamic->ParentLocatorEntries[j].PlatformDataLength); i+=2)
                    if ((Pdata[i] == '\0') && (Pdata[i+1] == '\0')) {
                        ParentName[i/2] = '\0';
                        break;
                        }
                    else
                        ParentName[i/2] = Pdata[i] ? Pdata[i] : Pdata[i+1];
                free (Pdata);
                if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ku", 4))
                    strncpy (CheckPath, ParentName, sizeof (CheckPath)-1);
                else
                    if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ru", 4)) {
                        const char *c;

                        if ((c = strrchr (szVHDPath, '\\'))) {
                            memcpy (CheckPath, szVHDPath, c-szVHDPath+1);
                            strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1));
                            }
                        }
                VhdPathToHostPath (CheckPath, CheckPath, sizeof (CheckPath));
                if (0 == GetVHDFooter(CheckPath,
                                      &sParentFooter,
                                      NULL,
                                      NULL,
                                      &ParentModificationTime,
                                      NULL,
                                      0)) {
                    if ((0 == memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID))) &&
                        ((sDynamic->ParentTimeStamp == ParentModificationTime) ||
                         ((NtoHl(sDynamic->ParentTimeStamp)-NtoHl(ParentModificationTime)) == 3600) ||
                         (sim_switches & SWMASK ('O'))))
                         strncpy (szParentVHDPath, CheckPath, ParentVHDPathSize);
                    else {
                        if (0 != memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID)))
                            sim_printf ("Error Invalid Parent VHD '%s' for Differencing VHD: %s\n", CheckPath, szVHDPath);
                        else
                            sim_printf ("Error Parent VHD '%s' has been modified since Differencing VHD: %s was created\n", CheckPath, szVHDPath);
                        Return = EINVAL;                /* File Corrupt/Invalid */
                        }
                    break;
                    }
                else {
                    struct stat statb;

                    if (0 == stat (CheckPath, &statb)) {
                        sim_printf ("Parent VHD '%s' corrupt for Differencing VHD: %s\n", CheckPath, szVHDPath);
                        Return = EBADF;                /* File Corrupt/Invalid */
                        break;
                        }
                    }
                }
            if (!*szParentVHDPath) {
                if (Return != EINVAL)                   /* File Not Corrupt? */
                    sim_printf ("Missing Parent VHD for Differencing VHD: %s\n", szVHDPath);
                Return = EBADF;
                }
            }
        }
    }
Return_Cleanup:
if (File)
    fclose(File);
if (aBAT && (0 != Return)) {
    free (*aBAT);
    *aBAT = NULL;
    }
return errno = Return;
}

struct VHD_IOData {
    VHD_Footer Footer;
    VHD_DynamicDiskHeader Dynamic;
    uint32 *BAT;
    FILE *File;
    char ParentVHDPath[512];
    struct VHD_IOData *Parent;
    };

static t_stat sim_vhd_disk_implemented (void)
{
return SCPE_OK;
}

static t_stat sim_vhd_disk_set_dtype (FILE *f, const char *dtype)
{
VHDHANDLE hVHD  = (VHDHANDLE)f;
int Status = 0;

memset (hVHD->Footer.DriveType, '\0', sizeof hVHD->Footer.DriveType);
memcpy (hVHD->Footer.DriveType, dtype, ((1+strlen (dtype)) < sizeof (hVHD->Footer.DriveType)) ? (1+strlen (dtype)) : sizeof (hVHD->Footer.DriveType));
hVHD->Footer.Checksum = 0;
hVHD->Footer.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Footer, sizeof(hVHD->Footer)));

if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Fixed) {
    if (WriteFilePosition(hVHD->File,
                          &hVHD->Footer,
                          sizeof(hVHD->Footer),
                          NULL,
                          NtoHll (hVHD->Footer.CurrentSize)))
        Status = errno;
    goto Cleanup_Return;
    }
else {
    uint64 position;

    position = sim_fsize_ex (hVHD->File);
    if (((int64)position) == -1) {
        Status = errno;
        goto Cleanup_Return;
        }
    position -= sizeof(hVHD->Footer);
    /* Update both copies on a dynamic disk */
    if (WriteFilePosition(hVHD->File,
                          &hVHD->Footer,
                          sizeof(hVHD->Footer),
                          NULL,
                          (uint64)0)) {
        Status = errno;
        goto Cleanup_Return;
        }
    if (WriteFilePosition(hVHD->File,
                          &hVHD->Footer,
                          sizeof(hVHD->Footer),
                          NULL,
                          position)) {
        Status = errno;
        goto Cleanup_Return;
        }
    }
Cleanup_Return:
if (Status)
    return SCPE_IOERR;
return SCPE_OK;
}

static const char *sim_vhd_disk_get_dtype (FILE *f)
{
VHDHANDLE hVHD  = (VHDHANDLE)f;

return (char *)(&hVHD->Footer.DriveType[0]);
}

static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess)
    {
    VHDHANDLE hVHD = (VHDHANDLE) calloc (1, sizeof(*hVHD));
    int NeedUpdate = FALSE;
    int Status;

    if (!hVHD)
        return (FILE *)hVHD;
    Status = GetVHDFooter (szVHDPath,
                           &hVHD->Footer,
                           &hVHD->Dynamic,
                           &hVHD->BAT,
                           NULL,
                           hVHD->ParentVHDPath,
                           sizeof (hVHD->ParentVHDPath));
    if (Status)
        goto Cleanup_Return;
    if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Differencing) {
        uint32 ParentModifiedTimeStamp;
        VHD_Footer ParentFooter;
        VHD_DynamicDiskHeader ParentDynamic;

        hVHD->Parent = (VHDHANDLE)sim_vhd_disk_open (hVHD->ParentVHDPath, "rb");
        if (!hVHD->Parent) {
            Status = errno;
            goto Cleanup_Return;
            }
        Status = GetVHDFooter (hVHD->ParentVHDPath,
                               &ParentFooter,
                               &ParentDynamic,
                               NULL,
                               &ParentModifiedTimeStamp,
                               NULL,
                               0);
        if (Status)
            goto Cleanup_Return;
        if ((0 != memcmp (hVHD->Dynamic.ParentUniqueID, ParentFooter.UniqueID, sizeof (ParentFooter.UniqueID))) || 
            (ParentModifiedTimeStamp != hVHD->Dynamic.ParentTimeStamp)) {
            if (sim_switches & SWMASK ('O')) {                      /* OVERRIDE consistency checks? */
                if ((sim_switches & SWMASK ('U')) &&                /* FIX (UPDATE) consistency checks AND */
                    (strchr (DesiredAccess, '+'))) {                /* open for write/update? */
                    memcpy (hVHD->Dynamic.ParentUniqueID, ParentFooter.UniqueID, sizeof (ParentFooter.UniqueID));
                    hVHD->Dynamic.ParentTimeStamp = ParentModifiedTimeStamp;
                    hVHD->Dynamic.Checksum = 0;
                    hVHD->Dynamic.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Dynamic, sizeof(hVHD->Dynamic)));
                    NeedUpdate = TRUE;
                    }
                }
            else {
                Status = EBADF;
                goto Cleanup_Return;
                }
            }
        }
    if (hVHD->Footer.SavedState) {
        Status = EAGAIN;                                /* Busy */
        goto Cleanup_Return;
        }
    hVHD->File = sim_fopen (szVHDPath, DesiredAccess);
    if (!hVHD->File) {
        Status = errno;
        goto Cleanup_Return;
        }
Cleanup_Return:
    if (Status) {
        sim_vhd_disk_close ((FILE *)hVHD);
        hVHD = NULL;
        }
    else {
        if (NeedUpdate) {                               /* Update Differencing Disk Header? */
            if (WriteFilePosition(hVHD->File,
                                  &hVHD->Dynamic,
                                  sizeof (hVHD->Dynamic),
                                  NULL,
                                  NtoHll (hVHD->Footer.DataOffset))) {
                sim_vhd_disk_close ((FILE *)hVHD);
                hVHD = NULL;
                }
            }
        }
    errno = Status;
    return (FILE *)hVHD;
    }

static t_stat
WriteVirtualDiskSectors(VHDHANDLE hVHD,
                        uint8 *buf,
                        t_seccnt sects,
                        t_seccnt *sectswritten,
                        uint32 SectorSize,
                        t_lba lba);

static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD)
    {
    VHDHANDLE hVHD = (VHDHANDLE) calloc (1, sizeof(*hVHD));
    VHDHANDLE Parent = NULL;
    int Status;
    uint32 SectorSize, SectorsPerBlock, BlockSize, BlockNumber, BitMapBytes, BitMapSectors, BlocksToMerge, NeededBlock;
    uint64 BlockOffset;
    size_t BytesRead;
    t_seccnt SectorsWritten;
    void *BlockData = NULL;

    if (!hVHD)
        return (FILE *)hVHD;
    if (0 != (Status = GetVHDFooter (szVHDPath,
                                     &hVHD->Footer,
                                     &hVHD->Dynamic,
                                     &hVHD->BAT,
                                     NULL,
                                     hVHD->ParentVHDPath,
                                     sizeof (hVHD->ParentVHDPath))))
        goto Cleanup_Return;
    if (NtoHl (hVHD->Footer.DiskType) != VHD_DT_Differencing) {
        Status = EINVAL;
        goto Cleanup_Return;
        }
    if (hVHD->Footer.SavedState) {
        Status = EAGAIN;                                /* Busy */
        goto Cleanup_Return;
        }
    SectorSize = 512;
    BlockSize = NtoHl (hVHD->Dynamic.BlockSize);
    BlockData = malloc (BlockSize*SectorSize);
    if (NULL == BlockData) {
        Status = errno;
        goto Cleanup_Return;
        }
    Parent = (VHDHANDLE)sim_vhd_disk_open (hVHD->ParentVHDPath, "rb+");
    if (!Parent) {
        Status = errno;
        goto Cleanup_Return;
        }
    hVHD->File = sim_fopen (szVHDPath, "rb");
    if (!hVHD->File) {
        Status = errno;
        goto Cleanup_Return;
        }
    SectorsPerBlock = NtoHl (hVHD->Dynamic.BlockSize)/SectorSize;
    BitMapBytes = (7+(NtoHl (hVHD->Dynamic.BlockSize)/SectorSize))/8;
    BitMapSectors = (BitMapBytes+SectorSize-1)/SectorSize;
    for (BlockNumber=BlocksToMerge=0; BlockNumber< NtoHl (hVHD->Dynamic.MaxTableEntries); ++BlockNumber) {
        if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY)
            continue;
        ++BlocksToMerge;
        }
    if (!sim_quiet)
        sim_printf ("Merging %s\ninto %s\n", szVHDPath, hVHD->ParentVHDPath);
    for (BlockNumber=NeededBlock=0; BlockNumber < NtoHl (hVHD->Dynamic.MaxTableEntries); ++BlockNumber) {
        uint32 BlockSectors = SectorsPerBlock;

        if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY)
            continue;
        ++NeededBlock;
        BlockOffset = SectorSize*((uint64)(NtoHl (hVHD->BAT[BlockNumber]) + BitMapSectors));
        if (((uint64)BlockNumber*SectorsPerBlock + BlockSectors) > ((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize)
            BlockSectors = (uint32)(((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize - (BlockNumber*SectorsPerBlock));
        if (ReadFilePosition(hVHD->File,
                             BlockData,
                             SectorSize*BlockSectors,
                             &BytesRead,
                             BlockOffset))
            break;
        if (WriteVirtualDiskSectors (Parent,
                                     (uint8*)BlockData,
                                     BlockSectors,
                                     &SectorsWritten,
                                     SectorSize,
                                     SectorsPerBlock*BlockNumber))
            break;
        if (!sim_quiet)
            sim_printf ("Merged %dMB.  %d%% complete.\r", (int)((((float)NeededBlock)*SectorsPerBlock)*SectorSize/1000000), (int)((((float)NeededBlock)*100)/BlocksToMerge));
        hVHD->BAT[BlockNumber] = VHD_BAT_FREE_ENTRY;
        }
    if (BlockNumber < NtoHl (hVHD->Dynamic.MaxTableEntries)) {
        Status = errno;
        }
    else {
        Status = 0;
        if (!sim_quiet)
            sim_printf ("Merged %dMB.  100%% complete.\n", (int)((((float)NeededBlock)*SectorsPerBlock)*SectorSize/1000000));
        fclose (hVHD->File);
        hVHD->File = NULL;
        (void)remove (szVHDPath);
        *ParentVHD = (char*) malloc (strlen (hVHD->ParentVHDPath)+1);
        strcpy (*ParentVHD, hVHD->ParentVHDPath);
        }
Cleanup_Return:
    free (BlockData);
    if (hVHD->File)
        fclose (hVHD->File);
    if (Status) {
        free (hVHD->BAT);
        free (hVHD);
        hVHD = NULL;
        sim_vhd_disk_close ((FILE *)Parent);
        }
    else {
        free (hVHD->BAT);
        free (hVHD);
        hVHD = Parent;
        }
    errno = Status;
    return (FILE *)hVHD;
    }

static int sim_vhd_disk_close (FILE *f)
{
VHDHANDLE hVHD = (VHDHANDLE)f;

if (NULL != hVHD) {
    if (hVHD->Parent)
        sim_vhd_disk_close ((FILE *)hVHD->Parent);
    free (hVHD->BAT);
    if (hVHD->File) {
        fflush (hVHD->File);
        fclose (hVHD->File);
        }
    free (hVHD);
    return 0;
    }
return -1;
}

static void sim_vhd_disk_flush (FILE *f)
{
VHDHANDLE hVHD = (VHDHANDLE)f;

if ((NULL != hVHD) && (hVHD->File))
    fflush (hVHD->File);
}

static t_offset sim_vhd_disk_size (FILE *f)
{
VHDHANDLE hVHD = (VHDHANDLE)f;

return (t_offset)(NtoHll (hVHD->Footer.CurrentSize));
}

#include <stdlib.h>
#include <time.h>
static void
_rand_uuid_gen (void *uuidaddr)
{
int i;
uint8 *b = (uint8 *)uuidaddr;
uint32 timenow = (uint32)time (NULL);

memcpy (uuidaddr, &timenow, sizeof (timenow));
srand ((unsigned)timenow);
for (i=4; i<16; i++) {
    b[i] = (uint8)rand();
    }
}

#if defined (_WIN32)
static void
uuid_gen (void *uuidaddr)
{
static
RPC_STATUS
(RPC_ENTRY *UuidCreate_c) (void *);

if (!UuidCreate_c) {
    HINSTANCE hDll;
    hDll = LoadLibraryA("rpcrt4.dll");
    UuidCreate_c = (RPC_STATUS (RPC_ENTRY *) (void *))GetProcAddress(hDll, "UuidCreate");
    }
if (UuidCreate_c)
    UuidCreate_c(uuidaddr);
else
    _rand_uuid_gen (uuidaddr);
}
#elif defined (HAVE_DLOPEN)
#include <dlfcn.h>

static void
uuid_gen (void *uuidaddr)
{
void (*uuid_generate_c) (void *) = NULL;
void *handle;

#define S__STR_QUOTE(tok) #tok
#define S__STR(tok) S__STR_QUOTE(tok)
    handle = dlopen("libuuid." S__STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL);
    if (handle)
        uuid_generate_c = (void (*)(void *))((size_t)dlsym(handle, "uuid_generate"));
if (uuid_generate_c)
    uuid_generate_c(uuidaddr);
else
    _rand_uuid_gen (uuidaddr);
    if (handle)
        dlclose(handle);
}
#else
static void
uuid_gen (void *uuidaddr)
{
_rand_uuid_gen (uuidaddr);
}
#endif

static VHDHANDLE
CreateVirtualDisk(const char *szVHDPath,
                  uint32 SizeInSectors,
                  uint32 BlockSize,
                  t_bool bFixedVHD)
{
VHD_Footer Footer;
VHD_DynamicDiskHeader Dynamic;
uint32 *BAT = NULL;
time_t now;
uint32 i;
FILE *File = NULL;
uint32 Status = 0;
uint32 BytesPerSector = 512;
uint64 SizeInBytes = ((uint64)SizeInSectors)*BytesPerSector;
uint64 TableOffset;
uint32 MaxTableEntries;
VHDHANDLE hVHD = NULL;

if (SizeInBytes > ((uint64)(1024*1024*1024))*2040) {
    Status = EFBIG;
    goto Cleanup_Return;
    }
File = sim_fopen (szVHDPath, "rb");
if (File) {
    fclose (File);
    File = NULL;
    Status = EEXIST;
    goto Cleanup_Return;
    }
File = sim_fopen (szVHDPath, "wb");
if (!File) {
    Status = errno;
    goto Cleanup_Return;
    }

memset (&Footer, 0, sizeof(Footer));
memcpy (Footer.Cookie, "conectix", 8);
Footer.Features = NtoHl (0x00000002);;
Footer.FileFormatVersion = NtoHl (0x00010000);;
Footer.DataOffset = NtoHll (bFixedVHD ? ((long long)-1) : (long long)(sizeof(Footer)));
time (&now);
Footer.TimeStamp = NtoHl ((uint32)(now-946684800));
memcpy (Footer.CreatorApplication, "simh", 4);
Footer.CreatorVersion = NtoHl (0x00040000);
memcpy (Footer.CreatorHostOS, "Wi2k", 4);
Footer.OriginalSize = NtoHll (SizeInBytes);
Footer.CurrentSize = NtoHll (SizeInBytes);
uuid_gen (Footer.UniqueID);
Footer.DiskType = NtoHl (bFixedVHD ? VHD_DT_Fixed : VHD_DT_Dynamic);
Footer.DiskGeometry = NtoHl (0xFFFF10FF);
if (1) { /* CHS Calculation */
    uint32 totalSectors = (uint32)(SizeInBytes/BytesPerSector);/* Total data sectors present in the disk image */
    uint32 cylinders;                                          /* Number of cylinders present on the disk */
    uint32 heads;                                              /* Number of heads present on the disk */
    uint32 sectorsPerTrack;                                    /* Sectors per track on the disk */
    uint32 cylinderTimesHeads;                                 /* Cylinders x heads */

    if (totalSectors > 65535 * 16 * 255)
        totalSectors = 65535 * 16 * 255;

    if (totalSectors >= 65535 * 16 * 63) {
        sectorsPerTrack = 255;
        heads = 16;
        cylinderTimesHeads = totalSectors / sectorsPerTrack;
        }
    else {
        sectorsPerTrack = 17;
        cylinderTimesHeads = totalSectors / sectorsPerTrack;

        heads = (cylinderTimesHeads + 1023) / 1024;

        if (heads < 4)
            heads = 4;
        if (cylinderTimesHeads >= (heads * 1024) || heads > 16)
            {
            sectorsPerTrack = 31;
            heads = 16;
            cylinderTimesHeads = totalSectors / sectorsPerTrack;
            }
        if (cylinderTimesHeads >= (heads * 1024))
            {
            sectorsPerTrack = 63;
            heads = 16;
            cylinderTimesHeads = totalSectors / sectorsPerTrack;
            }
        }
    cylinders = cylinderTimesHeads / heads;
    Footer.DiskGeometry = NtoHl ((cylinders<<16)|(heads<<8)|sectorsPerTrack);
    }
Footer.Checksum = NtoHl (CalculateVhdFooterChecksum(&Footer, sizeof(Footer)));

if (bFixedVHD) {
    if (WriteFilePosition(File,
                          &Footer,
                          sizeof(Footer),
                          NULL,
                          SizeInBytes))
        Status = errno;
    goto Cleanup_Return;
    }

/* Dynamic Disk */
memset (&Dynamic, 0, sizeof(Dynamic));
memcpy (Dynamic.Cookie, "cxsparse", 8);
Dynamic.DataOffset = NtoHll ((uint64)0xFFFFFFFFFFFFFFFFLL);
TableOffset = NtoHll(Footer.DataOffset)+sizeof(Dynamic);
Dynamic.TableOffset = NtoHll (TableOffset);
Dynamic.HeaderVersion = NtoHl (0x00010000);
if (0 == BlockSize)
    BlockSize = 2*1024*1024;
Dynamic.BlockSize = NtoHl (BlockSize);
MaxTableEntries = (uint32)((SizeInBytes+BlockSize-1)/BlockSize);
Dynamic.MaxTableEntries = NtoHl (MaxTableEntries);
Dynamic.Checksum = NtoHl (CalculateVhdFooterChecksum(&Dynamic, sizeof(Dynamic)));
BAT = (uint32*) malloc (BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector));
memset (BAT, 0, BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector));
for (i=0; i<MaxTableEntries; ++i)
    BAT[i] = VHD_BAT_FREE_ENTRY;

if (WriteFilePosition(File,
                      &Footer,
                      sizeof(Footer),
                      NULL,
                      0)) {
    Status = errno;
    goto Cleanup_Return;
    }
if (WriteFilePosition(File,
                      &Dynamic,
                      sizeof(Dynamic),
                      NULL,
                      NtoHll(Footer.DataOffset))) {
    Status = errno;
    goto Cleanup_Return;
    }
if (WriteFilePosition(File,
                      BAT,
                      BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector),
                      NULL,
                      NtoHll(Dynamic.TableOffset))) {
    Status = errno;
    goto Cleanup_Return;
    }
if (WriteFilePosition(File,
                      &Footer,
                      sizeof(Footer),
                      NULL,
                      NtoHll(Dynamic.TableOffset)+BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector))) {
    Status = errno;
    goto Cleanup_Return;
    }

Cleanup_Return:
free (BAT);
if (File)
    fclose (File);
if (Status) {
    if (Status != EEXIST)
        (void)remove (szVHDPath);
    }
else {
    hVHD = (VHDHANDLE)sim_vhd_disk_open (szVHDPath, "rb+");
    if (!hVHD)
        Status = errno;
    }
errno = Status;
return hVHD;
}

#if defined(__CYGWIN__) || defined(VMS) || defined(__APPLE__) || defined(__linux) || defined(__linux__) || defined(__unix__)
#include <unistd.h>
#endif
static void
ExpandToFullPath (const char *szFileSpec,
                  char *szFullFileSpecBuffer,
                  size_t BufferSize)
{
char *c;
#ifdef _WIN32
for (c = strchr (szFullFileSpecBuffer, '/'); c; c = strchr (szFullFileSpecBuffer, '/'))
    *c = '\\';
GetFullPathNameA (szFileSpec, (DWORD)BufferSize, szFullFileSpecBuffer, NULL);
for (c = strchr (szFullFileSpecBuffer, '\\'); c; c = strchr (szFullFileSpecBuffer, '\\'))
    *c = '/';
#else
char buffer[PATH_MAX];
char *wd = getcwd(buffer, PATH_MAX);

if ((szFileSpec[0] != '/') || (strchr (szFileSpec, ':')))
    snprintf (szFullFileSpecBuffer, BufferSize, "%s/%s", wd, szFileSpec);
else
    strncpy (szFullFileSpecBuffer, szFileSpec, BufferSize);
if ((c = strstr (szFullFileSpecBuffer, "]/")))
    memmove (c+1, c+2, strlen(c+2)+1);
memset (szFullFileSpecBuffer + strlen (szFullFileSpecBuffer), 0, BufferSize - strlen (szFullFileSpecBuffer));
#endif
}

static char *
HostPathToVhdPath (const char *szHostPath,
                   char *szVhdPath,
                   size_t VhdPathSize)
{
char *c, *d;

strncpy (szVhdPath, szHostPath, VhdPathSize-1);
if ((szVhdPath[1] == ':') && islower(szVhdPath[0]))
    szVhdPath[0] = toupper(szVhdPath[0]);
szVhdPath[VhdPathSize-1] = '\0';
if ((c = strrchr (szVhdPath, ']'))) {
    *c = '\0';
    if (!(d = strchr (szVhdPath, '[')))
        return d;
    *d = '/';
    while ((d = strchr (d, '.')))
        *d = '/';
    *c = '/';
    }
while ((c = strchr (szVhdPath, '/')))
    *c = '\\';
for (c = strstr (szVhdPath, "\\.\\"); c; c = strstr (szVhdPath, "\\.\\"))
    memmove (c, c+2, strlen(c+2)+1);
for (c = strstr (szVhdPath, "\\\\"); c; c = strstr (szVhdPath, "\\\\"))
    memmove (c, c+1, strlen(c+1)+1);
while ((c = strstr (szVhdPath, "\\..\\"))) {
    *c = '\0';
    d = strrchr (szVhdPath, '\\');
    if (d)
        memmove (d, c+3, strlen(c+3)+1);
    else
        return d;
    }
memset (szVhdPath + strlen (szVhdPath), 0, VhdPathSize - strlen (szVhdPath));
return szVhdPath;
}

static char *
VhdPathToHostPath (const char *szVhdPath,
                   char *szHostPath,
                   size_t HostPathSize)
{
char *c;
char *d = szHostPath;

strncpy (szHostPath, szVhdPath, HostPathSize-1);
szHostPath[HostPathSize-1] = '\0';
#if defined(VMS)
c = strchr (szVhdPath, ':');
if (*(c+1) != '\\')
    return NULL;
*(c+1) = '[';
d = strrchr (c+2, '\\');
if (d) {
    *d = ']';
    while ((d = strrchr (c+2, '\\')))
        *d = '.';
    }
else
    return NULL;
#else
while ((c = strchr (d, '\\')))
    *c = '/';
#endif
memset (szHostPath + strlen (szHostPath), 0, HostPathSize - strlen (szHostPath));
return szHostPath;
}

static VHDHANDLE
CreateDifferencingVirtualDisk(const char *szVHDPath,
                              const char *szParentVHDPath)
{
uint32 BytesPerSector = 512;
VHDHANDLE hVHD = NULL;
VHD_Footer ParentFooter;
VHD_DynamicDiskHeader ParentDynamic;
uint32 ParentTimeStamp;
uint32 Status = 0;
char *RelativeParentVHDPath = NULL;
char *FullParentVHDPath = NULL;
char *RelativeParentVHDPathUnicode = NULL;
char *FullParentVHDPathUnicode = NULL;
char *FullVHDPath = NULL;
char *TempPath = NULL;
size_t i, RelativeMatch, UpDirectories, LocatorsWritten = 0;
int64 LocatorPosition;

if ((Status = GetVHDFooter (szParentVHDPath,
                            &ParentFooter,
                            &ParentDynamic,
                            NULL,
                            &ParentTimeStamp,
                            NULL,
                            0)))
    goto Cleanup_Return;
hVHD = CreateVirtualDisk (szVHDPath,
                          (uint32)(NtoHll(ParentFooter.CurrentSize)/BytesPerSector),
                          NtoHl(ParentDynamic.BlockSize),
                          FALSE);
if (!hVHD) {
    Status = errno;
    goto Cleanup_Return;
    }
LocatorPosition = ((sizeof (hVHD->Footer) + BytesPerSector - 1)/BytesPerSector + (sizeof (hVHD->Dynamic) + BytesPerSector - 1)/BytesPerSector)*BytesPerSector;
hVHD->Dynamic.Checksum = 0;
RelativeParentVHDPath = (char*) calloc (1, BytesPerSector+2);
FullParentVHDPath = (char*) calloc (1, BytesPerSector+2);
RelativeParentVHDPathUnicode = (char*) calloc (1, BytesPerSector+2);
FullParentVHDPathUnicode = (char*) calloc (1, BytesPerSector+2);
FullVHDPath = (char*) calloc (1, BytesPerSector+2);
TempPath = (char*) calloc (1, BytesPerSector+2);
ExpandToFullPath (szParentVHDPath, TempPath, BytesPerSector);
HostPathToVhdPath (TempPath, FullParentVHDPath, BytesPerSector);
for (i=0; i < strlen (FullParentVHDPath); i++)
    hVHD->Dynamic.ParentUnicodeName[i*2+1] = FullParentVHDPath[i];  /* Big Endian Unicode */
for (i=0; i < strlen (FullParentVHDPath); i++)
    FullParentVHDPathUnicode[i*2] = FullParentVHDPath[i];           /* Little Endian Unicode */
ExpandToFullPath (szVHDPath, TempPath, BytesPerSector);
HostPathToVhdPath (TempPath, FullVHDPath, BytesPerSector);
for (i=0, RelativeMatch=UpDirectories=0; i<strlen(FullVHDPath); i++)
    if (FullVHDPath[i] == '\\') {
        if (memcmp (FullVHDPath, FullParentVHDPath, i+1))
            ++UpDirectories;
        else
            RelativeMatch = i;
        }
if (RelativeMatch) {
    char UpDir[4] = "..\\";

    UpDir[2] = FullParentVHDPath[RelativeMatch];
    if (UpDirectories)
        for (i=0; i<UpDirectories; i++)
            strcpy (RelativeParentVHDPath+strlen (RelativeParentVHDPath), UpDir);
    else
        strcpy (RelativeParentVHDPath+strlen (RelativeParentVHDPath), UpDir+1);
    strcpy (RelativeParentVHDPath+strlen (RelativeParentVHDPath), &FullParentVHDPath[RelativeMatch+1]);
    }
for (i=0; i < strlen(RelativeParentVHDPath); i++)
    RelativeParentVHDPathUnicode[i*2] = RelativeParentVHDPath[i];
hVHD->Dynamic.ParentTimeStamp = ParentTimeStamp;
memcpy (hVHD->Dynamic.ParentUniqueID, ParentFooter.UniqueID, sizeof (hVHD->Dynamic.ParentUniqueID));
/* There are two potential parent locators on current vhds */
memcpy (hVHD->Dynamic.ParentLocatorEntries[0].PlatformCode, "W2ku", 4);
hVHD->Dynamic.ParentLocatorEntries[0].PlatformDataSpace = NtoHl (BytesPerSector);
hVHD->Dynamic.ParentLocatorEntries[0].PlatformDataLength = NtoHl ((uint32)(2*strlen(FullParentVHDPath)));
hVHD->Dynamic.ParentLocatorEntries[0].Reserved = 0;
hVHD->Dynamic.ParentLocatorEntries[0].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector);
++LocatorsWritten;
if (RelativeMatch) {
    memcpy (hVHD->Dynamic.ParentLocatorEntries[1].PlatformCode, "W2ru", 4);
    hVHD->Dynamic.ParentLocatorEntries[1].PlatformDataSpace = NtoHl (BytesPerSector);
    hVHD->Dynamic.ParentLocatorEntries[1].PlatformDataLength = NtoHl ((uint32)(2*strlen(RelativeParentVHDPath)));
    hVHD->Dynamic.ParentLocatorEntries[1].Reserved = 0;
    hVHD->Dynamic.ParentLocatorEntries[1].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector);
    ++LocatorsWritten;
    }
hVHD->Dynamic.TableOffset = NtoHll (((LocatorPosition+LocatorsWritten*BytesPerSector + VHD_DATA_BLOCK_ALIGNMENT - 1)/VHD_DATA_BLOCK_ALIGNMENT)*VHD_DATA_BLOCK_ALIGNMENT);
hVHD->Dynamic.Checksum = 0;
hVHD->Dynamic.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Dynamic, sizeof(hVHD->Dynamic)));
hVHD->Footer.Checksum = 0;
hVHD->Footer.DiskType = NtoHl (VHD_DT_Differencing);
memcpy (hVHD->Footer.DriveType, ParentFooter.DriveType, sizeof (hVHD->Footer.DriveType));
hVHD->Footer.Checksum = NtoHl (CalculateVhdFooterChecksum (&hVHD->Footer, sizeof(hVHD->Footer)));

if (WriteFilePosition (hVHD->File,
                       &hVHD->Footer,
                       sizeof (hVHD->Footer),
                       NULL,
                       0)) {
    Status = errno;
    goto Cleanup_Return;
    }
if (WriteFilePosition (hVHD->File,
                       &hVHD->Dynamic,
                       sizeof (hVHD->Dynamic),
                       NULL,
                       NtoHll (hVHD->Footer.DataOffset))) {
    Status = errno;
    goto Cleanup_Return;
    }
if (WriteFilePosition (hVHD->File,
                       hVHD->BAT,
                       BytesPerSector*((NtoHl (hVHD->Dynamic.MaxTableEntries)*sizeof(*hVHD->BAT)+BytesPerSector-1)/BytesPerSector),
                       NULL,
                       NtoHll (hVHD->Dynamic.TableOffset))) {
    Status = errno;
    goto Cleanup_Return;
    }
if (WriteFilePosition (hVHD->File,
                       &hVHD->Footer,
                       sizeof (hVHD->Footer),
                       NULL,
                       NtoHll (hVHD->Dynamic.TableOffset)+BytesPerSector*((NtoHl (hVHD->Dynamic.MaxTableEntries)*sizeof(*hVHD->BAT)+BytesPerSector-1)/BytesPerSector))) {
    Status = errno;
    goto Cleanup_Return;
    }
if (hVHD->Dynamic.ParentLocatorEntries[0].PlatformDataLength)
    if (WriteFilePosition (hVHD->File,
                           FullParentVHDPathUnicode,
                           BytesPerSector,
                           NULL,
                           NtoHll (hVHD->Dynamic.ParentLocatorEntries[0].PlatformDataOffset))) {
        Status = errno;
        goto Cleanup_Return;
        }
if (hVHD->Dynamic.ParentLocatorEntries[1].PlatformDataLength)
    if (WriteFilePosition (hVHD->File,
                           RelativeParentVHDPathUnicode,
                           BytesPerSector,
                           NULL,
                           NtoHll (hVHD->Dynamic.ParentLocatorEntries[1].PlatformDataOffset))) {
        Status = errno;
        goto Cleanup_Return;
        }

Cleanup_Return:
free (RelativeParentVHDPath);
free (FullParentVHDPath);
free (RelativeParentVHDPathUnicode);
free (FullParentVHDPathUnicode);
free (FullVHDPath);
free (TempPath);
sim_vhd_disk_close ((FILE *)hVHD);
hVHD = NULL;
if (Status) {
    if ((EEXIST != Status) && (ENOENT != Status))
        (void)remove (szVHDPath);
    }
else {
    hVHD = (VHDHANDLE)sim_vhd_disk_open (szVHDPath, "rb+");
    if (!hVHD)
        Status = errno;
    }
errno = Status;
return hVHD;
}

static FILE *sim_vhd_disk_create (const char *szVHDPath, t_offset desiredsize)
{
return (FILE *)CreateVirtualDisk (szVHDPath, (uint32)(desiredsize/512), 0, (sim_switches & SWMASK ('X')));
}

static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szParentVHDPath)
{
return (FILE *)CreateDifferencingVirtualDisk (szVHDPath, szParentVHDPath);
}

static t_stat
ReadVirtualDiskSectors(VHDHANDLE hVHD,
                       uint8 *buf,
                       t_seccnt sects,
                       t_seccnt *sectsread,
                       uint32 SectorSize,
                       t_lba lba)
{
uint64 BlockOffset = ((uint64)lba)*SectorSize;
uint32 BlocksRead = 0;
uint32 SectorsInRead;
size_t BytesRead = 0;

if (!hVHD || (hVHD->File == NULL)) {
    errno = EBADF;
    return SCPE_IOERR;
    }
if ((BlockOffset + sects*SectorSize) > (uint64)NtoHll (hVHD->Footer.CurrentSize)) {
    errno = ERANGE;
    return SCPE_IOERR;
    }
if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Fixed) {
    if (ReadFilePosition(hVHD->File,
                         buf,
                         sects*SectorSize,
                         &BytesRead,
                         BlockOffset)) {
        if (sectsread)
            *sectsread = (t_seccnt)(BytesRead/SectorSize);
        return SCPE_IOERR;
        }
    if (sectsread)
        *sectsread /= SectorSize;
    return SCPE_OK;
    }
/* We are now dealing with a Dynamically expanding or differencing disk */
while (sects) {
    uint32 SectorsPerBlock = NtoHl (hVHD->Dynamic.BlockSize)/SectorSize;
    uint64 BlockNumber = lba/SectorsPerBlock;
    uint32 BitMapBytes = (7+(NtoHl (hVHD->Dynamic.BlockSize)/SectorSize))/8;
    uint32 BitMapSectors = (BitMapBytes+SectorSize-1)/SectorSize;

    SectorsInRead = SectorsPerBlock - lba%SectorsPerBlock;
    if (SectorsInRead > sects)
        SectorsInRead = sects;
    if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) {
        if (!hVHD->Parent)
            memset (buf, 0, SectorSize*SectorsInRead);
        else {
            if (ReadVirtualDiskSectors(hVHD->Parent,
                                       buf,
                                       SectorsInRead,
                                       NULL,
                                       SectorSize,
                                       lba)) {
                if (sectsread)
                    *sectsread = BlocksRead;
                return FALSE;
                }
            }
        }
    else {
        BlockOffset = SectorSize*((uint64)(NtoHl (hVHD->BAT[BlockNumber]) + lba%SectorsPerBlock + BitMapSectors));
        if (ReadFilePosition(hVHD->File,
                             buf,
                             SectorsInRead*SectorSize,
                             NULL,
                             BlockOffset)) {
            if (sectsread)
                *sectsread = BlocksRead;
            return SCPE_IOERR;
            }
        }
    sects -= SectorsInRead;
    buf = (uint8 *)(((char *)buf) + SectorSize*SectorsInRead);
    lba += SectorsInRead;
    BlocksRead += SectorsInRead;
    }
if (sectsread)
    *sectsread = BlocksRead;
return SCPE_OK;
}

static t_stat sim_vhd_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
{
VHDHANDLE hVHD = (VHDHANDLE)uptr->fileref;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

return ReadVirtualDiskSectors(hVHD, buf, sects, sectsread, ctx->sector_size, lba);
}

static t_stat sim_vhd_disk_clearerr (UNIT *uptr)
{
VHDHANDLE hVHD = (VHDHANDLE)uptr->fileref;

clearerr (hVHD->File);
return SCPE_OK;
}

static t_bool
BufferIsZeros(void *Buffer, size_t BufferSize)
{
size_t i;
char *c = (char *)Buffer;

for (i=0; i<BufferSize; ++i)
    if (c[i])
        return FALSE;
return TRUE;
}

static t_stat
WriteVirtualDiskSectors(VHDHANDLE hVHD,
                        uint8 *buf,
                        t_seccnt sects,
                        t_seccnt *sectswritten,
                        uint32 SectorSize,
                        t_lba lba)
{
uint64 BlockOffset = ((uint64)lba)*SectorSize;
uint32 BlocksWritten = 0;
uint32 SectorsInWrite;
size_t BytesWritten = 0;

if (!hVHD || !hVHD->File) {
    errno = EBADF;
    return SCPE_IOERR;
    }
if ((BlockOffset + sects*SectorSize) > (uint64)NtoHll(hVHD->Footer.CurrentSize)) {
    errno = ERANGE;
    return SCPE_IOERR;
    }
if (NtoHl(hVHD->Footer.DiskType) == VHD_DT_Fixed) {
    if (WriteFilePosition(hVHD->File,
                          buf,
                          sects*SectorSize,
                          &BytesWritten,
                          BlockOffset)) {
        if (sectswritten)
            *sectswritten = (t_seccnt)(BytesWritten/SectorSize);
        return SCPE_IOERR;
        }
    if (sectswritten)
        *sectswritten /= SectorSize;
    return SCPE_OK;
    }
/* We are now dealing with a Dynamically expanding or differencing disk */
while (sects) {
    uint32 SectorsPerBlock = NtoHl(hVHD->Dynamic.BlockSize)/SectorSize;
    uint64 BlockNumber = lba/SectorsPerBlock;
    uint32 BitMapBytes = (7+(NtoHl(hVHD->Dynamic.BlockSize)/SectorSize))/8;
    uint32 BitMapSectors = (BitMapBytes+SectorSize-1)/SectorSize;

    if (BlockNumber >= NtoHl(hVHD->Dynamic.MaxTableEntries)) {
        if (sectswritten)
            *sectswritten = BlocksWritten;
        return SCPE_EOF;
        }
    SectorsInWrite = 1;
    if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) {
        uint8 *BitMap = NULL;
        uint32 BitMapBufferSize = VHD_DATA_BLOCK_ALIGNMENT;
        uint8 *BitMapBuffer = NULL;
        void *BlockData = NULL;
        uint8 *BATUpdateBufferAddress;
        uint32 BATUpdateBufferSize;
        uint64 BATUpdateStorageAddress;

        if (!hVHD->Parent && BufferIsZeros(buf, SectorSize))
            goto IO_Done;
        /* Need to allocate a new Data Block. */
        BlockOffset = sim_fsize_ex (hVHD->File);
        if (((int64)BlockOffset) == -1)
            return SCPE_IOERR;
        if (BitMapSectors*SectorSize > BitMapBufferSize)
            BitMapBufferSize = BitMapSectors*SectorSize;
        BitMapBuffer = (uint8 *)calloc(1, BitMapBufferSize + SectorSize*SectorsPerBlock);
        if (BitMapBufferSize > BitMapSectors*SectorSize)
            BitMap = BitMapBuffer + BitMapBufferSize-BitMapBytes;
        else
            BitMap = BitMapBuffer;
        memset(BitMap, 0xFF, BitMapBytes);
        BlockOffset -= sizeof(hVHD->Footer);
        if (0 == (BlockOffset & ~(VHD_DATA_BLOCK_ALIGNMENT-1)))
            {  // Already aligned, so use padded BitMapBuffer
            if (WriteFilePosition(hVHD->File,
                                  BitMapBuffer,
                                  BitMapBufferSize + SectorSize*SectorsPerBlock,
                                  NULL,
                                  BlockOffset)) {
                free (BitMapBuffer);
                return SCPE_IOERR;
                }
            BlockOffset += BitMapBufferSize;
            }
        else
            {
            // align the data portion of the block to the desired alignment
            // compute the address of the data portion of the block
            BlockOffset += BitMapSectors*SectorSize;
            // round up this address to the desired alignment
            BlockOffset += VHD_DATA_BLOCK_ALIGNMENT-1;
            BlockOffset &= ~(VHD_DATA_BLOCK_ALIGNMENT-1);
            BlockOffset -= BitMapSectors*SectorSize;
            if (WriteFilePosition(hVHD->File,
                                  BitMap,
                                  SectorSize * (BitMapSectors + SectorsPerBlock),
                                  NULL,
                                  BlockOffset)) {
                free (BitMapBuffer);
                return SCPE_IOERR;
                }
            BlockOffset += BitMapSectors*SectorSize;
            }
        free(BitMapBuffer);
        BitMapBuffer = BitMap = NULL;
        /* the BAT block address is the beginning of the block bitmap */
        BlockOffset -= BitMapSectors*SectorSize;
        hVHD->BAT[BlockNumber] = NtoHl((uint32)(BlockOffset/SectorSize));
        BlockOffset += SectorSize * (SectorsPerBlock + BitMapSectors);
        if (WriteFilePosition(hVHD->File,
                              &hVHD->Footer,
                              sizeof(hVHD->Footer),
                              NULL,
                              BlockOffset))
            goto Fatal_IO_Error;
        /* Since a large VHD can have a pretty large BAT, and we've only changed one longword bat entry
           in the current BAT, we write just the aligned sector which contains the updated BAT entry */
        BATUpdateBufferAddress = (uint8 *)hVHD->BAT - (size_t)NtoHll(hVHD->Dynamic.TableOffset) + 
            (size_t)((((size_t)&hVHD->BAT[BlockNumber]) - (size_t)hVHD->BAT + (size_t)NtoHll(hVHD->Dynamic.TableOffset)) & ~(VHD_DATA_BLOCK_ALIGNMENT-1));
        /* If the starting of the BAT isn't on a VHD_DATA_BLOCK_ALIGNMENT boundary and we've just updated 
           a BAT entry early in the array, the buffer computed address might be before the start of the
           BAT table.  If so, only write the BAT data needed */
        if (BATUpdateBufferAddress < (uint8 *)hVHD->BAT) {
            BATUpdateBufferAddress = (uint8 *)hVHD->BAT;
            BATUpdateBufferSize = (uint32)((((size_t)&hVHD->BAT[BlockNumber]) - (size_t)hVHD->BAT) + 512) & ~511;
            BATUpdateStorageAddress = NtoHll(hVHD->Dynamic.TableOffset);
            }
        else {
            BATUpdateBufferSize = VHD_DATA_BLOCK_ALIGNMENT;
            BATUpdateStorageAddress = NtoHll(hVHD->Dynamic.TableOffset) + BATUpdateBufferAddress - ((uint8 *)hVHD->BAT);
            }
        /* If the total BAT is smaller than one VHD_DATA_BLOCK_ALIGNMENT, then be sure to only write out the BAT data */
        if ((size_t)(BATUpdateBufferAddress - (uint8 *)hVHD->BAT + BATUpdateBufferSize) > 512*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries) + 511)/512))
            BATUpdateBufferSize = (uint32)(512*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries) + 511)/512) - (BATUpdateBufferAddress - ((uint8 *)hVHD->BAT)));
        if (WriteFilePosition(hVHD->File,
                              BATUpdateBufferAddress,
                              BATUpdateBufferSize,
                              NULL,
                              BATUpdateStorageAddress))
            goto Fatal_IO_Error;
        if (hVHD->Parent)
            { /* Need to populate data block contents from parent VHD */
            uint32 BlockSectors = SectorsPerBlock;

            BlockData = malloc(SectorsPerBlock*SectorSize);

            if (((lba/SectorsPerBlock)*SectorsPerBlock + BlockSectors) > ((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize)
                BlockSectors = (uint32)(((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize - (lba/SectorsPerBlock)*SectorsPerBlock);
            if (ReadVirtualDiskSectors(hVHD->Parent,
                                       (uint8*) BlockData,
                                       BlockSectors,
                                       NULL,
                                       SectorSize,
                                       (lba/SectorsPerBlock)*SectorsPerBlock))
                goto Fatal_IO_Error;
            if (WriteVirtualDiskSectors(hVHD,
                                        (uint8*) BlockData,
                                        BlockSectors,
                                        NULL,
                                        SectorSize,
                                        (lba/SectorsPerBlock)*SectorsPerBlock))
                goto Fatal_IO_Error;
            free(BlockData);
            }
        continue;
Fatal_IO_Error:
        free (BitMap);
        free (BlockData);
        fclose (hVHD->File);
        hVHD->File = NULL;
        return SCPE_IOERR;
        }
    else {
        BlockOffset = 512*((uint64)(NtoHl(hVHD->BAT[BlockNumber]) + lba%SectorsPerBlock + BitMapSectors));
        SectorsInWrite = SectorsPerBlock - lba%SectorsPerBlock;
        if (SectorsInWrite > sects)
            SectorsInWrite = sects;
        if (WriteFilePosition(hVHD->File,
                              buf,
                              SectorsInWrite*SectorSize,
                              NULL,
                              BlockOffset)) {
            if (sectswritten)
                *sectswritten = BlocksWritten;
            return SCPE_IOERR;
            }
        }
IO_Done:
    sects -= SectorsInWrite;
    buf = (uint8 *)(((char *)buf) + SectorsInWrite*SectorSize);
    lba += SectorsInWrite;
    BlocksWritten += SectorsInWrite;
    }
if (sectswritten)
    *sectswritten = BlocksWritten;
return SCPE_OK;
}

static t_stat sim_vhd_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
{
VHDHANDLE hVHD = (VHDHANDLE)uptr->fileref;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;

return WriteVirtualDiskSectors(hVHD, buf, sects, sectswritten, ctx->sector_size, lba);
}
#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_disk.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/* sim_disk.h: simulator disk support library definitions

   Copyright (c) 2011, Mark Pizzolato

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the names of Robert M Supnik and 
   Mark Pizzolato shall not be used in advertising or otherwise to promote
   the sale, use or other dealings in this Software without prior written 
   authorization from Robert M Supnik and Mark Pizzolato.

   25-Jan-11    MP      Initial Implemementation
*/

#ifndef SIM_DISK_H_
#define SIM_DISK_H_    0

#ifdef  __cplusplus
extern "C" {
#endif

/* SIMH/Disk format */

typedef uint32          t_seccnt;                       /* disk sector count */
typedef uint32          t_lba;                          /* disk logical block address */

/* Unit flags */

#define DKUF_V_WLK      (UNIT_V_UF + 0)                 /* write locked */
#define DKUF_V_FMT      (UNIT_V_UF + 1)                 /* disk file format */
#define DKUF_W_FMT      2                               /* 2b of formats */
#define DKUF_N_FMT      (1u << DKUF_W_FMT)              /* number of formats */
#define DKUF_M_FMT      ((1u << DKUF_W_FMT) - 1)
#define DKUF_F_STD       0                              /* SIMH format */
#define DKUF_F_RAW       1                              /* Raw Physical Disk Access */
#define DKUF_F_VHD       2                              /* VHD format */
#define DKUF_V_UF       (DKUF_V_FMT + DKUF_W_FMT)
#define DKUF_WLK        (1u << DKUF_V_WLK)
#define DKUF_FMT        (DKUF_M_FMT << DKUF_V_FMT)
#define DKUF_WRP        (DKUF_WLK | UNIT_RO)

#define DK_F_STD        (DKUF_F_STD << DKUF_V_FMT)
#define DK_F_RAW        (DKUF_F_RAW << DKUF_V_FMT)
#define DK_F_VHD        (DKUF_F_VHD << DKUF_V_FMT)

#define DK_GET_FMT(u)   (((u)->flags >> DKUF_V_FMT) & DKUF_M_FMT)

/* Return status codes */

#define DKSE_OK         0                               /* no error */

typedef void (*DISK_PCALLBACK)(UNIT *unit, t_stat status);

/* Prototypes */

t_stat sim_disk_attach (UNIT *uptr, const char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, 
                        uint32 debugbit, const char *drivetype, uint32 pdp11_tracksize, int completion_delay);
t_stat sim_disk_detach (UNIT *uptr);
t_stat sim_disk_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
t_stat sim_disk_rdsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects, DISK_PCALLBACK callback);
t_stat sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects);
t_stat sim_disk_wrsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects, DISK_PCALLBACK callback);
t_stat sim_disk_unload (UNIT *uptr);
t_stat sim_disk_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_disk_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat sim_disk_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_disk_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat sim_disk_set_asynch (UNIT *uptr, int latency);
t_stat sim_disk_clr_asynch (UNIT *uptr);
t_stat sim_disk_reset (UNIT *uptr);
t_stat sim_disk_perror (UNIT *uptr, const char *msg);
t_stat sim_disk_clearerr (UNIT *uptr);
t_bool sim_disk_isavailable (UNIT *uptr);
t_bool sim_disk_isavailable_a (UNIT *uptr, DISK_PCALLBACK callback);
t_bool sim_disk_wrp (UNIT *uptr);
t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);
t_offset sim_disk_size (UNIT *uptr);
t_bool sim_disk_vhd_support (void);
t_bool sim_disk_raw_support (void);
void sim_disk_data_trace (UNIT *uptr, const uint8 *data, size_t lba, size_t len, const char* txt, int detail, uint32 reason);

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































Deleted src/sim_ether.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
/* sim_ether.c: OS-dependent network routines
  ------------------------------------------------------------------------------
   Copyright (c) 2002-2007, David T. Hittner

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the author shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from the author.

  ------------------------------------------------------------------------------

  This ethernet simulation is based on the PCAP and WinPcap packages.

  PCAP/WinPcap was chosen as the basis for network code since it is the most
  "universal" of the various network packages available. Using this style has
  allowed rapid network development for the major SIMH platforms. Developing
  a network package specifically for SIMH was rejected due to the time required;
  the advantage would be a more easily compiled and integrated code set.

  There are various problems associated with use of ethernet networking, which
  would be true regardless of the network package used, since there are no
  universally accepted networking methods. The most serious of these is getting
  the proper networking package loaded onto the system, since most environments
  do not come with the network interface packages loaded.

  The second most serious network issue relates to security. The network
  simulation needs to simulate operating system level functionality (packet
  driving). However, the host network programming interfaces tend to operate at
  the user level of functionality, so getting to the full functionality of
  the network interface usually requires that the person executing the
  network code be a privileged user of the host system. See the PCAP/WinPcap
  documentation for the appropriate host platform if unprivileged use of
  networking is needed - there may be known workarounds.

  Define one of the two macros below to enable networking:
    USE_NETWORK - Create statically linked network code
    USE_SHARED  - Create dynamically linked network code

  ------------------------------------------------------------------------------

  Supported/Tested Platforms:

  Windows(NT,2K,XP,2K3,Vista,Win7)     WinPcap         V3.0+
  Linux                     libpcap at least 0.9
  OpenBSD,FreeBSD,NetBSD    libpcap at least 0.9
  MAC OS/X                  libpcap at least 0.9
  Solaris Sparc             libpcap at least 0.9
  Solaris Intel             libpcap at least 0.9
  AIX                       ??
  HP/UX                     ??
  Compaq Tru64 Unix         ??
  VMS                       Alpha/Itanium VMS only, needs VMS libpcap
  
  WinPcap is available from: 
                        http://winpcap.polito.it/
  libpcap for VMS is available from: 
                        http://simh.trailing-edge.com/sources/vms-pcap.zip
  libpcap for other Unix platforms is available at: 
        NOTE: As of the release of this version of sim_ether.c ALL current 
              *nix platforms ship with a sufficiently new version of 
              libpcap, and ALL provide a libpcap-dev package for developing
              libpcap based applications.  The OS vendor supplied version
              of libpcap AND the libpcap-dev components are preferred for
              proper operation of both simh AND other applications on the 
              host system which use libpcap.
        Current Version:  http://www.tcpdump.org/daily/libpcap-current.tar.gz
        Released Version: http://www.tcpdump.org/release/

        When necessary (see NOTE above about vendor supplied libpcap), 
        we've gotten the tarball, unpacked, built and installed it with:
            gzip -dc libpcap-current.tar.gz | tar xvf -
            cd libpcap-directory-name
            ./configure
            make
            make install
        Note:  The "make install" step generally will have to be done as root.
        This will install libpcap in /usr/local/lib and /usr/local/include
        The current simh makefile will do the right thing to locate and 
        reference the OS provided libpcap or the one just installed.


  Note: Building for the platforms indicated above, with the indicated libpcap, 
  should automatically leverage the appropriate mechanisms contained here.  
  Things are structured so that it is likely to work for any other as yet 
  untested platform.  If it works for you, please let the author know so we 
  can update the table above.  If it doesn't work, then the following #define 
  variables can influence the operation on an untested platform.

  USE_BPF           - Determines if this code leverages a libpcap/WinPcap 
                      provided bpf packet filtering facility.  All tested 
                      environments have bpf facilities that work the way we 
                      need them to.  However a new one might not.  undefine 
                      this variable to let this code do its own filtering.
  USE_SETNONBLOCK   - Specifies whether the libpcap environment's non-blocking 
                      semantics are to be leveraged.  This helps to manage the 
                      varying behaviours of the kernel packet facilities 
                      leveraged by libpcap.
  USE_READER_THREAD - Specifies that packet reading should be done in the 
                      context of a separate thread.  The Posix threading 
                      APIs are used.  This option is less efficient than the
                      default non-threaded approach, but it exists since some 
                      platforms don't want to work with nonblocking libpcap 
                      semantics.   OpenBSD and NetBSD either don't have pthread 
                      APIs available, or they are too buggy to be useful. 
                      Using the threaded approach may require special compile 
                      and/or link time switches (i.e. -lpthread or -pthread, 
                      etc.) Consult the documentation for your platform as 
                      needed.  Although this may be 'less efficient' than the
                      non-threaded approach, the efficiency is an overall system
                      efficiency not necessarily a simulator efficiency.  This 
                      means that work is removed from the thread executing 
                      simulated instructions so the simulated system will most
                      likely run faster (given that modern host CPUs are 
                      multi-core and have someplace to do this work in parallel).
  MUST_DO_SELECT    - Specifies that, when USE_READER_THREAD is active,  
                      select() should be used to determine when available 
                      packets are ready for reading.  Otherwise, we depend 
                      on the libpcap/kernel packet timeout specified on 
                      pcap_open_live.  If USE_READER_THREAD is not set, then 
                      MUST_DO_SELECT is irrelevant
  HAVE_TAP_NETWORK  - Specifies that support for tap networking should be 
                      included.  This can be leveraged, along with OS bridging
                      capabilities to share a single LAN interface.  This 
                      allows device names of the form tap:tap0 to be specified
                      at open time.  This functionality is only useful/needed 
                      on *nix platforms since native sharing of Windows NIC 
                      devices works with no external magic.
  HAVE_VDE_NETWORK  - Specifies that support for vde networking should be 
                      included.  This can be leveraged, along with OS bridging
                      capabilities to share a single LAN interface.  It also
                      can allow a simulator to have useful networking 
                      functionality when running without root access.  This 
                      allows device names of the form vde:/tmp/switch to be 
                      specified at open time.  This functionality is only 
                      available on *nix platforms since the vde api isn't 
                      available on Windows.
  HAVE_SLIRP_NETWORK- Specifies that support for SLiRP networking should be 
                      included.  This can be leveraged to provide User Mode 
                      IP NAT connectivity for simulators.

  NEED_PCAP_SENDPACKET
                    - Specifies that you are using an older version of libpcap
                      which doesn't provide a pcap_sendpacket API.

  NOTE: Changing these defines is done in either sim_ether.h OR on the global 
        compiler command line which builds all of the modules included in a
        simulator.

  ------------------------------------------------------------------------------

  Modification history:

  30-Mar-12  MP   Added host NIC address determination on supported VMS platforms
  01-Mar-12  MP   Made host NIC address determination on *nix platforms more 
                  robust.
  01-Mar-12  MP   Added host NIC address determination work when building 
                  under Cygwin
  01-Mar-12  AGN  Add conditionals for Cygwin dynamic loading of wpcap.dll
  01-Mar-12  AGN  Specify the full /usr/lib for dlopen under Apple Mac OS X.
  17-Nov-11  MP   Added dynamic loading of libpcap on *nix platforms
  30-Oct-11  MP   Added support for vde (Virtual Distributed Ethernet) networking
  29-Oct-11  MP   Added support for integrated Tap networking interfaces on OSX
  12-Aug-11  MP   Cleaned up payload length determination
                  Fixed race condition detecting reflections when threaded 
                  reading and writing is enabled
  18-Apr-11  MP   Fixed race condition with self loopback packets in 
                  multithreaded environments
  09-Jan-11  MP   Fixed missing crc data when USE_READER_THREAD is defined and 
                  crc's are needed (only the pdp11_xu)
  16-Dec-10  MP   added priority boost for read and write threads when 
                  USE_READER_THREAD does I/O in separate threads.  This helps
                  throughput since it allows these I/O bound threads to preempt 
                  the main thread (which is executing simulated instructions).                  
  09-Dec-10  MP   allowed more flexible parsing of MAC address strings
  09-Dec-10  MP   Added support to determine if network address conflicts exist
  07-Dec-10  MP   Reworked DECnet self detection to the more general approach
                  of loopback self when a Physical Address is being set.
  04-Dec-10  MP   Changed eth_write to do nonblocking writes when 
                  USE_READER_THREAD is defined.
  20-Aug-10  TVO  Fix for Mac OSX 10.6
  17-Jun-10  MP   Fixed bug in the AUTODIN II hash filtering.
  14-Jun-10  MP   Added support for integrated Tap networking interfaces on BSD 
                  platforms.
  13-Jun-10  MP   Added support for integrated Tap networking interfaces on Linux 
                  platforms.
  31-May-10  MP   Added support for more TOE (TCP Offload Engine) features for IPv4
                  network traffic from the host and/or from hosts on the LAN.  These
                  new TOE features are: LSO (Large Send Offload) and Jumbo packet
                  fragmentation support.  These features allow a simulated network
                  device to support traffic when a host leverages a NIC's Large 
                  Send Offload capabilities to fregment and/or segment outgoing 
                  network traffic.  Additionally a simulated network device can 
                  reasonably exist on a LAN which is configured to use Jumbo frames.
  21-May-10  MP   Added functionality to fixup IP header checksums to accomodate 
                  packets from a host with a NIC which has TOE (TCP Offload Engine)
                  enabled which is expected to implement the checksum computations
                  in hardware.  Since we catch packets before they arrive at the
                  NIC the expected checksum insertions haven't been performed yet.
                  This processing is only done for packets sent from the hoat to 
                  the guest we're supporting.  In general this will be a relatively 
                  small number of packets so it is done for all IP frame packets
                  coming from the hoat to the guest.  In order to make the 
                  determination of packets specifically arriving from the host we
                  need to know the hardware MAC address of the host NIC.  Currently
                  determining a NIC's MAC address is relatively easy on Windows.
                  The non-windows code works on linux and may work on other *nix 
                  platforms either as is or with slight modifications.  The code, 
                  as implemented, only messes with this activity if the host 
                  interface MAC address can be determined.
  20-May-10  MP   Added general support to deal with receiving packets smaller 
                  than ETH_MIN_PACKET in length.  These come from packets
                  looped back by some bridging mechanism and need to be padded
                  to the minimum frame size.  A real NIC won't pass us any 
                  packets like that.  This fix belongs here since this layer
                  is responsible for interfacing to they physical layer 
                  devices, AND it belongs here to get CRC processing right.
  05-Mar-08  MP   Added optional multicast filtering support for doing
                  LANCE style AUTODIN II based hashed filtering.
  07-Feb-08  MP   Added eth_show_dev to display ethernet state
                  Changed the return value from eth_read to return whether
                  or not a packet was read.  No existing callers used or 
                  checked constant return value that previously was being
                  supplied.
  29-Jan-08  MP   Added eth_set_async to provide a mechanism (when 
                  USE_READER_THREAD is enabled) to allow packet reception 
                  to dynamically update the simulator event queue and 
                  potentially avoid polling for I/O.  This provides a minimal 
                  overhead (no polling) maximal responsiveness for network 
                  activities.
  29-Jan-08  MP   Properly sequenced activities in eth_close to avoid a race
                  condition when USE_READER_THREAD is enabled.
  25-Jan-08  MP   Changed the following when USE_READER_THREAD is enabled:
                  - Fixed bug when the simulated device doesn't need crc 
                    in packet data which is read.
                  - Added call to pcap_setmintocopy to minimize packet 
                    delivery latencies.
                  - Added ethq_destroy and used it to avoid a memory leak in
                    eth_close.
                  - Properly cleaned up pthread mutexes in eth_close.
                  Migrated to using sim_os_ms_sleep for a delay instead of
                  a call to select().
                  Fixed the bpf filter used when no traffic is to be matched.
                  Reworked eth_add_packet_crc32 implementation to avoid an
                  extra buffer copy while reading packets.
                  Fixedup #ifdef's relating to USE_SHARED so that setting 
                  USE_SHARED or USE_NETWORK will build a working network 
                  environment.
  23-Jan-08  MP   Reworked eth_packet_trace and eth_packet_trace_ex to allow
                  only output ethernet header+crc and provide a mechanism for
                  the simulated device to display full packet data debugging.
  17-May-07  DTH  Fixed non-ethernet device removal loop (from Naoki Hamada)
  15-May-07  DTH  Added dynamic loading of wpcap.dll;
                  Corrected exceed max index bug in ethX lookup
  04-May-07  DTH  Corrected failure to look up ethernet device names in
                  the registry on Windows XP x64
  10-Jul-06  RMS  Fixed linux conditionalization (from Chaskiel Grundman)
  02-Jun-06  JDB  Fixed compiler warning for incompatible sscanf parameter
  15-Dec-05  DTH  Patched eth_host_devices [remove non-ethernet devices]
                  (from Mark Pizzolato and Galen Tackett, 08-Jun-05)
                  Patched eth_open [tun fix](from Antal Ritter, 06-Oct-05)
  30-Nov-05  DTH  Added option to regenerate CRC on received packets; some
                  ethernet devices need to pass it on to the simulation, and by
                  the time libpcap/winpcap gets the packet, the host OS network
                  layer has already stripped CRC out of the packet
  01-Dec-04  DTH  Added Windows user-defined adapter names (from Timothe Litt)
  25-Mar-04  MP   Revised comments and minor #defines to deal with updated
                  libpcap which now provides pcap_sendpacket on all platforms.
  04-Feb-04  MP   Returned success/fail status from eth_write to support
                  determining if the current libpcap connection can successfully 
                  write packets.
                  Added threaded approach to reading packets since
                  this works better on some platforms (solaris intel) than the 
                  inconsistently implemented non-blocking read approach.
  04-Feb-04  DTH  Converted ETH_DEBUG to sim_debug
  13-Jan-04  MP   tested and fixed on OpenBSD, NetBS and FreeBSD.
  09-Jan-04  MP   removed the BIOCSHDRCMPLT ioctl() for OS/X
  05-Jan-04  DTH  Added eth_mac_scan
  30-Dec-03  DTH  Cleaned up queue routines, added no network support message
  26-Dec-03  DTH  Added ethernet show and queue functions from pdp11_xq
  15-Dec-03  MP   polished generic libpcap support.
  05-Dec-03  DTH  Genericized eth_devices() and #ifdefs
  03-Dec-03  MP   Added Solaris support
  02-Dec-03  DTH  Corrected decnet fix to use reflection counting
  01-Dec-03  DTH  Added BPF source filtering and reflection counting
  28-Nov-03  DTH  Rewrote eth_devices using universal pcap_findalldevs()
  25-Nov-03  DTH  Verified DECNET_FIX, reversed ifdef to mainstream code
  19-Nov-03  MP   Fixed BPF functionality on Linux/BSD.
  17-Nov-03  DTH  Added xBSD simplification
  14-Nov-03  DTH  Added #ifdef DECNET_FIX for problematic duplicate detection code
  13-Nov-03  DTH  Merged in __FreeBSD__ support
  21-Oct-03  MP   Added enriched packet dumping for debugging
  20-Oct-03  MP   Added support for multiple ethernet devices on VMS
  20-Sep-03  Ankan Add VMS support (Alpha only)
  29-Sep-03  MP   Changed separator character in eth_fmt_mac to be ":" to
                  format ethernet addresses the way the BPF compile engine
                  wants to see them.
                  Added BPF support to filter packets
                  Added missing printf in eth_close
  07-Jun-03  MP   Added WIN32 support for DECNET duplicate address detection.
  06-Jun-03  MP   Fixed formatting of Ethernet Protocol Type in eth_packet_trace
  30-May-03  DTH  Changed WIN32 to _WIN32 for consistency
  07-Mar-03  MP   Fixed Linux implementation of PacketGetAdapterNames to also
                  work on Red Hat 6.2-sparc and Debian 3.0r1-sparc.
  03-Mar-03  MP   Changed logging to be consistent on stdout and sim_log
  01-Feb-03  MP   Changed type of local variables in eth_packet_trace to
                  conform to the interface needs of eth_mac_fmt wich produces
                  char data instead of unsigned char data.  Suggested by the
                  DECC compiler.
  15-Jan-03  DTH  Corrected PacketGetAdapterNames parameter2 datatype
  26-Dec-02  DTH  Merged Mark Pizzolato's enhancements with main source
                  Added networking documentation
                  Changed _DEBUG to ETH_DEBUG
  20-Dec-02  MP   Added display of packet CRC to the eth_packet_trace.
                  This helps distinguish packets with identical lengths
                  and protocols.
  05-Dec-02  MP   With the goal of draining the input buffer more rapidly
                  changed eth_read to call pcap_dispatch repeatedly until
                  either a timeout returns nothing or a packet allowed by
                  the filter is seen.  This more closely reflects how the
                  pcap layer will work when the filtering is actually done
                  by a bpf filter.
  31-Oct-02  DTH  Added USE_NETWORK conditional
                  Reworked not attached test
                  Added OpenBSD support (from Federico Schwindt)
                  Added ethX detection simplification (from Megan Gentry)
                  Removed sections of temporary code
                  Added parameter validation
  23-Oct-02  DTH  Beta 5 released
  22-Oct-02  DTH  Added all_multicast and promiscuous support
                  Fixed not attached behavior
  21-Oct-02  DTH  Added NetBSD support (from Jason Thorpe)
                  Patched buffer size to make sure entire packet is read in
                  Made 'ethX' check characters passed as well as length
                  Corrected copyright again
  16-Oct-02  DTH  Beta 4 released
                  Corrected copyright
  09-Oct-02  DTH  Beta 3 released
                  Added pdp11 write acceleration (from Patrick Caulfield)
  08-Oct-02  DTH  Beta 2 released
                  Integrated with 2.10-0p4
                  Added variable vector and copyrights
  04-Oct-02  DTH  Added linux support (from Patrick Caulfield)
  03-Oct-02  DTH  Beta version of xq/sim_ether released for SIMH 2.09-11
  24-Sep-02  DTH  Finished eth_devices, eth_getname
  18-Sep-02  DTH  Callbacks implemented
  13-Sep-02  DTH  Basic packet read/write written
  20-Aug-02  DTH  Created Sim_Ether for O/S independant ethernet implementation

  ------------------------------------------------------------------------------
*/

#include <ctype.h>
#include "sim_ether.h"
#include "sim_sock.h"
#include "sim_timer.h"
#if defined(_WIN32)
#include <direct.h>
#else
#include <unistd.h>
#endif

#define MAX(a,b) (((a) > (b)) ? (a) : (b))

/* Internal routines - forward declarations */
static int _eth_get_system_id (char *buf, size_t buf_size);

/*============================================================================*/
/*                  OS-independant ethernet routines                          */
/*============================================================================*/

t_stat eth_mac_scan (ETH_MAC* mac, const char* strmac)
{
return eth_mac_scan_ex (mac, strmac, NULL);
}

t_stat eth_mac_scan_ex (ETH_MAC* mac, const char* strmac, UNIT *uptr)
{
  unsigned int a[6], g[6];
  FILE *f;
  char filebuf[64] = "";
  uint32 i;
  static const ETH_MAC zeros = {0,0,0,0,0,0};
  static const ETH_MAC ones  = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  ETH_MAC newmac;
  struct {
      uint32 bits;
      char system_id[37];
      char cwd[PATH_MAX];
      char file[PATH_MAX];
      ETH_MAC base_mac;
      char uname[64];
      char sim[128];
      } state;
  CONST char *cptr, *tptr;
  uint32 data;

  /* Allow generated MAC address */
  /* XX:XX:XX:XX:XX:XX{/bits{>file}} */
  /* bits (if specified) must be from 16 thru 48 */

  memset (&state, 0, sizeof(state));
  _eth_get_system_id (state.system_id, sizeof(state.system_id));
  strncpy (state.sim, sim_name, sizeof(state.sim));
  getcwd (state.cwd, sizeof(state.cwd));
  if (uptr)
    strncpy (state.uname, sim_uname (uptr), sizeof(state.uname)-1);
  cptr = strchr (strmac, '>');
  if (cptr) {
    state.file[sizeof(state.file)-1] = '\0';
    strncpy (state.file, cptr + 1, sizeof(state.file)-1);
    if ((f = fopen (state.file, "r"))) {
      filebuf[sizeof(filebuf)-1] = '\0';
      fgets (filebuf, sizeof(filebuf)-1, f);
      strmac = filebuf;
      fclose (f);
      strcpy (state.file, "");  /* avoid saving */
      }
    }
  cptr = strchr (strmac, '/');
  if (cptr) {
    state.bits = (uint32)strtotv (cptr + 1, &tptr, 10);
    if ((state.bits < 16) || (state.bits > 48))
      return sim_messagef (SCPE_ARG, "Invalid MAC address bits specifier '%d'. Valid values are from 16 thru 48\n", state.bits);
    }
  else
    state.bits = 48;
  data = eth_crc32 (0, (void *)&state, sizeof(state));
  for (i=g[0]=g[1]=0; i<4; i++)
    g[i+2] = (data >> (i << 3)) & 0xFF;
  if ((6 != sscanf(strmac, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) &&
      (6 != sscanf(strmac, "%x.%x.%x.%x.%x.%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) &&
      (6 != sscanf(strmac, "%x-%x-%x-%x-%x-%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])))
    return sim_messagef (SCPE_ARG, "Invalid MAC address format: '%s'\n", strmac);
  for (i=0; i<6; i++)
    if (a[i] > 0xFF)
      return sim_messagef (SCPE_ARG, "Invalid MAC address byte value: %02X\n", a[i]);
    else {
      uint32 mask, shift;
    
      state.base_mac[i] = a[i];
      if (((i + 1) << 3) < state.bits)
          shift = 0;
      else
          shift = ((i + 1) << 3) - state.bits;
      mask = 0xFF << shift;
      newmac[i] = (unsigned char)((a[i] & mask) | (g[i] & ~mask));
      }

  /* final check - mac cannot be broadcast or multicast address */
  if (!memcmp(newmac, zeros, sizeof(ETH_MAC)) ||  /* broadcast */
      !memcmp(newmac, ones,  sizeof(ETH_MAC)) ||  /* broadcast */
      (newmac[0] & 0x01)                          /* multicast */
     )
    return sim_messagef (SCPE_ARG, "Can't use Broadcast or MultiCast address as interface MAC address\n");

  /* new mac is OK */
  /* optionally save */
  if (state.file[0]) {              /* Save File specified? */
    f = fopen (state.file, "w");
    if (f == NULL)
      return sim_messagef (SCPE_ARG, "Can't open MAC address configuration file '%s'.\n", state.file);
    eth_mac_fmt (&newmac, filebuf);
    fprintf (f, "%s/48\n", filebuf);
    fprintf (f, "system-id: %s\n", state.system_id);
    fprintf (f, "directory: %s\n", state.cwd);
    fprintf (f, "simulator: %s\n", state.sim);
    fprintf (f, "device:    %s\n", state.uname);
    fprintf (f, "file:      %s\n", state.file);
    eth_mac_fmt (&state.base_mac, filebuf);
    fprintf (f, "base-mac:  %s\n", filebuf);
    fprintf (f, "specified: %d bits\n", state.bits);
    fprintf (f, "generated: %d bits\n", 48-state.bits);
    fclose (f);
    }
  /* copy into passed mac */
  memcpy (*mac, newmac, sizeof(ETH_MAC));
  return SCPE_OK;
}

void eth_mac_fmt(ETH_MAC* const mac, char* buff)
{
  const uint8* m = (const uint8*) mac;
  sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", m[0], m[1], m[2], m[3], m[4], m[5]);
  return;
}

static const uint32 crcTable[256] = {
  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};

uint32 eth_crc32(uint32 crc, const void* vbuf, size_t len)
{
  const uint32 mask = 0xFFFFFFFF;
  const unsigned char* buf = (const unsigned char*)vbuf;

  crc ^= mask;
  while (len > 8) {
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
    len -= 8;
  }
  while (0 != len--)
    crc = (crc >> 8) ^ crcTable[ (crc ^ (*buf++)) & 0xFF ];
  return(crc ^ mask);
}

int eth_get_packet_crc32_data(const uint8 *msg, int len, uint8 *crcdata)
{
  int crc_len;

  if (len <= ETH_MAX_PACKET) {
    uint32 crc = eth_crc32(0, msg, len);                  /* calculate CRC */
    uint32 ncrc = htonl(crc);                             /* CRC in network order */
    int size = sizeof(ncrc);                              /* size of crc field */
    memcpy(crcdata, &ncrc, size);                         /* append crc to packet */
    crc_len = len + size;                                 /* set packet crc length */
  } else {
    crc_len = 0;                                          /* appending crc would destroy packet */
  }
  return crc_len;
}

int eth_add_packet_crc32(uint8 *msg, int len)
{
  int crc_len;

  if (len <= ETH_MAX_PACKET) {
    crc_len = eth_get_packet_crc32_data(msg, len, &msg[len]);/* append crc to packet */
  } else {
    crc_len = 0;                                          /* appending crc would destroy packet */
  }
  return crc_len;
}

void eth_setcrc(ETH_DEV* dev, int need_crc)
{
  dev->need_crc = need_crc;
}

void eth_packet_trace_ex(ETH_DEV* dev, const uint8 *msg, int len, const char* txt, int detail, uint32 reason)
{
  if (dev->dptr->dctrl & reason) {
    char src[20];
    char dst[20];
    const unsigned short* proto = (const unsigned short*) &msg[12];
    uint32 crc = eth_crc32(0, msg, len);
    eth_mac_fmt((ETH_MAC*)msg, dst);
    eth_mac_fmt((ETH_MAC*)(msg+6), src);
    sim_debug(reason, dev->dptr, "%s  dst: %s  src: %s  proto: 0x%04X  len: %d  crc: %X\n",
          txt, dst, src, ntohs(*proto), len, crc);
    if (detail) {
      int i, same, group, sidx, oidx;
      char outbuf[80], strbuf[18];
      static const char hex[] = "0123456789ABCDEF";

      for (i=same=0; i<len; i += 16) {
        if ((i > 0) && (0 == memcmp(&msg[i], &msg[i-16], 16))) {
          ++same;
          continue;
        }
        if (same > 0) {
          sim_debug(reason, dev->dptr, "%04X thru %04X same as above\n", i-(16*same), i-1);
          same = 0;
        }
        group = (((len - i) > 16) ? 16 : (len - i));
        for (sidx=oidx=0; sidx<group; ++sidx) {
          outbuf[oidx++] = ' ';
          outbuf[oidx++] = hex[(msg[i+sidx]>>4)&0xf];
          outbuf[oidx++] = hex[msg[i+sidx]&0xf];
          if (isprint(msg[i+sidx]))
            strbuf[sidx] = msg[i+sidx];
          else
            strbuf[sidx] = '.';
        }
        outbuf[oidx] = '\0';
        strbuf[sidx] = '\0';
        sim_debug(reason, dev->dptr, "%04X%-48s %s\n", i, outbuf, strbuf);
      }
      if (same > 0) {
        sim_debug(reason, dev->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1);
      }
    }
  }
}

void eth_packet_trace(ETH_DEV* dev, const uint8 *msg, int len, const char* txt)
{
  eth_packet_trace_ex(dev, msg, len, txt, 0, dev->dbit);
}

void eth_packet_trace_detail(ETH_DEV* dev, const uint8 *msg, int len, const char* txt)
{
  eth_packet_trace_ex(dev, msg, len, txt, 1     , dev->dbit);
}

const char* eth_getname(int number, char* name, char *desc)
{
  ETH_LIST  list[ETH_MAX_DEVICE];
  int count = eth_devices(ETH_MAX_DEVICE, list);

  if ((number < 0) || (count <= number))
      return NULL;
  if (list[number].eth_api != ETH_API_PCAP) {
    sim_printf ("Eth: Pcap capable device not found.  You may need to run as root\n");
    return NULL;
    }

  strcpy(name, list[number].name);
  strcpy(desc, list[number].desc);
  return name;
}

const char* eth_getname_bydesc(const char* desc, char* name, char *ndesc)
{
  ETH_LIST  list[ETH_MAX_DEVICE];
  int count = eth_devices(ETH_MAX_DEVICE, list);
  int i;
  size_t j=strlen(desc);

  for (i=0; i<count; i++) {
    int found = 1;
    size_t k = strlen(list[i].desc);

    if (j != k) continue;
    for (k=0; k<j; k++)
      if (tolower(list[i].desc[k]) != tolower(desc[k]))
        found = 0;
    if (found == 0) continue;

    /* found a case-insensitive description match */
    strcpy(name, list[i].name);
    strcpy(ndesc, list[i].desc);
    return name;
  }
  /* not found */
  return NULL;
}

char* eth_getname_byname(const char* name, char* temp, char *desc)
{
  ETH_LIST  list[ETH_MAX_DEVICE];
  int count = eth_devices(ETH_MAX_DEVICE, list);
  size_t n;
  int i, found;

  found = 0;
  n = strlen(name);
  for (i=0; i<count && !found; i++) {
    if ((n == strlen(list[i].name)) &&
        (sim_strncasecmp(name, list[i].name, n) == 0)) {
      found = 1;
      strcpy(temp, list[i].name); /* only case might be different */
      strcpy(desc, list[i].desc);
    }
  }
  return (found ? temp : NULL);
}

char* eth_getdesc_byname(char* name, char* temp)
{
  ETH_LIST  list[ETH_MAX_DEVICE];
  int count = eth_devices(ETH_MAX_DEVICE, list);
  size_t n;
  int i, found;

  found = 0;
  n = strlen(name);
  for (i=0; i<count && !found; i++) {
    if ((n == strlen(list[i].name)) &&
        (sim_strncasecmp(name, list[i].name, n) == 0)) {
      found = 1;
      strcpy(temp, list[i].desc);
    }
  }
  return (found ? temp : NULL);
}

void eth_zero(ETH_DEV* dev)
{
  /* set all members to NULL OR 0 */
  memset(dev, 0, sizeof(ETH_DEV));
  dev->reflections = -1;                          /* not established yet */
}

static char*   (*p_pcap_lib_version) (void);

static ETH_DEV **eth_open_devices = NULL;
static int eth_open_device_count = 0;
static t_bool eth_show_active = FALSE;

#if defined (USE_NETWORK) || defined (USE_SHARED)
static void _eth_add_to_open_list (ETH_DEV* dev)
{
eth_open_devices = (ETH_DEV**)realloc(eth_open_devices, (eth_open_device_count+1)*sizeof(*eth_open_devices));
eth_open_devices[eth_open_device_count++] = dev;
}

static void _eth_remove_from_open_list (ETH_DEV* dev)
{
int i, j;

for (i=0; i<eth_open_device_count; ++i)
    if (eth_open_devices[i] == dev) {
        for (j=i+1; j<eth_open_device_count; ++j)
            eth_open_devices[j-1] = eth_open_devices[j];
        --eth_open_device_count;
        break;
        }
}
#endif

t_stat eth_show (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
  ETH_LIST  list[ETH_MAX_DEVICE];
  int number;

  eth_show_active = TRUE;
  number = eth_devices(ETH_MAX_DEVICE, list);
  fprintf(st, "ETH devices:\n");
  if (number == -1)
    fprintf(st, "  network support not available in simulator\n");
  else
    if (number == 0)
      fprintf(st, "  no network devices are available\n");
    else {
      size_t min, len;
      int i;
      for (i=0, min=0; i<number; i++)
        if ((len = strlen(list[i].name)) > min) min = len;
      for (i=0; i<number; i++)
        fprintf(st," eth%d\t%-*s (%s)\n", i, (int)min, list[i].name, list[i].desc);
    }
  if (p_pcap_lib_version) {
    fprintf(st, "%s\n", p_pcap_lib_version());
    }
  if (eth_open_device_count) {
    int i;
    char desc[ETH_DEV_DESC_MAX], *d;

    fprintf(st,"Open ETH Devices:\n");
    for (i=0; i<eth_open_device_count; i++) {
      d = eth_getdesc_byname(eth_open_devices[i]->name, desc);
      if (d)
        fprintf(st, " %-7s%s (%s)\n", eth_open_devices[i]->dptr->name, eth_open_devices[i]->dptr->units[0].filename, d);
      else
        fprintf(st, " %-7s%s\n", eth_open_devices[i]->dptr->name, eth_open_devices[i]->dptr->units[0].filename);
      eth_show_dev (st, eth_open_devices[i]);
      }
    }
  eth_show_active = FALSE;
  return SCPE_OK;
}

t_stat eth_show_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char *desc)
{
return eth_show (st, uptr, val, NULL);
}

t_stat ethq_init(ETH_QUE* que, int max)
{
  /* create dynamic queue if it does not exist */
  if (!que->item) {
    que->item = (struct eth_item *) calloc(max, sizeof(struct eth_item));
    if (!que->item) {
      /* failed to allocate memory */
      sim_printf("EthQ: failed to allocate dynamic queue[%d]\r\n", max);
      return SCPE_MEM;
    };
    que->max = max;
  };
  ethq_clear(que);
  return SCPE_OK;
}

t_stat ethq_destroy(ETH_QUE* que)
{
  /* release dynamic queue if it exists */
  ethq_clear(que);
  que->max = 0;
  if (que->item) {
    free(que->item);
    que->item = NULL;
  };
  return SCPE_OK;
}

void ethq_clear(ETH_QUE* que)
{
  int i;

  /* free up any extended packets */
  for (i=0; i<que->max; ++i)
    if (que->item[i].packet.oversize) {
      free (que->item[i].packet.oversize);
      que->item[i].packet.oversize = NULL;
      }
  /* clear packet array */
  memset(que->item, 0, sizeof(struct eth_item) * que->max);
  /* clear rest of structure */
  que->count = que->head = que->tail = 0;
}

void ethq_remove(ETH_QUE* que)
{
  struct eth_item* item = &que->item[que->head];

  if (que->count) {
    if (item->packet.oversize)
      free (item->packet.oversize);
    memset(item, 0, sizeof(struct eth_item));
    if (++que->head == que->max)
      que->head = 0;
    que->count--;
  }
}

void ethq_insert_data(ETH_QUE* que, int32 type, const uint8 *data, int used, size_t len, size_t crc_len, const uint8 *crc_data, int32 status)
{
  struct eth_item* item;

  /* if queue empty, set pointers to beginning */
  if (!que->count) {
    que->head = 0;
    que->tail = -1;
  }

  /* find new tail of the circular queue */
  if (++que->tail == que->max)
    que->tail = 0;
  if (++que->count > que->max) {
    que->count = que->max;
    /* lose oldest packet */
    if (++que->head == que->max)
      que->head = 0;
    que->loss++;
    }
  if (que->count > que->high)
    que->high = que->count;

  /* set information in (new) tail item */
  item = &que->item[que->tail];
  item->type = type;
  item->packet.len = len;
  item->packet.used = used;
  item->packet.crc_len = crc_len;
  if (MAX (len, crc_len) <= sizeof (item->packet.msg) - ETH_CRC_SIZE) {
    memcpy(item->packet.msg, data, ((len > crc_len) ? len : crc_len));
    if (crc_data && (crc_len > len))
      memcpy(&item->packet.msg[len], crc_data, ETH_CRC_SIZE);
    }
  else {
    item->packet.oversize = (uint8 *)realloc (item->packet.oversize, ((len > crc_len) ? len : crc_len));
    memcpy(item->packet.oversize, data, ((len > crc_len) ? len : crc_len));
    if (crc_data && (crc_len > len))
      memcpy(&item->packet.oversize[len], crc_data, ETH_CRC_SIZE);
    }
  item->packet.status = status;
}

void ethq_insert(ETH_QUE* que, int32 type, ETH_PACK* pack, int32 status)
{
ethq_insert_data(que, type, pack->oversize ? pack->oversize : pack->msg, pack->used, pack->len, pack->crc_len, NULL, status);
}

/*============================================================================*/
/*                        Non-implemented versions                            */
/*============================================================================*/

#if !defined (USE_NETWORK) && !defined (USE_SHARED)
const char *eth_capabilities(void)
    {return "no Ethernet";}
t_stat eth_open(ETH_DEV* dev, const char* name, DEVICE* dptr, uint32 dbit)
  {return SCPE_NOFNC;}
t_stat eth_close (ETH_DEV* dev)
  {return SCPE_NOFNC;}
t_stat eth_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
  {
  fprintf (st, "%s attach help\n\n", dptr->name);
  fprintf (st, "This simulator was not built with ethernet device support\n");
  return SCPE_OK;
  }
t_stat eth_check_address_conflict (ETH_DEV* dev, 
                                   ETH_MAC* const mac)
  {return SCPE_NOFNC;}
t_stat eth_set_throttle (ETH_DEV* dev, uint32 time, uint32 burst, uint32 delay)
  {return SCPE_NOFNC;}
t_stat eth_set_async (ETH_DEV *dev, int latency)
  {return SCPE_NOFNC;}
t_stat eth_clr_async (ETH_DEV *dev)
  {return SCPE_NOFNC;}
t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
  {return SCPE_NOFNC;}
int eth_read (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
  {return SCPE_NOFNC;}
t_stat eth_filter (ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
                   ETH_BOOL all_multicast, ETH_BOOL promiscuous)
  {return SCPE_NOFNC;}
t_stat eth_filter_hash (ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
                   ETH_BOOL all_multicast, ETH_BOOL promiscuous, ETH_MULTIHASH* const hash)
  {return SCPE_NOFNC;}
int eth_devices (int max, ETH_LIST* dev)
  {return -1;}
void eth_show_dev (FILE* st, ETH_DEV* dev)
  {}
static int _eth_get_system_id (char *buf, size_t buf_size)
  {memset (buf, 0, buf_size); return 0;}
#else    /* endif unimplemented */

const char *eth_capabilities(void)
 {
#if defined (USE_READER_THREAD)
 return "Threaded "
#else
 return "Polled "
#endif
     "Ethernet Packet transports"
#if defined (HAVE_PCAP_NETWORK)
     ":PCAP"
#endif
#if defined (HAVE_TAP_NETWORK)
     ":TAP"
#endif
#if defined (HAVE_VDE_NETWORK)
     ":VDE"
#endif
#if defined (HAVE_SLIRP_NETWORK)
     ":NAT"
#endif
     ":UDP";
 }

#if (defined (xBSD) || defined (__APPLE__)) && (defined (HAVE_TAP_NETWORK) || defined (HAVE_PCAP_NETWORK))
#include <sys/ioctl.h>
#include <net/bpf.h>
#endif

#if defined (HAVE_PCAP_NETWORK)
/*============================================================================*/
/*      WIN32, Linux, and xBSD routines use WinPcap and libpcap packages      */
/*        OpenVMS Alpha uses a WinPcap port and an associated execlet         */
/*============================================================================*/

#include <pcap.h>
#include <string.h>
#else
struct pcap_pkthdr {
    uint32 caplen;  /* length of portion present */
    uint32 len;     /* length this packet (off wire) */
};
#define PCAP_ERRBUF_SIZE 256
typedef void * pcap_t;  /* Pseudo Type to avoid compiler errors */
#define DLT_EN10MB 1    /* Dummy Value to avoid compiler errors */
#endif /* HAVE_PCAP_NETWORK */

#ifdef HAVE_TAP_NETWORK
#if defined(__linux) || defined(__linux__)
#include <sys/ioctl.h> 
#include <net/if.h> 
#include <linux/if_tun.h> 
#elif defined(HAVE_BSDTUNTAP)
#include <sys/types.h>
#include <net/if_types.h>
#include <net/if.h>
#else /* We don't know how to do this on the current platform */
#undef HAVE_TAP_NETWORK
#endif
#endif /* HAVE_TAP_NETWORK */

#ifdef HAVE_VDE_NETWORK
#ifdef  __cplusplus
extern "C" {
#endif
#include <libvdeplug.h>
#ifdef  __cplusplus
}
#endif
#endif /* HAVE_VDE_NETWORK */

#ifdef HAVE_SLIRP_NETWORK
#include "sim_slirp.h"
#endif /* HAVE_SLIRP_NETWORK */

/* Allows windows to look up user-defined adapter names */
#if defined(_WIN32)
#include <winreg.h>
#endif

#ifdef HAVE_DLOPEN
#include <dlfcn.h>
#endif

#if defined(USE_SHARED) && (defined(_WIN32) || defined(HAVE_DLOPEN))
/* Dynamic DLL loading technique and modified source comes from
   Etherial/WireShark capture_pcap.c */

/* Dynamic DLL load variables */
#ifdef _WIN32
static HINSTANCE hLib = NULL;               /* handle to DLL */
#else
static void *hLib = 0;                      /* handle to Library */
#endif
static int lib_loaded = 0;                  /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */
static const char* lib_name =
#if defined(_WIN32) || defined(__CYGWIN__)
                          "wpcap.dll";
#elif defined(__APPLE__)
                          "/usr/lib/libpcap.A.dylib";
#else
#define __STR_QUOTE(tok) #tok
#define __STR(tok) __STR_QUOTE(tok)
                          "libpcap." __STR(HAVE_DLOPEN);
#endif
static const char* no_pcap = 
#if defined(_WIN32) || defined(__CYGWIN__)
                          "wpcap load failure";
#else
                          "libpcap load failure";
#endif

/* define pointers to pcap functions needed */
static void    (*p_pcap_close) (pcap_t *);
static int     (*p_pcap_compile) (pcap_t *, struct bpf_program *, const char *, int, bpf_u_int32);
static int     (*p_pcap_datalink) (pcap_t *);
static int     (*p_pcap_dispatch) (pcap_t *, int, pcap_handler, u_char *);
static int     (*p_pcap_findalldevs) (pcap_if_t **, char *);
static void    (*p_pcap_freealldevs) (pcap_if_t *);
static void    (*p_pcap_freecode) (struct bpf_program *);
static char*   (*p_pcap_geterr) (pcap_t *);
static int     (*p_pcap_lookupnet) (const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
static pcap_t* (*p_pcap_open_live) (const char *, int, int, int, char *);
#ifdef _WIN32
static int     (*p_pcap_setmintocopy) (pcap_t* handle, int);
static HANDLE  (*p_pcap_getevent) (pcap_t *);
#else
#ifdef MUST_DO_SELECT
static int     (*p_pcap_get_selectable_fd) (pcap_t *);
#endif
static int     (*p_pcap_fileno) (pcap_t *);
#endif
static int     (*p_pcap_sendpacket) (pcap_t* handle, const u_char* msg, int len);
static int     (*p_pcap_setfilter) (pcap_t *, struct bpf_program *);
static int     (*p_pcap_setnonblock)(pcap_t* a, int nonblock, char *errbuf);

/* load function pointer from DLL */
typedef int (*_func)();

static void load_function(const char* function, _func* func_ptr) {
#ifdef _WIN32
    *func_ptr = (_func)((size_t)GetProcAddress(hLib, function));
#else
    *func_ptr = (_func)((size_t)dlsym(hLib, function));
#endif
    if (*func_ptr == 0) {
    sim_printf ("Eth: Failed to find function '%s' in %s\r\n", function, lib_name);
    lib_loaded = 3;
  }
}

static void try_load_function(const char* function, _func* func_ptr) {
#ifdef _WIN32
    *func_ptr = (_func)((size_t)GetProcAddress(hLib, function));
#else
    *func_ptr = (_func)((size_t)dlsym(hLib, function));
#endif
}

/* load wpcap.dll as required */
int load_pcap(void) {
  switch(lib_loaded) {
    case 0:                  /* not loaded */
            /* attempt to load DLL */
#ifdef _WIN32
      if (1) {
        BOOL(WINAPI *p_SetDllDirectory)(LPCTSTR);
        UINT(WINAPI *p_GetSystemDirectory)(LPTSTR lpBuffer, UINT uSize);

        p_SetDllDirectory = (BOOL(WINAPI *)(LPCTSTR)) GetProcAddress(GetModuleHandle("kernel32.dll"), "SetDllDirectoryA");
        p_GetSystemDirectory = (UINT(WINAPI *)(LPTSTR, UINT)) GetProcAddress(GetModuleHandle("kernel32.dll"), "GetSystemDirectoryA");
        if (p_SetDllDirectory && p_GetSystemDirectory) {
          char npcap_path[512] = "";

          if (p_GetSystemDirectory (npcap_path, sizeof(npcap_path) - 7))
            sim_strlcat (npcap_path, "\\Npcap", sizeof(npcap_path));
          if (p_SetDllDirectory(npcap_path))
            hLib = LoadLibraryA(lib_name);
          p_SetDllDirectory (NULL);
          }
        if (hLib == NULL)
          hLib = LoadLibraryA(lib_name);
        }
#else
      hLib = dlopen(lib_name, RTLD_NOW);
#endif
      if (hLib == 0) {
        /* failed to load DLL */
        sim_printf ("Eth: Failed to load %s\r\n", lib_name);
#ifdef _WIN32
        sim_printf ("Eth: You must install Npcap or WinPcap 4.x to use networking\r\n");
#else
        sim_printf ("Eth: You must install libpcap to use networking\r\n");
#endif
        lib_loaded = 2;
        break;
      } else {
        /* library loaded OK */
        lib_loaded = 1;
      }

      /* load required functions; sets dll_load=3 on error */
      load_function("pcap_close",        (_func *) &p_pcap_close);
      load_function("pcap_compile",      (_func *) &p_pcap_compile);
      load_function("pcap_datalink",     (_func *) &p_pcap_datalink);
      load_function("pcap_dispatch",     (_func *) &p_pcap_dispatch);
      load_function("pcap_findalldevs",  (_func *) &p_pcap_findalldevs);
      load_function("pcap_freealldevs",  (_func *) &p_pcap_freealldevs);
      load_function("pcap_freecode",     (_func *) &p_pcap_freecode);
      load_function("pcap_geterr",       (_func *) &p_pcap_geterr);
      load_function("pcap_lookupnet",    (_func *) &p_pcap_lookupnet);
      load_function("pcap_open_live",    (_func *) &p_pcap_open_live);
#ifdef _WIN32
      load_function("pcap_setmintocopy", (_func *) &p_pcap_setmintocopy);
      load_function("pcap_getevent",     (_func *) &p_pcap_getevent);
#else
#ifdef MUST_DO_SELECT
      load_function("pcap_get_selectable_fd",     (_func *) &p_pcap_get_selectable_fd);
#endif
      load_function("pcap_fileno",       (_func *) &p_pcap_fileno);
#endif
      load_function("pcap_sendpacket",   (_func *) &p_pcap_sendpacket);
      load_function("pcap_setfilter",    (_func *) &p_pcap_setfilter);
      load_function("pcap_setnonblock",  (_func *) &p_pcap_setnonblock);
      load_function("pcap_lib_version",  (_func *) &p_pcap_lib_version);

      if ((lib_loaded == 1) && (!eth_show_active)) {
        /* log successful load */
        sim_printf("%s\n", p_pcap_lib_version());
      }
      break;
    default:                /* loaded or failed */
      break;
  }
  return (lib_loaded == 1) ? 1 : 0;
}

/* define functions with dynamic revectoring */
void pcap_close(pcap_t* a) {
  if (load_pcap() != 0) {
    p_pcap_close(a);
  }
}

/* Some platforms's pcap.h have an ancient declaration of pcap_compile which doesn't have a const in the bpf string argument */
#if !defined (BPF_CONST_STRING)
int pcap_compile(pcap_t* a, struct bpf_program* b, char* c, int d, bpf_u_int32 e) {
#else
int pcap_compile(pcap_t* a, struct bpf_program* b, const char* c, int d, bpf_u_int32 e) {
#endif
  if (load_pcap() != 0) {
    return p_pcap_compile(a, b, c, d, e);
  } else {
    return 0;
  }
}

int pcap_datalink(pcap_t* a) {
  if (load_pcap() != 0) {
    return p_pcap_datalink(a);
  } else {
    return 0;
  }
}

int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) {
  if (load_pcap() != 0) {
    return p_pcap_dispatch(a, b, c, d);
  } else {
    return 0;
  }
}

int pcap_findalldevs(pcap_if_t** a, char* b) {
  if (load_pcap() != 0) {
    return p_pcap_findalldevs(a, b);
  } else {
    *a = 0;
    strcpy(b, no_pcap);
    return -1;
  }
}

void pcap_freealldevs(pcap_if_t* a) {
  if (load_pcap() != 0) {
    p_pcap_freealldevs(a);
  }
}

void pcap_freecode(struct bpf_program* a) {
  if (load_pcap() != 0) {
    p_pcap_freecode(a);
  }
}

char* pcap_geterr(pcap_t* a) {
  if (load_pcap() != 0) {
    return p_pcap_geterr(a);
  } else {
    return (char*) 0;
  }
}

int pcap_lookupnet(const char* a, bpf_u_int32* b, bpf_u_int32* c, char* d) {
  if (load_pcap() != 0) {
    return p_pcap_lookupnet(a, b, c, d);
  } else {
    return 0;
  }
}

pcap_t* pcap_open_live(const char* a, int b, int c, int d, char* e) {
  if (load_pcap() != 0) {
    return p_pcap_open_live(a, b, c, d, e);
  } else {
    return (pcap_t*) 0;
  }
}

#ifdef _WIN32
int pcap_setmintocopy(pcap_t* a, int b) {
  if (load_pcap() != 0) {
    return p_pcap_setmintocopy(a, b);
  } else {
    return 0;
  }
}

HANDLE pcap_getevent(pcap_t* a) {
  if (load_pcap() != 0) {
    return p_pcap_getevent(a);
  } else {
    return (HANDLE) 0;
  }
}

#else
#ifdef MUST_DO_SELECT
int pcap_get_selectable_fd(pcap_t* a) {
  if (load_pcap() != 0) {
    return p_pcap_get_selectable_fd(a);
  } else {
    return 0;
  }
}
#endif

int pcap_fileno(pcap_t * a) {
  if (load_pcap() != 0) {
    return p_pcap_fileno(a);
  } else {
    return 0;
  }
}
#endif

int pcap_sendpacket(pcap_t* a, const u_char* b, int c) {
  if (load_pcap() != 0) {
    return p_pcap_sendpacket(a, b, c);
  } else {
    return 0;
  }
}

int pcap_setfilter(pcap_t* a, struct bpf_program* b) {
  if (load_pcap() != 0) {
    return p_pcap_setfilter(a, b);
  } else {
    return 0;
  }
}

int pcap_setnonblock(pcap_t* a, int nonblock, char *errbuf) {
  if (load_pcap() != 0) {
    return p_pcap_setnonblock(a, nonblock, errbuf);
  } else {
    return 0;
  }
}
#endif /* defined(USE_SHARED) && (defined(_WIN32) || defined(HAVE_DLOPEN)) */

/* Some platforms have always had pcap_sendpacket */
#if defined(_WIN32) || defined(__VMS)
#define HAS_PCAP_SENDPACKET 1
#else
/* The latest libpcap and WinPcap all have pcap_sendpacket */
#if !defined (NEED_PCAP_SENDPACKET)
#define HAS_PCAP_SENDPACKET 1
#endif
#endif

#if !defined (HAS_PCAP_SENDPACKET)
/* libpcap has no function to write a packet, so we need to implement
   pcap_sendpacket() for compatibility with the WinPcap base code.
   Return value: 0=Success, -1=Failure */
int pcap_sendpacket(pcap_t* handle, const u_char* msg, int len)
{
#if defined (__linux) || defined (__linux__)
  return (send(pcap_fileno(handle), msg, len, 0) == len)? 0 : -1;
#else
  return (write(pcap_fileno(handle), msg, len) == len)? 0 : -1;
#endif /* linux */
}
#endif /* !HAS_PCAP_SENDPACKET */

#if defined(_WIN32) || defined(__CYGWIN__)
/* extracted from WinPcap's Packet32.h */
struct _PACKET_OID_DATA {
    uint32 Oid;                 ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h
                                ///< for a complete list of valid codes.
    uint32 Length;              ///< Length of the data field
    uint8 Data[1];              ///< variable-lenght field that contains the information passed to or received 
                                ///< from the adapter.
}; 
typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;
typedef void **LPADAPTER;
#define OID_802_3_CURRENT_ADDRESS               0x01010102 /* Extracted from ntddmdis.h */

static int pcap_mac_if_win32(const char *AdapterName, unsigned char MACAddress[6])
{
  LPADAPTER         lpAdapter;
  PPACKET_OID_DATA  OidData;
  int               Status;
  int               ReturnValue;
#ifdef _WIN32
  HMODULE           hDll;         /* handle to DLL */
#else
  static void       *hDll = NULL; /* handle to Library */
  typedef int BOOLEAN;
#endif
  LPADAPTER (*p_PacketOpenAdapter)(const char *AdapterName);
  void (*p_PacketCloseAdapter)(LPADAPTER lpAdapter);
  int (*p_PacketRequest)(LPADAPTER  AdapterObject,BOOLEAN Set,PPACKET_OID_DATA  OidData);

#ifdef _WIN32
  hDll = LoadLibraryA("packet.dll");
  p_PacketOpenAdapter = (LPADAPTER (*)(const char *AdapterName))GetProcAddress(hDll, "PacketOpenAdapter");
  p_PacketCloseAdapter = (void (*)(LPADAPTER lpAdapter))GetProcAddress(hDll, "PacketCloseAdapter");
  p_PacketRequest = (int (*)(LPADAPTER  AdapterObject,BOOLEAN Set,PPACKET_OID_DATA  OidData))GetProcAddress(hDll, "PacketRequest");
#else
  hDll = dlopen("packet.dll", RTLD_NOW);
  p_PacketOpenAdapter = (LPADAPTER (*)(const char *AdapterName))dlsym(hDll, "PacketOpenAdapter");
  p_PacketCloseAdapter = (void (*)(LPADAPTER lpAdapter))dlsym(hDll, "PacketCloseAdapter");
  p_PacketRequest = (int (*)(LPADAPTER  AdapterObject,BOOLEAN Set,PPACKET_OID_DATA  OidData))dlsym(hDll, "PacketRequest");
#endif
  
  /* Open the selected adapter */

  lpAdapter =   p_PacketOpenAdapter(AdapterName);

  if (!lpAdapter || (*lpAdapter == (void *)-1)) {
#ifdef _WIN32
      FreeLibrary(hDll);
#else
      dlclose(hDll);
#endif
    return -1;
  }

  /* Allocate a buffer to get the MAC adress */

  OidData = (PACKET_OID_DATA *)malloc(6 + sizeof(PACKET_OID_DATA));
  if (OidData == NULL) {
    p_PacketCloseAdapter(lpAdapter);
#ifdef _WIN32
    FreeLibrary(hDll);
#else
    dlclose(hDll);
#endif
    return -1;
  }

  /* Retrieve the adapter MAC querying the NIC driver */

  OidData->Oid = OID_802_3_CURRENT_ADDRESS;

  OidData->Length = 6;
  memset(OidData->Data, 0, 6);

  Status = p_PacketRequest(lpAdapter, FALSE, OidData);
  if(Status) {
    memcpy(MACAddress, OidData->Data, 6);
    ReturnValue = 0;
  } else
    ReturnValue = -1;

  free(OidData);
  p_PacketCloseAdapter(lpAdapter);
#ifdef _WIN32
  FreeLibrary(hDll);
#else
  dlclose(hDll);
#endif
  return ReturnValue;
}

#endif  /* defined(_WIN32) || defined(__CYGWIN__) */

#if defined (__VMS) && !defined(__VAX)
#include <descrip.h>
#include <iodef.h>
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#include <stsdef.h>
#include <nmadef.h>

static int pcap_mac_if_vms(const char *AdapterName, unsigned char MACAddress[6])
{
  char VMS_Device[16];
  $DESCRIPTOR(Device, VMS_Device);
  unsigned short iosb[4];
  unsigned short *w;
  unsigned char *pha = NULL;
  unsigned char *hwa = NULL;
  int tmpval;
  int status;
  unsigned short characteristics[512];
  long chardesc[] = {sizeof(characteristics), (long)&characteristics};
  unsigned short chan;
#pragma member_alignment save
#pragma nomember_alignment
  static struct {
    short fmt;
    long val_fmt;
    short pty;
    long val_pty;
    short pad;
    long val_pad;
    } setup  = {
        NMA$C_PCLI_FMT, NMA$C_LINFM_ETH,
        NMA$C_PCLI_PTY, 0x0090,
        NMA$C_PCLI_PAD, NMA$C_STATE_OFF,
    };
#pragma member_alignment restore
    long setupdesc[] = {sizeof(setup), (long)&setup};

  /* Convert Interface Name to VMS Device Name */
  /* This is a name shuffle */
  /*   WE0 becomes EWA0:    */
  /*   SE1 becomes ESB0:    */
  /*   XE0 becomes EXA0:    */
  tmpval = (int)(AdapterName[2]-'0');
  if ((tmpval < 0) || (tmpval > 25))
    return -1;
  VMS_Device[0] = toupper(AdapterName[1]);
  VMS_Device[1] = toupper(AdapterName[0]);
  VMS_Device[2] = 'A' + tmpval;
  VMS_Device[3] = '0';
  VMS_Device[4] = '\0';
  VMS_Device[5] = '\0';
  Device.dsc$w_length = strlen(VMS_Device);
  if (!$VMS_STATUS_SUCCESS( sys$assign (&Device, &chan, 0, 0, 0) ))
    return -1;
  status = sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRL|IO$M_STARTUP, &iosb, 0, 0, 
                     0, &setupdesc, 0, 0, 0, 0);
  if ((!$VMS_STATUS_SUCCESS(status)) || (!$VMS_STATUS_SUCCESS(iosb[0]))) {
    sys$dassgn(chan);
    return -1;
    }
  status = sys$qiow (0, chan, IO$_SENSEMODE|IO$M_CTRL, &iosb, 0, 0, 
                     0, &chardesc, 0, 0, 0, 0);
  sys$dassgn(chan);
  if ((!$VMS_STATUS_SUCCESS(status)) || (!$VMS_STATUS_SUCCESS(iosb[0])))
    return -1;
  for (w=characteristics; w < &characteristics[iosb[1]]; ) {
    if ((((*w)&0xFFF) == NMA$C_PCLI_HWA) && (6 == *(w+1)))
      hwa = (unsigned char *)(w + 2);
    if ((((*w)&0xFFF) == NMA$C_PCLI_PHA) && (6 == *(w+1)))
      pha = (unsigned char *)(w + 2);
    if (((*w)&0x1000) == 0)
      w += 3;                       /* Skip over Longword Parameter */
    else
      w += (2 + ((1 + *(w+1))/2));  /* Skip over String Parameter */
    }
  if (pha != NULL)                  /* Prefer Physical Address */
    memcpy(MACAddress, pha, 6);
  else
    if (hwa != NULL)                /* Fallback to Hardware Address */
      memcpy(MACAddress, hwa, 6);
    else
      return -1;
  return 0;
}
#endif /* defined (__VMS) && !defined(__VAX) */

static void eth_get_nic_hw_addr(ETH_DEV* dev, const char *devname)
{
  memset(&dev->host_nic_phy_hw_addr, 0, sizeof(dev->host_nic_phy_hw_addr));
  dev->have_host_nic_phy_addr = 0;
  if (dev->eth_api != ETH_API_PCAP)
    return;
#if defined(_WIN32) || defined(__CYGWIN__)
  if (!pcap_mac_if_win32(devname, dev->host_nic_phy_hw_addr))
    dev->have_host_nic_phy_addr = 1;
#elif defined (__VMS) && !defined(__VAX)
  if (!pcap_mac_if_vms(devname, dev->host_nic_phy_hw_addr))
    dev->have_host_nic_phy_addr = 1;
#elif !defined(__CYGWIN__) && !defined(__VMS)
  if (1) {
    char command[1024];
    FILE *f;
    int i;
    const char *patterns[] = {
        "grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]",
        "egrep [0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]:[0-9a-fA-F]?[0-9a-fA-F]",
        NULL};

    memset(command, 0, sizeof(command));
    for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) {
      snprintf(command, sizeof(command)-1, "ifconfig %s | %s  >NIC.hwaddr", devname, patterns[i]);
      (void)system(command);
      if (NULL != (f = fopen("NIC.hwaddr", "r"))) {
        while (0 == dev->have_host_nic_phy_addr) {
          if (fgets(command, sizeof(command)-1, f)) {
            char *p1, *p2;

            p1 = strchr(command, ':');
            while (p1) {
              p2 = strchr(p1+1, ':');
              if (p2 <= p1+3) {
                unsigned int mac_bytes[6];
                if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) {
                  dev->host_nic_phy_hw_addr[0] = mac_bytes[0];
                  dev->host_nic_phy_hw_addr[1] = mac_bytes[1];
                  dev->host_nic_phy_hw_addr[2] = mac_bytes[2];
                  dev->host_nic_phy_hw_addr[3] = mac_bytes[3];
                  dev->host_nic_phy_hw_addr[4] = mac_bytes[4];
                  dev->host_nic_phy_hw_addr[5] = mac_bytes[5];
                  dev->have_host_nic_phy_addr = 1;
                  }
                break;
                }
              p1 = p2;
              }
            }
          else
            break;
          }
        fclose(f);
        remove("NIC.hwaddr");
        }
      }
    }
#endif
}

#if defined(__APPLE__)
#include <uuid/uuid.h>
#include <unistd.h>
static int _eth_get_system_id (char *buf, size_t buf_size)
{
static struct timespec wait = {5, 0};   /* 5 seconds */
static uuid_t uuid;

memset (buf, 0, buf_size);
if (buf_size < 37)
  return -1;
if (gethostuuid (uuid, &wait))
  memset (uuid, 0, sizeof(uuid));
uuid_unparse_lower(uuid, buf);
return 0;
}

#elif defined(_WIN32)
static int _eth_get_system_id (char *buf, size_t buf_size)
{
  LONG status;
  DWORD reglen, regtype;
  HKEY reghnd;

  memset (buf, 0, buf_size);
#ifndef KEY_WOW64_64KEY
#define KEY_WOW64_64KEY         (0x0100)
#endif
  if ((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Cryptography", 0, KEY_QUERY_VALUE|KEY_WOW64_64KEY, &reghnd)) != ERROR_SUCCESS)
    return -1;
  reglen = buf_size;
  if ((status = RegQueryValueExA (reghnd, "MachineGuid", NULL, &regtype, buf, &reglen)) != ERROR_SUCCESS) {
    RegCloseKey (reghnd);
    return -1;
    }
  RegCloseKey (reghnd );
  /* make sure value is the right type, bail if not acceptable */
  if ((regtype != REG_SZ) || (reglen > buf_size))
    return -1;
  /* registry value seems OK */
  return 0;
}

#else
static int _eth_get_system_id (char *buf, size_t buf_size)
{
FILE *f;

memset (buf, 0, buf_size);
if ((f = fopen ("/etc/machine-id", "r"))) {
  fread (buf, 1, buf_size, f);
  fclose (f);
  }
else {
  if ((f = popen ("hostname", "r"))) {
    fread (buf, 1, buf_size, f);
    pclose (f);
    }
  }
while ((strlen (buf) > 0) && sim_isspace(buf[strlen (buf) - 1]))
  buf[strlen (buf) - 1] = '\0';
return 0;
}
#endif

/* Forward declarations */
static void
_eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data);

static t_stat
_eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine);

static void
_eth_error(ETH_DEV* dev, const char* where);

#if defined(HAVE_SLIRP_NETWORK)
static void _slirp_callback (void *opaque, const unsigned char *buf, int len)
{
struct pcap_pkthdr header;

memset(&header, 0, sizeof(header));
header.caplen = header.len = len;
_eth_callback((u_char *)opaque, &header, buf);
}
#endif

#if defined (USE_READER_THREAD)
#include <pthread.h>

static void *
_eth_reader(void *arg)
{
ETH_DEV* volatile dev = (ETH_DEV*)arg;
int status = 0;
int sel_ret = 0;
int do_select = 0;
SOCKET select_fd = 0;
#if defined (_WIN32)
HANDLE hWait = (dev->eth_api == ETH_API_PCAP) ? pcap_getevent ((pcap_t*)dev->handle) : NULL;
#endif

switch (dev->eth_api) {
  case ETH_API_PCAP:
#if defined (HAVE_PCAP_NETWORK)
#if defined (MUST_DO_SELECT)
    do_select = 1;
    select_fd = pcap_get_selectable_fd((pcap_t *)dev->handle);
#endif
#endif
    break;
  case ETH_API_TAP:
  case ETH_API_VDE:
  case ETH_API_UDP:
  case ETH_API_NAT:
    do_select = 1;
    select_fd = dev->fd_handle;
    break;
  }

sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which, in general, won't be readily yielding the processor 
   when this thread needs to run */
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

while (dev->handle) {
#if defined (_WIN32)
  if (dev->eth_api == ETH_API_PCAP) {
    if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250))
      sel_ret = 1;
    }
  if ((dev->eth_api == ETH_API_UDP) || (dev->eth_api == ETH_API_NAT))
#endif /* _WIN32 */
  if (1) {
    if (do_select) {
#ifdef HAVE_SLIRP_NETWORK
      if (dev->eth_api == ETH_API_NAT) {
        sel_ret = sim_slirp_select ((SLIRP*)dev->handle, 250);
        }
      else
#endif
        {
        fd_set setl;
        struct timeval timeout;
        
        FD_ZERO(&setl);
        FD_SET(select_fd, &setl);
        timeout.tv_sec = 0;
        timeout.tv_usec = 250*1000;
        sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
        }
      }
    else
      sel_ret = 1;
    if (sel_ret < 0 && errno != EINTR) 
      break;
    }
  if (sel_ret > 0) {
    if (!dev->handle)
      break;
    /* dispatch read request queue available packets */
    switch (dev->eth_api) {
#ifdef HAVE_PCAP_NETWORK
      case ETH_API_PCAP:
        status = pcap_dispatch ((pcap_t*)dev->handle, -1, &_eth_callback, (u_char*)dev);
        break;
#endif
#ifdef HAVE_TAP_NETWORK
      case ETH_API_TAP:
        if (1) {
          struct pcap_pkthdr header;
          int len;
          u_char buf[ETH_MAX_JUMBO_FRAME];

          memset(&header, 0, sizeof(header));
          len = read(dev->fd_handle, buf, sizeof(buf));
          if (len > 0) {
            status = 1;
            header.caplen = header.len = len;
            _eth_callback((u_char *)dev, &header, buf);
            }
          else {
            if (len < 0)
              status = -1;
            else
              status = 0;
            }
          }
        break;
#endif /* HAVE_TAP_NETWORK */
#ifdef HAVE_VDE_NETWORK
      case ETH_API_VDE:
        if (1) {
          struct pcap_pkthdr header;
          int len;
          u_char buf[ETH_MAX_JUMBO_FRAME];

          memset(&header, 0, sizeof(header));
          len = vde_recv((VDECONN *)dev->handle, buf, sizeof(buf), 0);
          if (len > 0) {
            status = 1;
            header.caplen = header.len = len;
            _eth_callback((u_char *)dev, &header, buf);
            }
          else {
            if (len < 0)
              status = -1;
            else
              status = 0;
            }
          }
        break;
#endif /* HAVE_VDE_NETWORK */
#ifdef HAVE_SLIRP_NETWORK
      case ETH_API_NAT:
        sim_slirp_dispatch ((SLIRP*)dev->handle);
        status = 1;
        break;
#endif /* HAVE_SLIRP_NETWORK */
      case ETH_API_UDP:
        if (1) {
          struct pcap_pkthdr header;
          int len;
          u_char buf[ETH_MAX_JUMBO_FRAME];

          memset(&header, 0, sizeof(header));
          len = (int)sim_read_sock (select_fd, (char *)buf, (int32)sizeof(buf));
          if (len > 0) {
            status = 1;
            header.caplen = header.len = len;
            _eth_callback((u_char *)dev, &header, buf);
            }
          else {
            if (len < 0)
              status = -1;
            else
              status = 0;
            }
          }
        break;
      }
    if ((status > 0) && (dev->asynch_io)) {
      int wakeup_needed;

      pthread_mutex_lock (&dev->lock);
      wakeup_needed = (dev->read_queue.count != 0);
      pthread_mutex_unlock (&dev->lock);
      if (wakeup_needed) {
        sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n");
        sim_activate_abs (dev->dptr->units, dev->asynch_io_latency);
        }
      }
    if (status < 0) {
      ++dev->receive_packet_errors;
      _eth_error (dev, "_eth_reader");
      if (dev->handle) { /* Still attached? */
#if defined (_WIN32)
        hWait = (dev->eth_api == ETH_API_PCAP) ? pcap_getevent ((pcap_t*)dev->handle) : NULL;
#endif
        if (do_select) {
          select_fd = dev->fd_handle;
#if !defined (_WIN32) && defined(HAVE_PCAP_NETWORK)
          if (dev->eth_api == ETH_API_PCAP)
            select_fd = pcap_get_selectable_fd((pcap_t *)dev->handle);
#endif
          }
        }
      }
    }
  }

sim_debug(dev->dbit, dev->dptr, "Reader Thread Exiting\n");
return NULL;
}

static void *
_eth_writer(void *arg)
{
ETH_DEV* volatile dev = (ETH_DEV*)arg;
ETH_WRITE_REQUEST *request;

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which in general won't be readily yielding the processor when 
   this thread needs to run */
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");

pthread_mutex_lock (&dev->writer_lock);
while (dev->handle) {
  pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
  while (NULL != (request = dev->write_requests)) {
    /* Pull buffer off request list */
    dev->write_requests = request->next;
    pthread_mutex_unlock (&dev->writer_lock);

    if (dev->throttle_delay != ETH_THROT_DISABLED_DELAY) {
      uint32 packet_delta_time = sim_os_msec() - dev->throttle_packet_time;
      dev->throttle_events <<= 1;
      dev->throttle_events += (packet_delta_time < dev->throttle_time) ? 1 : 0;
      if ((dev->throttle_events & dev->throttle_mask) == dev->throttle_mask) {
        sim_os_ms_sleep (dev->throttle_delay);
        ++dev->throttle_count;
        }
      dev->throttle_packet_time = sim_os_msec();
      }
    dev->write_status = _eth_write(dev, &request->packet, NULL);

    pthread_mutex_lock (&dev->writer_lock);
    /* Put buffer on free buffer list */
    request->next = dev->write_buffers;
    dev->write_buffers = request;
    }
  }
pthread_mutex_unlock (&dev->writer_lock);

sim_debug(dev->dbit, dev->dptr, "Writer Thread Exiting\n");
return NULL;
}
#endif

t_stat eth_set_async (ETH_DEV *dev, int latency)
{
#if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO)
char *msg = "Eth: can't operate asynchronously, must poll\r\n";
sim_printf ("%s", msg);
return SCPE_NOFNC;
#else
int wakeup_needed;

dev->asynch_io = 1;
dev->asynch_io_latency = latency;
pthread_mutex_lock (&dev->lock);
wakeup_needed = (dev->read_queue.count != 0);
pthread_mutex_unlock (&dev->lock);
if (wakeup_needed) {
  sim_debug(dev->dbit, dev->dptr, "Queueing automatic poll\n");
  sim_activate_abs (dev->dptr->units, dev->asynch_io_latency);
  }
#endif
return SCPE_OK;
}

t_stat eth_clr_async (ETH_DEV *dev)
{
#if !defined(USE_READER_THREAD) || !defined(SIM_ASYNCH_IO)
return SCPE_NOFNC;
#else
/* make sure device exists */
if (!dev) return SCPE_UNATT;

dev->asynch_io = 0;
return SCPE_OK;
#endif
}

t_stat eth_set_throttle (ETH_DEV* dev, uint32 time, uint32 burst, uint32 delay)
{
if (!dev)
  return SCPE_IERR;
dev->throttle_time = time;
dev->throttle_burst = burst;
dev->throttle_delay = delay;
dev->throttle_mask = (1 << dev->throttle_burst) - 1;
return SCPE_OK;
}

static t_stat _eth_open_port(char *savname, int *eth_api, void **handle, SOCKET *fd_handle, char errbuf[PCAP_ERRBUF_SIZE], char *bpf_filter, void *opaque, DEVICE *dptr, uint32 dbit)
{
int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ;

if (bufsz < ETH_MAX_JUMBO_FRAME)
  bufsz = ETH_MAX_JUMBO_FRAME;    /* Enable handling of jumbo frames */

*eth_api = 0;
*handle = NULL;
*fd_handle = 0;

/* attempt to connect device */
memset(errbuf, 0, PCAP_ERRBUF_SIZE);
if (0 == strncmp("tap:", savname, 4)) {
  int  tun = -1;    /* TUN/TAP Socket */
  int  on = 1;
  const char *devname = savname + 4;

  while (isspace(*devname))
      ++devname;
#if defined(HAVE_TAP_NETWORK)
  if (!strcmp(savname, "tap:tapN")) {
    sim_printf ("Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n");
    return SCPE_OPENERR | SCPE_NOMESSAGE;
    }
#endif
#if (defined(__linux) || defined(__linux__)) && defined(HAVE_TAP_NETWORK)
  if ((tun = open("/dev/net/tun", O_RDWR)) >= 0) {
    struct ifreq ifr; /* Interface Requests */

    memset(&ifr, 0, sizeof(ifr));
    /* Set up interface flags */
    strcpy(ifr.ifr_name, devname);
    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;

    /* Send interface requests to TUN/TAP driver. */
    if (ioctl(tun, TUNSETIFF, &ifr) >= 0) {
      if (ioctl(tun, FIONBIO, &on)) {
        strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
        close(tun);
        }
      else {
        *fd_handle = tun;
        strcpy(savname, ifr.ifr_name);
        }
      }
    else
      strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
    }
  else
    strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
#elif defined(HAVE_BSDTUNTAP) && defined(HAVE_TAP_NETWORK)
  if (1) {
    char dev_name[64] = "";

    snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", devname);
    dev_name[sizeof(dev_name)-1] = '\0';

    if ((tun = open(dev_name, O_RDWR)) >= 0) {
      if (ioctl(tun, FIONBIO, &on)) {
        strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
        close(tun);
        }
      else {
        *fd_handle = tun;
        strcpy(savname, devname);
        }
#if defined (__APPLE__)
      if (1) {
        struct ifreq ifr;
        int s;

        memset (&ifr, 0, sizeof(ifr));
        ifr.ifr_addr.sa_family = AF_INET;
        strncpy(ifr.ifr_name, savname, sizeof(ifr.ifr_name));
        if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
          if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) {
            ifr.ifr_flags |= IFF_UP;
            if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr)) {
              strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
              close(tun);
              }
            }
          close(s);
          }
        }
#endif
      }
    else
      strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
  }
#else
  strncpy(errbuf, "No support for tap: devices", PCAP_ERRBUF_SIZE-1);
#endif /* !defined(__linux) && !defined(HAVE_BSDTUNTAP) */
  if (0 == errbuf[0]) {
    *eth_api = ETH_API_TAP;
    *handle = (void *)1;  /* Flag used to indicated open */
    }
  }
else { /* !tap: */
  if (0 == strncmp("vde:", savname, 4)) {
#if defined(HAVE_VDE_NETWORK)
    struct vde_open_args voa;
    const char *devname = savname + 4;

    memset(&voa, 0, sizeof(voa));
    if (!strcmp(savname, "vde:vdedevice")) {
      sim_printf ("Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\r\n");
      return SCPE_OPENERR | SCPE_NOMESSAGE;
      }
    while (isspace(*devname))
        ++devname;
    if (!(*handle = (void*) vde_open((char *)devname, (char *)"simh", &voa)))
      strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
    else {
      *eth_api = ETH_API_VDE;
      *fd_handle = vde_datafd((VDECONN*)(*handle));
      }
#else
    strncpy(errbuf, "No support for vde: network devices", PCAP_ERRBUF_SIZE-1);
#endif /* defined(HAVE_VDE_NETWORK) */
    }
  else { /* !vde: */
    if (0 == strncmp("nat:", savname, 4)) {
#if defined(HAVE_SLIRP_NETWORK)
      const char *devname = savname + 4;

      while (isspace(*devname))
          ++devname;
      if (!(*handle = (void*) sim_slirp_open(devname, opaque, &_slirp_callback, dptr, dbit)))
        strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
      else {
        *eth_api = ETH_API_NAT;
        *fd_handle = 0;
        }
#else
      strncpy(errbuf, "No support for nat: network devices", PCAP_ERRBUF_SIZE-1);
#endif /* defined(HAVE_SLIRP_NETWORK) */
      }
    else { /* not nat: */
      if (0 == strncmp("udp:", savname, 4)) {
        char localport[CBUFSIZE], host[CBUFSIZE], port[CBUFSIZE];
        char hostport[2*CBUFSIZE];
        const char *devname = savname + 4;

        if (!strcmp(savname, "udp:sourceport:remotehost:remoteport")) {
          sim_printf ("Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n");
          return SCPE_OPENERR | SCPE_NOMESSAGE;
          }

        while (isspace(*devname))
            ++devname;
        if (SCPE_OK != sim_parse_addr_ex (devname, host, sizeof(host), "localhost", port, sizeof(port), localport, sizeof(localport), NULL))
          return SCPE_OPENERR;

        if (localport[0] == '\0')
          strcpy (localport, port);
        sprintf (hostport, "%s:%s", host, port);
        if ((SCPE_OK == sim_parse_addr (hostport, NULL, 0, NULL, NULL, 0, NULL, "localhost")) &&
            (0 == strcmp (localport, port))) {
          sim_printf ("Eth: Must specify different udp localhost ports\r\n");
          return SCPE_OPENERR | SCPE_NOMESSAGE;
          }
        *fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, SIM_SOCK_OPT_DATAGRAM);
        if (INVALID_SOCKET == *fd_handle)
            return SCPE_OPENERR;
        *eth_api = ETH_API_UDP;
        *handle = (void *)1;  /* Flag used to indicated open */
        }
      else { /* not udp:, so attempt to open the parameter as if it were an explicit device name */
#if defined(HAVE_PCAP_NETWORK)
        *handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
        if (!*handle) { /* can't open device */
          sim_printf ("Eth: pcap_open_live error - %s\r\n", errbuf);
          return SCPE_OPENERR | SCPE_NOMESSAGE;
          }
        *eth_api = ETH_API_PCAP;
#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
        /* Tell the kernel that the header is fully-formed when it gets it.
           This is required in order to fake the src address. */
        if (1) {
          int one = 1;
          ioctl(pcap_fileno(*handle), BIOCSHDRCMPLT, &one);
          }
#endif /* xBSD */
#if defined(_WIN32)
        pcap_setmintocopy ((pcap_t*)(*handle), 0);
#endif
#if !defined (USE_READER_THREAD)
#ifdef USE_SETNONBLOCK
        /* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
        if (pcap_setnonblock (*handle, 1, errbuf) == -1) {
          sim_printf ("Eth: Failed to set non-blocking: %s\r\n", errbuf);
          }
#endif
#if defined (__APPLE__)
        if (1) {
          /* Deliver packets immediately, needed for OS X 10.6.2 and later
           * (Snow-Leopard).
           * See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
           * the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110
           */
          int v = 1;
          ioctl(pcap_fileno(*handle), BIOCIMMEDIATE, &v);
          }
#endif /* defined (__APPLE__) */
#endif /* !defined (USE_READER_THREAD) */
#else
        strncpy (errbuf, "Unknown or unsupported network device", PCAP_ERRBUF_SIZE-1);
#endif /* defined(HAVE_PCAP_NETWORK) */
        } /* not udp:, so attempt to open the parameter as if it were an explicit device name */
      } /* !nat: */
    } /* !vde: */
  } /* !tap: */
if (errbuf[0])
  return SCPE_OPENERR;

#ifdef USE_BPF
if (bpf_filter && (*eth_api == ETH_API_PCAP)) {
  struct bpf_program bpf;
  int status;
  bpf_u_int32  bpf_subnet, bpf_netmask;

  if (pcap_lookupnet(savname, &bpf_subnet, &bpf_netmask, errbuf)<0)
    bpf_netmask = 0;
  /* compile filter string */
  if ((status = pcap_compile((pcap_t*)(*handle), &bpf, bpf_filter, 1, bpf_netmask)) < 0) {
    sprintf(errbuf, "%s", pcap_geterr((pcap_t*)(*handle)));
    sim_printf("Eth: pcap_compile error: %s\r\n", errbuf);
    /* show erroneous BPF string */
    sim_printf ("Eth: BPF string is: |%s|\r\n", bpf_filter);
    }
  else {
    /* apply compiled filter string */
    if ((status = pcap_setfilter((pcap_t*)(*handle), &bpf)) < 0) {
      sprintf(errbuf, "%s", pcap_geterr((pcap_t*)(*handle)));
      sim_printf("Eth: pcap_setfilter error: %s\r\n", errbuf);
      }
    else {
#ifdef USE_SETNONBLOCK
      /* set file non-blocking */
      status = pcap_setnonblock ((pcap_t*)(*handle), 1, errbuf);
#endif /* USE_SETNONBLOCK */
      }
    pcap_freecode(&bpf);
    }
  }
#endif /* USE_BPF */
return SCPE_OK;
}

t_stat eth_open(ETH_DEV* dev, const char* name, DEVICE* dptr, uint32 dbit)
{
t_stat r;
int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ;
char errbuf[PCAP_ERRBUF_SIZE];
char temp[1024], desc[1024] = "";
const char* savname = name;
char namebuf[4*CBUFSIZE];
int   num;

if (bufsz < ETH_MAX_JUMBO_FRAME)
  bufsz = ETH_MAX_JUMBO_FRAME;    /* Enable handling of jumbo frames */

/* initialize device */
eth_zero(dev);

/* translate name of type "ethX" to real device name */
if ((strlen(name) == 4)
    && (tolower(name[0]) == 'e')
    && (tolower(name[1]) == 't')
    && (tolower(name[2]) == 'h')
    && isdigit(name[3])
   ) {
  num = atoi(&name[3]);
  savname = eth_getname(num, temp, desc);
  if (savname == NULL) /* didn't translate */
    return SCPE_OPENERR;
  }
else {
  /* are they trying to use device description? */
  savname = eth_getname_bydesc(name, temp, desc);
  if (savname == NULL) { /* didn't translate */
    /* probably is not ethX and has no description */
    savname = eth_getname_byname(name, temp, desc);
    if (savname == NULL) {/* didn't translate */
      savname = name;
      desc[0] = '\0';   /* no description */
      }
    }
  }

namebuf[sizeof(namebuf)-1] = '\0';
strncpy (namebuf, savname, sizeof(namebuf)-1);
savname = namebuf;
r = _eth_open_port(namebuf, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, NULL, (void *)dev, dptr, dbit);

if (errbuf[0]) {
  sim_printf ("Eth: open error - %s\r\n", errbuf);
  return SCPE_OPENERR | SCPE_NOMESSAGE;
  }
if (r != SCPE_OK)
  return r;

if (!strcmp (desc, "No description available"))
    strcpy (desc, "");
sim_printf ("Eth: opened OS device %s%s%s\r\n", savname, desc[0] ? " - " : "", desc);

/* get the NIC's hardware MAC address */
eth_get_nic_hw_addr(dev, savname);

/* save name of device */
dev->name = (char *)malloc(strlen(savname)+1);
strcpy(dev->name, savname);

/* save debugging information */
dev->dptr = dptr;
dev->dbit = dbit;

#if defined (USE_READER_THREAD)
if (1) {
  pthread_attr_t attr;

  ethq_init (&dev->read_queue, 200);         /* initialize FIFO queue */
  pthread_mutex_init (&dev->lock, NULL);
  pthread_mutex_init (&dev->writer_lock, NULL);
  pthread_mutex_init (&dev->self_lock, NULL);
  pthread_cond_init (&dev->writer_cond, NULL);
  pthread_attr_init(&attr);
  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
#if defined(__hpux)
  {
    /* libpcap needs sizeof(long) * 8192 bytes on the stack */
    size_t stack_size;
    const size_t min_stack_size = sizeof(long) * 8192 * 3 / 2;
    if (!pthread_attr_getstacksize(&attr, &stack_size) && stack_size < min_stack_size) {
      pthread_attr_setstacksize(&attr, min_stack_size);
    }
  }
#endif /* defined(__hpux) */
  pthread_create (&dev->reader_thread, &attr, _eth_reader, (void *)dev);
  pthread_create (&dev->writer_thread, &attr, _eth_writer, (void *)dev);
  pthread_attr_destroy(&attr);
  }
#endif /* defined (USE_READER_THREAD */
_eth_add_to_open_list (dev);
return SCPE_OK;
}

static t_stat _eth_close_port(int eth_api, pcap_t *pcap, SOCKET pcap_fd)
{
switch (eth_api) {
#ifdef HAVE_PCAP_NETWORK
  case ETH_API_PCAP:
    pcap_close(pcap);
    break;
#endif
#ifdef HAVE_TAP_NETWORK
  case ETH_API_TAP:
    close(pcap_fd);
    break;
#endif
#ifdef HAVE_VDE_NETWORK
  case ETH_API_VDE:
    vde_close((VDECONN*)pcap);
    break;
#endif
#ifdef HAVE_SLIRP_NETWORK
  case ETH_API_NAT:
    sim_slirp_close((SLIRP*)pcap);
    break;
#endif
  case ETH_API_UDP:
    sim_close_sock(pcap_fd);
    break;
  }
return SCPE_OK;
}

t_stat eth_close(ETH_DEV* dev)
{
pcap_t *pcap;
SOCKET pcap_fd;

/* make sure device exists */
if (!dev) return SCPE_UNATT;

/* close the device */
pcap_fd = dev->fd_handle;                   /* save handle to possibly close later */
pcap = (pcap_t *)dev->handle;
dev->handle = NULL;
dev->fd_handle = 0;
dev->have_host_nic_phy_addr = 0;

#if defined (USE_READER_THREAD)
pthread_join (dev->reader_thread, NULL);
pthread_mutex_destroy (&dev->lock);
pthread_cond_signal (&dev->writer_cond);
pthread_join (dev->writer_thread, NULL);
pthread_mutex_destroy (&dev->self_lock);
pthread_mutex_destroy (&dev->writer_lock);
pthread_cond_destroy (&dev->writer_cond);
if (1) {
  ETH_WRITE_REQUEST *buffer;
   while (NULL != (buffer = dev->write_buffers)) {
    dev->write_buffers = buffer->next;
    free(buffer);
    }
  while (NULL != (buffer = dev->write_requests)) {
    dev->write_requests = buffer->next;
    free(buffer);
    }
  }
ethq_destroy (&dev->read_queue);         /* release FIFO queue */
#endif

_eth_close_port (dev->eth_api, pcap, pcap_fd);
sim_printf ("Eth: closed %s\r\n", dev->name);

/* clean up the mess */
free(dev->name);
free(dev->bpf_filter);
eth_zero(dev);
_eth_remove_from_open_list (dev);
return SCPE_OK;
}

t_stat eth_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "%s attach help\n\n", dptr->name);
fprintf (st, "   sim> SHOW ETHERNET\n");
fprintf (st, "   libpcap version 1.0.0\n");
fprintf (st, "   ETH devices:\n");
fprintf (st, "    eth0   en0                                  (No description available)\n");
#if defined(HAVE_TAP_NETWORK)
fprintf (st, "    eth1   tap:tapN                             (Integrated Tun/Tap support)\n");
#endif
#if defined(HAVE_SLIRP_NETWORK)
fprintf (st, "    eth2   vde:device                           (Integrated VDE support)\n");
#endif
#if defined(HAVE_SLIRP_NETWORK)
fprintf (st, "    eth3   nat:{optional-nat-parameters}        (Integrated NAT (SLiRP) support)\n");
#endif
fprintf (st, "    eth4   udp:sourceport:remotehost:remoteport (Integrated UDP bridge support)\n");
fprintf (st, "   sim> ATTACH %s eth0\n\n", dptr->name);
fprintf (st, "or equivalently:\n\n");
fprintf (st, "   sim> ATTACH %s en0\n\n", dptr->name);
#if defined(HAVE_SLIRP_NETWORK)
sim_slirp_attach_help (st, dptr, uptr, flag, cptr);
#endif
return SCPE_OK;
}

static int _eth_rand_byte()
{
static int rand_initialized = 0;

if (!rand_initialized)
  srand((unsigned int)sim_os_msec());
return (rand() & 0xFF);
}

t_stat eth_check_address_conflict (ETH_DEV* dev, 
                                   ETH_MAC* const mac)
{
ETH_PACK send, recv;
t_stat status;
uint32 i;
int responses = 0;
uint32 offset, function;
char mac_string[32];

eth_mac_fmt(mac, mac_string);
sim_debug(dev->dbit, dev->dptr, "Determining Address Conflict for MAC address: %s\n", mac_string);

/* The process of checking address conflicts is used in two ways:
   1) to determine the behavior of the currently running packet 
      delivery facility regarding whether it may receive copies 
      of every packet sent (and how many). 
   2) to verify if a MAC address which this facility is planning 
      to use as the source address of packets is already in use 
      by some other node on the local network 
   Case #1, doesn't require (and explicitly doesn't want) any 
   interaction or response from other systems on the LAN so 
   therefore no considerations regarding switch packet forwarding 
   are important.  Meanwhile, Case #2 does require responses from 
   other components on the LAN to provide useful functionality. 
   The original designers of this mechanism did this when essentially 
   all LANs were single collision domains (i.e. ALL nodes which might 
   be affected by an address conflict were physically present on a single
   Ethernet cable which might have been extended by a couple of repeaters).
   Since that time, essentially no networks are single collision domains.  
   Thick and thinwire Ethernet cables don't exist and very few networks 
   even have hubs.  Today, essentially all LANs are deployed using one 
   or more layers of network switches.  In a switched LAN environment, the 
   switches on the LAN "learn" which ports on the LAN source traffic from 
   which MAC addresses and then forward traffic destined for particular 
   MAC address to the appropriate ports.  If a particular MAC address is
   already in use somewhere on the LAN, then the switches "know" where 
   it is.  The host based test using the loopback protocol is poorly 
   designed to detect this condition.  This test is performed by the host
   first changing the device's Physical MAC address to the address which
   is to be tested, and then sending a loopback packet FROM AND TO this
   MAC address with a loopback reply to be sent by a system which may be
   currently using the MAC address.  If no reply is received, then the 
   MAC address is presumed to be unused.  The sending of this packet will
   result in its delivery to the right system since the switch port/MAC
   address tables know where to deliver packets destined to this MAC 
   address, however the response it generates won't be delivered to the 
   system performing the test since the switches on the LAN won't know 
   about the local port being the right target for packets with this MAC 
   address.  A better test design to detect these conflicts would be for 
   the testing system to send a loopback packet FROM the current physical
   MAC address (BEFORE changing it) TO the MAC address being tested with 
   the loopback response coming to the current physical MAC address of 
   the device.  If a response is received, then the address is in use and
   the attempt to change the device's MAC address should fail.  Since we 
   can't change the software running in these simulators to implement this
   better conflict detection approach, we can still "do the right thing" 
   in the sim_ether layer.  We're already handling the loopback test 
   packets specially since we always had to avoid receiving the packets 
   which were being sent, but needed to allow for the incoming loopback 
   packets to be properly dealt with.  We can extend this current special
   handling to change outgoing "loopback to self" packets to have source 
   AND loopback destination addresses in the packets to be the host NIC's
   physical address.  The switch network will already know the correct 
   MAC/port relationship for the host NIC's physical address, so loopback 
   response packets will be delivered as needed.

   Code in _eth_write and _eth_callback provide the special handling to 
   perform the described loopback packet adjustments, and code in 
   eth_filter_hash makes sure that the loopback response packets are received.

   */

/* build a loopback forward request packet */
memset (&send, 0, sizeof(ETH_PACK));
send.len = ETH_MIN_PACKET;                              /* minimum packet size */
for (i=0; i<send.len; i++)
  send.msg[i] = _eth_rand_byte();
memcpy(&send.msg[0], mac, sizeof(ETH_MAC));             /* target address */
memcpy(&send.msg[6], mac, sizeof(ETH_MAC));             /* source address */
send.msg[12] = 0x90;                                    /* loopback packet type */
send.msg[13] = 0;
send.msg[14] = 0;                                       /* Offset */
send.msg[15] = 0;
send.msg[16] = 2;                                       /* Forward */
send.msg[17] = 0;
memcpy(&send.msg[18], mac, sizeof(ETH_MAC));            /* Forward Destination */
send.msg[24] = 1;                                       /* Reply */
send.msg[25] = 0;

eth_filter(dev, 1, (ETH_MAC *)mac, 0, 0);

/* send the packet */
status = _eth_write (dev, &send, NULL);
if (status != SCPE_OK) {
  const char *msg;
  msg = (dev->eth_api == ETH_API_PCAP) ?
      "Eth: Error Transmitting packet: %s\r\n"
        "You may need to run as root, or install a libpcap version\r\n"
        "which is at least 0.9 from your OS vendor or www.tcpdump.org\r\n" :
      "Eth: Error Transmitting packet: %s\r\n"
        "You may need to run as root.\r\n";
  sim_printf(msg, strerror(errno));
  return status;
  }

sim_os_ms_sleep (300);   /* time for a conflicting host to respond */

eth_packet_trace_detail (dev, send.msg, send.len, "Sent-Address-Check");

/* empty the read queue and count the responses */
do {
  memset (&recv, 0, sizeof(ETH_PACK));
  status = eth_read (dev, &recv, NULL);
  eth_packet_trace_detail (dev, recv.msg, recv.len, "Recv-Address-Check");
  offset = 16 + (recv.msg[14] | (recv.msg[15] << 8));
  function = 0;
  if ((offset+2) < recv.len)
    function = recv.msg[offset] | (recv.msg[offset+1] << 8);
  if (((0 == memcmp(send.msg+12, recv.msg+12, 2)) &&   /* Protocol Match */
       (function == 1) &&                              /* Function is Reply */
       (0 == memcmp(&send.msg[offset], &recv.msg[offset], send.len-offset))) || /* Content Match */
      (0 == memcmp(send.msg, recv.msg, send.len)))     /* Packet Match (Reflection) */
    responses++;
  } while (recv.len > 0);

sim_debug(dev->dbit, dev->dptr, "Address Conflict = %d\n", responses);
return responses;
}

t_stat eth_reflect(ETH_DEV* dev)
{
/* Test with an address no NIC should have. */
/* We do this to avoid reflections from the wire, */
/* in the event that a simulated NIC has a MAC address conflict. */
static ETH_MAC mac = {0xfe,0xff,0xff,0xff,0xff,0xfe};

sim_debug(dev->dbit, dev->dptr, "Determining Reflections...\n");

dev->reflections = 0;
dev->reflections = eth_check_address_conflict (dev, &mac);

sim_debug(dev->dbit, dev->dptr, "Reflections = %d\n", dev->reflections);
return dev->reflections;
}

static void
_eth_error(ETH_DEV* dev, const char* where)
{
char msg[64];
const char *netname = "";
time_t now;

time(&now);
sim_printf ("%s", asctime(localtime(&now)));
switch (dev->eth_api) {
  case ETH_API_PCAP:
      netname = "pcap";
      break;
  case ETH_API_TAP:
      netname = "tap";
      break;
  case ETH_API_VDE:
      netname = "vde";
      break;
  case ETH_API_UDP:
      netname = "udp";
      break;
  case ETH_API_NAT:
      netname = "nat";
      break;
  }
sprintf(msg, "%s(%s): ", where, netname);
switch (dev->eth_api) {
#if defined(HAVE_PCAP_NETWORK)
  case ETH_API_PCAP:
      sim_printf ("%s%s\n", msg, pcap_geterr ((pcap_t*)dev->handle));
      break;
#endif
  default:
      sim_err_sock (INVALID_SOCKET, msg);
      break;
  }
#ifdef USE_READER_THREAD
pthread_mutex_lock (&dev->lock);
++dev->error_waiting_threads;
if (!dev->error_needs_reset)
  dev->error_needs_reset = (((dev->transmit_packet_errors + dev->receive_packet_errors)%ETH_ERROR_REOPEN_THRESHOLD) == 0);
pthread_mutex_unlock (&dev->lock);
#else
dev->error_needs_reset = (((dev->transmit_packet_errors + dev->receive_packet_errors)%ETH_ERROR_REOPEN_THRESHOLD) == 0);
#endif
/* Limit errors to 1 per second (per invoking thread (reader and writer)) */
sim_os_sleep (1);
/* 
 When all of the threads which can reference this ETH_DEV object are
 simultaneously waiting in this routine, we have the potential to close
 and reopen the network connection.
 We do this after ETH_ERROR_REOPEN_THRESHOLD total errors have occurred.  
 In practice could be as frequently as once every ETH_ERROR_REOPEN_THRESHOLD/2 
 seconds, but normally would be about once every 1.5*ETH_ERROR_REOPEN_THRESHOLD 
 seconds (ONLY when the error condition exists).
 */
#ifdef USE_READER_THREAD
pthread_mutex_lock (&dev->lock);
if ((dev->error_waiting_threads == 2) &&
    (dev->error_needs_reset)) {
#else
if (dev->error_needs_reset) {
#endif
  char errbuf[PCAP_ERRBUF_SIZE];
  t_stat r;

  _eth_close_port(dev->eth_api, (pcap_t *)dev->handle, dev->fd_handle);
  sim_os_sleep (ETH_ERROR_REOPEN_PAUSE);

  r = _eth_open_port(dev->name, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, dev->bpf_filter, (void *)dev, dev->dptr, dev->dbit);
  dev->error_needs_reset = FALSE;
  if (r == SCPE_OK)
    sim_printf ("%s ReOpened: %s \n", msg, dev->name);
  else
    sim_printf ("%s ReOpen Attempt Failed: %s - %s\n", msg, dev->name, errbuf);
  ++dev->error_reopen_count;
  }
#ifdef USE_READER_THREAD
--dev->error_waiting_threads;
pthread_mutex_unlock (&dev->lock);
#endif
}

static
t_stat _eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
{
int status = 1;   /* default to failure */

/* make sure device exists */
if ((!dev) || (dev->eth_api == ETH_API_NONE)) return SCPE_UNATT;

/* make sure packet exists */
if (!packet) return SCPE_ARG;

/* make sure packet is acceptable length */
if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
  int loopback_self_frame = LOOPBACK_SELF_FRAME(packet->msg, packet->msg);
  int loopback_physical_response = LOOPBACK_PHYSICAL_RESPONSE(dev, packet->msg);

  eth_packet_trace (dev, packet->msg, packet->len, "writing");

  /* record sending of loopback packet (done before actual send to avoid race conditions with receiver) */
  if (loopback_self_frame || loopback_physical_response) {
    /* Direct loopback responses to the host physical address since our physical address
       may not have been learned yet. */
    if (loopback_self_frame && dev->have_host_nic_phy_addr) {
      memcpy(&packet->msg[6],  dev->host_nic_phy_hw_addr, sizeof(ETH_MAC));
      memcpy(&packet->msg[18], dev->host_nic_phy_hw_addr, sizeof(ETH_MAC));
      eth_packet_trace (dev, packet->msg, packet->len, "writing-fixed");
    }
#ifdef USE_READER_THREAD
    pthread_mutex_lock (&dev->self_lock);
#endif
    dev->loopback_self_sent += dev->reflections;
    dev->loopback_self_sent_total++;
#ifdef USE_READER_THREAD
    pthread_mutex_unlock (&dev->self_lock);
#endif
  }

    /* dispatch write request (synchronous; no need to save write info to dev) */
  switch (dev->eth_api) {
#ifdef HAVE_PCAP_NETWORK
    case ETH_API_PCAP:
      status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len);
      break;
#endif
#ifdef HAVE_TAP_NETWORK
    case ETH_API_TAP:
      status = (((int)packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1);
      break;
#endif
#ifdef HAVE_VDE_NETWORK
    case ETH_API_VDE:
      status = vde_send((VDECONN*)dev->handle, (void *)packet->msg, packet->len, 0);
      if ((status == (int)packet->len) || (status == 0))
        status = 0;
      else
        if ((status == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
          status = 0;
        else
          status = 1;
      break;
#endif
#ifdef HAVE_SLIRP_NETWORK
    case ETH_API_NAT:
      status = sim_slirp_send((SLIRP*)dev->handle, (char *)packet->msg, (size_t)packet->len, 0);
      if ((status == (int)packet->len) || (status == 0))
        status = 0;
      else
        status = 1;
      break;
#endif
    case ETH_API_UDP:
      status = (((int32)packet->len == sim_write_sock (dev->fd_handle, (char *)packet->msg, (int32)packet->len)) ? 0 : -1);
      break;
    }
  ++dev->packets_sent;              /* basic bookkeeping */
  /* On error, correct loopback bookkeeping */
  if ((status != 0) && loopback_self_frame) {
#ifdef USE_READER_THREAD
    pthread_mutex_lock (&dev->self_lock);
#endif
    dev->loopback_self_sent -= dev->reflections;
    dev->loopback_self_sent_total--;
#ifdef USE_READER_THREAD
    pthread_mutex_unlock (&dev->self_lock);
#endif
    }
  if (status != 0) {
    ++dev->transmit_packet_errors;
    _eth_error (dev, "_eth_write");
    }

  } /* if packet->len */

/* call optional write callback function */
if (routine)
  (routine)(status);

return ((status == 0) ? SCPE_OK : SCPE_IOERR);
}

t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
{
#ifdef USE_READER_THREAD
ETH_WRITE_REQUEST *request;
int write_queue_size = 1;

/* make sure device exists */
if ((!dev) || (dev->eth_api == ETH_API_NONE)) return SCPE_UNATT;

/* Get a buffer */
pthread_mutex_lock (&dev->writer_lock);
if (NULL != (request = dev->write_buffers))
  dev->write_buffers = request->next;
pthread_mutex_unlock (&dev->writer_lock);
if (NULL == request)
  request = (ETH_WRITE_REQUEST *)malloc(sizeof(*request));

/* Copy buffer contents */
request->packet.len = packet->len;
request->packet.used = packet->used;
request->packet.status = packet->status;
request->packet.crc_len = packet->crc_len;
memcpy(request->packet.msg, packet->msg, packet->len);

/* Insert buffer at the end of the write list (to make sure that */
/* packets make it to the wire in the order they were presented here) */
pthread_mutex_lock (&dev->writer_lock);
request->next = NULL;
if (dev->write_requests) {
  ETH_WRITE_REQUEST *last_request = dev->write_requests;

  ++write_queue_size;
  while (last_request->next) {
    last_request = last_request->next;
    ++write_queue_size;
    }
  last_request->next = request;
  }
else
    dev->write_requests = request;
if (write_queue_size > dev->write_queue_peak)
  dev->write_queue_peak = write_queue_size;
pthread_mutex_unlock (&dev->writer_lock);

/* Awaken writer thread to perform actual write */
pthread_cond_signal (&dev->writer_cond);

/* Return with a status from some prior write */
if (routine)
  (routine)(dev->write_status);
return dev->write_status;
#else
return _eth_write(dev, packet, routine);
#endif
}

static int
_eth_hash_lookup(ETH_MULTIHASH hash, const u_char* data)
{
int key = 0x3f & (eth_crc32(0, data, 6) >> 26);

key ^= 0x3f;
return (hash[key>>3] & (1 << (key&0x7)));
}

#if 0
static int
_eth_hash_validate(ETH_MAC *MultiCastList, int count, ETH_MULTIHASH hash)
{
ETH_MULTIHASH lhash;
int i;

memset(lhash, 0, sizeof(lhash));
for (i=0; i<count; ++i) {
  int key = 0x3f & (eth_crc32(0, MultiCastList[i], 6) >> 26);

  key ^= 0x3F;
  printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X Key: %X, Byte: %X, Val: %X\n", 
      MultiCastList[i][0], MultiCastList[i][1], MultiCastList[i][2], MultiCastList[i][3], MultiCastList[i][4], MultiCastList[i][5], 
      key, key>>3, (1 << (key&0x7)));
  lhash[key>>3] |= (1 << (key&0x7));
  }
if (memcmp(hash, lhash, sizeof(lhash))) {
  printf("Inconsistent Computed Hash:\n");
  printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", 
         hash[0], hash[1], hash[2], hash[3], 
         hash[4], hash[5], hash[6], hash[7]);
  printf("Was:       %02X %02X %02X %02X %02X %02X %02X %02X\n", 
         lhash[0], lhash[1], lhash[2], lhash[3], 
         lhash[4], lhash[5], lhash[6], lhash[7]);
  }
else {
  printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", 
         hash[0], hash[1], hash[2], hash[3], 
         hash[4], hash[5], hash[6], hash[7]);
  printf("Was:       %02X %02X %02X %02X %02X %02X %02X %02X\n", 
         lhash[0], lhash[1], lhash[2], lhash[3], 
         lhash[4], lhash[5], lhash[6], lhash[7]);
  }
return 0;
}

static void
_eth_test_multicast_hash()
{
ETH_MAC tMacs[] = {
                   {0xAB, 0x00, 0x04, 0x01, 0xAC, 0x10},
                   {0xAB, 0x00, 0x00, 0x04, 0x00, 0x00},
                   {0x09, 0x00, 0x2B, 0x00, 0x00, 0x0F},
                   {0x09, 0x00, 0x2B, 0x02, 0x01, 0x04},
                   {0x09, 0x00, 0x2B, 0x02, 0x01, 0x07},
                   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
                   {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01}};
ETH_MULTIHASH thash = {0x01, 0x40, 0x00, 0x00, 0x48, 0x88, 0x40, 0x00};

_eth_hash_validate(tMacs, sizeof(tMacs)/sizeof(tMacs[0]), thash);
}
#endif

/* The IP header */
struct IPHeader {
  uint8 verhlen;          /* Version & Header Length in dwords */
#define IP_HLEN(IP) (((IP)->verhlen&0xF)<<2) /* Header Length in Bytes */
#define IP_VERSION(IP) ((((IP)->verhlen)>>4)&0xF) /* IP Version */
  uint8 tos;              /* Type of service */
  uint16 total_len;       /* Length of the packet in dwords */
  uint16 ident;           /* unique identifier */
  uint16 flags;           /* Fragmentation Flags */
#define IP_DF_FLAG (0x4000)
#define IP_MF_FLAG (0x2000)
#define IP_OFFSET_MASK (0x1FFF)
#define IP_FRAG_DF(IP) (ntohs(((IP)->flags))&IP_DF_FLAG)
#define IP_FRAG_MF(IP) (ntohs(((IP)->flags))&IP_MF_FLAG)
#define IP_FRAG_OFFSET(IP) (ntohs(((IP)->flags))&IP_OFFSET_MASK)
  uint8 ttl;              /* Time to live */
  uint8 proto;            /* Protocol number (TCP, UDP etc) */
  uint16 checksum;        /* IP checksum */
  uint32 source_ip;       /* Source Address */
  uint32 dest_ip;         /* Destination Address */
  };

/* ICMP header */
struct ICMPHeader {
  uint8 type;          /* ICMP packet type */
  uint8 code;          /* Type sub code */
  uint16 checksum;     /* ICMP Checksum */
  uint32 otherstuff[1];/* optional data */
  };

struct UDPHeader {
  uint16 source_port;
  uint16 dest_port;
  uint16 length;      /* The length of the entire UDP datagram, including both header and Data fields. */
  uint16 checksum;
  };

struct TCPHeader {
  uint16 source_port;
  uint16 dest_port;
  uint32 sequence_number;
  uint32 acknowledgement_number;
  uint16 data_offset_and_flags;
#define TCP_DATA_OFFSET(TCP) ((ntohs((TCP)->data_offset_and_flags)>>12)<<2)
#define TCP_CWR_FLAG (0x80)
#define TCP_ECR_FLAG (0x40)
#define TCP_URG_FLAG (0x20)
#define TCP_ACK_FLAG (0x10)
#define TCP_PSH_FLAG (0x08)
#define TCP_RST_FLAG (0x04)
#define TCP_SYN_FLAG (0x02)
#define TCP_FIN_FLAG (0x01)
#define TCP_FLAGS_MASK (0xFFF)
  uint16 window;
  uint16 checksum;
  uint16 urgent;
  uint16 otherstuff[1];  /* The rest of the packet */
  };

#ifndef IPPROTO_TCP
#define IPPROTO_TCP             6               /* tcp */
#endif
#ifndef IPPROTO_UDP
#define IPPROTO_UDP             17              /* user datagram protocol */
#endif
#ifndef IPPROTO_ICMP
#define IPPROTO_ICMP            1               /* control message protocol */
#endif

static uint16 
ip_checksum(uint16 *buffer, int size) 
{
unsigned long cksum = 0;
    
/* Sum all the words together, adding the final byte if size is odd  */
while (size > 1) {
  cksum += *buffer++;
  size -= sizeof(*buffer);
}
if (size) {
  uint16 endword;
  uint8 *endbytes = (uint8 *)&endword;

  endbytes[0] = *((uint8 *)buffer);
  endbytes[1] = 0;
  cksum += endword;
  }

/* Do a little shuffling  */
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
    
/* Return the bitwise complement of the resulting mishmash  */
return (uint16)(~cksum);
}

static uint16 
pseudo_checksum(uint16 len, uint16 proto, uint16 *src_addr, uint16 *dest_addr, uint8 *buff)
{
uint32 sum;

/* Sum the data first */
sum = 0xffff&(~ip_checksum((uint16 *)buff, len));

/* add the pseudo header which contains the IP source and destinationn addresses */
sum += src_addr[0];
sum += src_addr[1];
sum += dest_addr[0];
sum += dest_addr[1];
/* and the protocol number and the length of the UDP packet */
sum = sum + htons(proto) + htons(len);

/* Do a little shuffling  */
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
    
/* Return the bitwise complement of the resulting mishmash  */
return (uint16)(~sum);
}

static void
_eth_fix_ip_jumbo_offload(ETH_DEV* dev, u_char* msg, int len)
{
const unsigned short* proto = (const unsigned short*) &msg[12];
struct IPHeader *IP;
struct TCPHeader *TCP = NULL;
struct UDPHeader *UDP;
struct ICMPHeader *ICMP;
uint16 orig_checksum;
uint16 payload_len;
uint16 mtu_payload;
uint16 ip_flags;
uint16 frag_offset;
struct pcap_pkthdr header;
uint16 orig_tcp_flags;

/* Only interested in IP frames */
if (ntohs(*proto) != 0x0800) {
  ++dev->jumbo_dropped; /* Non IP Frames are dropped */
  return;
  }
IP = (struct IPHeader *)&msg[14];
if (IP_VERSION(IP) != 4) {
  ++dev->jumbo_dropped; /* Non IPv4 jumbo frames are dropped */
  return;
  }
if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len)) {
  ++dev->jumbo_dropped; /* Bogus header length frames are dropped */
  return;
  }
if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP)) {
  ++dev->jumbo_dropped; /* Previously fragmented, but currently jumbo sized frames are dropped */
  return;
  }
switch (IP->proto) {
  case IPPROTO_UDP:
    UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP));
    if (ntohs(UDP->length) > (len-IP_HLEN(IP))) {
      ++dev->jumbo_dropped; /* Bogus UDP packet length (packet contained length exceeds packet size) frames are dropped */
      return;
      }
    if (UDP->checksum == 0)
      break; /* UDP Checksums are disabled */
    orig_checksum = UDP->checksum;
    UDP->checksum = 0;
    UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP);
    if (orig_checksum != UDP->checksum)
      eth_packet_trace (dev, msg, len, "reading jumbo UDP header Checksum Fixed");
    break;
  case IPPROTO_ICMP:
    ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP));
    orig_checksum = ICMP->checksum;
    ICMP->checksum = 0;
    ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP));
    if (orig_checksum != ICMP->checksum)
      eth_packet_trace (dev, msg, len, "reading jumbo ICMP header Checksum Fixed");
    break;
  case IPPROTO_TCP:
    TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
    if ((TCP_DATA_OFFSET(TCP) > (len-IP_HLEN(IP))) || (TCP_DATA_OFFSET(TCP) < 20)) {
      ++dev->jumbo_dropped; /* Bogus TCP packet header length (packet contained length exceeds packet size) frames are dropped */
      return;
      }
    /* We don't do anything with the TCP checksum since we're going to resegment the TCP data below */
    break;
  default:
    ++dev->jumbo_dropped; /* We onlt handle UDP, ICMP and TCP jumbo frames others are dropped */
    return;
  }
/* Reasonable Checksums are now in the jumbo packet, but we've got to actually */
/* deliver ONLY standard sized ethernet frames.  Our job here is to now act as */
/* a router might have to and fragment these IPv4 frames as they are delivered */
/* into the virtual NIC. We do this by walking down the packet and dispatching */
/* a chunk at a time recomputing an appropriate header for each chunk. For */
/* datagram oriented protocols (UDP and ICMP) this is done by simple packet */
/* fragmentation.  For TCP this is done by breaking large packets into separate */
/* TCP packets. */
memset(&header, 0, sizeof(header));
switch (IP->proto) {
  case IPPROTO_UDP:
  case IPPROTO_ICMP:
    ++dev->jumbo_fragmented;
    /* When we're performing LSO (Large Send Offload), we're given a 
       'template' header which may not include a value being populated 
       in the IP header length (which is only 16 bits).
       We process as payload everything which isn't known header data. */
    payload_len = (uint16)(len - (14 + IP_HLEN(IP)));
    mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP));
    frag_offset = 0;
    while (payload_len > 0) {
      ip_flags = frag_offset;
      if (payload_len > mtu_payload) {
        ip_flags |= IP_MF_FLAG;
        IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP));
        }
      else {
        IP->total_len = htons(payload_len + IP_HLEN(IP));
        }
      IP->flags = htons(ip_flags);
      IP->checksum = 0;
      IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
      header.caplen = header.len = 14 + ntohs(IP->total_len);
      eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment");
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
      if (1) {
        /* Debugging is easier if we read packets directly with pcap
           (i.e. we can use Wireshark to verify packet contents)
           we don't want to do this all the time for 2 reasons:
             1) sending through pcap involves kernel transitions and
             2) if the current system reflects sent packets, the 
                recieving side will receive and process 2 copies of 
                any packets sent this way. */
        ETH_PACK pkt;

        memset(&pkt, 0, sizeof(pkt));
        memcpy(pkt.msg, ((u_char *)IP)-14, header.len);
        pkt.len = header.len;
        _eth_write(dev, &pkt, NULL);
        }
#else
      _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14);
#endif
      payload_len -= (ntohs(IP->total_len) - IP_HLEN(IP));
      frag_offset += (ntohs(IP->total_len) - IP_HLEN(IP))>>3;
      if (payload_len > 0) {
        /* Move the MAC and IP headers down to just prior to the next payload segment */
        memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP));
        IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - IP_HLEN(IP));
        }
      }
    break;
  case IPPROTO_TCP:
    ++dev->jumbo_fragmented;
    eth_packet_trace_ex (dev, ((u_char *)IP)-14, len, "Fragmenting Jumbo TCP segment", 1, dev->dbit);
    TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
    orig_tcp_flags = ntohs(TCP->data_offset_and_flags);
    /* When we're performing LSO (Large Send Offload), we're given a 
       'template' header which may not include a value being populated 
       in the IP header length (which is only 16 bits).
       We process as payload everything which isn't known header data. */
    payload_len = (uint16)(len - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)));
    mtu_payload = ETH_MIN_JUMBO_FRAME - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
    while (payload_len > 0) {
      if (payload_len > mtu_payload) {
        TCP->data_offset_and_flags = htons(orig_tcp_flags&~(TCP_PSH_FLAG|TCP_FIN_FLAG|TCP_RST_FLAG));
        IP->total_len = htons(mtu_payload + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
        }
      else {
        TCP->data_offset_and_flags = htons(orig_tcp_flags);
        IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
        }
      IP->checksum = 0;
      IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
      TCP->checksum = 0;
      TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP);
      header.caplen = header.len = 14 + ntohs(IP->total_len);
      eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit);
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
      if (1) {
        /* Debugging is easier if we read packets directly with pcap
           (i.e. we can use Wireshark to verify packet contents)
           we don't want to do this all the time for 2 reasons:
             1) sending through pcap involves kernel transitions and
             2) if the current system reflects sent packets, the 
                recieving side will receive and process 2 copies of 
                any packets sent this way. */
        ETH_PACK pkt;

        memset(&pkt, 0, sizeof(pkt));
        memcpy(pkt.msg, ((u_char *)IP)-14, header.len);
        pkt.len = header.len;
        _eth_write(dev, &pkt, NULL);
        }
#else
      _eth_callback((u_char *)dev, &header, ((u_char *)IP)-14);
#endif
      payload_len -= (ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)));
      if (payload_len > 0) {
        /* Move the MAC, IP and TCP headers down to just prior to the next payload segment */
        memcpy(((u_char *)IP) + ntohs(IP->total_len) - (14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)), ((u_char *)IP) - 14, 14 + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
        IP = (struct IPHeader *)(((u_char *)IP) + ntohs(IP->total_len) - (IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)));
        TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
        TCP->sequence_number = htonl(mtu_payload + ntohl(TCP->sequence_number));
        }
      }
    break;
  }
}

static void
_eth_fix_ip_xsum_offload(ETH_DEV* dev, const u_char* msg, int len)
{
const unsigned short* proto = (const unsigned short*) &msg[12];
struct IPHeader *IP;
struct TCPHeader *TCP;
struct UDPHeader *UDP;
struct ICMPHeader *ICMP;
uint16 orig_checksum;

/* Only need to process locally originated packets */
if ((!dev->have_host_nic_phy_addr) || (memcmp(msg+6, dev->host_nic_phy_hw_addr, 6)))
  return;
/* Only interested in IP frames */
if (ntohs(*proto) != 0x0800)
  return;
IP = (struct IPHeader *)&msg[14];
if (IP_VERSION(IP) != 4)
  return; /* Only interested in IPv4 frames */
if ((IP_HLEN(IP) > len) || (ntohs(IP->total_len) > len))
  return; /* Bogus header length */
orig_checksum = IP->checksum;
IP->checksum = 0;
IP->checksum = ip_checksum((uint16 *)IP, IP_HLEN(IP));
if (orig_checksum != IP->checksum)
  eth_packet_trace (dev, msg, len, "reading IP header Checksum Fixed");
if (IP_FRAG_OFFSET(IP) || IP_FRAG_MF(IP))
  return; /* Insufficient data to compute payload checksum */
switch (IP->proto) {
  case IPPROTO_UDP:
    UDP = (struct UDPHeader *)(((char *)IP)+IP_HLEN(IP));
    if (ntohs(UDP->length) > (len-IP_HLEN(IP)))
      return; /* packet contained length exceeds packet size */
    if (UDP->checksum == 0)
      return; /* UDP Checksums are disabled */
    orig_checksum = UDP->checksum;
    UDP->checksum = 0;
    UDP->checksum = pseudo_checksum(ntohs(UDP->length), IPPROTO_UDP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)UDP);
    if (orig_checksum != UDP->checksum)
      eth_packet_trace (dev, msg, len, "reading UDP header Checksum Fixed");
    break;
  case IPPROTO_TCP:
    TCP = (struct TCPHeader *)(((char *)IP)+IP_HLEN(IP));
    orig_checksum = TCP->checksum;
    TCP->checksum = 0;
    TCP->checksum = pseudo_checksum(ntohs(IP->total_len)-IP_HLEN(IP), IPPROTO_TCP, (uint16 *)(&IP->source_ip), (uint16 *)(&IP->dest_ip), (uint8 *)TCP);
    if (orig_checksum != TCP->checksum)
      eth_packet_trace (dev, msg, len, "reading TCP header Checksum Fixed");
    break;
  case IPPROTO_ICMP:
    ICMP = (struct ICMPHeader *)(((char *)IP)+IP_HLEN(IP));
    orig_checksum = ICMP->checksum;
    ICMP->checksum = 0;
    ICMP->checksum = ip_checksum((uint16 *)ICMP, ntohs(IP->total_len)-IP_HLEN(IP));
    if (orig_checksum != ICMP->checksum)
      eth_packet_trace (dev, msg, len, "reading ICMP header Checksum Fixed");
    break;
  }
}

static int
_eth_process_loopback (ETH_DEV* dev, const u_char* data, uint32 len)
{
int protocol = data[12] | (data[13] << 8);
ETH_PACK  response;
uint32 offset, function;

if (protocol != 0x0090)     /* !ethernet loopback */
  return 0;

if (LOOPBACK_REFLECTION_TEST_PACKET(dev, data))
  return 0;                 /* Ignore reflection check packet */

offset   = 16 + (data[14] | (data[15] << 8));
if (offset >= len)
  return 0;
function = data[offset] | (data[offset+1] << 8);

if (function != 2) /*forward*/
  return 0;

/* The only packets we should be responding to are ones which 
   we received due to them being directed to our physical MAC address, 
   OR the Broadcast address OR to a Multicast address we're listening to 
   (we may receive others if we're in promiscuous mode, but shouldn't 
   respond to them) */
if ((0 == (data[0]&1)) &&           /* Multicast or Broadcast */
    (0 != memcmp(dev->filter_address[0], data, sizeof(ETH_MAC))))
  return 0;

/* Attempts to forward to multicast or broadcast addresses are explicitly 
   ignored by consuming the packet and doing nothing else */
if (data[offset+2]&1)
  return 1;

eth_packet_trace (dev, data, len, "rcvd");

sim_debug(dev->dbit, dev->dptr, "_eth_process_loopback()\n");

/* create forward response packet */
memset(&response, 0, sizeof(response));
response.len = len;
memcpy(response.msg, data, len);
memcpy(&response.msg[0], &response.msg[offset+2], sizeof(ETH_MAC));
memcpy(&response.msg[6], dev->filter_address[0], sizeof(ETH_MAC));
offset += 8 - 16; /* Account for the Ethernet Header and Offset value in this number  */
response.msg[14] = offset & 0xFF;
response.msg[15] = (offset >> 8) & 0xFF;

/* send response packet */
eth_write(dev, &response, NULL);

eth_packet_trace(dev, response.msg, response.len, ((function == 1) ? "loopbackreply" : "loopbackforward"));

++dev->loopback_packets_processed;

return 1;
}

static void
_eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data)
{
ETH_DEV*  dev = (ETH_DEV*) info;
int to_me;
int from_me = 0;
int i;
int bpf_used;

if (LOOPBACK_PHYSICAL_RESPONSE(dev, data)) {
  u_char *datacopy = (u_char *)malloc(header->len);

  /* Since we changed the outgoing loopback packet to have the physical MAC address of the
     host's interface instead of the programmatically set physical address of this pseudo
     device, we restore parts of the modified packet back as needed */
  memcpy(datacopy, data, header->len);
  memcpy(datacopy, dev->physical_addr, sizeof(ETH_MAC));
  memcpy(datacopy+18, dev->physical_addr, sizeof(ETH_MAC));
  _eth_callback(info, header, datacopy);
  free(datacopy);
  return;
}
switch (dev->eth_api) {
  case ETH_API_PCAP:
#ifdef USE_BPF
    bpf_used = 1;
    to_me = 1;
    /* AUTODIN II hash mode? */
    if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast))
      to_me = _eth_hash_lookup(dev->hash, data);
    break;
#endif /* USE_BPF */
  case ETH_API_TAP:
  case ETH_API_VDE:
  case ETH_API_UDP:
  case ETH_API_NAT:
    bpf_used = 0;
    to_me = 0;
    eth_packet_trace (dev, data, header->len, "received");

    for (i = 0; i < dev->addr_count; i++) {
      if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1;
      if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1;
    }

    /* all multicast mode? */
    if (dev->all_multicast && (data[0] & 0x01)) to_me = 1;

    /* promiscuous mode? */
    if (dev->promiscuous) to_me = 1;

    /* AUTODIN II hash mode? */
    if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01))
      to_me = _eth_hash_lookup(dev->hash, data);
    break;
  default:
    bpf_used = to_me = 0;                           /* Should NEVER happen */
    abort();
    break;
  }

/* detect reception of loopback packet to our physical address */
if ((LOOPBACK_SELF_FRAME(dev->physical_addr, data)) ||
    (LOOPBACK_PHYSICAL_REFLECTION(dev, data))) {
#ifdef USE_READER_THREAD
  pthread_mutex_lock (&dev->self_lock);
#endif
  dev->loopback_self_rcvd_total++;
  /* lower reflection count - if already zero, pass it on */
  if (dev->loopback_self_sent > 0) {
    eth_packet_trace (dev, data, header->len, "ignored");
    dev->loopback_self_sent--;
    to_me = 0;
    }
  else
    if (!bpf_used)
      from_me = 0;
#ifdef USE_READER_THREAD
  pthread_mutex_unlock (&dev->self_lock);
#endif
  }

if (bpf_used ? to_me : (to_me && !from_me)) {
  if (header->len > ETH_MIN_JUMBO_FRAME) {
    if (header->len <= header->caplen) {/* Whole Frame captured? */
      u_char *datacopy = (u_char *)malloc(header->len);
      memcpy(datacopy, data, header->len);
      _eth_fix_ip_jumbo_offload(dev, datacopy, header->len);
      free(datacopy);
      }
    else
      ++dev->jumbo_truncated;
    return;
    }
  if (_eth_process_loopback(dev, data, header->len))
    return;  
#if defined (USE_READER_THREAD)
  if (1) {
    int crc_len = 0;
    uint8 crc_data[4];
    uint32 len = header->len;
    u_char *moved_data = NULL;

    if (header->len < ETH_MIN_PACKET) {   /* Pad runt packets before CRC append */
      moved_data = (u_char *)malloc(ETH_MIN_PACKET);
      memcpy(moved_data, data, len);
      memset(moved_data + len, 0, ETH_MIN_PACKET-len);
      len = ETH_MIN_PACKET;
      data = moved_data;
      }

    /* If necessary, fix IP header checksums for packets originated locally */
    /* but were presumed to be traversing a NIC which was going to handle that task */
    /* This must be done before any needed CRC calculation */
    _eth_fix_ip_xsum_offload(dev, (const u_char*)data, len);
    
    if (dev->need_crc)
      crc_len = eth_get_packet_crc32_data(data, len, crc_data);

    eth_packet_trace (dev, data, len, "rcvqd");

    pthread_mutex_lock (&dev->lock);
    ethq_insert_data(&dev->read_queue, ETH_ITM_NORMAL, data, 0, len, crc_len, crc_data, 0);
    ++dev->packets_received;
    pthread_mutex_unlock (&dev->lock);
    free(moved_data);
    }
#else /* !USE_READER_THREAD */
  /* set data in passed read packet */
  dev->read_packet->len = header->len;
  memcpy(dev->read_packet->msg, data, header->len);
  /* Handle runt case and pad with zeros.  */
  /* The real NIC won't hand us runts from the wire, BUT we may be getting */
  /* some packets looped back before they actually traverse the wire */
  /* (by an internal bridge device for instance) */
  if (header->len < ETH_MIN_PACKET) {
    memset(&dev->read_packet->msg[header->len], 0, ETH_MIN_PACKET-header->len);
    dev->read_packet->len = ETH_MIN_PACKET;
    }
  /* If necessary, fix IP header checksums for packets originated by the local host */
  /* but were presumed to be traversing a NIC which was going to handle that task */
  /* This must be done before any needed CRC calculation */
  _eth_fix_ip_xsum_offload(dev, dev->read_packet->msg, dev->read_packet->len);
  if (dev->need_crc)
    dev->read_packet->crc_len = eth_add_packet_crc32(dev->read_packet->msg, dev->read_packet->len);
  else
    dev->read_packet->crc_len = 0;

  eth_packet_trace (dev, dev->read_packet->msg, dev->read_packet->len, "reading");

  ++dev->packets_received;

  /* call optional read callback function */
  if (dev->read_callback)
    (dev->read_callback)(0);
#endif
  }
}

int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
{
int status;

/* make sure device exists */

if ((!dev) || (dev->eth_api == ETH_API_NONE)) return 0;

/* make sure packet exists */
if (!packet) return 0;

packet->len = 0;
#if !defined (USE_READER_THREAD)
/* set read packet */
dev->read_packet = packet;

/* set optional callback routine */
dev->read_callback = routine;

/* dispatch read request to either receive a filtered packet or timeout */
do {
  switch (dev->eth_api) {
#ifdef HAVE_PCAP_NETWORK
    case ETH_API_PCAP:
      status = pcap_dispatch((pcap_t*)dev->handle, 1, &_eth_callback, (u_char*)dev);
      break;
#endif
#ifdef HAVE_TAP_NETWORK
    case ETH_API_TAP:
      if (1) {
        struct pcap_pkthdr header;
        int len;
        u_char buf[ETH_MAX_JUMBO_FRAME];

        memset(&header, 0, sizeof(header));
        len = read(dev->fd_handle, buf, sizeof(buf));
        if (len > 0) {
          status = 1;
          header.caplen = header.len = len;
          _eth_callback((u_char *)dev, &header, buf);
          }
        else {
          if (len < 0)
            status = -1;
          else
            status = 0;
          }
        }
      break;
#endif /* HAVE_TAP_NETWORK */
#ifdef HAVE_VDE_NETWORK
    case ETH_API_VDE:
      if (1) {
        struct pcap_pkthdr header;
        int len;
        u_char buf[ETH_MAX_JUMBO_FRAME];

        memset(&header, 0, sizeof(header));
        len = vde_recv((VDECONN*)dev->handle, buf, sizeof(buf), 0);
        if (len > 0) {
          status = 1;
          header.caplen = header.len = len;
          _eth_callback((u_char *)dev, &header, buf);
          }
        else {
          if (len < 0)
            status = -1;
          else
            status = 0;
          }
        }
      break;
#endif /* HAVE_VDE_NETWORK */
    case ETH_API_UDP:
      if (1) {
        struct pcap_pkthdr header;
        int len;
        u_char buf[ETH_MAX_JUMBO_FRAME];

        memset(&header, 0, sizeof(header));
        len = (int)sim_read_sock (dev->fd_handle, (char *)buf, (int32)sizeof(buf));
        if (len > 0) {
          status = 1;
          header.caplen = header.len = len;
          _eth_callback((u_char *)dev, &header, buf);
          }
        else {
          if (len < 0)
            status = -1;
          else
            status = 0;
          }
        }
      break;
    }
  } while ((status > 0) && (0 == packet->len));
if (status < 0) {
  ++dev->receive_packet_errors;
  _eth_error (dev, "eth_reader");
  }

#else /* USE_READER_THREAD */

  status = 0;
  pthread_mutex_lock (&dev->lock);
  if (dev->read_queue.count > 0) {
    ETH_ITEM* item = &dev->read_queue.item[dev->read_queue.head];
    packet->len = item->packet.len;
    packet->crc_len = item->packet.crc_len;
    memcpy(packet->msg, item->packet.msg, ((packet->len > packet->crc_len) ? packet->len : packet->crc_len));
    status = 1;
    ethq_remove(&dev->read_queue);
  }
  pthread_mutex_unlock (&dev->lock);  
  if ((status) && (routine))
    routine(0);
#endif

return status;
}

t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
                  ETH_BOOL all_multicast, ETH_BOOL promiscuous)
{
return eth_filter_hash(dev, addr_count, addresses, 
                       all_multicast, promiscuous, 
                       NULL);
}

t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
                       ETH_BOOL all_multicast, ETH_BOOL promiscuous, 
                       ETH_MULTIHASH* const hash)
{
int i;
char buf[116+66*ETH_FILTER_MAX];
char errbuf[PCAP_ERRBUF_SIZE];
char mac[20];
char* buf2;
t_stat status;
#ifdef USE_BPF
struct bpf_program bpf;
#endif

/* make sure device exists */
if (!dev) return SCPE_UNATT;

/* filter count OK? */
if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX))
  return SCPE_ARG;
else
  if (!addresses) return SCPE_ARG;

/* test reflections.  This is done early in this routine since eth_reflect */
/* calls eth_filter recursively and thus changes the state of the device. */
if (dev->reflections == -1)
  status = eth_reflect(dev);

/* set new filter addresses */
for (i = 0; i < addr_count; i++)
  memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC));
dev->addr_count = addr_count;

/* store other flags */
dev->all_multicast = all_multicast;
dev->promiscuous   = promiscuous;

/* store multicast hash data */
dev->hash_filter = (hash != NULL);
if (hash) {
  memcpy(dev->hash, hash, sizeof(*hash));
  sim_debug(dev->dbit, dev->dptr, "Multicast Hash: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n",
                                  dev->hash[0], dev->hash[1], dev->hash[2], dev->hash[3], 
                                  dev->hash[4], dev->hash[5], dev->hash[6], dev->hash[7]);
  }

/* print out filter information if debugging */
if (dev->dptr->dctrl & dev->dbit) {
  sim_debug(dev->dbit, dev->dptr, "Filter Set\n");
  for (i = 0; i < addr_count; i++) {
    char mac[20];
    eth_mac_fmt(&dev->filter_address[i], mac);
    sim_debug(dev->dbit, dev->dptr, "  Addr[%d]: %s\n", i, mac);
    }
  if (dev->all_multicast) {
    sim_debug(dev->dbit, dev->dptr, "All Multicast\n");
    }
  if (dev->promiscuous) {
    sim_debug(dev->dbit, dev->dptr, "Promiscuous\n");
    }
  }

/* setup BPF filters and other fields to minimize packet delivery */
strcpy(buf, "");

/* construct destination filters - since the real ethernet interface was set
   into promiscuous mode by eth_open(), we need to filter out the packets that
   our simulated interface doesn't want. */
if (!dev->promiscuous) {
  for (i = 0; i < addr_count; i++) {
    eth_mac_fmt(&dev->filter_address[i], mac);
    if (!strstr(buf, mac))    /* eliminate duplicates */
      sprintf(&buf[strlen(buf)], "%s(ether dst %s)", (*buf) ? " or " : "((", mac);
    }
  if (dev->all_multicast || dev->hash_filter)
    sprintf(&buf[strlen(buf)], "%s(ether multicast)", (*buf) ? " or " : "((");
  if (strlen(buf) > 0)
    sprintf(&buf[strlen(buf)], ")");
  }

/* construct source filters - this prevents packets from being reflected back 
   by systems where WinPcap and libpcap cause packet reflections. Note that
   some systems do not reflect packets at all. This *assumes* that the 
   simulated NIC will not send out packets with multicast source fields. */
if ((addr_count > 0) && (dev->reflections > 0)) {
  if (strlen(buf) > 0)
    sprintf(&buf[strlen(buf)], " and ");
  sprintf (&buf[strlen(buf)], "not (");
  buf2 = &buf[strlen(buf)];
  for (i = 0; i < addr_count; i++) {
    if (dev->filter_address[i][0] & 0x01) continue; /* skip multicast addresses */
    eth_mac_fmt(&dev->filter_address[i], mac);
    if (!strstr(buf2, mac))   /* eliminate duplicates */
      sprintf(&buf2[strlen(buf2)], "%s(ether src %s)", (*buf2) ? " or " : "", mac);
    }
  sprintf (&buf[strlen(buf)], ")");
  if (1 == strlen(buf2)) {          /* all addresses were multicast? */
    buf[strlen(buf)-6] = '\0';      /* Remove "not ()" */
    if (strlen(buf) > 0)
        buf[strlen(buf)-5] = '\0';  /* remove " and " */
    }
  }
if (strlen(buf) > 0)
  sprintf(&buf[strlen(buf)], ")");
/* When changing the Physical Address on a LAN interface, VMS sends out a 
   loopback packet with the source and destination addresses set to the same 
   value as the Physical Address which is being setup.  This packet is
   designed to find and help diagnose MAC address conflicts (which also 
   include DECnet address conflicts). Normally, this packet would not be 
   seen by the sender, only by the other machine that has the same Physical 
   Address (or possibly DECnet address). If the ethernet subsystem is 
   reflecting packets, the network startup will fail to start if it sees the 
   reflected packet, since it thinks another system is using this Physical 
   Address (or DECnet address). We have to let these packets through, so 
   that if another machine has the same Physical Address (or DECnet address)
   that we can detect it. Both eth_write() and _eth_callback() help by 
   checking the reflection count - eth_write() adds the reflection count to
   dev->loopback_self_sent, and _eth_callback() check the value - if the
   dev->loopback_self_sent count is zero, then the packet has come from 
   another machine with the same address, and needs to be passed on to the 
   simulated machine. */
memset(dev->physical_addr, 0, sizeof(ETH_MAC));
dev->loopback_self_sent = 0;
/* check for physical address in filters */
if ((addr_count) && (dev->reflections > 0)) {
  for (i = 0; i < addr_count; i++) {
    if (dev->filter_address[i][0]&1)
      continue;  /* skip all multicast addresses */
    eth_mac_fmt(&dev->filter_address[i], mac);
    if (strcmp(mac, "00:00:00:00:00:00") != 0) {
      memcpy(dev->physical_addr, &dev->filter_address[i], sizeof(ETH_MAC));
      /* let packets through where dst and src are the same as our physical address */
      sprintf (&buf[strlen(buf)], " or ((ether dst %s) and (ether src %s))", mac, mac);
      if (dev->have_host_nic_phy_addr) {
        eth_mac_fmt(&dev->host_nic_phy_hw_addr, mac);
        sprintf(&buf[strlen(buf)], " or ((ether dst %s) and (ether proto 0x9000))", mac);
      }
      break;
      }
    }
  }
if ((0 == strlen(buf)) && (!dev->promiscuous)) /* Empty filter means match nothing */
  strcpy(buf, "ether host fe:ff:ff:ff:ff:ff"); /* this should be a good match nothing filter */
sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);

/* get netmask, which is a required argument for compiling.  The value, 
   in our case isn't actually interesting since the filters we generate 
   aren't referencing IP fields, networks or values */

#ifdef USE_BPF
if (dev->eth_api == ETH_API_PCAP) {
  bpf_u_int32  bpf_subnet, bpf_netmask;

  if (pcap_lookupnet(dev->name, &bpf_subnet, &bpf_netmask, errbuf)<0)
    bpf_netmask = 0;
  /* compile filter string */
  if ((status = pcap_compile((pcap_t*)dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
    sprintf(errbuf, "%s", pcap_geterr((pcap_t*)dev->handle));
    sim_printf("Eth: pcap_compile error: %s\r\n", errbuf);
    /* show erroneous BPF string */
    sim_printf ("Eth: BPF string is: |%s|\r\n", buf);
    }
  else {
    /* apply compiled filter string */
    if ((status = pcap_setfilter((pcap_t*)dev->handle, &bpf)) < 0) {
      sprintf(errbuf, "%s", pcap_geterr((pcap_t*)dev->handle));
      sim_printf("Eth: pcap_setfilter error: %s\r\n", errbuf);
      }
    else {
      /* Save BPF filter string */
      dev->bpf_filter = (char *)realloc(dev->bpf_filter, 1 + strlen(buf));
      strcpy (dev->bpf_filter, buf);
#ifdef USE_SETNONBLOCK
      /* set file non-blocking */
      status = pcap_setnonblock (dev->handle, 1, errbuf);
#endif /* USE_SETNONBLOCK */
      }
    pcap_freecode(&bpf);
    }
#ifdef USE_READER_THREAD
  pthread_mutex_lock (&dev->lock);
  ethq_clear (&dev->read_queue); /* Empty FIFO Queue when filter list changes */
  pthread_mutex_unlock (&dev->lock);
#endif
  }
#endif /* USE_BPF */

return SCPE_OK;
}

/*
     The libpcap provided API pcap_findalldevs() on most platforms, will 
     leverage the getifaddrs() API if it is available in preference to 
     alternate platform specific methods of determining the interface list.

     A limitation of getifaddrs() is that it returns only interfaces which
     have associated addresses.  This may not include all of the interesting
     interfaces that we are interested in since a host may have dedicated
     interfaces for a simulator, which is otherwise unused by the host.

     One could hand craft the the build of libpcap to specifically use 
     alternate methods to implement pcap_findalldevs().  However, this can 
     get tricky, and would then result in a sort of deviant libpcap.

     This routine exists to allow platform specific code to validate and/or 
     extend the set of available interfaces to include any that are not
     returned by pcap_findalldevs.

*/
int eth_host_devices(int used, int max, ETH_LIST* list)
{
pcap_t* conn = NULL;
int i, j, datalink = 0;
char errbuf[PCAP_ERRBUF_SIZE];

for (i=0; i<used; ++i) {
  /* Cull any non-ethernet interface types */
#if defined(HAVE_PCAP_NETWORK)
  conn = pcap_open_live(list[i].name, ETH_MAX_PACKET, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
  if (NULL != conn)
    datalink = pcap_datalink(conn), pcap_close(conn);
  list[i].eth_api = ETH_API_PCAP;
#endif
  if ((NULL == conn) || (datalink != DLT_EN10MB)) {
    for (j=i; j<used-1; ++j)
      list[j] = list[j+1];
    --used;
    --i;
    }
  } /* for */

#if defined(_WIN32)
/* replace device description with user-defined adapter name (if defined) */
for (i=0; i<used; i++) {
  char regkey[2048];
  unsigned char regval[2048];
  LONG status;
  DWORD reglen, regtype;
  HKEY reghnd;

  /* These registry keys don't seem to exist for all devices, so we simply ignore errors. */
  /* Windows XP x64 registry uses wide characters by default,
     so we force use of narrow characters by using the 'A'(ANSI) version of RegOpenKeyEx.
     This could cause some problems later, if this code is internationalized. Ideally,
     the pcap lookup will return wide characters, and we should use them to build a wide
     registry key, rather than hardcoding the string as we do here. */
  if (list[i].name[strlen( "\\Device\\NPF_" )] == '{') {
    sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
             "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", list[i].name+
             strlen( "\\Device\\NPF_" ) );
    if ((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, &reghnd)) != ERROR_SUCCESS)
      continue;
    reglen = sizeof(regval);

    /* look for user-defined adapter name, bail if not found */  
    /* same comment about Windows XP x64 (above) using RegQueryValueEx */
    if ((status = RegQueryValueExA (reghnd, "Name", NULL, &regtype, regval, &reglen)) != ERROR_SUCCESS) {
      RegCloseKey (reghnd);
      continue;
      }
    /* make sure value is the right type, bail if not acceptable */
    if ((regtype != REG_SZ) || (reglen > sizeof(regval))) {
      RegCloseKey (reghnd);
      continue;
      }
    /* registry value seems OK, finish up and replace description */
    RegCloseKey (reghnd );
    sprintf (list[i].desc, "%s", regval);
    }
  } /* for */
#endif

#ifdef HAVE_TAP_NETWORK
if (used < max) {
#if defined(__OpenBSD__)
  sprintf(list[used].name, "%s", "tap:tunN");
#else
  sprintf(list[used].name, "%s", "tap:tapN");
#endif
  sprintf(list[used].desc, "%s", "Integrated Tun/Tap support");
  list[used].eth_api = ETH_API_TAP;
  ++used;
  }
#endif
#ifdef HAVE_VDE_NETWORK
if (used < max) {
  sprintf(list[used].name, "%s", "vde:device");
  sprintf(list[used].desc, "%s", "Integrated VDE support");
  list[used].eth_api = ETH_API_VDE;
  ++used;
  }
#endif
#ifdef HAVE_SLIRP_NETWORK
if (used < max) {
  sprintf(list[used].name, "%s", "nat:{optional-nat-parameters}");
  sprintf(list[used].desc, "%s", "Integrated NAT (SLiRP) support");
  list[used].eth_api = ETH_API_NAT;
  ++used;
  }
#endif

if (used < max) {
  sprintf(list[used].name, "%s", "udp:sourceport:remotehost:remoteport");
  sprintf(list[used].desc, "%s", "Integrated UDP bridge support");
  list[used].eth_api = ETH_API_UDP;
  ++used;
  }

return used;
}

int eth_devices(int max, ETH_LIST* list)
{
int i = 0;
char errbuf[PCAP_ERRBUF_SIZE];
#ifndef DONT_USE_PCAP_FINDALLDEVS
pcap_if_t* alldevs;
pcap_if_t* dev;

memset(list, 0, max*sizeof(*list));
errbuf[0] = '\0';
/* retrieve the device list */
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
  sim_printf ("Eth: error in pcap_findalldevs: %s\r\n", errbuf);
  }
else {
  /* copy device list into the passed structure */
  for (i=0, dev=alldevs; dev && (i < max); dev=dev->next, ++i) {
    if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;
    strncpy(list[i].name, dev->name, sizeof(list[i].name)-1);
    if (dev->description)
      strncpy(list[i].desc, dev->description, sizeof(list[i].desc)-1);
    else
      strncpy(list[i].desc, "No description available", sizeof(list[i].desc)-1);
    }

  /* free device list */
  pcap_freealldevs(alldevs);
  }
#endif

/* Add any host specific devices and/or validate those already found */
i = eth_host_devices(i, max, list);

/* If no devices were found and an error message was left in the buffer, display it */
if ((i == 0) && (errbuf[0])) {
    sim_printf ("Eth: pcap_findalldevs warning: %s\r\n", errbuf);
    }

/* return device count */
return i;
}

void eth_show_dev (FILE *st, ETH_DEV* dev)
{
fprintf(st, "Ethernet Device:\n");
if (!dev) {
  fprintf(st, "-- Not Attached\n");
  return;
  }
fprintf(st, "  Name:                    %s\n", dev->name);
fprintf(st, "  Reflections:             %d\n", dev->reflections);
fprintf(st, "  Self Loopbacks Sent:     %d\n", dev->loopback_self_sent_total);
fprintf(st, "  Self Loopbacks Rcvd:     %d\n", dev->loopback_self_rcvd_total);
if (dev->have_host_nic_phy_addr) {
  char hw_mac[20];

  eth_mac_fmt(&dev->host_nic_phy_hw_addr, hw_mac);
  fprintf(st, "  Host NIC Address:        %s\n", hw_mac);
  }
if (dev->jumbo_dropped)
  fprintf(st, "  Jumbo Dropped:           %d\n", dev->jumbo_dropped);
if (dev->jumbo_fragmented)
  fprintf(st, "  Jumbo Fragmented:        %d\n", dev->jumbo_fragmented);
if (dev->jumbo_truncated)
  fprintf(st, "  Jumbo Truncated:         %d\n", dev->jumbo_truncated);
if (dev->packets_sent)
  fprintf(st, "  Packets Sent:            %d\n", dev->packets_sent);
if (dev->transmit_packet_errors)
  fprintf(st, "  Send Packet Errors:      %d\n", dev->transmit_packet_errors);
if (dev->packets_received)
  fprintf(st, "  Packets Received:        %d\n", dev->packets_received);
if (dev->receive_packet_errors)
  fprintf(st, "  Read Packet Errors:      %d\n", dev->receive_packet_errors);
if (dev->error_reopen_count)
  fprintf(st, "  Error ReOpen Count:      %d\n", dev->error_reopen_count);
if (dev->loopback_packets_processed)
  fprintf(st, "  Loopback Packets:        %d\n", dev->loopback_packets_processed);
#if defined(USE_READER_THREAD)
fprintf(st, "  Asynch Interrupts:       %s\n", dev->asynch_io?"Enabled":"Disabled");
if (dev->asynch_io)
  fprintf(st, "  Interrupt Latency:       %d uSec\n", dev->asynch_io_latency);
if (dev->throttle_count)
  fprintf(st, "  Throttle Delays:         %d\n", dev->throttle_count);
fprintf(st, "  Read Queue: Count:       %d\n", dev->read_queue.count);
fprintf(st, "  Read Queue: High:        %d\n", dev->read_queue.high);
fprintf(st, "  Read Queue: Loss:        %d\n", dev->read_queue.loss);
fprintf(st, "  Peak Write Queue Size:   %d\n", dev->write_queue_peak);
#endif
if (dev->bpf_filter)
  fprintf(st, "  BPF Filter: %s\n", dev->bpf_filter);
#if defined(HAVE_SLIRP_NETWORK)
if (dev->eth_api == ETH_API_NAT)
  sim_slirp_show ((SLIRP *)dev->handle, st);
#endif
}
#endif /* USE_NETWORK */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_ether.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
/* sim_ether.h: OS-dependent network information
  ------------------------------------------------------------------------------

   Copyright (c) 2002-2005, David T. Hittner

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the author shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from the author.

  ------------------------------------------------------------------------------

  Modification history:

  01-Mar-12  AGN  Cygwin doesn't have non-blocking pcap I/O pcap (it uses WinPcap)
  17-Nov-11  MP   Added dynamic loading of libpcap on *nix platforms
  30-Oct-11  MP   Added support for vde (Virtual Distributed Ethernet) networking
  18-Apr-11  MP   Fixed race condition with self loopback packets in 
                  multithreaded environments
  09-Dec-10  MP   Added support to determine if network address conflicts exist
  07-Dec-10  MP   Reworked DECnet self detection to the more general approach
                  of loopback self when any Physical Address is being set.
  04-Dec-10  MP   Changed eth_write to do nonblocking writes when 
                  USE_READER_THREAD is defined.
  07-Feb-08  MP   Added eth_show_dev to display ethernet state
  28-Jan-08  MP   Added eth_set_async
  23-Jan-08  MP   Added eth_packet_trace_ex and ethq_destroy
  30-Nov-05  DTH  Added CRC length to packet and more field comments
  04-Feb-04  DTH  Added debugging information
  14-Jan-04  MP   Generalized BSD support issues
  05-Jan-04  DTH  Added eth_mac_scan
  26-Dec-03  DTH  Added ethernet show and queue functions from pdp11_xq
  23-Dec-03  DTH  Added status to packet
  01-Dec-03  DTH  Added reflections, tweaked decnet fix items
  25-Nov-03  DTH  Verified DECNET_FIX, reversed ifdef to mainstream code
  14-Nov-03  DTH  Added #ifdef DECNET_FIX for problematic duplicate detection code
  07-Jun-03  MP   Added WIN32 support for DECNET duplicate address detection.
  05-Jun-03  DTH  Added used to struct eth_packet
  01-Feb-03  MP   Changed some uint8 strings to char* to reflect usage 
  22-Oct-02  DTH  Added all_multicast and promiscuous support
  21-Oct-02  DTH  Corrected copyright again
  16-Oct-02  DTH  Fixed copyright
  08-Oct-02  DTH  Integrated with 2.10-0p4, added variable vector and copyrights
  03-Oct-02  DTH  Beta version of xq/sim_ether released for SIMH 2.09-11
  15-Aug-02  DTH  Started XQ simulation

  ------------------------------------------------------------------------------
*/

#ifndef SIM_ETHER_H
#define SIM_ETHER_H

#include "sim_defs.h"
#include "sim_sock.h"

#ifdef  __cplusplus
extern "C" {
#endif

/* make common BSD code a bit easier to read in this file */
/* OS/X seems to define and compile using one of these BSD types */
#if defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__)
#define xBSD 1
#endif
#if !defined(__FreeBSD__) && !defined(_WIN32) && !defined(VMS) && !defined(__CYGWIN__) && !defined(__APPLE__)
#define USE_SETNONBLOCK 1
#endif

/* cygwin dowsn't have the right features to use the threaded network I/O */
#if defined(__CYGWIN__) || defined(__ZAURUS__) // psco added check for Zaurus platform
#define DONT_USE_READER_THREAD
#endif

#if ((((defined(__sun) || defined(__sun__)) && defined(__i386__)) || defined(__linux)) && !defined(DONT_USE_READER_THREAD))
#define USE_READER_THREAD 1
#endif

#if defined(DONT_USE_READER_THREAD)
#undef USE_READER_THREAD
#endif

/* make common winpcap code a bit easier to read in this file */
#if defined(_WIN32) || defined(VMS) || defined(__CYGWIN__)
#define PCAP_READ_TIMEOUT -1
#else
#define PCAP_READ_TIMEOUT  1
#endif

/* set related values to have correct relationships */
#if defined (USE_READER_THREAD)
#if defined (USE_SETNONBLOCK)
#undef USE_SETNONBLOCK
#endif /* USE_SETNONBLOCK */
#undef PCAP_READ_TIMEOUT
#define PCAP_READ_TIMEOUT 15
#if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS) && !defined(__CYGWIN__)) || defined (HAVE_TAP_NETWORK) || defined (HAVE_VDE_NETWORK)
#define MUST_DO_SELECT 1
#endif
#endif /* USE_READER_THREAD */

/* give priority to USE_NETWORK over USE_SHARED */
#if defined(USE_NETWORK) && defined(USE_SHARED)
#undef USE_SHARED
#endif
/* USE_SHARED only works on Windows or if HAVE_DLOPEN */
#if defined(USE_SHARED) && !defined(_WIN32) && !defined(HAVE_DLOPEN)
#undef USE_SHARED
#endif

/* USE_SHARED implies shared pcap, so force HAVE_PCAP_NETWORK */
#if defined(USE_SHARED) && !defined(HAVE_PCAP_NETWORK)
#define HAVE_PCAP_NETWORK 1
#endif

/*
  USE_BPF is defined to let this code leverage the libpcap/OS kernel provided 
  BPF packet filtering.  This generally will enhance performance.  It may not 
  be available in some environments and/or it may not work correctly, so 
  undefining this will still provide working code here.
*/
#if defined(HAVE_PCAP_NETWORK)
#define USE_BPF 1
#if defined (_WIN32) && !defined (BPF_CONST_STRING)
#define BPF_CONST_STRING 1
#endif
#else
#define DONT_USE_PCAP_FINDALLDEVS 1
#endif

#if defined (USE_READER_THREAD)
#include <pthread.h>
#endif

/* structure declarations */

#define ETH_PROMISC            1                        /* promiscuous mode = true */
#define ETH_TIMEOUT           -1                        /* read timeout in milliseconds (immediate) */
#define ETH_FILTER_MAX        20                        /* maximum address filters */
#define ETH_DEV_NAME_MAX     256                        /* maximum device name size */
#define ETH_DEV_DESC_MAX     256                        /* maximum device description size */
#define ETH_MIN_PACKET        60                        /* minimum ethernet packet size */
#define ETH_MAX_PACKET      1514                        /* maximum ethernet packet size */
#define ETH_MAX_JUMBO_FRAME 65536                       /* maximum ethernet jumbo frame size (or Offload Segment Size) */
#define ETH_MAX_DEVICE        20                        /* maximum ethernet devices */
#define ETH_CRC_SIZE           4                        /* ethernet CRC size */
#define ETH_FRAME_SIZE (ETH_MAX_PACKET+ETH_CRC_SIZE)    /* ethernet maximum frame size */
#define ETH_MIN_JUMBO_FRAME ETH_MAX_PACKET              /* Threshold size for Jumbo Frame Processing */

#define LOOPBACK_SELF_FRAME(phy_mac, msg)                                                     \
    (((msg)[12] == 0x90) && ((msg)[13] == 0x00) &&              /* Ethernet Loopback */       \
     ((msg)[16] == 0x02) && ((msg)[17] == 0x00) &&              /* Forward Function */        \
     ((msg)[24] == 0x01) && ((msg)[25] == 0x00) &&              /* Next Function - Reply */   \
     (memcmp(phy_mac, (msg),    6) == 0) &&                     /* Ethernet Destination */    \
     (memcmp(phy_mac, (msg)+6,  6) == 0) &&                     /* Ethernet Source */         \
     (memcmp(phy_mac, (msg)+18, 6) == 0))                       /* Forward Address */

#define LOOPBACK_PHYSICAL_RESPONSE(dev, msg)                                                    \
    ((dev->have_host_nic_phy_addr) &&                                                           \
     ((msg)[12] == 0x90) && ((msg)[13] == 0x00) &&              /* Ethernet Loopback */         \
     ((msg)[14] == 0x08) && ((msg)[15] == 0x00) &&              /* Skipcount - 8 */             \
     ((msg)[16] == 0x02) && ((msg)[17] == 0x00) &&              /* Last Function - Forward */   \
     ((msg)[24] == 0x01) && ((msg)[25] == 0x00) &&              /* Function - Reply */          \
     (memcmp(dev->host_nic_phy_hw_addr, (msg)+18, 6) == 0) &&   /* Forward Address - Host MAC */\
     (memcmp(dev->host_nic_phy_hw_addr, (msg),    6) == 0) &&   /* Ethernet Source - Host MAC */\
     (memcmp(dev->physical_addr,  (msg)+6,  6) == 0))           /* Ethernet Source */

#define LOOPBACK_PHYSICAL_REFLECTION(dev, msg)                                                  \
    ((dev->have_host_nic_phy_addr) &&                                                           \
     ((msg)[12] == 0x90) && ((msg)[13] == 0x00) &&              /* Ethernet Loopback */         \
     ((msg)[16] == 0x02) && ((msg)[17] == 0x00) &&              /* Forward Function */          \
     ((msg)[24] == 0x01) && ((msg)[25] == 0x00) &&              /* Next Function - Reply */     \
     (memcmp(dev->host_nic_phy_hw_addr, (msg)+6,  6) == 0) &&   /* Ethernet Source - Host MAC */\
     (memcmp(dev->host_nic_phy_hw_addr, (msg)+18, 6) == 0))     /* Forward Address - Host MAC */

#define LOOPBACK_REFLECTION_TEST_PACKET(dev, msg)                                                \
    ((dev->have_host_nic_phy_addr) &&                                                            \
     ((msg)[12] == 0x90) && ((msg)[13] == 0x00) &&             /* Ethernet Loopback */           \
     ((msg)[14] == 0x00) && ((msg)[15] == 0x00) &&             /* Skipcount - 0 */               \
     ((msg)[16] == 0x02) && ((msg)[17] == 0x00) &&             /* Forward Function */            \
     ((msg)[24] == 0x01) && ((msg)[25] == 0x00) &&             /* Next Function - Reply */       \
     ((msg)[00] == 0xFE) && ((msg)[01] == 0xFF) &&             /* Ethernet Destination - Reflection Test MAC */\
     ((msg)[02] == 0xFF) && ((msg)[03] == 0xFF) &&                                               \
     ((msg)[04] == 0xFF) && ((msg)[05] == 0xFE) &&                                               \
     (memcmp(dev->host_nic_phy_hw_addr, (msg)+6,  6) == 0))    /* Ethernet Source - Host MAC */

struct eth_packet {
  uint8   msg[ETH_FRAME_SIZE];                          /* ethernet frame (message) */
  uint8   *oversize;                                    /* oversized frame (message) */
  uint32  len;                                          /* packet length without CRC */
  uint32  used;                                         /* bytes processed (used in packet chaining) */
  int     status;                                       /* transmit/receive status */
  uint32  crc_len;                                      /* packet length with CRC */
};

struct eth_item {
  int                 type;                             /* receive (0=setup, 1=loopback, 2=normal) */
#define ETH_ITM_SETUP    0
#define ETH_ITM_LOOPBACK 1
#define ETH_ITM_NORMAL   2
  struct eth_packet   packet;
};

struct eth_queue {
  int                 max;
  int                 count;
  int                 head;
  int                 tail;
  int                 loss;
  int                 high;
  struct eth_item*    item;
};

struct eth_list {
  char    name[ETH_DEV_NAME_MAX];
  char    desc[ETH_DEV_DESC_MAX];
  int     eth_api;
};

typedef int ETH_BOOL;
typedef unsigned char ETH_MAC[6];
typedef unsigned char ETH_MULTIHASH[8];
typedef struct eth_packet  ETH_PACK;
typedef void (*ETH_PCALLBACK)(int status);
typedef struct eth_list ETH_LIST;
typedef struct eth_queue ETH_QUE;
typedef struct eth_item ETH_ITEM;
struct eth_write_request {
  struct eth_write_request *next;
  ETH_PACK packet;
  };
typedef struct eth_write_request ETH_WRITE_REQUEST;

struct eth_device {
  char*         name;                                   /* name of ethernet device */
  void*         handle;                                 /* handle of implementation-specific device */
  SOCKET        fd_handle;                              /* fd to kernel device (where needed) */
  char*         bpf_filter;                             /* bpf filter currently in effect */
  int           eth_api;                                /* Designator for which API is being used to move packets */
#define ETH_API_NONE 0                                  /* No API in use yet */
#define ETH_API_PCAP 1                                  /* Pcap API in use */
#define ETH_API_TAP  2                                  /* tun/tap API in use */
#define ETH_API_VDE  3                                  /* VDE API in use */
#define ETH_API_UDP  4                                  /* UDP API in use */
#define ETH_API_NAT  5                                  /* NAT (SLiRP) API in use */
  ETH_PCALLBACK read_callback;                          /* read callback function */
  ETH_PCALLBACK write_callback;                         /* write callback function */
  ETH_PACK*     read_packet;                            /* read packet */
  ETH_MAC       filter_address[ETH_FILTER_MAX];         /* filtering addresses */
  int           addr_count;                             /* count of filtering addresses */
  ETH_BOOL      promiscuous;                            /* promiscuous mode flag */
  ETH_BOOL      all_multicast;                          /* receive all multicast messages */
  ETH_BOOL      hash_filter;                            /* filter using AUTODIN II multicast hash */
  ETH_MULTIHASH hash;                                   /* AUTODIN II multicast hash */
  int32         loopback_self_sent;                     /* loopback packets sent but not seen */
  int32         loopback_self_sent_total;               /* total loopback packets sent */
  int32         loopback_self_rcvd_total;               /* total loopback packets seen */
  ETH_MAC       physical_addr;                          /* physical address of interface */
  int32         have_host_nic_phy_addr;                 /* flag indicating that the host_nic_phy_hw_addr is valid */
  ETH_MAC       host_nic_phy_hw_addr;                   /* MAC address of the attached NIC */
  uint32        jumbo_fragmented;                       /* Giant IPv4 Frames Fragmented */
  uint32        jumbo_dropped;                          /* Giant Frames Dropped */
  uint32        jumbo_truncated;                        /* Giant Frames too big for capture buffer - Dropped */
  uint32        packets_sent;                           /* Total Packets Sent */
  uint32        packets_received;                       /* Total Packets Received */
  uint32        loopback_packets_processed;             /* Total Loopback Packets Processed */
  uint32        transmit_packet_errors;                 /* Total Send Packet Errors */
  uint32        receive_packet_errors;                  /* Total Read Packet Errors */
  int32         error_waiting_threads;                  /* Count of threads currently waiting after an error */
  ETH_BOOL      error_needs_reset;                      /* Flag indicating to force reset */
#define ETH_ERROR_REOPEN_THRESHOLD 10                   /* Attempt ReOpen after 20 send/receive errors */
#define ETH_ERROR_REOPEN_PAUSE 4                        /* Seconds to pause between closing and reopening LAN */
  uint32        error_reopen_count;                     /* Count of ReOpen Attempts */
  DEVICE*       dptr;                                   /* device ethernet is attached to */
  uint32        dbit;                                   /* debugging bit */
  int           reflections;                            /* packet reflections on interface */
  int           need_crc;                               /* device needs CRC (Cyclic Redundancy Check) */
  /* Throttling control parameters: */
  uint32        throttle_time;                          /* ms burst time window */
#define ETH_THROT_DEFAULT_TIME 5                        /* 5ms Default burst time window */
  uint32        throttle_burst;                         /* packets passed with throttle_time which trigger throttling */
#define ETH_THROT_DEFAULT_BURST 4                       /* 4 Packet burst in time window */
  uint32        throttle_delay;                         /* ms to delay when throttling.  0 disables throttling */
#define ETH_THROT_DISABLED_DELAY 0                      /* 0 Delay disables throttling */
#define ETH_THROT_DEFAULT_DELAY 10                      /* 10ms Delay during burst */
  /* Throttling state variables: */
  uint32        throttle_mask;                          /* match test for threshold detection (1 << throttle_burst) - 1 */
  uint32        throttle_events;                        /* keeps track of packet arrival values */
  uint32        throttle_packet_time;                   /* time last packet was transmitted */
  uint32        throttle_count;                         /* Total Throttle Delays */
#if defined (USE_READER_THREAD)
  int           asynch_io;                              /* Asynchronous Interrupt scheduling enabled */
  int           asynch_io_latency;                      /* instructions to delay pending interrupt */
  ETH_QUE       read_queue;
  pthread_mutex_t     lock;
  pthread_t     reader_thread;                          /* Reader Thread Id */
  pthread_t     writer_thread;                          /* Writer Thread Id */
  pthread_mutex_t     writer_lock;
  pthread_mutex_t     self_lock;
  pthread_cond_t      writer_cond;
  ETH_WRITE_REQUEST *write_requests;
  int write_queue_peak;
  ETH_WRITE_REQUEST *write_buffers;
  t_stat write_status;
#endif
};

typedef struct eth_device  ETH_DEV;

/* prototype declarations*/

t_stat eth_open   (ETH_DEV* dev, const char* name,      /* open ethernet interface */
                   DEVICE* dptr, uint32 dbit);
t_stat eth_close  (ETH_DEV* dev);                       /* close ethernet interface */
t_stat eth_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
t_stat eth_write  (ETH_DEV* dev, ETH_PACK* packet,      /* write sychronous packet; */
                   ETH_PCALLBACK routine);              /*  callback when done */
int eth_read      (ETH_DEV* dev, ETH_PACK* packet,      /* read single packet; */
                   ETH_PCALLBACK routine);              /*  callback when done*/
t_stat eth_filter (ETH_DEV* dev, int addr_count,        /* set filter on incoming packets */
                   ETH_MAC* const addresses,
                   ETH_BOOL all_multicast,
                   ETH_BOOL promiscuous);
t_stat eth_filter_hash (ETH_DEV* dev, int addr_count,   /* set filter on incoming packets with AUTODIN II based hash */
                        ETH_MAC* const addresses,
                        ETH_BOOL all_multicast,
                        ETH_BOOL promiscuous,
                        ETH_MULTIHASH* const hash);
t_stat eth_check_address_conflict (ETH_DEV* dev, 
                                   ETH_MAC* const address);
int eth_devices   (int max, ETH_LIST* dev);             /* get ethernet devices on host */
void eth_setcrc   (ETH_DEV* dev, int need_crc);         /* enable/disable CRC mode */
t_stat eth_set_async (ETH_DEV* dev, int latency);       /* set read behavior to be async */
t_stat eth_clr_async (ETH_DEV* dev);                    /* set read behavior to be not async */
t_stat eth_set_throttle (ETH_DEV* dev, uint32 time, uint32 burst, uint32 delay); /* set transmit throttle parameters */
uint32 eth_crc32(uint32 crc, const void* vbuf, size_t len); /* Compute Ethernet Autodin II CRC for buffer */

void eth_packet_trace (ETH_DEV* dev, const uint8 *msg, int len, const char* txt); /* trace ethernet packet header+crc */
void eth_packet_trace_ex (ETH_DEV* dev, const uint8 *msg, int len, const char* txt, int detail, uint32 reason); /* trace ethernet packet */
t_stat eth_show (FILE* st, UNIT* uptr,                  /* show ethernet devices */
                 int32 val, CONST void* desc);
t_stat eth_show_devices (FILE* st, DEVICE *dptr,        /* show ethernet devices */
                         UNIT* uptr, int32 val, CONST char* desc);
void eth_show_dev (FILE*st, ETH_DEV* dev);              /* show ethernet device state */

void eth_mac_fmt (ETH_MAC* const add, char* buffer);    /* format ethernet mac address */
t_stat eth_mac_scan (ETH_MAC* mac, const char* strmac); /* scan string for mac, put in mac */
t_stat eth_mac_scan_ex (ETH_MAC* mac,                   /* scan string for mac, put in mac */
                        const char* strmac, UNIT *uptr);/* for specified unit */

t_stat ethq_init (ETH_QUE* que, int max);               /* initialize FIFO queue */
void ethq_clear  (ETH_QUE* que);                        /* clear FIFO queue */
void ethq_remove (ETH_QUE* que);                        /* remove item from FIFO queue */
void ethq_insert (ETH_QUE* que, int32 type,             /* insert item into FIFO queue */
                  ETH_PACK* packet, int32 status);
void ethq_insert_data(ETH_QUE* que, int32 type,         /* insert item into FIFO queue */
                  const uint8 *data, int used, size_t len, 
                  size_t crc_len, const uint8 *crc_data, int32 status);
t_stat ethq_destroy(ETH_QUE* que);                      /* release FIFO queue */

const char *eth_capabilities(void);

#ifdef  __cplusplus
}
#endif

#endif                                                  /* _SIM_ETHER_H */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_fio.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
/* sim_fio.c: simulator file I/O library

   Copyright (c) 1993-2008, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   03-Jun-11    MP      Simplified VMS 64b support and made more portable
   02-Feb-11    MP      Added sim_fsize_ex and sim_fsize_name_ex returning t_addr
                        Added export of sim_buf_copy_swapped and sim_buf_swap_data
   28-Jun-07    RMS     Added VMS IA64 support (from Norm Lastovica)
   10-Jul-06    RMS     Fixed linux conditionalization (from Chaskiel Grundman)
   15-May-06    RMS     Added sim_fsize_name
   21-Apr-06    RMS     Added FreeBSD large file support (from Mark Martinec)
   19-Nov-05    RMS     Added OS/X large file support (from Peter Schorn)
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   17-Jul-04    RMS     Fixed bug in optimized sim_fread (reported by Scott Bailey)
   26-May-04    RMS     Optimized sim_fread (suggested by John Dundas)
   02-Jan-04    RMS     Split out from SCP

   This library includes:

   sim_finit         -       initialize package
   sim_fopen         -       open file
   sim_fread         -       endian independent read (formerly fxread)
   sim_write         -       endian independent write (formerly fxwrite)
   sim_fseek         -       conditionally extended (>32b) seek (
   sim_fseeko        -       extended seek (>32b if available)
   sim_fsize         -       get file size
   sim_fsize_name    -       get file size of named file
   sim_fsize_ex      -       get file size as a t_offset
   sim_fsize_name_ex -       get file size as a t_offset of named file
   sim_buf_copy_swapped -    copy data swapping elements along the way
   sim_buf_swap_data -       swap data elements inplace in buffer
   sim_shmem_open            create or attach to a shared memory region
   sim_shmem_close           close a shared memory region


   sim_fopen and sim_fseek are OS-dependent.  The other routines are not.
   sim_fsize is always a 32b routine (it is used only with small capacity random
   access devices like fixed head disks and DECtapes).
*/

#include "sim_defs.h"

t_bool sim_end;                     /* TRUE = little endian, FALSE = big endian */
t_bool sim_taddr_64;                /* t_addr is > 32b and Large File Support available */
t_bool sim_toffset_64;              /* Large File (>2GB) file I/O Support available */

#if defined(fprintf)                /* Make sure to only use the C rtl stream I/O routines */
#undef fprintf
#undef fputs
#undef fputc
#endif

/* OS-independent, endian independent binary I/O package

   For consistency, all binary data read and written by the simulator
   is stored in little endian data order.  That is, in a multi-byte
   data item, the bytes are written out right to left, low order byte
   to high order byte.  On a big endian host, data is read and written
   from high byte to low byte.  Consequently, data written on a little
   endian system must be byte reversed to be usable on a big endian
   system, and vice versa.

   These routines are analogs of the standard C runtime routines
   fread and fwrite.  If the host is little endian, or the data items
   are size char, then the calls are passed directly to fread or
   fwrite.  Otherwise, these routines perform the necessary byte swaps.
   Sim_fread swaps in place, sim_fwrite uses an intermediate buffer.
*/

int32 sim_finit (void)
{
union {int32 i; char c[sizeof (int32)]; } end_test;

end_test.i = 1;                                         /* test endian-ness */
sim_end = (end_test.c[0] != 0);
sim_toffset_64 = (sizeof(t_offset) > sizeof(int32));    /* Large File (>2GB) support */
sim_taddr_64 = sim_toffset_64 && (sizeof(t_addr) > sizeof(int32));
return sim_end;
}

void sim_buf_swap_data (void *bptr, size_t size, size_t count)
{
uint32 j;
int32 k;
unsigned char by, *sptr, *dptr;

if (sim_end || (count == 0) || (size == sizeof (char)))
    return;
for (j = 0, dptr = sptr = (unsigned char *) bptr;       /* loop on items */
     j < count; j++) { 
    for (k = (int32)(size - 1); k >= (((int32) size + 1) / 2); k--) {
        by = *sptr;                                     /* swap end-for-end */
        *sptr++ = *(dptr + k);
        *(dptr + k) = by;
        }
    sptr = dptr = dptr + size;                          /* next item */
    }
}

size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr)
{
size_t c;

if ((size == 0) || (count == 0))                        /* check arguments */
    return 0;
c = fread (bptr, size, count, fptr);                    /* read buffer */
if (sim_end || (size == sizeof (char)) || (c == 0))     /* le, byte, or err? */
    return c;                                           /* done */
sim_buf_swap_data (bptr, size, count);
return c;
}

void sim_buf_copy_swapped (void *dbuf, const void *sbuf, size_t size, size_t count)
{
size_t j;
int32 k;
const unsigned char *sptr = (const unsigned char *)sbuf;
unsigned char *dptr = (unsigned char *)dbuf;

if (sim_end || (size == sizeof (char))) {
    memcpy (dptr, sptr, size * count);
    return;
    }
for (j = 0; j < count; j++) {                           /* loop on items */
    for (k = (int32)(size - 1); k >= 0; k--)
        *(dptr + k) = *sptr++;
    dptr = dptr + size;
    }
}

size_t sim_fwrite (const void *bptr, size_t size, size_t count, FILE *fptr)
{
size_t c, nelem, nbuf, lcnt, total;
int32 i;
const unsigned char *sptr;
unsigned char *sim_flip;

if ((size == 0) || (count == 0))                        /* check arguments */
    return 0;
if (sim_end || (size == sizeof (char)))                 /* le or byte? */
    return fwrite (bptr, size, count, fptr);            /* done */
sim_flip = (unsigned char *)malloc(FLIP_SIZE);
if (!sim_flip)
    return 0;
nelem = FLIP_SIZE / size;                               /* elements in buffer */
nbuf = count / nelem;                                   /* number buffers */
lcnt = count % nelem;                                   /* count in last buf */
if (lcnt) nbuf = nbuf + 1;
else lcnt = nelem;
total = 0;
sptr = (const unsigned char *) bptr;                    /* init input ptr */
for (i = (int32)nbuf; i > 0; i--) {                     /* loop on buffers */
    c = (i == 1)? lcnt: nelem;
    sim_buf_copy_swapped (sim_flip, sptr, size, c);
    sptr = sptr + size * count;
    c = fwrite (sim_flip, size, c, fptr);
    if (c == 0) {
        free(sim_flip);
        return total;
        }
    total = total + c;
    }
free(sim_flip);
return total;
}

/* Forward Declaration */

t_offset sim_ftell (FILE *st);

/* Get file size */

t_offset sim_fsize_ex (FILE *fp)
{
t_offset pos, sz;

if (fp == NULL)
    return 0;
pos = sim_ftell (fp);
sim_fseek (fp, 0, SEEK_END);
sz = sim_ftell (fp);
sim_fseeko (fp, pos, SEEK_SET);
return sz;
}

t_offset sim_fsize_name_ex (const char *fname)
{
FILE *fp;
t_offset sz;

if ((fp = sim_fopen (fname, "rb")) == NULL)
    return 0;
sz = sim_fsize_ex (fp);
fclose (fp);
return sz;
}

uint32 sim_fsize_name (const char *fname)
{
return (uint32)(sim_fsize_name_ex (fname));
}

uint32 sim_fsize (FILE *fp)
{
return (uint32)(sim_fsize_ex (fp));
}

/* OS-dependent routines */

/* Optimized file open */

FILE *sim_fopen (const char *file, const char *mode)
{
#if defined (VMS)
return fopen (file, mode, "ALQ=32", "DEQ=4096",
        "MBF=6", "MBC=127", "FOP=cbt,tef", "ROP=rah,wbh", "CTX=stm");
#elif (defined (__linux) || defined (__linux__) || defined (__hpux) || defined (_AIX)) && !defined (DONT_DO_LARGEFILE)
return fopen64 (file, mode);
#else
return fopen (file, mode);
#endif
}

#if !defined (DONT_DO_LARGEFILE)
/* 64b VMS */

#if ((defined (__ALPHA) || defined (__ia64)) && defined (VMS) && (__DECC_VER >= 60590001)) || \
    ((defined(__sun) || defined(__sun__)) && defined(_LARGEFILE_SOURCE))
#define S_SIM_IO_FSEEK_EXT_ 1
int sim_fseeko (FILE *st, t_offset offset, int whence)
{
return fseeko (st, (off_t)offset, whence);
}

t_offset sim_ftell (FILE *st)
{
return (t_offset)(ftello (st));
}

#endif

/* Alpha UNIX - natively 64b */

#if defined (__ALPHA) && defined (__unix__)             /* Alpha UNIX */
#define S_SIM_IO_FSEEK_EXT_ 1
int sim_fseeko (FILE *st, t_offset offset, int whence)
{
return fseek (st, offset, whence);
}

t_offset sim_ftell (FILE *st)
{
return (t_offset)(ftell (st));
}

#endif

/* Windows */

#if defined (_WIN32)
#define S_SIM_IO_FSEEK_EXT_ 1
#include <sys/stat.h>

int sim_fseeko (FILE *st, t_offset offset, int whence)
{
fpos_t fileaddr;
struct _stati64 statb;

switch (whence) {

    case SEEK_SET:
        fileaddr = (fpos_t)offset;
        break;

    case SEEK_END:
        if (_fstati64 (_fileno (st), &statb))
            return (-1);
        fileaddr = statb.st_size + offset;
        break;
    case SEEK_CUR:
        if (fgetpos (st, &fileaddr))
            return (-1);
        fileaddr = fileaddr + offset;
        break;

    default:
        errno = EINVAL;
        return (-1);
        }

return fsetpos (st, &fileaddr);
}

t_offset sim_ftell (FILE *st)
{
fpos_t fileaddr;
if (fgetpos (st, &fileaddr))
    return (-1);
return (t_offset)fileaddr;
}

#endif                                                  /* end Windows */

/* Linux */

#if defined (__linux) || defined (__linux__) || defined (__hpux) || defined (_AIX)
#define S_SIM_IO_FSEEK_EXT_ 1
int sim_fseeko (FILE *st, t_offset xpos, int origin)
{
return fseeko64 (st, (off64_t)xpos, origin);
}

t_offset sim_ftell (FILE *st)
{
return (t_offset)(ftello64 (st));
}

#endif                                                  /* end Linux with LFS */

/* Apple OS/X */

#if defined (__APPLE__) || defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) || defined (__CYGWIN__) 
#define S_SIM_IO_FSEEK_EXT_ 1
int sim_fseeko (FILE *st, t_offset xpos, int origin) 
{
return fseeko (st, (off_t)xpos, origin);
}

t_offset sim_ftell (FILE *st)
{
return (t_offset)(ftello (st));
}

#endif  /* end Apple OS/X */
#endif /* !DONT_DO_LARGEFILE */

/* Default: no OS-specific routine has been defined */

#if !defined (S_SIM_IO_FSEEK_EXT_)
int sim_fseeko (FILE *st, t_offset xpos, int origin)
{
return fseek (st, (long) xpos, origin);
}

t_offset sim_ftell (FILE *st)
{
return (t_offset)(ftell (st));
}
#endif

int sim_fseek (FILE *st, t_addr offset, int whence)
{
return sim_fseeko (st, (t_offset)offset, whence);
}

#if defined(_WIN32)
#include <io.h>
int sim_set_fsize (FILE *fptr, t_addr size)
{
return _chsize(_fileno(fptr), (long)size);
}

int sim_set_fifo_nonblock (FILE *fptr)
{
return -1;
}

struct SHMEM {
    HANDLE hMapping;
    size_t shm_size;
    void *shm_base;
    };

t_stat sim_shmem_open (const char *name, size_t size, SHMEM **shmem, void **addr)
{
*shmem = (SHMEM *)calloc (1, sizeof(**shmem));

if (*shmem == NULL)
    return SCPE_MEM;

(*shmem)->hMapping = INVALID_HANDLE_VALUE;
(*shmem)->shm_size = size;
(*shmem)->shm_base = NULL;
(*shmem)->hMapping = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)size, name);
if ((*shmem)->hMapping == INVALID_HANDLE_VALUE) {
    sim_shmem_close (*shmem);
    *shmem = NULL;
    return SCPE_OPENERR;
    }
(*shmem)->shm_base = MapViewOfFile ((*shmem)->hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if ((*shmem)->shm_base == NULL) {
    sim_shmem_close (*shmem);
    *shmem = NULL;
    return SCPE_OPENERR;
    }

*addr = (*shmem)->shm_base;
return SCPE_OK;
}

void sim_shmem_close (SHMEM *shmem)
{
if (shmem == NULL)
    return;
if (shmem->shm_base != NULL)
    UnmapViewOfFile (shmem->shm_base);
if (shmem->hMapping != INVALID_HANDLE_VALUE)
    CloseHandle (shmem->hMapping);
free (shmem);
}

#else /* !defined(_WIN32) */
#include <unistd.h>
int sim_set_fsize (FILE *fptr, t_addr size)
{
return ftruncate(fileno(fptr), (off_t)size);
}

#include <sys/stat.h>
#include <fcntl.h>

int sim_set_fifo_nonblock (FILE *fptr)
{
struct stat stbuf;

if (!fptr || fstat (fileno(fptr), &stbuf))
    return -1;
#if defined(S_IFIFO) && defined(O_NONBLOCK)
if ((stbuf.st_mode & S_IFIFO)) {
    int flags = fcntl(fileno(fptr), F_GETFL, 0);
    return fcntl(fileno(fptr), F_SETFL, flags | O_NONBLOCK);
    }
#endif
return -1;
}

#include <sys/mman.h>

struct SHMEM {
    int shm_fd;
    size_t shm_size;
    void *shm_base;
    };

t_stat sim_shmem_open (const char *name, size_t size, SHMEM **shmem, void **addr)
{
#ifdef HAVE_SHM_OPEN
*shmem = (SHMEM *)calloc (1, sizeof(**shmem));

*addr = NULL;
if (*shmem == NULL)
    return SCPE_MEM;

(*shmem)->shm_base = MAP_FAILED;
(*shmem)->shm_size = size;
(*shmem)->shm_fd = shm_open (name, O_RDWR, 0);
if ((*shmem)->shm_fd == -1) {
    (*shmem)->shm_fd = shm_open (name, O_CREAT | O_RDWR, 0660);
    if ((*shmem)->shm_fd == -1) {
        sim_shmem_close (*shmem);
        *shmem = NULL;
        return SCPE_OPENERR;
        }
    if (ftruncate((*shmem)->shm_fd, size)) {
        sim_shmem_close (*shmem);
        *shmem = NULL;
        return SCPE_OPENERR;
        }
    }
else {
    struct stat statb;

    if ((fstat ((*shmem)->shm_fd, &statb)) ||
        (statb.st_size != (*shmem)->shm_size)) {
        sim_shmem_close (*shmem);
        *shmem = NULL;
        return SCPE_OPENERR;
        }
    }
(*shmem)->shm_base = mmap(NULL, (*shmem)->shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, (*shmem)->shm_fd, 0);
if ((*shmem)->shm_base == MAP_FAILED) {
    sim_shmem_close (*shmem);
    *shmem = NULL;
    return SCPE_OPENERR;
    }
*addr = (*shmem)->shm_base;
return SCPE_OK;
#else
return SCPE_NOFNC;
#endif
}

void sim_shmem_close (SHMEM *shmem)
{
if (shmem == NULL)
    return;
if (shmem->shm_base != MAP_FAILED)
    munmap (shmem->shm_base, shmem->shm_size);
if (shmem->shm_fd != -1)
    close (shmem->shm_fd);
free (shmem);
}

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_fio.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/* sim_fio.h: simulator file I/O library headers

   Copyright (c) 1993-2008, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   be used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   02-Feb-11    MP      Added sim_fsize_ex and sim_fsize_name_ex returning t_addr
                        Added export of sim_buf_copy_swapped and sim_buf_swap_data
   15-May-06    RMS     Added sim_fsize_name
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   02-Jan-04    RMS     Split out from SCP
*/

#ifndef SIM_FIO_H_
#define SIM_FIO_H_     0

#ifdef  __cplusplus
extern "C" {
#endif

#define FLIP_SIZE       (1 << 16)                       /* flip buf size */
#define fxread(a,b,c,d)         sim_fread (a, b, c, d)
#define fxwrite(a,b,c,d)        sim_fwrite (a, b, c, d)

int32 sim_finit (void);
#if (defined (__linux) || defined (__linux__) || defined (__hpux) || defined (_AIX) ||         \
     (defined (VMS) && (defined (__ALPHA) || defined (__ia64)) && (__DECC_VER >= 60590001)) || \
     ((defined(__sun) || defined(__sun__)) && defined(_LARGEFILE_SOURCE)) ||                   \
     defined (_WIN32) || defined (__APPLE__) || defined (__CYGWIN__) ||                        \
     defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__)) && !defined (DONT_DO_LARGEFILE)
typedef t_int64        t_offset;
#else
typedef int32        t_offset;
#if !defined (DONT_DO_LARGEFILE)
#define DONT_DO_LARGEFILE 1
#endif
#endif
FILE *sim_fopen (const char *file, const char *mode);
int sim_fseek (FILE *st, t_addr offset, int whence);
int sim_fseeko (FILE *st, t_offset offset, int whence);
int sim_set_fsize (FILE *fptr, t_addr size);
int sim_set_fifo_nonblock (FILE *fptr);
size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr);
size_t sim_fwrite (const void *bptr, size_t size, size_t count, FILE *fptr);
uint32 sim_fsize (FILE *fptr);
uint32 sim_fsize_name (const char *fname);
t_offset sim_ftell (FILE *st);
t_offset sim_fsize_ex (FILE *fptr);
t_offset sim_fsize_name_ex (const char *fname);
void sim_buf_swap_data (void *bptr, size_t size, size_t count);
void sim_buf_copy_swapped (void *dptr, const void *bptr, size_t size, size_t count);
typedef struct SHMEM SHMEM;
t_stat sim_shmem_open (const char *name, size_t size, SHMEM **shmem, void **addr);
void sim_shmem_close (SHMEM *shmem);

extern t_bool sim_taddr_64;         /* t_addr is > 32b and Large File Support available */
extern t_bool sim_toffset_64;       /* Large File (>2GB) file I/O support */
extern t_bool sim_end;              /* TRUE = little endian, FALSE = big endian */

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































Deleted src/sim_frontpanel.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
/* sim_frontpanel.h: simulator frontpanel API definitions

   Copyright (c) 2015, Mark Pizzolato

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   MARK PIZZOLATO BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Mark Pizzolato shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Mark Pizzolato.

   15-Jan-15    MP      Initial implementation
   01-Apr-15    MP      Added register indirect, mem_examine and mem_deposit
   03-Apr-15    MP      Added logic to pass simulator startup messages in
                        panel error text if the connection to the simulator
                        shuts down while it is starting.
   04-Apr-15    MP      Added mount and dismount routines to connect and 
                        disconnect removable media

   This module defines interface between a front panel application and a simh
   simulator.  Facilities provide ways to gather information from and to 
   observe and control the state of a simulator.

   Any application which wants to use this API needs to:
      1) include this file in the application code
      2) compile sim_frontpanel.c and sim_sock.c from the top level directory 
         of the simh source.
      3) link the sim_frontpanel and sim_sock object modules and libpthreads 
         into the application.
      4) Use a simh simulator built from the same version of simh that the
         sim_frontpanel and sim_sock modules came from.
*/

#ifndef SIM_FRONTPANEL_H_
#define SIM_FRONTPANEL_H_     0

#ifdef  __cplusplus
extern "C" {
#endif

#include <stdlib.h>

#if !defined(__VAX)         /* Unsupported platform */

#define SIM_FRONTPANEL_VERSION   4

/**

    sim_panel_start_simulator       A starts a simulator with a particular 
                                    configuration

        sim_path            the path to the simulator binary
        sim_config          the configuration to run the simulator with
        device_panel_count  the number of sub panels for connected devices

    Note 1: - The path specified must be either a fully specified path or 
              it could be merey the simulator name if the simulator binary
              is located in the current PATH.
            - The simulator binary must be built from the same version 
              simh source code that the frontpanel API was acquired fron 
              (the API and the simh framework must speak the same language) 

    Note 2: - Configuration file specified should contain device setup 
              statements (enable, disable, CPU types and attach commands).
              It should not start a simulator running.
 */

typedef struct PANEL PANEL;

PANEL *
sim_panel_start_simulator (const char *sim_path,
                           const char *sim_config,
                           size_t device_panel_count);

PANEL *
sim_panel_start_simulator_debug (const char *sim_path,
                                 const char *sim_config,
                                 size_t device_panel_count,
                                 const char *debug_file);

/**

    sim_panel_add_device_panel - creates a sub panel associated 
                                 with a specific simulator panel

        simulator_panel     the simulator panel to connect to
        device_name         the simulator's name for the device
 */

PANEL *
sim_panel_add_device_panel (PANEL *simulator_panel,
                            const char *device_name);

/**

    sim_panel_destroy   to shutdown a panel or sub panel.

    Note: destroying a simulator panel will also destroy any 
          related sub panels
 */

int
sim_panel_destroy (PANEL *panel);

/**

   The frontpanel API exposes the state of a simulator via access to 
   simh register variables that the simulator and its devices define.
   These registers certainly include any architecturally described 
   registers (PC, PSL, SP, etc.), but also include anything else
   the simulator uses as internal state to implement the running 
   simulator.

   The registers that a particular frontpanel application mught need 
   access to are specified by the application when it calls: 
   
   sim_panel_add_register
   sim_panel_add_register_bits 
   sim_panel_add_register_array
and
   sim_panel_add_register_indirect
   sim_panel_add_register_indirect_bits

        name         the name the simulator knows this register by
        device_name  the device this register is part of.  Defaults to
                     the device of the panel (in a device panel) or the
                     default device in the simulator (usually the CPU).
        element_count number of elements in the register array
        size         the size (in local storage) of the buffer which will
                     receive the data in the simulator's register
        addr         a pointer to the location of the buffer which will 
                     be loaded with the data in the simulator's register
        bit_width    the number of values to populate in the bits array
        bits         an array of integers which is bit_width long that 
                     will receive each bit's current accumulated value.
                     The accumulated value will range from 0 thru the 
                     the sample_depth specified when calling 
                     sim_panel_set_sampling_parameters().
 */

int
sim_panel_add_register (PANEL *panel,
                        const char *name,
                        const char *device_name,
                        size_t size,
                        void *addr);

int
sim_panel_add_register_bits (PANEL *panel,
                             const char *name,
                             const char *device_name,
                             size_t bit_width,
                             int *bits);

int
sim_panel_add_register_array (PANEL *panel,
                              const char *name,
                              const char *device_name,
                              size_t element_count,
                              size_t size,
                              void *addr);

int
sim_panel_add_register_indirect (PANEL *panel,
                                 const char *name,
                                 const char *device_name,
                                 size_t size,
                                 void *addr);

int
sim_panel_add_register_indirect_bits (PANEL *panel,
                                      const char *name,
                                      const char *device_name,
                                      size_t bit_width,
                                      int *bits);

/**

    A panel application has a choice of two different methods of getting 
    the values contained in the set of registers it has declared interest in via
    the sim_panel_add_register APIs.
    
       1)  The values can be polled (when ever it is desired) by calling
           sim_panel_get_registers().
       2)  The panel can call sim_panel_set_display_callback_interval() to 
           specify a callback routine and a periodic rate that the callback 
           routine should be called.  The panel API will make a best effort 
           to deliver the current register state at the desired rate.


   Note 1: The buffers described in a panel's register set will be 
           dynamically revised as soon as data is available from the 
           simulator.  The callback routine merely serves as a notification 
           that a complete register set has arrived.
   Note 2: The callback routine should, in general, not run for a long time
           or frontpanel interactions with the simulator may be disrupted.  
           Setting a flag, signaling an event or posting a message are 
           reasonable activities to perform in a callback routine.
 */

int
sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time);

typedef void (*PANEL_DISPLAY_PCALLBACK)(PANEL *panel, 
                                        unsigned long long simulation_time,
                                        void *context);

int
sim_panel_set_display_callback_interval (PANEL *panel, 
                                         PANEL_DISPLAY_PCALLBACK callback, 
                                         void *context, 
                                         int usecs_between_callbacks);

/**

    When a front panel application wants to get averaged bit sample
    values, it must first declare the sampling parameters that will
    be used while collecting the bit values.

   sim_panel_set_sampling_parameters 

        sample_frequency    cycles/instructions between sample captures
        sample_depth        how many samples to accumulate in the rolling
                            average for each bit sample.  Returned bit
                            sample values will range from 0 thru this 
                            value.
 */

int
sim_panel_set_sampling_parameters (PANEL *panel,
                                   unsigned int sample_frequency,
                                   unsigned int sample_depth);

/**

    When a front panel application needs to change the running
    state of a simulator one of the following routines should 
    be called:  
    
    sim_panel_exec_halt     - Stop instruction execution
    sim_panel_exec_boot     - Boot a simulator from a specific device
    sim_panel_exec_run      - Start/Resume a simulator running instructions
    sim_panel_exec_step     - Have a simulator execute a single step
 */

int
sim_panel_exec_halt (PANEL *panel);

int
sim_panel_exec_boot (PANEL *panel, const char *device);

int
sim_panel_exec_run (PANEL *panel);

int
sim_panel_exec_step (PANEL *panel);

/**

    When a front panel application wants to describe conditions that 
    should stop instruction execution an execution or an output
    breakpoint should be used.  To established or clear a breakpoint, 
    one of the following routines should be called:  
    
    sim_panel_break_set          - Establish a simulation breakpoint
    sim_panel_break_clear        - Cancel/Delete a previously defined
                                   breakpoint
    sim_panel_break_output_set   - Establish a simulator output 
                                   breakpoint
    sim_panel_break_output_clear - Cancel/Delete a previously defined
                                   output breakpoint
    
    Note: Any breakpoint switches/flags must be located at the 
          beginning of the condition string
 */

int
sim_panel_break_set (PANEL *panel, const char *condition);

int
sim_panel_break_clear (PANEL *panel, const char *condition);

int
sim_panel_break_output_set (PANEL *panel, const char *condition);

int
sim_panel_break_output_clear (PANEL *panel, const char *condition);


/**

    When a front panel application needs to change or access
    memory or a register one of the following routines should 
    be called:  
    
    sim_panel_gen_examine        - Examine register or memory
    sim_panel_gen_deposit        - Deposit to register or memory
    sim_panel_mem_examine        - Examine memory location
    sim_panel_mem_deposit        - Deposit to memory location
    sim_panel_set_register_value - Deposit to a register or memory 
                                   location
 */


/**

   sim_panel_gen_examine

        name_or_addr the name the simulator knows this register by
        size         the size (in local storage) of the buffer which will
                     receive the data returned when examining the simulator
        value        a pointer to the buffer which will be loaded with the
                     data returned when examining the simulator
 */

int
sim_panel_gen_examine (PANEL *panel, 
                       const char *name_or_addr,
                       size_t size,
                       void *value);
/**

   sim_panel_gen_deposit

        name_or_addr the name the simulator knows this register by
        size         the size (in local storage) of the buffer which
                     contains the data to be deposited into the simulator
        value        a pointer to the buffer which contains the data to 
                     be deposited into the simulator
 */

int
sim_panel_gen_deposit (PANEL *panel, 
                       const char *name_or_addr,
                       size_t size,
                       const void *value);

/**

   sim_panel_mem_examine

        addr_size    the size (in local storage) of the buffer which 
                     contains the memory address of the data to be examined
                     in the simulator
        addr         a pointer to the buffer containing the memory address
                     of the data to be examined in the simulator
        value_size   the size (in local storage) of the buffer which will
                     receive the data returned when examining the simulator
        value        a pointer to the buffer which will be loaded with the
                     data returned when examining the simulator
 */

int
sim_panel_mem_examine (PANEL *panel, 
                       size_t addr_size,
                       const void *addr,
                       size_t value_size,
                       void *value);

/**

   sim_panel_mem_deposit

        addr_size    the size (in local storage) of the buffer which 
                     contains the memory address of the data to be deposited
                     into the simulator
        addr         a pointer to the buffer containing the memory address
                     of the data to be deposited into the simulator
        value_size   the size (in local storage) of the buffer which will
                     contains the data to be deposited into the simulator
        value        a pointer to the buffer which contains the data to be
                     deposited into the simulator
 */

int
sim_panel_mem_deposit (PANEL *panel, 
                       size_t addr_size,
                       const void *addr,
                       size_t value_size,
                       const void *value);

/**

   sim_panel_set_register_value

        name        the name of a simulator register or a memory address
                    which is to receive a new value
        value       the new value in character string form.  The string 
                    must be in the native/natural radix that the simulator 
                    uses when referencing that register
 */
int
sim_panel_set_register_value (PANEL *panel,
                              const char *name,
                              const char *value);

/**

    When a front panel application needs to change the media
    in a simulated removable media device one of the following 
    routines should be called:

    sim_panel_mount    - mounts the indicated media file on a device
    sim_panel_dismount - dismounts the currently mounted media file 
                         from a device
 */

/**

   sim_panel_mount

        device      the name of a simulator device/unit
        switches    any switches appropriate for the desire attach
        path        the path on the local system to be attached
 */

int
sim_panel_mount (PANEL *panel,
                 const char *device,
                 const char *switches,
                 const char *path);

/**

   sim_panel_dismount

        device      the name of a simulator device/unit
 */

int
sim_panel_dismount (PANEL *panel,
                    const char *device);


typedef enum {
    Halt,       /* Simulation is halted (instructions not being executed) */
    Run,        /* Simulation is executing instructions */
    Error       /* Panel simulator is in an error state and should be */
                /* closed (destroyed).  sim_panel_get_error might help */
                /* explain why */
    } OperationalState;

OperationalState
sim_panel_get_state (PANEL *panel);

/**

    All APIs routines which return an int return 0 for 
    success and -1 for an error.  

    An API which returns an error (-1), will not change the panel state.
    
    sim_panel_get_error     - the details of the most recent error
    sim_panel_clear_error   - clears the error buffer
 */

const char *sim_panel_get_error (void);
void sim_panel_clear_error (void);

/**

    The panek<->simulator wire protocol can be traced if protocol problems arise.
    
    sim_panel_set_debug_file    - Specifies the log file to record debug traffic
    sim_panel_set_debug_mode    - Specifies the debug detail to be recorded
    sim_panel_flush_debug       - Flushes debug output to disk

 */
void
sim_panel_set_debug_file (PANEL *panel, const char *debug_file);

#define DBG_XMT         1   /* Transmit Data */
#define DBG_RCV         2   /* Receive Data */
#define DBG_REQ         4   /* Request Data */
#define DBG_RSP         8   /* Response Data */

void
sim_panel_set_debug_mode (PANEL *panel, int debug_bits);

void
sim_panel_flush_debug (PANEL *panel);

#endif /* !defined(__VAX) */

#ifdef  __cplusplus
}
#endif

#endif /* SIM_FRONTPANEL_H_ */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_rev.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
/* sim_rev.h: simulator revisions and current rev level

   Copyright (c) 1993-2012, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.
*/

#ifndef SIM_REV_H_
#define SIM_REV_H_     0

#ifndef SIM_MAJOR
#define SIM_MAJOR       4
#endif
#ifndef SIM_MINOR
#define SIM_MINOR       0
#endif
#ifndef SIM_PATCH
#define SIM_PATCH       0
#endif
#ifndef SIM_DELTA
#define SIM_DELTA       0
#endif

#ifndef SIM_VERSION_MODE
#define SIM_VERSION_MODE "Beta"
#endif

#if defined(SIM_NEED_GIT_COMMIT_ID)
#include ".git-commit-id.h"
#endif

#if !defined(SIM_GIT_COMMIT_ID)
#define SIM_GIT_COMMIT_ID $Format:%H$
#endif

/*
  The comment section below reflects the manual editing process which was in place
  prior to the use of the git source control system on at https://gihub.com/simh/simh

  Details about all future fixes will be visible in the source control system's 
  history.

*/

/*
   V3.9 revision history

patch   date            module(s) and fix(es)

  0     01-May-2012     scp.c:
                        - added *nix READLINE support (Mark Pizzolato)
                        - fixed handling of DO with no arguments (Dave Bryan)
                        - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan)
                        - clarified some help messages (Mark Pizzolato)
                        - added "SHOW SHOW" and "SHOW <dev> SHOW" commands (Mark Pizzolato)
                        - fixed bug in deposit stride for numeric input (John Dundas)

                        sim_console.c
                        - added support for BREAK key on Windows (Mark Pizzolato)

                        sim_ether.c
                        - major revision (Dave Hittner and Mark Pizzolato)
                        - fixed array overrun which caused SEGFAULT on hosts with many
                          devices which libpcap can access.
                        - fixed duplicate MAC address detection to work reliably on switch
                          connected LANs

                        sim_tmxr.c:
                        - made telnet option negotiation more reliable, VAX simulator now 
                          works with PuTTY as console (Mark Pizzolato)

                        h316_cpu.c:
                        - fixed bugs in MPY, DIV introduced in 3.8-1 (from Theo Engel)
                        - fixed bugs in double precision, normalization, SC (from Adrian Wise)
                        - fixed XR behavior (from Adrian Wise)

                        hp2100 all peripherals (Dave Bryan):
                        - Changed I/O signal handlers for newly revised signal model
                        - Deprecated DEVNO modifier in favor of SC

                        hp2100_cpu.c (Dave Bryan):
                        - Minor speedup in "is_mapped"
                        - Added casts to cpu_mod, dmasio, dmapio, cpu_reset, dma_reset
                        - Fixed I/O return status bug for DMA cycles
                        - Failed I/O cycles now stop on failing instruction
                        - Revised DMA for new multi-card paradigm
                        - Consolidated DMA reset routines
                        - DMA channels renamed from 0,1 to 1,2 to match documentation
                        - Changed I/O instructions, handlers, and DMA for revised signal model
                        - Changed I/O dispatch table to use DIB pointers
                        - Removed DMA latency counter
                        - Fixed DMA requests to enable stealing every cycle
                        - Fixed DMA priority for channel 1 over channel 2
                        - Corrected comments for "cpu_set_idle"

                        hp2100_cpu.h:
                        - Changed declarations for VMS compiler

                        hp2100_cpu0.c (Dave Bryan):
                        - Removed DS note regarding PIF card (is now implemented)

                        hp2100_cpu4.c (Dave Bryan):
                        - Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR

                        hp2100_cpu5.c (Dave Bryan):
                        - Added sign extension for dim count in "cpu_ema_resolve"
                        - Eliminated unused variable in "cpu_ema_vset"

                        hp2100_cpu6.c (Dave Bryan):
                        - DMA channels renamed from 0,1 to 1,2 to match documentation

                        hp2100_cpu7.c (Dave Bryan):
                        - Corrected "opsize" parameter type in vis_abs

                        hp2100_defs.h (Dave Bryan):
                        - Added hp_setsc, hp_showsc functions to support SC modifier
                        - DMA channels renamed from 0,1 to 1,2 to match documentation
                        - Revised I/O signal enum values for concurrent signals
                        - Revised I/O macros for new signal handling
                        - Added DA and DC device select code assignments

                        hp2100_di.c, hp2100_di.h (Dave Bryan):
                        - Implemented 12821A HP-IB Disc Interface

                        hp2100_di_da.c (Dave Bryan):
                        - Implemented 7906H/20H/25H ICD disc drives

                        hp2100_dp.c (Dave Bryan):
                        - Added CNTLR_TYPE cast to dp_settype
 
                        hp2100_ds.c (Dave Bryan):
                        - Rewritten to use the MAC/ICD disc controller library
                        - ioIOO now notifies controller service of parameter output
                        - Corrected SRQ generation and FIFO under/overrun detection
                        - Corrected Clear command to conform to the hardware
                        - Fixed Request Status to return Unit Unavailable if illegal
                        - Seek and Cold Load Read now Seek Check if seek in progress
                        - Remodeled command wait for seek completion
                        - Corrected status returns for disabled drive, auto-seek
                          beyond drive limits, Request Sector Address and Wakeup
                          with invalid or offline unit
                        - Address verification reenabled if auto-seek during
                          Read Without Verify

                        hp2100_fp1.c (Dave Bryan):
                        - Added missing precision on constant "one" in fp_trun
                        - Completed the comments for divide; no code changes

                        hp2100_ipl.c (Dave Bryan):
                        - Added CARD_INDEX casts to dib.card_index
                        - A failed STC may now be retried
                        - Consolidated reporting of consecutive CRS signals
                        - Revised for new multi-card paradigm

                        hp2100_lps.c (Dave Bryan):
                        - Revised detection of CLC at last DMA cycle
                        - Corrected 12566B (DIAG mode) jumper settings

                        hp2100_ms.c (Dave Bryan):
                        - Added CNTLR_TYPE cast to ms_settype
 
                        hp2100_mt.c (Dave Bryan):
                        - Removed redundant MTAB_VUN from "format" MTAB entry
                        - Fixed command scanning error in mtcio ioIOO handler

                        hp2100_stddev.c (Dave Bryan):
                        - Add TBG as a logical name for the CLK device
 
                        hp2100_sys.c (Dave Bryan):
                        - Deprecated DEVNO in favor of SC
                        - Added hp_setsc, hp_showsc functions to support SC modifier
                        - Added DA and dummy DC devices
                        - DMA channels renamed from 0,1 to 1,2 to match documentation
                        - Changed DIB access for revised signal model
 
                        hp_disclib.c, hp_disclib.h (Dave Bryan)
                        - Created MAC/ICD disc controller library

                        i1401_cd.c:
                        - fixed read stacker operation in column binary mode
                        - fixed punch stacker operation (Van Snyder)

                        id_pas.c:
                        - fixed TT_GET_MODE test to use TTUF_MODE_x (Michael Bloom)
                        - revised to use clock coscheduling

                        id_tt.c, id_ttc.p:
                        - revised to use clock coscheduling

                        id_uvc.c:
                        - added clock coscheduling routine

                        1401_cpu.c:
                        - reverted multiple tape indicator implementation
                        - fixed EOT indicator test not to clear indicator (Van Snyder)
                        - fixed divide not to clear word marks in quotient (Van Snyder)
                        - revised divide algorithm (Van Snyder)

                        i1401_mt.c:
                        - reverted multiple tape indicator implementation
                        - fixed END indicator test not to clear indicator (Van Snyder)
                        - fixed backspace over tapemark not to set EOR (Van Snyder)
                        - added no rewind option (Van Snyder)

                        i1401_sys.c:
                        - fixed misuse of & instead of && in decode (Peter Schorn)

                        pdp1_cpu.c:
                        - fixed misuse of & instead of && in Ea_ch (Michael Bloom)

                        pdp1_stddev.c:
                        - fixed unitialized variable in tty output service (Michael Bloom)

                        pdp10_fe.c:
                        - revised to use clock coscheduling

                        pdp11_defs.h:
                        - fixed priority of PIRQ vs IO; added INT_INTERNALn

                        pdp11_io.c:
                        - fixed Qbus interrupts to treat all IO devices (except clock) as BR4
                        - fixed order of int_internal (Jordi Guillaumes i Pons)

                        ppd11_rf.c
                        - fixed bug in updating mem addr extension (Peter Schorn)

                        pdp11_rk.c:
                        - fixed bug in read header (Walter F Mueller)

                        pdp11_rl.c:
                        - added debug support

                        pdp11_rq.c:
                        - added RD32 support

                        pdp11_tq.c: (Mark Pizzolato)
                        - set UNIT_SXC flag when a tape mark is encountered 
                          during forward motion read operations
                        - fixed logic which clears UNIT_SXC to check command modifier
                        - added CMF_WR flag to tq_cmf entry for OP_WTM
                        - made non-immediate rewind positioning operations take 2 seconds
                        - added UNIT_IDLE flag to tq units.
                        - fixed debug output of tape file positions when they are 64b
                        - added more debug output after positioning operations
                        - added textual display of the command being performed
                        - fixed comments about register addresses
                        
                        pdp11_ts.c:
                        - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato)

                        pdp11_tu.c:
                        - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato)

                        pdp11_vh.c: (Mark Pizzolato)
                        - fixed SET VH LINES=n to correctly adjust the number
                          of lines available to be 8, 16, 24, or 32.
                        - fixed performance issue avoiding redundant polling

                        pdp11_xq.c: (Mark Pizzolato)
                        - Fixed missing information from save/restore which
                          caused operations to not complete correctly after 
                          a restore until the OS reset the controller.
                        - Added address conflict check during attach.
                        - Fixed loopback processing to correctly handle forward packets.
                        - Fixed interrupt dispatch issue which caused delivered packets 
                          (in and out) to sometimes not interrupt the CPU after processing.
                        - Fixed the SCP visibile SA registers to always display the 
                          ROM mac address, even after it is changed by SET XQ MAC=.
                        - Added changes so that the Console DELQA diagnostic (>>>TEST 82) 
                          will succeed.
                        - Added DELQA-T (aka DELQA Plus) device emulation support.
                        - Added dropped frame statistics to record when the receiver discards
                          received packets due to the receiver being disabled, or due to the
                          XQ device's packet receive queue being full.
                        - Fixed bug in receive processing when we're not polling.  This could
                          cause receive processing to never be activated again if we don't 
                          read all available packets via eth_read each time we get the 
                          opportunity.
                        - Added the ability to Coalesce received packet interrupts.  This
                          is enabled by SET XQ POLL=DELAY=nnn where nnn is a number of 
                          microseconds to delay the triggering of an interrupt when a packet
                          is received.
                        - Added SET XQ POLL=DISABLE (aka SET XQ POLL=0) to operate without 
                          polling for packet read completion.
                        - Changed the sanity and id timer mechanisms to use a separate timer
                          unit so that transmit and recieve activities can be dealt with
                          by the normal xq_svc routine.
                          Dynamically determine the timer polling rate based on the 
                          calibrated tmr_poll and clk_tps values of the simulator.
                        - Enabled the SET XQ POLL to be meaningful if the simulator currently
                          doesn't support idling.
                        - Changed xq_debug_setup to use sim_debug instead of printf so that
                          all debug output goes to the same place.
                        - Restored the call to xq_svc after all successful calls to eth_write
                          to allow receive processing to happen before the next event
                          service time.  This must have been inadvertently commented out 
                          while other things were being tested.

                        pdp11_xu.c: (Mark Pizzolato)
                        - Added SHOW XU FILTERS modifier (Dave Hittner)
                        - Corrected SELFTEST command, enabling use by VMS 3.7, VMS 4.7, and Ultrix 1.1 (Dave Hittner)
                        - Added address conflict check during attach.
                        - Added loopback processing support
                        - Fixed the fact that no broadcast packets were received by the DEUNA
                        - Fixed transmitted packets to have the correct source MAC address.
                        - Fixed incorrect address filter setting calling eth_filter().

                        pdp18b_stddev.c:
                        - added clock coscheduling
                        - revised TTI to use clock coscheduling and to fix perpetual CAF bug
                        
                        pdp18b_ttx.c:
                        - revised to use clock coscheduling

                        pdp8_clk.c:
                        - added clock coscheduling

                        pdp8_fpp.c: (Rick Murphy)
                        - many bug fixes; now functional

                        pdp8_tt.c:
                        - revised to use clock coscheduling and to fix perpetual CAF bug

                        pdp8_ttx.c:
                        - revised to use clock cosheduling

                        pdp8_sys.c:
                        - added link to FPP

                        pdp8_td.c:
                        - fixed SDLC to clear AC (Dave Gesswein)

                        sds_mt.c:
                        - fixed bug in scan function decode (Peter Schorn)

                        vax_cpu.c:
                        - revised idle design (Mark Pizzolato)
                        - fixed bug in SET CPU IDLE
                        - fixed failure to clear PSL<tp> in BPT, XFC

                        vax_cpu1.c:
                        - revised idle design Mark Pizzolato)
                        - added VEC_QMODE test in interrupt handler

                        vax_fpa.c:
                        - fixed integer overflow bug in EMODx (Camiel Vanderhoeven)
                        - fixed POLYx normalizing before add mask bug (Camiel Vanderhoeven)
                        - fixed missing arguments in 32b floating add (Mark Pizzolato)

                        vax_octa.c (Camiel Vanderhoeven)
                        - fixed integer overflow bug in EMODH
                        - fixed POLYH normalizing before add mask bug

                        vax_stddev.c:
                        - revised to use clock coscheduling

                        vax_syscm.c:
                        - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato)

                        vax_sysdev.c:
                        - added power clear call to boot routine (Mark Pizzolato)

                        vax780_sbi.c:
                        - added AUTORESTART switch support (Mark Pizzolato)

                        vax780_stddev.c
                        - added REBOOT support (Mark Pizzolato)
                        - revised to use clock coscheduling

                        vaxmod_def.h
                        - moved all Qbus devices to BR4; deleted RP definitions


   V3.8 revision history

  1     08-Feb-09       scp.c:
                        - revised RESTORE unit logic for consistency
                        - "detach_all" ignores error status returns if shutting down (Dave Bryan)
                        - DO cmd missing params now default to null string (Dave Bryan)
                        - DO cmd sub_args now allows "\\" to specify literal backslash (Dave Bryan)
                        - decommitted MTAB_VAL
                        - fixed implementation of MTAB_NC
                        - fixed warnings in help printouts
                        - fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan)  

                        sim_tape.c:
                        - fixed signed/unsigned warning in sim_tape_set_fmt (Dave Bryan)

                        sim_tmxr.c, sim_tmxr.h:
                        - added line connection order to tmxr_poll_conn,
                          added tmxr_set_lnorder and tmxr_show_lnorder (Dave Bryan)
                        - print device and line to which connection was made (Dave Bryan)
                        - added three new standardized SHOW routines

                        all terminal multiplexers:
                        - revised for new common SHOW routines in TMXR library
                        - rewrote set size routines not to use MTAB_VAL

                        hp2100_cpu.c (Dave Bryan):
                        - VIS and IOP are now mutually exclusive on 1000-F
                        - Removed A/B shadow register variables
                        - Moved hp_setdev, hp_showdev to hp2100_sys.c
                        - Moved non-existent memory checks to WritePW
                        - Fixed mp_dms_jmp to accept lower bound, check write protection
                        - Corrected DMS violation register set conditions
                        - Refefined ABORT to pass address, moved def to hp2100_cpu.h
                        - Combined dms and dms_io routines
                        - JSB to 0/1 with W5 out and fence = 0 erroneously causes MP abort
                        - Unified I/O slot dispatch by adding DIBs for CPU, MP, and DMA
                        - Rewrote device I/O to model backplane signals
                        - EDT no longer passes DMA channel
                        - Added SET CPU IDLE/NOIDLE, idle detection for DOS/RTE
                        - Breakpoints on interrupt trap cells now work

                        hp2100_cpu0.c (Dave Bryan):
                        - .FLUN and self-tests for VIS and SIGNAL are NOP if not present
                        - Moved microcode function prototypes to hp2100_cpu1.h
                        - Removed option-present tests (now in UIG dispatchers)
                        - Added "user microcode" dispatcher for unclaimed instructions

                        hp2100_cpu1.c (Dave Bryan):
                        - Moved microcode function prototypes to hp2100_cpu1.h
                        - Moved option-present tests to UIG dispatchers
                        - Call "user microcode" dispatcher for unclaimed UIG instructions

                        hp2100_cpu2.c (Dave Bryan):
                        - Moved microcode function prototypes to hp2100_cpu1.h
                        - Removed option-present tests (now in UIG dispatchers)
                        - Updated mp_dms_jmp calling sequence
                        - Fixed DJP, SJP, and UJP jump target validation
                        - RVA/B conditionally updates dms_vr before returning value
                        
                        hp2100_cpu3.c (Dave Bryan):
                        - Moved microcode function prototypes to hp2100_cpu1.h
                        - Removed option-present tests (now in UIG dispatchers)
                        - Updated mp_dms_jmp calling sequence

                        hp2100_cpu4.c, hp2100_cpu7.c (Dave Bryan):
                        - Moved microcode function prototypes to hp2100_cpu1.h
                        - Removed option-present tests (now in UIG dispatchers)

                        hp2100_cpu5.c (Dave Bryan):
                        - Moved microcode function prototypes to hp2100_cpu1.h
                        - Removed option-present tests (now in UIG dispatchers)
                        - Redefined ABORT to pass address, moved def to hp2100_cpu.h
                        - Rewrote device I/O to model backplane signals

                        hp2100_cpu6.c (Dave Bryan):
                        - Corrected .SIP debug formatting
                        - Moved microcode function prototypes to hp2100_cpu1.h
                        - Removed option-present tests (now in UIG dispatchers)
                        - Rewrote device I/O to model backplane signals

                        hp2100 all peripherals (Dave Bryan):
                        - Rewrote device I/O to model backplane signals

                        hp2100_baci.c (Dave Bryan):
                        - Fixed STC,C losing interrupt request on BREAK
                        - Changed Telnet poll to connect immediately after reset or attach
                        - Added REG_FIT to register variables < 32-bit size
                        - Moved fmt_char() function to hp2100_sys.c

                        hp2100_dp.c, hp2100_dq.c (Dave Bryan):
                        - Added REG_FIT to register variables < 32-bit size

                        hp2100_dr.c (Dave Bryan):
                        - Revised drc_boot to use ibl_copy

                        hp2100_fp1.c (Dave Bryan):
                        - Quieted bogus gcc warning in fp_exec

                        hp2100_ipl.c (Dave Bryan):
                        - Changed socket poll to connect immediately after reset or attach
                        - Revised EDT handler to refine completion delay conditions
                        - Revised ipl_boot to use ibl_copy

                        hp2100_lpt.c (Dave Bryan):
                        - Changed CTIME register width to match documentation

                        hp2100_mpx.c (Dave Bryan):
                        - Implemented 12792C eight-channel terminal multiplexer

                        hp2100_ms.c (Dave Bryan):
                        - Revised to use AR instead of saved_AR in boot

                        hp2100_mt.c (Dave Bryan):
                        - Fixed missing flag after CLR command
                        - Moved write enable and format commands from MTD to MTC
                        
                        hp2100_mux.c (Dave Bryan):
                        - SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed
                        - Changed Telnet poll to connect immediately after reset or attach
                        - Added LINEORDER support
                        - Added BREAK deferral to allow RTE break-mode to work

                        hp2100_pif.c (Dave Bryan):
                        - Implemented 12620A/12936A Privileged Interrupt Fences

                        hp2100_sys.c (Dave Bryan):
                        - Fixed IAK instruction dual-use mnemonic display
                        - Moved hp_setdev, hp_showdev from hp2100_cpu.c
                        - Changed sim_load to use WritePW instead of direct M[] access
                        - Added PIF device
                        - Moved fmt_char() function from hp2100_baci.c
                        - Added MPX device

                        hp2100_cpu.h (Dave Bryan):
                        - Rearranged declarations with hp2100_cpu.c and hp2100_defs.h
                        - Added mp_control to CPU state externals

                        hp2100_cpu1.h (Dave Bryan):
                        - Moved microcode function prototypes here

                        hp2100_defs.h (Dave Bryan):
                        - Added POLL_FIRST to indicate immediate connection attempt
                        - Rearranged declarations with hp2100_cpu.h
                        - Added PIF device
                        - Declared fmt_char() function
                        - Added MPX device

                        i1401_cpu.c:
                        - fixed bug in ZA and ZS (Bob Abeles)
                        - fixed tape indicator implementation (Bob Abeles)
                        - added missing magtape modifier A (Van Snyder)

                        i1401_mt.c:
                        - added -n (no rewind) option to BOOT (Van Snyder)
                        - fixed bug to mask input to 6b on read (Bob Abeles)

                        lgp_stddev.c:
                        - changed encode character from # to !, due to overlap

                        pdp11_cpu.c:
                        - fixed failure to clear cpu_bme on RESET (Walter Mueller)

                        pdp11_dz.c:
                        - added MTAB_NC modifier on SET LOG command (Walter Mueller)

                        pdp11_io.c, vax_io.c, vax780_uba.c:
                        - revised to use PDP-11 I/O library

                        pdp11_io_lib.c:
                        - created common library for Unibus/Qbus support routines

                        pdp11_cis.c, vax_cis.c:
                        - fixed bug in ASHP left overflow calc (Word/NibbleLShift)
                        - fixed bug in DIVx (LntDstr calculation)

                        sds_lp.c:
                        - fixed loss of carriage control position on space op

                        vax_stddev.c, vax780_stddev.c
                        - modified to resync TODR on any clock reset

  0     15-Jun-08       scp.c:
                        - fixed bug in local/global register search (Mark Pizzolato)
                        - fixed bug in restore of RO units (Mark Pizzolato)
                        - added SET/SHO/NO BR with default argument (Dave Bryan)

                        sim_tmxr.c
                        - worked around Telnet negotiation problem with QCTerm (Dave Bryan)

                        gri_defs.h, gri_cpu.c, gri_sys.c:
                        - added GRI-99 support

                        hp2100_baci.c (Dave Bryan):
                        - Implemented 12966A Buffered Asynchronous Communications Interface simulator

                        hp2100_cpu.c (Dave Bryan):
                        - Memory ex/dep and bkpt type default to current map mode
                        - Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA
                        - Corrected MP W5 (JSB) jumper action, SET/SHOW reversal,
                          mp_mevff clear on interrupt with I/O instruction in trap cell
                        - Removed DBI support from 1000-M (was temporary for RTE-6/VM)
                        - Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags
                        - Enabled SIGNAL instructions, SIG debug flag
                        - Fixed single stepping through interrupts

                        hp2100_cpu0.c (Dave Bryan and Holger Veit):
                        - Removed and implemented "cpu_rte_vma" and "cpu_rte_os"
                        - Removed and implemented "cpu_vis" and "cpu_signal"
                        - Removed and implemented "cpu_rte_ema"

                        hp2100_cpu1.c (Dave Bryan):
                        - Added fprint_ops, fprint_regs for debug printouts
                        - Enabled DIAG as NOP on 1000 F-Series
                        - Fixed VIS and SIGNAL to depend on the FPP and HAVE_INT64

                        hp2100_cpu3.c (Dave Bryan):
                        - Fixed unsigned divide bug in .DDI
                        - Fixed unsigned multiply bug in .DMP
                        - Added implementation of DBI self-test

                        hp2100_cpu4.c (Dave Bryan):
                        - Fixed B register return bug in /CMRT

                        hp2100_cpu5.c (Holger Veit):
                        - Implemented RTE-6/VM Virtual Memory Area firmware
                        - Implemented RTE-IV Extended Memory Area firmware

                        hp2100_cpu6.c (Dave Bryan):
                        - Implemented RTE-6/VM OS accelerator firmware

                        hp2100_cpu7.c (Holger Veit):
                        - Implemented Vector Instruction Set and SIGNAL/1000 firmware

                        hp2100_ds.c (Dave Bryan):
                        - Corrected and verified ioCRS action
                        - Corrected DPTR register definition from FLDATA to DRDATA

                        hp2100_fp.c (Mark Pizzolato)
                        - Corrected fp_unpack mantissa high-word return

                        hp2100_fp1.c (Dave Bryan):
                        - Reworked "complement" to avoid inlining bug in gcc-4.x
                        - Fixed uninitialized return in fp_accum when setting

                        hp2100_mux.c (Dave Bryan):
                        - Sync mux poll with console poll for idle compatibility

                        hp2100_stddev.c (Dave Bryan):
                        - Fixed PTR trailing null counter for tape re-read
                        - Added IPTICK register to CLK to display CPU instr/tick
                        - Corrected and verified ioCRS actions
                        - Changed TTY console poll to 10 msec. real time
                        - Synchronized CLK with TTY if set for 10 msec.
                        - Added UNIT_IDLE to TTY and CLK
                        - Removed redundant control char handling definitions
                        - Changed TTY output wait from 100 to 200 for MSU BASIC

                        hp2100_sys.c (Dave Bryan):
                        - Added BACI device
                        - Added RTE OS/VMA/EMA mnemonics
                        - Changed fprint_sym to handle step with irq pending

                        hp2100_cpu.h (Dave Bryan):
                        - Added calc_defer() prototype
                        - Added extern sim_deb, cpu_dev, DEB flags for debug printouts
                        - Added extern intaddr, mp_viol, mp_mevff, calc_int, dev_ctl,
                          ReadIO, WriteIO for RTE-6/VM microcode support

                        hp2100_cpu1.h (Dave Bryan):
                        - Corrected OP_AFF to OP_AAFF for SIGNAL/1000
                        - Removed unused operand patterns
                        - Added fprint_ops, fprint_regs for debug printouts
                        - Revised OP_KKKAKK operand profile to OP_CCCACC for $LOC

                        hp2100_defs.h (Dave Bryan):
                        - Added BACI device
                        - Added 16/32-bit unsigned-to-signed conversions
                        - Changed TMR_MUX to TMR_POLL for idle support
                        - Added POLLMODE, sync_poll() declaration
                        - Added I_MRG, I_ISZ, I_IOG, I_STF, and I_SFS instruction masks
                        - Added I_MRG_I, I_JSB, I_JSB_I, and I_JMP instruction masks

                        nova_defs.h (Bruce Ray):
                        - added support for third-party 64KW memory

                        nova_clk.c (Bruce Ray):
                        - renamed to RTC, to match DG literature

                        nova_cpu.c (Bruce Ray):
                        - added support for third-party 64KW memory
                        - added Nova 3 "secret" instructions
                        - added CPU history support

                        nova_dkp.c (Bruce Ray):
                        - renamed to DKP, to match DG literature
                        - fixed numerous bugs in both documented and undocumented behavior
                        - changed bootstrap code to DG official sequence

                        nova_dsk.c (Bruce Ray):
                        - renamed to DSK, to match DG literature
                        - added support for undocumented behavior
                        - changed bootstrap code to DG official sequence

                        nova_mta.c (Bruce Ray):
                        - renamed to MTA, to match DG literature
                        - changed bootstrap code to DG official sequence

                        nova_plt.c, nova_pt.c (Bruce Ray):
                        - added 7B/8B support

                        nova_sys.c (Bruce Ray):
                        - fixed mistaken instruction mnemonics

                        pdp11_cpu.c, pdp11_io.c, pdp11_rh.c:
                        - fixed DMA memory address limit test (John Dundas)
                        - fixed MMR0 treatment in RESET (Walter Mueller)

                        pdp11_cpumod.h, pdp11_cpumod.c:
                        - fixed write behavior of 11/70 MBRK, LOSIZE, HISIZE (Walter Mueller)
                        - added support to set default state of KDJ11B,E clock control register

                        pdp11_dc.c:
                        - added support for DC11

                        pdp11_defs.h:
                        - added KE, KG, RC, DC support
                        - renamed DL11 devices

                        pdp11_dl.c:
                        - renamed devices to DLI/DLO, to match DC11
                        - added modem control

                        pdp11_io.c:
                        - added autoconfigure support for DC11

                        pdp11_ke.c:
                        - added support for KE11A

                        pdp11_kg.c (John Dundas):
                        - added support for KG11A

                        pdp11_rc.c (John Dundas):
                        - added support for RC11

                        pdp11_sys.c:
                        - modified to allow -A, -B use with 8b devices
                        - added KE, KG, RC, DC support
                        - renamed DL11 devices

                        vax_cmode.c, vax_io.c, vax780_uba.c:
                        - fixed declarations (Mark Pizzolato)


   V3.7 revision history 

  3     02-Sep-07       scp.c:
                        - fixed bug in SET THROTTLE command

                        pdp10_cpu.c:
                        - fixed non-portable usage in SHOW HISTORY routine

                        pdp11_ta.c:
                        - forward op at BOT skips initial file gap

                        pdp8_ct.c:
                        - forward op at BOT skips initial file gap
                        - fixed handling of BEOT

                        vax_cpu.c:
                        - fixed bug in read access g-format indexed specifiers

  2     12-Jul-07       sim_ether.c (Dave Hittner):
                        - fixed non-ethernet device removal loop (Naoki Hamada)
                        - added dynamic loading of wpcap.dll;
                        - corrected exceed max index bug in ethX lookup
                        - corrected failure to look up ethernet device names in
                          the registry on Windows XP x64

                        sim_timer.c:
                        - fixed idle timer event selection algorithm
  
                        h316_lp.c:
                        - fixed loss of last print line (Theo Engel)

                        h316_mt.c:
                        - fixed bug in write without stop (Theo Engel)

                        h316_stddev.c:
                        - fixed bug in clock increment (Theo Engel)

                        i1401_cpu.c:
                        - added recognition of overlapped operation modifiers
                        - remove restriction on load-mode binary tape operations

                        i1401_mt.c:
                        - fixed read tape mark operation (Van Snyder)
                        - remove restriction on load-mode binary tape operations

                        pdp1_cpu.c:
                        - fixed typo in SBS clear (Norm Lastovica)

                        pdp11_rh.c, pdp11_rp.c, pdp11_tu.c:
                        - CS1 DVA is in the device, not the MBA

                        pdp8_ct.c:
                        - fixed typo (Norm Lastovica)

                        vax_cpu.c:
                        - revised idle detector

  1     14-May-07       scp.c:
                        - modified sim_instr invocation to call sim_rtcn_init_all
                        - fixed bug in get_sim_opt (reported by Don North)
                        - fixed bug in RESTORE with changed memory size
                        - added global 'RESTORE in progress' flag
                        - fixed breakpoint actions in DO command file processing
                          (Dave Bryan)

                        all CPU's with clocks:
                        - removed clock initialization (now done in SCP)

                        hp2100_cpu.c (Dave Bryan):
                        - EDT passes input flag and DMA channel in dat parameter

                        hp2100_ipl.c (Dave Bryan):
                        - IPLI EDT delays DMA completion interrupt for TSB

                        hp2100_mux.c (Dave Bryan):
                        - corrected "mux_sta" size from 16 to 21 elements
                        - fixed "muxc_reset" to clear lines 16-20
                        - fixed control card OTx to set current channel number
                        - fixed to set "muxl_ibuf" in response to a transmit interrupt
                        - changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits
                        - fixed to set "mux_rchp" when a line break is received
                        - fixed incorrect "odd_par" table values
                        - reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity
                        - rixed mux reset (ioCRS) to clear port parameters
                        - fixed to use PUT_DCH instead of PUT_CCH for data channel status
                        - added DIAG/TERM modifiers to implement diagnostic mode

                        pdp11_cpumod.c:
                        - changed memory size routine to work with RESTORE

                        pdp11_hk.c:
                        - NOP and DCLR (at least) do not check drive type
                        - MR2 and MR3 only updated on NOP

                        pdp10_tu.c, pdp11_tu.c:
                        - TMK sets FCE only on read (Naoki Hamada)

                        pdp11_xu.c:
                        - added missing FC_RMAL command
                        - cleared multicast on write

                        vax_moddefs.h, vax_cpu1.c:
                        - separated PxBR and SBR mbz checks

                        vax780_defs.h
                        - separated PxBR and SBR mbz checks
                        - modified mbz checks to reflect 780 microcode patches
                          (Naoki Hamada)

                        vax_mmu.c:
                        - added address masking to all SBR-based memory reads

  0     30-Jan-07       scp.c:
                        - implemented throttle commands
                        - added -e to control error processing in DO command files
                          (Dave Bryan)

                        sim_console.c:
                        - fixed handling of non-printable characters in KSR mode

                        sim_tape.c:
                        - fixed bug in reverse operations for P7B-format tapes
                        - fixed bug in reverse operations across erase gaps

                        sim_timer.c:
                        - added throttle support
                        - added idle support (based on work by Mark Pizzolato)

                        gri_stddev.c, h316_stddev.c, pdp18b_tt1.c
                        - fixed handling of non-printable characters in KSR mode

                        hp2100_cpu.c, hp2100_cpu0.c, hp2100_cpu1.c, hp2100_cpu2.c,
                        hp2100_cpu3.c, hp2100_cpu4.c (Dave Bryan):
                        - reorganized CPU modules for easier addition of new instructions
                        - added Double Integer instructions, 1000-F CPU, 2114 and
                          2115 CPUs, 12K and 24K memory sizes, 12607B and 12578A DMA
                          controllers, and 21xx binary loader protection
                        - fixed DMS self-test instruction execution on 1000-M
                        - fixed indirect interrupt holdoff logic

                        hp2100_ds.c:
                        - fixed REQUEST STATUS to clear status-1 (Dave Bryan)

                        hp2100_fp1.c:
                        - Added Floating Point Processor (Dave Bryan)

                        hp2100_lps.c:
                        - fixed diag-mode CLC response

                        i7094_cpu.c:
                        - fixed new bug in halt IO wait loop
                        - added IFT, EFT expanded core test instructions

                        id16_cpu.c, id32_cpu.c:
                        - removed separate multiplexor clock
                        - added idle support

                        id_pas.c:
                        - synced multiplexor poll to real-time clock

                        id_tt.c, id_ttp.c:
                        - fixed handling of non-printable characters in KSR mode
                        - synced keyboard poll to real-time clock

                        id_uvc.c:
                        - changed line-time clock to be free-running

                        pdp1_cpu.c:
                        - added 16-channel sequence break system (API) support
                        - added PDP-1D support

                        pdp1_clk.c:
                        - first release

                        pdp1_dcs.c:
                        - first release

                        pdp1_stddev.c:
                        - separated TTI, TTO for API support

                        pdp1_sys.c:
                        - added PDP-1D, 16-channel SBS, clock, DCS support
                        - fixed bugs in character input, block loader

                        pdp10_cpu.c:
                        - added idle support

                        pdp10_defs.h, pdp10_sys.c:
                        - added CR support

                        pdp10_fe.c, pdp10_tim.c:
                        - synced keyboard poll to real-time clock

                        pdp11_cr.c:
                        - revised for PDP-10 compatibility (CD11 only)

                        pdp11_cpu.c:
                        - added idle support
                        - fixed bug in ASH -32 C value

                        pdp11_rf.c:
                        - fixed unit mask (John Dundas)

                        pdp11_stddev.c, vax_stddev.c, vax780_stddev.c:
                        - synced keyboard poll to real-time clock
                        - added clock coscheduling support

                        pdp11_ta.c:
                        - first release

                        pdp11_vh.c:
                        - synced service poll to real-time clock
                        - changed device to be off by default

                        pdp11_dz.c, pdp11_xq.c, pdp11_xu.c:
                        - synced service poll to real-time clock

                        pdp11_sys.c:
                        - fixed operand order in EIS instructions (W.F.J. Mueller)
                        - added TA11 support

                        pdp18b_cpu.c:
                        - fixed incorrect value of PC on instruction fetch mem mmgt error
                        - fixed PDP-15 handling of mem mmgt traps (sets API 3)
                        - fixed PDP-15 handling of CAL API 4 (sets only if 0-3 inactive)
                        - fixed PDP-15 CAF to clear memory management mode register
                        - fixed boundary test in KT15/XVM (reported by Andrew Warkentin)
                        - added XVM RDCLK instruction
                        - added idle support and infinite loop detection

                        pdp18b_rf.c:
                        - fixed bug, DSCD does not clear function register

                        pdp18b_stddev.c:
                        - added PDP-15 program-selectable duplex handling instruction
                        - fixed PDP-15 handling of reader out-of-tape
                        - fixed handling of non-printable characters in KSR mode
                        - added XVM RDCLK instruction
                        - changed real-time clock to be free running
                        - synced keyboard poll to real-time clock

                        pdp18b_tt1.c
                        - fixed handling of non-printable characters in KSR mode

                        pdp18b_sys.c:
                        - added XVM RDCLK instruction

                        pdp8_cpu.c:
                        - fixed SC value after DVI overflow (Don North)
                        - added idle support and infinite loop detection

                        pdp8_ct.c:
                        - first release

                        pdp8_clk.c:
                        - changed real-time clock to be free running

                        pdp8_sys.c:
                        - added TA8E support
                        - added ability to disambiguate overlapping IOT definitions

                        pdp8_tt.c:
                        - fixed handling of non-printable characters in KSR mode
                        - synced keyboard poll to real-time clock

                        vax_cpu.c, vax_cpu1.c:
                        - added idle support

                        vax_syscm.c:
                        - fixed operand order in EIS instructions (W.F.J. Mueller)


   V3.6 revision history 

  1     25-Jul-06       sim_console.c:
                        - implemented SET/SHOW PCHAR

                        all DECtapes:
                        - fixed conflict in ATTACH switches

                        hp2100_ms.c (Dave Bryan):
                        - added CAPACITY as alternate for REEL
                        - fixed EOT test for unlimited reel size

                        i1620_cd.c (Tom McBride):
                        - fixed card reader fgets call
                        - fixed card reader boot sequence

                        i7094_cd.c:
                        - fixed problem with 80 column full cards

                        i7094_cpu.c:
                        - fixed bug in halt IO wait loop

                        i7094_sys.c:
                        - added binary loader (courtesy of Dave Pitt)

                        pdp1_cpu.c:
                        - fixed bugs in MUS and DIV

                        pdp11_cis.c:
                        - added interrupt tests to character instructions
                        - added 11/44 stack probe test to MOVCx (only)

                        pdp11_dl.c:
                        - first release

                        pdp11_rf.c:
                        - first release

                        pdp11_stddev.c:
                        - added UC support to TTI, TTO

                        pdp18b_cpu.c:
                        - fixed RESET to clear AC, L, and MQ

                        pdp18b_dt.c:
                        - fixed checksum calculation bug for Type 550

                        pdp18b_fpp.c:
                        - fixed bugs in left shift, multiply

                        pdp18b_stddev.c:
                        - fixed Baudot letters/figures inversion for PDP-4
                        - fixed letters/figures tracking for PDP-4
                        - fixed PDP-4/PDP-7 default terminal to be local echo

                        pdp18b_sys.c:
                        - added Fiodec, Baudot display
                        - generalized LOAD to handle HRI, RIM, and BIN files

                        pdp8_ttx.c:
                        - fixed bug in DETACH routine

  0     15-May-06       scp.c:
                        - revised save file format to save options, unit capacity

                        sim_tape.c, sim_tape.h:
                        - added support for finite reel size
                        - fixed bug in P7B write record

                        most magtapes:
                        - added support for finite reel size

                        h316_cpu.c: fixed bugs in LLL, LRL (Theo Engel)

                        h316_lp.c: fixed bug in blanks backscanning (Theo Engel)

                        h316_stddev.c: fixed bugs in punch state handling (Theo Engel)

                        i1401_cpu.c: fixed bug in divide (reported by Van Snyder)

                        i16_cpu.c: fixed bug in DH (Mark Hittinger)

                        i32_cpu.c:
                        - fixed bug in DH (Mark Hittinger)
                        - added support for 8 register banks in 8/32

                        i7094: first release

                        id_io.c: fixed bug, GO preserves EXA and SSTA (Davis Johnson)

                        id_idc.c:
                        - fixed WD/WH handling (Davis Johnson)
                        - fixed bug, nop command should be ignored (Davis Johnson)

                        nova_cpu.c: fixed bug in DIVS (Mark Hittinger)

                        pdp11_cis.c: (all reported by John Dundas)
                        - fixed bug in decode table
                        - fixed bug in ASHP
                        - fixed bug in write decimal string with mmgt enabled
                        - fixed bug in 0-length strings in multiply/divide

                        pdp11_cpu.c: fixed order of operand fetching in XOR for SDSD models

                        pdp11_cr.c: added CR11/CD11 support

                        pdp11_tc.c:
                        - fixed READ to set extended data bits in TCST (Alan Frisbie)

                        vax780_fload.c: added FLOAD command

                        vax780_sbi.c: fixed writes to ACCS

                        vax780_stddev.c: revised timer logic for EVKAE (reported by Tim Stark)

                        vax_cis.c: (all reported by Tim Stark)
                        - fixed MOVTC, MOVTUC to preserve cc's through page faults
                        - fixed MOVTUC to stop on translated == escape
                        - fixed CVTPL to set registers before destination reg write
                        - fixed CVTPL to set correct cc bit on overflow
                        - fixed EDITPC to preserve cc's through page faults
                        - fixed EDITPC EO$BLANK_ZERO count, cc test
                        - fixed EDITPC EO$INSERT to insert fill instead of blank
                        - fixed EDITPC EO$LOAD_PLUS/MINUS to skip character

                        vax_cpu.c:
                        - added KESU capability to virtual examine
                        - fixed bugs in virtual examine
                        - rewrote CPU history function for improved usability
                        (bugs below reported by Tim Stark)
                        - fixed fault cleanup to clear PSL<tp>
                        - fixed ADAWI r-mode to preserve dst<31:16>
                        - fixed ACBD/G to test correct operand
                        - fixed access checking on modify-class specifiers
                        - fixed branch address calculation in CPU history
                        - fixed bug in reported VA on faulting cross-page write

                        vax_cpu1.c: (all reported by Tim Stark)
                        - added access check on system PTE for 11/780
                        - added mbz check in LDPCTX for 11/780

                        vax_cmode.c: (all reported by Tim Stark)
                        - fixed omission of SXT
                        - fixed order of operand fetching in XOR

                        vax_fpa.c: (all reported by Tim Stark)
                        - fixed POLYD, POLYG to clear R4, R5
                        - fixed POLYD, POLYG to set R3 correctly
                        - fixed POLYD, POLYG to not exit prematurely if arg = 0
                        - fixed POLYD, POLYG to do full 64b multiply
                        - fixed POLYF, POLYD, POLYG to remove truncation on add
                        - fixed POLYF, POLYD, POLYG to mask mul reslt to 31b/63b/63b
                        - fixed fp add routine to test for zero via fraction
                          to support "denormal" argument from POLYF, POLYD, POLYG
                        - fixed bug in 32b floating multiply routine
                        - fixed bug in 64b extended modulus routine

                        vax_mmu.c:
                        - added access check on system PTE for 11/780

                        vax_octa.c: (all reported by Tim Stark)
                        - fixed MNEGH to test negated sign, clear C
                        - fixed carry propagation in qp_inc, qp_neg, qp_add
                        - fixed pack routines to test for zero via fraction
                        - fixed ACBH to set cc's on result
                        - fixed POLYH to set R3 correctly
                        - fixed POLYH to not exit prematurely if arg = 0
                        - fixed POLYH to mask mul reslt to 127b
                        - fixed fp add routine to test for zero via fraction
                          to support "denormal" argument from POLYH
                        - fixed EMODH to concatenate 15b of 16b extension
                        - fixed bug in reported VA on faulting cross-page write


   V3.5 revision history 

patch   date            module(s) and fix(es)

  2     07-Jan-06       scp.c:
                        - added breakpoint spaces
                        - added REG_FIT support

                        sim_console.c: added ASCII character processing routines

                        sim_tape.c, sim_tape.h:
                        - added write support for P7B format
                        - fixed bug in write forward (Dave Bryan)

                        h316_stddev.c, hp2100_stddev.c, hp2100_mux.c, id_tt.c,
                        id_ttp.c, id_pas.c, pdp8_tt.c, pdp8_ttx.c, pdp11_stddev.c,
                        pdp11_dz.c, pdp18b_stddev.c, pdp18b_tt1.c, vax_stddev,
                        gri_stddev.c:
                        - revised to support new character handling routines

                        pdp10_rp.c: fixed DCLR not to clear disk address

                        pdp11_hk.c: fixed overlapped seek interaction with NOP, etc

                        pdp11_rh.c: added enable/disable routine

                        pdp11_rq.c, pdp11_tm.c, pdp11_tq.c, pdp11_ts.c
                        - widened address display to 64b when USE_ADDR64

                        pdp11_rp.c:
                        - fixed DCLR not to clear disk address
                        - fixed device enable/disable logic to include Massbus adapter
                        - widened address display to 64b when USE_ADDR64

                        pdp11_tu.c:
                        - fixed device enable/disable logic to include Massbus adapter
                        - widened address display to 64b when USE_ADDR64
                        - changed default adapter to TM03 (for VMS)

                        pdp8_df.c, pdp8_dt.c, pdp8_rf.c:
                        - fixed unaligned access bug (Doug Carman)

                        pdp8_rl.c: fixed IOT 61 decoding bug (David Gesswein)

                        vax_cpu.c:
                        - fixed breakpoint detection when USE_ADDR64 option is active
                        - fixed CVTfi to trap on integer overflow if PSW<iv> set

  1     15-Oct-05       All CPU's, other sources: fixed declaration inconsistencies
                        (Sterling Garwood)

                        i1401_cpu.c: added control for old/new character encodings

                        i1401_cd.c, i1401_lpt.c, i1401_tty.c:
                        - changed character encodings to be consistent with 7094
                        - changed column binary format to be consistent with 7094
                        - added choice of business or Fortran set for output encoding

                        i1401_sys.c: changed WM character to ` under new encodings

                        i1620_cd.c, i1620_lpt.c, i1620_tty.c:
                        - changed character encodings to be consistent with 7094

                        pdp10_cpu.c: changed MOVNI to eliminate gcc warning

                        pdp11_io.c: fixed bug in autoconfiguration (missing XU)

                        vax_io.c: fixed bug in autoconfiguration (missing XU)

                        vax_fpa.c: fixed bug in 32b structure definitions (Jason Stevens)

  0     1-Sep-05        Note: most source modules have been edited to improve
                        readability and to fix declaration and cast problems in C++

                        all instruction histories: fixed reversed arguments to calloc

                        scp.c: revised to trim trailing spaces on file inputs

                        sim_sock.c: fixed SIGPIPE error on Unix

                        sim_ether.c: added Windows user-defined adapter names (Timothe Litt)

                        sim_tape.c: fixed misallocation of TPC map array

                        sim_tmxr.c: added support for SET <unit> DISCONNECT

                        hp2100_mux.c: added SET MUXLn DISCONNECT

                        i1401_cpu.c:
                        - fixed SSB-SSG clearing on RESET (reported by Ralph Reinke)
                        - removed error stops in MCE

                        i1401_cd.c: fixed read, punch to ignore modifier on 1, 4 char inst
                        (reported by Van Snyder)

                        id_pas.c:
                        - fixed bug in SHOW CONN/STATS
                        - added SET PASLn DISCONNECT

                        pdp10_ksio.c: revised for new autoconfiguration interface

                        pdp11_cpu.c: replaced WAIT clock queue check with API call

                        pdp11_cpumod.c: added additional 11/60 registers

                        pdp11_io.c: revised autoconfiguration algorithm and interface

                        pdp11_dz.c: revised for new autoconfiguration interface

                        pdp11_vh.c:
                        - revised for new autoconfiguration interface
                        - fixed bug in vector display routine

                        pdp11_xu.c: fixed runt packet processing (Tim Chapman)

                        pdp18b_cpu.c, pdp18b_sys.c:
                        - removed spurious AAS instruction

                        pdp18b_tt1.c:
                        - fixed bug in SHOW CONN/STATS
                        - fixed bug in SET LOG/NOLOG
                        - added SET TTOXn DISCONNECT

                        pdp8_ttx.c:
                        - fixed bug in SHOW CONN/STATS
                        - fixed bug in SET LOG/NOLOG
                        - added SET TTOXn DISCONNECT

                        sds_mux.c:
                        - fixed bug in SHOW CONN/STATS
                        - added SET MUXLn DISCONNECT

                        vaxmod_defs.h: added QDSS support

                        vax_io.c: revised autoconfiguration algorithm and interface

   V3.4 revision history 

  0     01-May-04       scp.c:
                        - fixed ASSERT code
                        - revised syntax for SET DEBUG (Dave Bryan)
                        - revised interpretation of fprint_sym, fparse_sym returns
                        - moved DETACH sanity tests into detach_unit

                        sim_sock.h and sim_sock.c:
                        - added test for WSAEINPROGRESS (Tim Riker)

                        many: revised detach routines to test for attached state

                        hp2100_cpu.c: reorganized CPU options (Dave Bryan)

                        hp2100_cpu1.c: reorganized EIG routines (Dave Bryan)

                        hp2100_fp1.c: added FFP support (Dave Bryan)

                        id16_cpu.c:
                        - fixed bug in show history routine (Mark Hittinger)
                        - revised examine/deposit to do words rather than bytes

                        id32_cpu.c:
                        - fixed bug in initial memory allocation
                        - fixed bug in show history routine (Mark Hittinger)
                        - revised examine/deposit to do words rather than bytes

                        id16_sys.c, id32_sys:
                        - revised examine/deposit to do words rather than bytes

                        pdp10_tu.c:
                        - fixed bug, ERASE and WREOF should not clear done (reported
                          by Rich Alderson)
                        - fixed error reporting

                        pdp11_tu.c: fixed error reporting

   V3.3 revision history 

  2     08-Mar-05       scp.c: added ASSERT command (Dave Bryan)

                        h316_defs.h: fixed IORETURN macro

                        h316_mt.c: fixed error reporting from OCP (Philipp Hachtmann)

                        h316_stddev.c: fixed bug in OCP '0001 (Philipp Hachtmann)

                        hp2100_cpu.c: split out EAU and MAC instructions

                        hp2100_cpu1.c: (Dave Bryan)
                        - fixed missing MPCK on JRS target
                        - removed EXECUTE instruction (is NOP in actual microcode)

                        hp2100_fp: (Dave Bryan)
                        - fixed missing negative overflow renorm in StoreFP

                        i1401_lp.c: fixed bug in write_line (reported by Van Snyder)

                        id32_cpu.c: fixed branches to mask new PC (Greg Johnson)

                        pdp11_cpu.c: fixed bugs in RESET for 11/70 (reported by Tim Chapman)

                        pdp11_cpumod.c:
                        - fixed bug in SHOW MODEL (Sergey Okhapkin)
                        - made SYSID variable for 11/70 (Tim Chapman)
                        - added MBRK write case for 11/70 (Tim Chapman)

                        pdp11_rq: added RA60, RA71, RA81 disks

                        pdp11_ry: fixed bug in boot code (reported by Graham Toal)

                        vax_cpu.c: fixed initial state of cpu_extmem

  1     05-Jan-05       h316_cpu.c: fixed bug in DIV

                        h316_stddev.c:
                        - fixed bug in SKS '104 (reported by Philipp Hachtmann)
                        - fixed bug in SKS '504
                        - adder reader/punch ASCII file support
                        - added Teletype reader/punch support

                        h316_dp.c: fixed bug in skip on !seeking

                        h316_mt.c: fixed bug in DMA/DMC support

                        h316_lp.c: fixed bug in DMA/DMC support

                        hp2100_cpu.c:
                        - fixed DMA reset to clear alternate CTL flop (Dave Bryan)
                        - fixed DMA reset to not clear control words (Dave Bryan)
                        - fixed SBS, CBS, TBS to do virtual reads
                        - separated A/B from M[0/1], for DMA IO (Dave Bryan)
                        - added SET CPU 21MX-M, 21MX-E (Dave Brian)
                        - disabled TIMER/EXECUTE/DIAG instructions for 21MX-M (Dave Bryan)
                        - added post-processor to maintain T/M consistency (Dave Bryan)

                        hp2100_ds.c: first release

                        hp2100_lps.c (all changes from Dave Bryan)
                        - added restart when set online, etc.
                        - fixed col count for non-printing chars

                        hp2100_lpt.c (all changes from Dave Bryan)
                        - added restart when set online, etc.

                        hp2100_sys.c (all changes from Dave Bryan):
                        - added STOP_OFFLINE, STOP_PWROFF messages

                        i1401_sys.c: added address argument support (Van Snyder)

                        id_mt.c: added read-only file support

                        lgp_cpu.c, lgp_sys.c: modified VM pointer setup

                        pdp11_cpu.c: fixed WAIT to work in all modes (John Dundas)

                        pdp11_tm.c, pdp11_ts.c: added read-only file support

                        sds_mt.c: added read-only file support

  0     23-Nov-04       scp.c:
                        - added reset_all_p (powerup)
                        - fixed comma-separated SET options (Dave Bryan)
                        - changed ONLINE/OFFLINE to ENABLED/DISABLED (Dave Bryan)
                        - modified to flush device buffers on stop (Dave Bryan)
                        - changed HELP to suppress duplicate command displays

                        sim_console.c:
                        - moved SET/SHOW DEBUG under CONSOLE hierarchy

                        hp2100_cpu.c: (all fixes by Dave Bryan)
                        - moved MP into its own device; added MP option jumpers
                        - modified DMA to allow disabling
                        - modified SET CPU 2100/2116 to truncate memory > 32K
                        - added -F switch to SET CPU to force memory truncation
                        - fixed S-register behavior on 2116
                        - fixed LIx/MIx behavior for DMA on 2116 and 2100
                        - fixed LIx/MIx behavior for empty I/O card slots
                        - modified WRU to be REG_HRO
                        - added BRK and DEL to save console settings
                        - fixed use of "unsigned int16" in cpu_reset

                        hp2100_dp.c: (all fixes by Dave Bryan)
                        - fixed enable/disable from either device
                        - fixed ANY ERROR status for 12557A interface
                        - fixed unattached drive status for 12557A interface
                        - status cmd without prior STC DC now completes (12557A)
                        - OTA/OTB CC on 13210A interface also does CLC CC
                        - fixed RAR model
                        - fixed seek check on 13210 if sector out of range

                        hp2100_dq.c: (all fixes by Dave Bryan)
                        - fixed enable/disable from either device
                        - shortened xtime from 5 to 3 (drive avg 156KW/second)
                        - fixed not ready/any error status
                        - fixed RAR model

                        hp2100_dr.c: (all fixes by Dave Bryan)
                        - fixed enable/disable from either device
                        - fixed sector return in status word
                        - provided protected tracks and "Writing Enabled" status bit
                        - fixed DMA last word write, incomplete sector fill value
                        - added "parity error" status return on writes for 12606
                        - added track origin test for 12606
                        - added SCP test for 12606
                        - fixed 12610 SFC operation
                        - added "Sector Flag" status bit
                        - added "Read Inhibit" status bit for 12606
                        - fixed current-sector determination
                        - added TRACKPROT modifier

                        hp2100_ipl.c, hp2100_ms.c: (all fixes by Dave Bryan)
                        - fixed enable/disable from either device

                        hp2100_lps.c: (all fixes by Dave Bryan)
                        - added SET OFFLINE/ONLINE, POWEROFF/POWERON
                        - fixed status returns for error conditions
                        - fixed handling of non-printing characters
                        - fixed handling of characters after column 80
                        - improved timing model accuracy for RTE
                        - added fast/realistic timing
                        - added debug printouts

                        hp2100_lpt.c: (all fixes by Dave Bryan)
                        - added SET OFFLINE/ONLINE, POWEROFF/POWERON
                        - fixed status returns for error conditions
                        - fixed TOF handling so form remains on line 0

                        hp2100_stddev.c (all fixes by Dave Bryan)
                        - added paper tape loop mode, DIAG/READER modifiers to PTR
                        - added PV_LEFT to PTR TRLLIM register
                        - modified CLK to permit disable

                        hp2100_sys.c: (all fixes by Dave Bryan)
                        - added memory protect device
                        - fixed display of CCA/CCB/CCE instructions

                        i1401_cpu.c: added =n to SHOW HISTORY

                        id16_cpu.c: added instruction history

                        id32_cpu.c: added =n to SHOW HISTORY

                        pdp10_defs.h: revised Unibus DMA API's

                        pdp10_ksio.c: revised Unibus DMA API's

                        pdp10_lp20.c: revised Unibus DMA API's

                        pdp10_rp.c: replicated register state per drive

                        pdp10_tu.c:
                        - fixed to set FCE on short record
                        - fixed to return bit<15> in drive type
                        - fixed format specification, 1:0 are don't cares
                        - implemented write check
                        - TMK is cleared by new motion command, not DCLR
                        - DONE is set on data transfers, ATA on non data transfers

                        pdp11_defs.h: 
                        - revised Unibus/Qbus DMA API's
                        - added CPU type and options flags

                        pdp11_cpumod.h, pdp11_cpumod.c:
                        - new routines for setting CPU type and options

                        pdp11_io.c: revised Unibus/Qbus DMA API's

                        all PDP-11 DMA peripherals:
                        - revised Unibus/Qbus DMA API's

                        pdp11_hk.c: CS2 OR must be zero for M+

                        pdp11_rh.c, pdp11_rp.c, pdp11_tu.c:
                        - split Massbus adapter from controllers
                        - replicated RP register state per drive
                        - added TM02/TM03 with TE16/TU45/TU77 drives

                        pdp11_rq.c, pdp11_tq.c:
                        - provided different default timing for PDP-11, VAX
                        - revised to report CPU bus type in stage 1
                        - revised to report controller type reflecting bus type
                        - added -L switch (LBNs) to RAUSER size specification

                        pdp15_cpu.c: added =n to SHOW HISTORY

                        pdp15_fpp.c:
                        - fixed URFST to mask low 9b of fraction
                        - fixed exception PC setting

                        pdp8_cpu.c: added =n to SHOW HISTORY

                        vax_defs.h:
                        - added octaword, compatibility mode support

                        vax_moddefs.h: 
                        - revised Unibus/Qbus DMA API's

                        vax_cpu.c:
                        - moved processor-specific code to vax_sysdev.c
                        - added =n to SHOW HISTORY

                        vax_cpu1.c:
                        - moved processor-specific IPR's to vax_sysdev.c
                        - moved emulation trap to vax_cis.c
                        - added support for compatibility mode

                        vax_cis.c: new full VAX CIS instruction emulator

                        vax_octa.c: new full VAX octaword and h_floating instruction emulator

                        vax_cmode.c: new full VAX compatibility mode instruction emulator

                        vax_io.c:
                        - revised Unibus/Qbus DMA API's

                        vax_io.c, vax_stddev.c, vax_sysdev.c:
                        - integrated powerup into RESET (with -p)

                        vax_sys.c:
                        - fixed bugs in parsing indirect displacement modes
                        - fixed bugs in displaying and parsing character data

                        vax_syscm.c: added display and parse for compatibility mode

                        vax_syslist.c:
                        - split from vax_sys.c
                        - removed PTR, PTP

   V3.2 revision history 

  3     03-Sep-04       scp.c:
                        - added ECHO command (Dave Bryan)
                        - qualified RESTORE detach with SIM_SW_REST

                        sim_console: added OS/2 EMX fixes (Holger Veit)

                        sim_sock.h: added missing definition for OS/2 (Holger Veit)

                        hp2100_cpu.c: changed error stops to report PC not PC + 1
                        (Dave Bryan)

                        hp2100_dp.c: functional and timing fixes (Dave Bryan)
                        - controller sets ATN for all commands except read status
                        - controller resumes polling for ATN interrupts after read status
                        - check status on unattached drive set busy and not ready
                        - check status tests wrong unit for write protect status
                        - drive on line sets ATN, will set FLG if polling

                        hp2100_dr.c: fixed CLC to stop operation (Dave Bryan)

                        hp2100_ms.c: functional and timing fixes (Dave Bryan)
                        - fixed erroneous execution of rejected command
                        - fixed erroneous execution of select-only command
                        - fixed erroneous execution of clear command
                        - fixed odd byte handling for read
                        - fixed spurious odd byte status on 13183A EOF
                        - modified handling of end of medium
                        - added detailed timing, with fast and realistic modes
                        - added reel sizes to simulate end of tape
                        - added debug printouts

                        hp2100_mt.c: modified handling of end of medium (Dave Bryan)

                        hp2100_stddev.c: added tab to control char set (Dave Bryan)

                        pdp11_rq.c: VAX controllers luns start at 0 (Andreas Cejna)

                        vax_cpu.c: fixed bug in EMODD/G, second word of quad dst not probed

  2     17-Jul-04       scp.c: fixed problem ATTACHing to read only files
                        (John Dundas)

                        sim_console.c: revised Windows console code (Dave Bryan)

                        sim_fio.c: fixed problem in big-endian read
                        (reported by Scott Bailey)

                        gri_cpu.c: updated MSR, EAO functions

                        hp_stddev.c: generalized handling of control char echoing
                        (Dave Bryan)

                        vax_sys.c: fixed bad block initialization routine

  1     10-Jul-04       scp.c: added SET/SHOW CONSOLE subhierarchy

                        hp2100_cpu.c: fixes and added features (Dave Bryan)
                        - SBT increments B after store
                        - DMS console map must check dms_enb
                        - SFS x,C and SFC x,C work
                        - MP violation clears automatically on interrupt
                        - SFS/SFC 5 is not gated by protection enabled
                        - DMS enable does not disable mem prot checks
                        - DMS status inconsistent at simulator halt
                        - Examine/deposit are checking wrong addresses
                        - Physical addresses are 20b not 15b
                        - Revised DMS to use memory rather than internal format
                        - Added instruction printout to HALT message
                        - Added M and T internal registers
                        - Added N, S, and U breakpoints
                        Revised IBL facility to conform to microcode
                        Added DMA EDT I/O pseudo-opcode
                        Separated DMA SRQ (service request) from FLG

                        all HP2100 peripherals:
                        - revised to make SFS x,C and SFC x,C work
                        - revised to separate SRQ from FLG

                        all HP2100 IBL bootable peripherals:
                        - revised boot ROMs to use IBL facility
                        - revised SR values to preserve SR<5:3>

                        hp2100_lps.c, hp2100_lpt.c: fixed timing
                        
                        hp2100_dp.c: fixed interpretation of SR<0>

                        hp2100_dr.c: revised boot code to use IBL algorithm

                        hp2100_mt.c, hp2100_ms.c: fixed spurious timing error after CLC
                         (Dave Bryan)

                        hp2100_stddev.c:
                        - fixed input behavior during typeout for RTE-IV
                        - suppressed nulls on TTY output for RTE-IV

                        hp2100_sys.c: added SFS x,C and SFC x,C to print/parse routines

                        pdp10_fe.c, pdp11_stddev.c, pdp18b_stddev.c, pdp8_tt.c, vax_stddev.c:
                        - removed SET TTI CTRL-C option

                        pdp11_tq.c:
                        - fixed bug in reporting write protect (reported by Lyle Bickley)
                        - fixed TK70 model number and media ID (Robert Schaffrath)

                        pdp11_vh.c: added DHQ11 support (John Dundas)

                        pdp11_io.c, vax_io.c: fixed DHQ11 autoconfigure (John Dundas)

                        pdp11_sys.c, vax_sys.c: added DHQ11 support (John Dundas)

                        vax_cpu.c: fixed bug in DIVBx, DIVWx (reported by Peter Trimmel)

  0     04-Apr-04       scp.c:
                        - added sim_vm_parse_addr and sim_vm_fprint_addr
                        - added REG_VMAD
                        - moved console logging to SCP
                        - changed sim_fsize to use descriptor rather than name
                        - added global device/unit show modifiers
                        - added device debug support (Dave Hittner)
                        - moved device and unit flags, updated save format

                        sim_ether.c:
                        - further generalizations (Dave Hittner, Mark Pizzolato)

                        sim_tmxr.h, sim_tmxr.c:
                        - added tmxr_linemsg
                        - changed TMXR definition to support variable number of lines

                        sim_libraries:
                        - new console library (sim_console.h, sim_console.c)
                        - new file I/O library (sim_fio.h, sim_fio.c)
                        - new timer library (sim_timer.h, sim_timer.c)

                        all terminal multiplexors: revised for tmxr library changes

                        all DECtapes:
                        - added STOP_EOR to enable end-of-reel stop
                        - revised for device debug support

                        all variable-sized devices: revised for sim_fsize change

                        eclipse_cpu.c, nova_cpu.c: fixed device enable/disable support
                           (Bruce Ray)

                        nova_defs.h, nova_sys.c, nova_qty.c:
                        - added QTY and ALM support (Bruce Ray)

                        id32_cpu.c, id_dp.c: revised for device debug support

                        lgp: added LGP-30 [LGP-21] simulator

                        pdp1_sys.c: fixed bug in LOAD (Mark Crispin)

                        pdp10_mdfp.c:
                        - fixed bug in floating unpack
                        - fixed bug in FIXR (Philip Stone, fixed by Chris Smith)

                        pdp11_dz.c: added per-line logging

                        pdp11_rk.c:
                        - added formatting support
                        - added address increment inhibit support
                        - added transfer overrun detection

                        pdp11_hk.c, pdp11_rp.c: revised for device debug support

                        pdp11_rq.c: fixed bug in interrupt control (Tom Evans)

                        pdp11_ry.c: added VAX support

                        pdp11_tm.c, pdp11_tq.c, pdp11_ts.c: revised for device debug support

                        pdp11_xu.c: replaced stub with real implementation (Dave Hittner)

                        pdp18b_cpu.c:
                        - fixed bug in XVM g_mode implementation
                        - fixed bug in PDP-15 indexed address calculation
                        - fixed bug in PDP-15 autoindexed address calculation

                        pdp18b_fpp.c: fixed bugs in instruction decode

                        pdp18b_stddev.c:
                        - fixed clock response to CAF
                        - fixed bug in hardware read-in mode bootstrap

                        pdp18b_sys.c: fixed XVM instruction decoding errors

                        pdp18b_tt1.c: added support for 1-16 additional terminals

                        vax_moddef.h, vax_cpu.c, vax_sysdev.c:
                        - added extended physical memory support (Mark Pizzolato)
                        - added RXV21 support

                        vax_cpu1.c:
                        - added PC read fault in EXTxV
                        - fixed PC write fault in INSV

   V3.1 revision history

  0     29-Dec-03       sim_defs.h, scp.c: added output stall status

                        all console emulators: added output stall support

                        sim_ether.c (Dave Hittner, Mark Pizzolato, Anders Ahgren):
                        - added Alpha/VMS support
                        - added FreeBSD, Mac OS/X support
                        - added TUN/TAP support
                        - added DECnet duplicate address detection

                        all memory buffered devices (fixed head disks, floppy disks):
                        - cleaned up buffer copy code

                        all DECtapes:
                        - fixed reverse checksum in read all
                        - added DECtape off reel message
                        - simplified timing

                        eclipse_cpu.c (Charles Owen):
                        - added floating point support
                        - added programmable interval timer support
                        - bug fixes

                        h316_cpu.c:
                        - added instruction history
                        - added DMA/DMC support
                        - added device ENABLE/DISABLE support
                        - change default to HSA option included

                        h316_dp.c: added moving head disk support

                        h316_fhd.c: added fixed head disk support

                        h316_mt.c: added magtape support

                        h316_sys.c: added new device support

                        nova_dkp.c (Charles Owen):
                        - fixed bug in flag clear sequence
                        - added diagnostic mode support for disk sizing

`                       nova_mt.c (Charles Owen):
                        - fixed bug, space operations return record count
                        - fixed bug, reset doesn't cancel rewind

                        nova_sys.c: added floating point, timer support (Charles Owen)

                        i1620_cpu.c: fixed bug in branch digit (Dave Babcock)

                        pdp1_drm.c:
                        - added parallel drum support
                        - fixed bug in serial drum instructin decoding

                        pdp1_sys.c: added parallel drum support, mnemonics

                        pdp11_cpu.c:
                        - added autoconfiguration controls
                        - added support for 18b-only Qbus devices
                        - cleaned up addressing/bus definitions

                        pdp11_rk.c, pdp11_ry.c, pdp11_tm.c, pdp11_hk.c:
                        - added Q18 attribute

                        pdp11_io.c:
                        - added autoconfiguration controls
                        - fixed bug in I/O configuration (Dave Hittner)

                        pdp11_rq.c:
                        - revised MB->LBN conversion for greater accuracy
                        - fixed bug with multiple RAUSER drives

                        pdp11_tc.c: changed to be off by default (base config is Qbus)

                        pdp11_xq.c (Dave Hittner, Mark Pizzolato):
                        - fixed second controller interrupts
                        - fixed bugs in multicast and promiscuous setup
  
                        pdp18b_cpu.c:
                        - added instruction history
                        - fixed PDP-4,-7,-9 autoincrement bug
                        - change PDP-7,-9 default to API option included

                        pdp8_defs.h, pdp8_sys.c:
                        - added DECtape off reel message
                        - added support for TSC8-75 (ETOS) option
                        - added support for TD8E controller

                        pdp8_cpu.c: added instruction history

                        pdp8_rx.c:
                        - fixed bug in RX28 read status (Charles Dickman)
                        - fixed double density write

                        pdp8_td.c: added TD8E controller

                        pdp8_tsc.c: added TSC8-75 option

                        vax_cpu.c:
                        - revised instruction history for dynamic sizing
                        - added autoconfiguration controls

                        vax_io.c:
                        - added autoconfiguration controls
                        - fixed bug in I/O configuration (Dave Hittner)

                        id16_cpu.c: revised instruction decoding

                        id32_cpu.c:
                        - revised instruction decoding
                        - added instruction history

   V3.0 revision history 

  2     15-Sep-03       scp.c:
                        - fixed end-of-file problem in dep, idep
                        - fixed error on trailing spaces in dep, idep

                        pdp1_stddev.c
                        - fixed system hang if continue after PTR error
                        - added PTR start/stop functionality
                        - added address switch functionality to PTR BOOT

                        pdp1_sys.c: added multibank capability to LOAD
  
                        pdp18b_cpu.c:
                        - fixed priorities in PDP-15 API (PI between 3 and 4)
                        - fixed sign handling in PDP-15 unsigned mul/div
                        - fixed bug in CAF, must clear API subsystem

                        i1401_mt.c:
                        - fixed tape read end-of-record handling based on real 1401
                        - added diagnostic read (space forward)

                        i1620_cpu.c
                        - fixed bug in immediate index add (Michael Short)

  1     27-Jul-03       pdp1_cpu.c: updated to detect indefinite I/O wait

                        pdp1_drm.c: fixed incorrect logical, missing activate, break

                        pdp1_lp.c:
                        - fixed bugs in instruction decoding, overprinting
                        - updated to detect indefinite I/O wait

                        pdp1_stddev.c:
                        - changed RIM loader to be "hardware"
                        - updated to detect indefinite I/O wait

                        pdp1_sys.c: added block loader format support to LOAD

                        pdp10_rp.c: fixed bug in read header

                        pdp11_rq: fixed bug in user disk size (Chaskiel M Grundman)

                        pdp18b_cpu.c:
                        - added FP15 support
                        - added XVM support
                        - added EAE support to the PDP-4
                        - added PDP-15 "re-entrancy ECO"
                        - fixed memory protect/skip interaction
                        - fixed CAF to only reset peripherals

                        pdp18b_fpp.c: added FP15

                        pdp18b_lp.c: fixed bug in Type 62 overprinting

                        pdp18b_rf.c: fixed bug in set size routine

                        pdp18b_stddev.c:
                        - increased PTP TIME for PDP-15 operating systems
                        - added hardware RIM loader for PDP-7, PDP-9, PDP-15

                        pdp18b_sys.c: added FP15, KT15, XVM instructions

                        pdp8b_df.c, pdp8_rf.c: fixed bug in set size routine

                        hp2100_dr.c:
                        - fixed drum sizes
                        - fixed variable capacity interaction with SAVE/RESTORE

                        i1401_cpu.c: revised fetch to model hardware more closely

                        ibm1130: fixed bugs found by APL 1130

                        nova_dsk.c: fixed bug in set size routine

                        altairz80: fixed bug in real-time clock on Windows host

  0     15-Jun-03       scp.c:
                        - added ASSIGN/DEASSIGN
                        - changed RESTORE to detach files
                        - added u5, u6 unit fields
                        - added USE_ADDR64 support
                        - changed some structure fields to unsigned

                        scp_tty.c: added extended file seek

                        sim_sock.c: fixed calling sequence in stubs

                        sim_tape.c:
                        - added E11 and TPC format support
                        - added extended file support

                        sim_tmxr.c: fixed bug in SHOW CONNECTIONS

                        all magtapes:
                        - added multiformat support
                        - added extended file support

                        i1401_cpu.c:
                        - fixed mnemonic, instruction lengths, and reverse
                           scan length check bug for MCS
                        - fixed MCE bug, BS off by 1 if zero suppress
                        - fixed chaining bug, D lost if return to SCP
                        - fixed H branch, branch occurs after continue
                        - added check for invalid 8 character MCW, LCA

                        i1401_mt.c: fixed load-mode end of record response

                        nova_dsk.c: fixed variable size interaction with restore

                        pdp1_dt.c: fixed variable size interaction with restore

                        pdp10_rp.c: fixed ordering bug in attach

                        pdp11_cpu.c:
                        - fixed bug in MMR1 update (Tim Stark)
                        - fixed bug in memory size table

                        pdp11_lp.c, pdp11_rq.c: added extended file support

                        pdp11_rl.c, pdp11_rp.c, pdp11_ry.c: fixed ordering bug in attach

                        pdp11_tc.c: fixed variable size interaction with restore

                        pdp11_xq.c:
                        - corrected interrupts on IE state transition (code by Tom Evans)
                        - added interrupt clear on soft reset (first noted by Bob Supnik)
                        - removed interrupt when setting XL or RL (multiple people)
                        - added SET/SHOW XQ STATS
                        - added SHOW XQ FILTERS
                        - added ability to split received packet into multiple buffers
                        - added explicit runt & giant packet processing

                        vax_fpa.c:
                        - fixed integer overflow bug in CVTfi
                        - fixed multiple bugs in EMODf

                        vax_io.c: optimized byte and word DMA routines

                        vax_sysdev.c:
                        - added calibrated delay to ROM reads (Mark Pizzolato)
                        - fixed calibration problems in interval timer (Mark Pizzolato)

                        pdp1_dt.c: fixed variable size interaction with restore

                        pdp18b_dt.c: fixed variable size interaction with restore

                        pdp18b_mt.c: fixed bug in MTTR

                        pdp18b_rf.c: fixed variable size interaction with restore

                        pdp8_df.c, pdp8_rf.c: fixed variable size interaction
                        with restore

                        pdp8_dt.c: fixed variable size interaction with restore

                        pdp8_mt.c: fixed bug in SKTR

                        hp2100_dp.c,hp2100_dq.c:
                        - fixed bug in read status (13210A controller)
                        - fixed bug in seek completion

                        id_pt.c: fixed type declaration (Mark Pizzolato)

                        gri_cpu.c: fixed bug in SC queue pointer management

   V2.10 revision history

  4     03-Mar-03       scp.c
                        - added .ini startup file capability
                        - added multiple breakpoint actions
                        - added multiple switch evaluation points
                        - fixed bug in multiword deposits to file

                        sim_tape.c: magtape simulation library

                        h316_stddev.c: added set line frequency command

                        hp2100_mt.c, hp2100_ms.c: revised to use magtape library

                        i1401_mt.c: revised to use magtape library

                        id_dp.c, id_idc.c: fixed cylinder overflow on writes

                        id_mt.c:
                        - fixed error handling to stop selector channel
                        - revised to use magtape library

                        id16_sys.c, id32_sys.c: added relative addressing support

                        id_uvc.c:
                        - added set frequency command to line frequency clock
                        - improved calibration algorithm for precision clock

                        nova_clk.c: added set line frequency command

                        nova_dsk.c: fixed autosizing algorithm

                        nova_mt.c: revised to use magtape library

                        pdp10_tu.c: revised to use magtape library

                        pdp11_cpu.c: fixed bug in MMR1 update (Tim Stark)

                        pdp11_stddev.c
                        - added set line frequency command
                        - added set ctrl-c command

                        pdp11_rq.c:
                        - fixed ordering problem in queue process
                        - fixed bug in vector calculation for VAXen
                        - added user defined drive support

                        pdp11_ry.c: fixed autosizing algorithm

                        pdp11_tm.c, pdp11_ts.c: revised to use magtape library

                        pdp11_tq.c:
                        - fixed ordering problem in queue process
                        - fixed overly restrictive test for bad modifiers
                        - fixed bug in vector calculation for VAXen
                        - added variable controller, user defined drive support
                        - revised to use magtape library

                        pdp18b_cpu.c: fixed three EAE bugs (Hans Pufal)

                        pdp18b_mt.c:
                        - fixed bugs in BOT error handling, interrupt handling
                        - revised to use magtape library

                        pdp18b_rf.c:
                        - removed 22nd bit from disk address
                        - fixed autosizing algorithm

                        pdp18b_stddev.c:
                        - added set line frequency command
                        - added set ctrl-c command

                        pdp18b_sys.c: fixed FMTASC printouts (Hans Pufal)

                        pdp8_clk.c: added set line frequency command

                        pdp8_df.c, pdp8_rf.c, pdp8_rx.c: fixed autosizing algorithm

                        pdp8_mt.c:
                        - fixed bug in BOT error handling
                        - revised to use magtape library

                        pdp8_tt.c: added set ctrl-c command

                        sds_cpu.c: added set line frequency command

                        sds_mt.c: revised to use magtape library

                        vax_stddev.c: added set ctrl-c command

  3     06-Feb-03       scp.c:
                        - added dynamic extension of the breakpoint table
                        - added breakpoint actions

                        hp2100_cpu.c: fixed last cycle bug in DMA output (found by
                        Mike Gemeny)

                        hp2100_ipl.c: individual links are full duplex (found by
                        Mike Gemeny)

                        pdp11_cpu.c: changed R, SP to track PSW<rs,cm> respectively

                        pdp18b_defs.h, pdp18b_sys.c: added RB09 fixed head disk,
                        LP09 printer

                        pdp18b_rf.c:
                        - fixed IOT decoding (Hans Pufal)
                        - fixed address overrun logic
                        - added variable number of platters and autosizing

                        pdp18b_rf.c:
                        - fixed IOT decoding
                        - fixed bug in command initiation

                        pdp18b_rb.c: new RB09 fixed head disk

                        pdp18b_lp.c: new LP09 line printer

                        pdp8_df.c: added variable number of platters and autosizing

                        pdp8_rf.c: added variable number of platters and autosizing

                        nova_dsk.c: added variable number of platters and autosizing

                        id16_cpu.c: fixed bug in SETM, SETMR (Mark Pizzolato)

  2     15-Jan-03       scp.c:
                        - added dynamic memory size flag and RESTORE support
                        - added EValuate command
                        - added get_ipaddr routine
                        - added ! (OS command) feature (Mark Pizzolato)
                        - added BREAK support to sim_poll_kbd (Mark Pizzolato)

                        sim_tmxr.c:
                        - fixed bugs in IAC+IAC handling (Mark Pizzolato)
                        - added IAC+BRK handling (Mark Pizzolato)

                        sim_sock.c:
                        - added use count for Windows start/stop
                        - added sim_connect_sock

                        pdp1_defs.h, pdp1_cpu.c, pdp1_sys.c, pdp1_drm.c:
                        added Type 24 serial drum

                        pdp18_defs.h: added PDP-4 drum support

                        hp2100_cpu.c: added 21MX IOP support

                        hp2100_ipl.c: added HP interprocessor link support

                        pdp11_tq.c: fixed bug in transfer end packet length

                        pdp11_xq.c:
                        - added VMScluster support (thanks to Mark Pizzolato)
                        - added major performance enhancements (thanks to Mark Pizzolato)
                        - added local packet processing
                        - added system id broadcast

                        pdp11_stddev.c: changed default to 7b (for early UNIX)

                        vax_cpu.c, vax_io.c, vax_stddev.c, vax_sysdev.c:
                        added console halt capability (Mark Pizzolato)

                        all terminals and multiplexors: added BREAK support

  1     21-Nov-02       pdp1_stddev.c: changed typewriter to half duplex
                        (Derek Peschel)

                        pdp10_tu.c:
                        - fixed bug in bootstrap (reported by Michael Thompson)
                        - fixed bug in read (reported by Harris Newman)

  0     15-Nov-02       SCP and libraries
                        scp.c:
                        - added Telnet console support
                        - removed VT emulation support
                        - added support for statically buffered devices
                        - added HELP <command>
                        - fixed bugs in set_logon, ssh_break (David Hittner)
                        - added VMS file optimization (Robert Alan Byer)
                        - added quiet mode, DO with parameters, GUI interface,
                           extensible commands (Brian Knittel)
                        - added DEVICE context and flags
                        - added central device enable/disable support
                        - modified SAVE/GET to save and restore flags
                        - modified boot routine calling sequence
                        scp_tty.c:
                        - removed VT emulation support
                        - added sim_os_sleep, renamed sim_poll_kbd, sim_putchar
                        sim_tmxr.c:
                        - modified for Telnet console support
                        - fixed bug in binary (8b) support
                        sim_sock.c: modified for Telnet console support
                        sim_ether.c: new library for Ethernet (David Hittner)

                        all magtapes:
                        - added support for end of medium
                        - cleaned up BOT handling

                        all DECtapes: added support for RT11 image file format

                        most terminals and multiplexors:
                        - added support for 7b vs 8b character processing

                        PDP-1
                        pdp1_cpu.c, pdp1_sys.c, pdp1_dt.c: added PDP-1 DECtape support

                        PDP-8
                        pdp8_cpu.c, all peripherals:
                        - added variable device number support
                        - added new device enabled/disable support
                        pdp8_rx.c: added RX28/RX02 support

                        PDP-11
                        pdp11_defs.h, pdp11_io.c, pdp11_sys.c, all peripherals:
                        - added variable vector support
                        - added new device enable/disable support
                        - added autoconfiguration support
                        all bootstraps: modified to support variable addresses
                        dec_mscp.h, pdp11_tq.c: added TK50 support
                        pdp11_rq.c:
                        - added multicontroller support
                        - fixed bug in HBE error log packet
                        - fixed bug in ATP processing
                        pdp11_ry.c: added RX211/RX02 support
                        pdp11_hk.c: added RK611/RK06/RK07 support
                        pdp11_tq.c: added TMSCP support
                        pdp11_xq.c: added DEQNA/DELQA support (David Hittner)
                        pdp11_pclk.c: added KW11P support
                        pdp11_ts.c:
                        - fixed bug in CTL decoding
                        - fixed bug in extended status XS0_MOT
                        pdp11_stddev.c: removed paper tape to its own module

                        PDP-18b
                        pdp18b_cpu.c, all peripherals:
                        - added variable device number support
                        - added new device enabled/disabled support

                        VAX
                        dec_dz.h: fixed bug in number of boards calculation
                        vax_moddefs.h, vax_io.c, vax_sys.c, all peripherals:
                        - added variable vector support
                        - added new device enable/disable support
                        - added autoconfiguration support
                        vax_sys.c:
                        - generalized examine/deposit
                        - added TMSCP, multiple RQDX3, DEQNA/DELQA support
                        vax_stddev.c: removed paper tape, now uses PDP-11 version
                        vax_sysdev.c:
                        - allowed NVR to be attached to file
                        - removed unused variables (David Hittner)

                        PDP-10
                        pdp10_defs.h, pdp10_ksio.c, all peripherals:
                        - added variable vector support
                        - added new device enable/disable support
                        pdp10_defs.h, pdp10_ksio.c: added support for standard PDP-11
                           peripherals, added RX211 support
                        pdp10_pt.c: rewritten to reference common implementation

                        Nova, Eclipse:
                        nova_cpu.c, eclipse_cpu.c, all peripherals:
                        - added new device enable/disable support

                        HP2100
                        hp2100_cpu:
                        - fixed bugs in the EAU, 21MX, DMS, and IOP instructions
                        - fixed bugs in the memory protect and DMS functions
                        - created new options to enable/disable EAU, MPR, DMS
                        - added new device enable/disable support
                        hp2100_fp.c:
                        - recoded to conform to 21MX microcode algorithms
                        hp2100_stddev.c:
                        - fixed bugs in TTY reset, OTA, time base generator
                        - revised BOOT support to conform to RBL loader
                        - added clock calibration
                        hp2100_dp.c:
                        - changed default to 13210A
                        - added BOOT support
                        hp2100_dq.c:
                        - finished incomplete functions, fixed head switching
                        - added BOOT support
                        hp2100_ms.c:
                        - fixed bugs found by diagnostics
                        - added 13183 support
                        - added BOOT support
                        hp2100_mt.c:
                        - fixed bugs found by diagnostics
                        - disabled by default
                        hp2100_lpt.c: implemented 12845A controller
                        hp2100_lps.c:
                        - renamed 12653A controller
                        - added diagnostic mode for MPR, DCPC diagnostics
                        - disabled by default

                        IBM 1620: first release

   V2.9 revision history

  11    20-Jul-02       i1401_mt.c: on read, end of record stores group mark
                           without word mark (Van Snyder)

                        i1401_dp.c: reworked address generation and checking

                        vax_cpu.c: added infinite loop detection and halt to
                           boot ROM option (Mark Pizzolato)

                        vax_fpa.c: changed function names to prevent conflict
                           with C math library

                        pdp11_cpu.c: fixed bug in MMR0 update logic (from
                           John Dundas)

                        pdp18b_stddev.c: added "ASCII mode" for reader and
                           punch (Hans Pufal)

                        gri_*.c: added GRI-909 simulator

                        scp.c: added DO echo, DO exit (Brian Knittel)

                        scp_tty.c: added Windows priority hacking (from
                           Mark Pizzolato)

  10    15-Jun-02       scp.c: fixed error checking on calls to fxread/fxwrite
                           (Norm Lastovic)

                        scp_tty.c, sim_vt.h, sim_vt.c: added VTxxx emulation
                           support for Windows (Fischer Franz)

                        sim_sock.c: added OS/2 support (Holger Veit)

                        pdp11_cpu.c: fixed bugs (John Dundas)
                        - added special case for PS<15:12> = 1111 to MFPI
                        - removed special case from MTPI
                        - added masking of relocation adds 

                        i1401_cpu.c:
                        - added multiply/divide
                        - fixed bugs (Van Snyder)
                           o 5 and 7 character H, 7 character doesn't branch
                           o 8 character NOP
                           o 1401-like memory dump

                        i1401_dp.c: added 1311 disk

  9     04-May-02       pdp11_rq: fixed bug in polling routine

  8     03-May-02       scp.c:
                        - changed LOG/NOLOG to SET LOG/NOLOG
                        - added SHOW LOG
                        - added SET VT/NOVT and SHOW VT for VT emulation
  
                        sim_sock.h: changed VMS stropt.h include to ioctl.h

                        vax_cpu.c
                        - added TODR powerup routine to set date, time on boot
                        - fixed exception flows to clear trap request
                        - fixed register logging in autoincrement indexed

                        vax_stddev.c: added TODR powerup routine
                        
                        vax_cpu1.c: fixed exception flows to clear trap request

  7     30-Apr-02       scp.c: fixed bug in clock calibration when (real) clock
                           jumps forward due too far (Jonathan Engdahl)
  
                        pdp11_cpu.c: fixed bugs, added features (John Dundas
                           and Wolfgang Helbig)
                        - added HTRAP and BPOK to maintenance register
                        - added trap on kernel HALT if MAINT<HTRAP> set
                        - fixed red zone trap, clear odd address and nxm traps
                        - fixed RTS SP, don't increment restored SP
                        - fixed TSTSET, write dst | 1 rather than prev R0 | 1
                        - fixed DIV, set N=0,Z=1 on div by zero (J11, 11/70)
                        - fixed DIV, set set N=Z=0 on overfow (J11, 11/70)
                        - fixed ASH, ASHC, count = -32 used implementation-
                           dependent 32 bit right shift
                        - fixed illegal instruction test to detect 000010
                        - fixed write-only page test

                        pdp11_rp.c: fixed SHOW ADDRESS command

                        vaxmod_defs.h: fixed DZ vector base and number of lines

                        dec_dz.h:
                        - fixed interrupt acknowledge routines
                        - fixed SHOW ADDRESS command

                        all magtape routines: added test for badly formed
                           record length (suggested by Jonathan Engdahl)

  6     18-Apr-02       vax_cpu.c: fixed CASEL condition codes

                        vax_cpu1.c: fixed vfield pos > 31 test to be unsigned

                        vax_fpu.c: fixed EDIV overflow test for 0 quotient

  5     14-Apr-02       vax_cpu1.c:
                        - fixed interrupt, prv_mode set to 0 (Tim Stark)
                        - fixed PROBEx to mask mode to 2b (Kevin Handy)

  4     1-Apr-02        pdp11_rq.c: fixed bug, reset cleared write protect status

                        pdp11_ts.c: fixed bug in residual frame count after space

  3     15-Mar-02       pdp11_defs.h: changed default model to KDJ11A (11/73)

                        pdp11_rq.c: adjusted delays for M+ timing bugs

                        hp2100_cpu.c, pdp10_cpu.c, pdp11_cpu.c: tweaked abort
                           code for ANSI setjmp/longjmp compliance

                        hp2100_cpu.c, hp2100_fp.c, hp2100_stddev.c, hp2100_sys.c:
                           revised to allocate memory dynamically

  2     01-Mar-02       pdp11_cpu.c:
                        - fixed bugs in CPU registers
                        - fixed double operand evaluation order for M+

                        pdp11_rq.c: added delays to initialization for
                           RSX11M+ prior to V4.5

  1     20-Feb-02       scp.c: fixed bug in clock calibration when (real)
                        time runs backwards

                        pdp11_rq.c: fixed bug in host timeout logic

                        pdp11_ts.c: fixed bug in message header logic

                        pdp18b_defs.h, pdp18b_dt.c, pdp18b_sys.c: added
                           PDP-7 DECtape support

                        hp2100_cpu.c:
                        - added floating point and DMS
                        - fixed bugs in DIV, ASL, ASR, LBT, SBT, CBT, CMW

                        hp2100_sys.c: added floating point, DMS

                        hp2100_fp.c: added floating point

                        ibm1130: added Brian Knittel's IBM 1130 simulator

  0     30-Jan-02       scp.c:
                        - generalized timer package for multiple timers
                        - added circular register arrays
                        - fixed bugs, line spacing in modifier display
                        - added -e switch to attach
                        - moved device enable/disable to simulators

                        scp_tty.c: VAX specific fix (Robert Alan Byer)

                        sim_tmxr.c, sim_tmxr.h:
                        - added tmxr_fstats, tmxr_dscln
                        - renamed tmxr_fstatus to tmxr_fconns

                        sim_sock.c, sim_sock.h: added VMS support (from
                        Robert Alan Byer)

                        pdp_dz.h, pdp18b_tt1.c, nova_tt1.c:
                        - added SET DISCONNECT
                        - added SHOW STATISTICS

                        pdp8_defs.h: fixed bug in interrupt enable initialization

                        pdp8_ttx.c: rewrote as unified multiplexor

                        pdp11_cpu.c: fixed calc_MMR1 macro (Robert Alan Byer)

                        pdp11_stddev.c: fixed bugs in KW11L (John Dundas)

                        pdp11_rp.c: fixed bug in 18b mode boot

                        pdp11 bootable I/O devices: fixed register setup at boot
                           exit (Doug Carman)

                        hp2100_cpu.c:
                        - fixed DMA register tables (Bill McDermith)
                        - fixed SZx,SLx,RSS bug (Bill McDermith)
                        - fixed flop restore logic (Bill McDermith)

                        hp2100_mt.c: fixed bug on write of last character

                        hp2100_dq,dr,ms,mux.c: added new disk, magtape, and terminal
                           multiplexor controllers

                        i1401_cd.c, i1401_mt.c: new zero footprint bootstraps
                           (Van Snyder)

                        i1401_sys.c: fixed symbolic display of H, NOP with no trailing
                           word mark (Van Snyder)

                        most CPUs:
                        - replaced OLDPC with PC queue
                        - implemented device enable/disable locally

   V2.8 revision history

5       25-Dec-01       scp.c: fixed bug in DO command (John Dundas)

                        pdp10_cpu.c:
                        - moved trap-in-progress to separate variable
                        - cleaned up declarations
                        - cleaned up volatile state for GNU C longjmp

                        pdp11_cpu.c: cleaned up declarations
  
                        pdp11_rq.c: added RA-class disks

4       17-Dec-01       pdp11_rq.c: added delayed processing of packets

3       16-Dec-01       pdp8_cpu.c:
                        - mode A EAE instructions didn't clear GTF
                        - ASR shift count > 24 mis-set GTF
                        - effective shift count == 32 didn't work

2       07-Dec-01       scp.c: added breakpoint package

                        all CPU's: revised to use new breakpoint package

1       05-Dec-01       scp.c: fixed bug in universal register name logic

0       30-Nov-01       Reorganized simh source and documentation tree

                        scp: Added DO command, universal registers, extended
                           SET/SHOW logic

                        pdp11: overhauled PDP-11 for DMA map support, shared
                           sources with VAX, dynamic buffer allocation

                        18b pdp: overhauled interrupt structure

                        pdp8: added RL8A

                        pdp10: fixed two ITS-related bugs (Dave Conroy)

   V2.7 revision history

patch   date            module(s) and fix(es)

15      23-Oct-01       pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: fixed bugs
                           error interrupt handling

                        pdp10_defs.h, pdp10_ksio.c, pdp10_fe.c, pdp10_fe.c,
                        pdp10_rp.c, pdp10_tu.c: reworked I/O page interface
                           to use symbolic base addresses and lengths

14      20-Oct-01       dec_dz.h, sim_tmxr_h, sim_tmxr.c: fixed bug in Telnet
                           state handling (Thord Nilson), removed
                           tmxr_getchar, added tmxr_rqln and tmxr_tqln

13      18-Oct-01       pdp11_tm.c: added stub diagnostic register clock
                           for RSTS/E (Thord Nilson)

12      15-Oct-01       pdp11_defs.h, pdp11_cpu.c, pdp11_tc.c, pdp11_ts.c,
                           pdp11_rp.c: added operations logging

11      8-Oct-01        scp.c: added sim_rev.h include and version print

                        pdp11_cpu.c: fixed bug in interrupt acknowledge,
                           multiple outstanding interrupts caused the lowest
                           rather than the highest to be acknowledged

10      7-Oct-01        pdp11_stddev.c: added monitor bits (CSR<7>) for full
                           KW11L compatibility, needed for RSTS/E autoconfiguration

9       6-Oct-01        pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: rewrote interrupt
                           logic from RH11/RH70 schematics, to mimic hardware quirks

                        dec_dz.c: fixed bug in carrier detect logic, carrier
                           detect was being cleared on next modem poll

8       4-Oct-01        pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: undid edit of
                           28-Sep-01; real problem was level-sensitive nature of
                           CS1_SC, but CS1_SC can only trigger an interrupt if
                           DONE is set

7       2-Oct-01        pdp11_rp.c, pdp10_rp.c: CS1_SC is evaluated as a level-
                           sensitive, rather than an edge-sensitive, input to
                           interrupt request

6       30-Sep-01       pdp11_rp.c, pdp10_rp.c: separated out CS1<5:0> to per-
                           drive registers

                        pdp10_tu.c: based on above, cleaned up handling of
                           non-existent formatters, fixed non-data transfer
                           commands clearing DONE

5       28-Sep-01       pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: controller should
                           interrupt if ATA or SC sets when IE is set, was
                           interrupting only if DON = 1 as well

4       27-Sep-01       pdp11_ts.c:
                        - NXM errors should return TC4 or TC5; were returning TC3
                        - extended features is part of XS2; was returned in XS3
                        - extended characteristics (fifth) word needed for RSTS/E

                        pdp11_tc.c: stop, stop all do cause an interrupt

                        dec_dz.h: scanner should find a ready output line, even
                           if there are no connections; needed for RSTS/E autoconfigure

                        scp.c:
                        - added routine sim_qcount for 1130
                        - added "simulator exit" detach routine for 1130

                        sim_defs.h: added header for sim_qcount

3       20-Sep-01       pdp11_ts.c: boot code binary was incorrect

2       19-Sep-01       pdp18b_cpu.c: EAE should interpret initial count of 00
                           as 100

                        scp.c: modified Macintosh support

1       17-Sep-01       pdp8_ttx.c: new module for PDP-8 multi-terminal support

                        pdp18b_tt1.c: modified to use sim_tmxr library

                        nova_tt1.c: modified to use sim_tmxr library

                        dec_dz.h: added autodisconnect support

                        scp.c: removed old multiconsole support

                        sim_tmxr.c: modified calling sequence for sim_putchar_ln

                        sim_sock.c: added Macintosh sockets support
*/

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_serial.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
/* sim_serial.c: OS-dependent serial port routines

   Copyright (c) 2008, J. David Bryan

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the author shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from the author.

   The author gratefully acknowledges the assistance of Holger Veit with the
   UNIX-specific code and testing.

   07-Oct-08    JDB     [serial] Created file


   This module provides OS-dependent routines to access serial ports on the host
   machine.  The terminal multiplexer library uses these routines to provide
   serial connections to simulated terminal interfaces.

   Currently, the module supports Windows and UNIX.  Use on other systems
   returns error codes indicating that the functions failed, inhibiting serial
   port support in SIMH.

   The following routines are provided:

     sim_open_serial        open a serial port
     sim_config_serial      change baud rate and character framing configuration
     sim_control_serial     manipulate and/or return the modem bits on a serial port
     sim_read_serial        read from a serial port
     sim_write_serial       write to a serial port
     sim_close_serial       close a serial port
     sim_show_serial        shows the available host serial ports


   The calling sequences are as follows:


   SERHANDLE sim_open_serial (char *name)
   --------------------------------------

   The serial port referenced by the OS-dependent "name" is opened.  If the open
   is successful, and "name" refers to a serial port on the host system, then a
   handle to the port is returned.  If not, then the value INVALID_HANDLE is
   returned.


   t_stat sim_config_serial (SERHANDLE port, const char *config)
   -------------------------------------------------------------

   The baud rate and framing parameters (character size, parity, and number of
   stop bits) of the serial port associated with "port" are set.  If any
   "config" field value is unsupported by the host system, or if the combination
   of values (e.g., baud rate and number of stop bits) is unsupported, SCPE_ARG
   is returned.  If the configuration is successful, SCPE_OK is returned.


   sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
   -------------------------------------------------------------------------------------------------

   The DTR and RTS line of the serial port is set or cleared as indicated in 
   the respective bits_to_set or bits_to_clear parameters.  If the 
   incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, 
   DSR and CTS are returned.

   If unreasonable or nonsense bits_to_set or bits_to_clear bits are 
   specified, then the return status is SCPE_ARG;
   If an error occurs, SCPE_IOERR is returned.


   int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk)
   ----------------------------------------------------------------------------

   A non-blocking read is issued for the serial port indicated by "port" to get
   at most "count" bytes into the string "buffer".  If a serial line break was
   detected during the read, the variable pointed to by "brk" is set to 1.  If
   the read is successful, the actual number of characters read is returned.  If
   no characters were available, then the value 0 is returned.  If an error
   occurs, then the value -1 is returned.


   int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
   ------------------------------------------------------------------

   A write is issued to the serial port indicated by "port" to put "count"
   characters from "buffer".  If the write is successful, the actual number of
   characters written is returned.  If an error occurs, then the value -1 is
   returned.


   void sim_close_serial (SERHANDLE port)
   --------------------------------------

   The serial port indicated by "port" is closed.


   int sim_serial_devices (int max, SERIAL_LIST* list)
   ---------------------------------------------------

   enumerates the available host serial ports


   t_stat sim_show_serial (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, const void* desc)
   ---------------------------------

   displays the available host serial ports

*/


#include "sim_defs.h"
#include "sim_serial.h"
#include "sim_tmxr.h"

#include <ctype.h>

#define SER_DEV_NAME_MAX     256                        /* maximum device name size */
#define SER_DEV_DESC_MAX     256                        /* maximum device description size */
#define SER_DEV_CONFIG_MAX    64                        /* maximum device config size */
#define SER_MAX_DEVICE        64                        /* maximum serial devices */

typedef struct serial_list {
    char    name[SER_DEV_NAME_MAX];
    char    desc[SER_DEV_DESC_MAX];
    } SERIAL_LIST;

typedef struct serial_config {                          /* serial port configuration */
    uint32 baudrate;                                    /* baud rate */
    uint32 charsize;                                    /* character size in bits */
    char   parity;                                      /* parity (N/O/E/M/S) */
    uint32 stopbits;                                    /* 0/1/2 stop bits (0 implies 1.5) */
    } SERCONFIG;

static int       sim_serial_os_devices (int max, SERIAL_LIST* list);
static SERHANDLE sim_open_os_serial    (char *name);
static void      sim_close_os_serial   (SERHANDLE port);
static t_stat    sim_config_os_serial  (SERHANDLE port, SERCONFIG config);


static struct open_serial_device {
    SERHANDLE port;
    TMLN *line;
    char name[SER_DEV_NAME_MAX];
    char config[SER_DEV_CONFIG_MAX];
    } *serial_open_devices = NULL;
static int serial_open_device_count = 0;

static struct open_serial_device *_get_open_device (SERHANDLE port)
{
int i;

for (i=0; i<serial_open_device_count; ++i)
    if (serial_open_devices[i].port == port)
        return &serial_open_devices[i];
return NULL;
}

static struct open_serial_device *_get_open_device_byname (const char *name)
{
int i;

for (i=0; i<serial_open_device_count; ++i)
    if (0 == strcmp(name, serial_open_devices[i].name))
        return &serial_open_devices[i];
return NULL;
}

static struct open_serial_device *_serial_add_to_open_list (SERHANDLE port, TMLN *line, const char *name, const char *config)
{
serial_open_devices = (struct open_serial_device *)realloc(serial_open_devices, (++serial_open_device_count)*sizeof(*serial_open_devices));
memset(&serial_open_devices[serial_open_device_count-1], 0, sizeof(serial_open_devices[serial_open_device_count-1]));
serial_open_devices[serial_open_device_count-1].port = port;
serial_open_devices[serial_open_device_count-1].line = line;
strncpy(serial_open_devices[serial_open_device_count-1].name, name, sizeof(serial_open_devices[serial_open_device_count-1].name)-1);
if (config)
    strncpy(serial_open_devices[serial_open_device_count-1].config, config, sizeof(serial_open_devices[serial_open_device_count-1].config)-1);
return &serial_open_devices[serial_open_device_count-1];
}

static void _serial_remove_from_open_list (SERHANDLE port)
{
int i, j;

for (i=0; i<serial_open_device_count; ++i)
    if (serial_open_devices[i].port == port) {
        for (j=i+1; j<serial_open_device_count; ++j)
            serial_open_devices[j-1] = serial_open_devices[j];
        --serial_open_device_count;
        break;
        }
}

/* Generic error message handler.

   This routine should be called for unexpected errors.  Some error returns may
   be expected, e.g., a "file not found" error from an "open" routine.  These
   should return appropriate status codes to the caller, allowing SCP to print
   an error message if desired, rather than printing this generic error message.
*/

static void sim_error_serial (const char *routine, int error)
{
sim_printf ("Serial: %s fails with error %d\n", routine, error);
return;
}

/* Used when sorting a list of serial port names */
static int _serial_name_compare (const void *pa, const void *pb)
{
const SERIAL_LIST *a = (const SERIAL_LIST *)pa;
const SERIAL_LIST *b = (const SERIAL_LIST *)pb;

return strcmp(a->name, b->name);
}

static int sim_serial_devices (int max, SERIAL_LIST *list)
{
int i, j, ports = sim_serial_os_devices(max, list);

/* Open ports may not show up in the list returned by sim_serial_os_devices 
   so we add the open ports to the list removing duplicates before sorting 
   the resulting list */

for (i=0; i<serial_open_device_count; ++i) {
    for (j=0; j<ports; ++j)
        if (0 == strcmp(serial_open_devices[i].name, list[j].name))
            break;
    if (j<ports)
        continue;
    if (ports >= max)
        break;
    strcpy(list[ports].name, serial_open_devices[i].name);
    strcpy(list[ports].desc, serial_open_devices[i].config);
    ++ports;
    }
if (ports) /* Order the list returned alphabetically by the port name */
    qsort (list, ports, sizeof(list[0]), _serial_name_compare);
return ports;
}

static char* sim_serial_getname (int number, char* name)
{
SERIAL_LIST  list[SER_MAX_DEVICE];
int count = sim_serial_devices(SER_MAX_DEVICE, list);

if (count <= number)
    return NULL;
strcpy(name, list[number].name);
return name;
}

static char* sim_serial_getname_bydesc (char* desc, char* name)
{
SERIAL_LIST  list[SER_MAX_DEVICE];
int count = sim_serial_devices(SER_MAX_DEVICE, list);
int i;
size_t j=strlen(desc);

for (i=0; i<count; i++) {
    int found = 1;
    size_t k = strlen(list[i].desc);

    if (j != k)
        continue;
    for (k=0; k<j; k++)
        if (tolower(list[i].desc[k]) != tolower(desc[k]))
            found = 0;
    if (found == 0)
        continue;

    /* found a case-insensitive description match */
    strcpy(name, list[i].name);
    return name;
    }
/* not found */
return NULL;
}

static char* sim_serial_getname_byname (char* name, char* temp)
{
SERIAL_LIST  list[SER_MAX_DEVICE];
int count = sim_serial_devices(SER_MAX_DEVICE, list);
size_t n;
int i, found;

found = 0;
n = strlen(name);
for (i=0; i<count && !found; i++) {
    if ((n == strlen(list[i].name)) &&
        (sim_strncasecmp(name, list[i].name, n) == 0)) {
        found = 1;
        strcpy(temp, list[i].name); /* only case might be different */
        }
    }
return (found ? temp : NULL);
}

char* sim_serial_getdesc_byname (char* name, char* temp)
{
SERIAL_LIST  list[SER_MAX_DEVICE];
int count = sim_serial_devices(SER_MAX_DEVICE, list);
size_t n;
int i, found;

found = 0;
n = strlen(name);
for (i=0; i<count && !found; i++) {
    if ((n == strlen(list[i].name)) &&
        (sim_strncasecmp(name, list[i].name, n) == 0)) {
        found = 1;
        strcpy(temp, list[i].desc);
        }
    }
  return (found ? temp : NULL);
}

t_stat sim_show_serial (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
{
SERIAL_LIST  list[SER_MAX_DEVICE];
int number = sim_serial_devices(SER_MAX_DEVICE, list);

fprintf(st, "Serial devices:\n");
if (number == -1)
    fprintf(st, "  serial support not available in simulator\n");
else
if (number == 0)
    fprintf(st, "  no serial devices are available\n");
else {
    size_t min, len;
    int i;
    for (i=0, min=0; i<number; i++)
        if ((len = strlen(list[i].name)) > min)
            min = len;
    for (i=0; i<number; i++)
        fprintf(st," ser%d\t%-*s%s%s%s\n", i, (int)min, list[i].name, list[i].desc[0] ? " (" : "", list[i].desc, list[i].desc[0] ? ")" : "");
    }
if (serial_open_device_count) {
    int i;
    char desc[SER_DEV_DESC_MAX], *d;

    fprintf(st,"Open Serial Devices:\n");
    for (i=0; i<serial_open_device_count; i++) {
        d = sim_serial_getdesc_byname(serial_open_devices[i].name, desc);
        fprintf(st, " %s\tLn%02d %s%s%s%s\tConfig: %s\n", serial_open_devices[i].line->mp->dptr->name, (int)(serial_open_devices[i].line->mp->ldsc-serial_open_devices[i].line),
                    serial_open_devices[i].line->destination, d ? " {" : "", d ? d : "", d ? ")" : "", serial_open_devices[i].line->serconfig);
        }
    }
return SCPE_OK;
}

SERHANDLE sim_open_serial (char *name, TMLN *lp, t_stat *stat)
{
char temp1[1024], devname [1024];
char *savname = name;
SERHANDLE port = INVALID_HANDLE;
CONST char *config;
t_stat status;

config = get_glyph_nc (name, devname, ';');             /* separate port name from optional config params */

if ((config == NULL) || (*config == '\0'))
    config = "9600-8N1";

if (stat)
    *stat = SCPE_OK;

/* translate name of type "serX" to real device name */
if ((strlen(devname) <= 5)
    && (tolower(devname[0]) == 's')
    && (tolower(devname[1]) == 'e')
    && (tolower(devname[2]) == 'r')
    && (isdigit(devname[3]))
    && (isdigit(devname[4]) || (devname[4] == '\0'))
   ) {
    int num = atoi(&devname[3]);
    savname = sim_serial_getname(num, temp1);
    if (savname == NULL) {                              /* didn't translate */
        if (stat)
            *stat = SCPE_OPENERR;
        return INVALID_HANDLE;
        }
    }
else {
    /* are they trying to use device description? */
    savname = sim_serial_getname_bydesc(devname, temp1);
    if (savname == NULL) {                              /* didn't translate */
        /* probably is not serX and has no description */
        savname = sim_serial_getname_byname(devname, temp1);
        if (savname == NULL) /* didn't translate */
            savname = devname;
        }
    }

if (_get_open_device_byname (savname)) {
    if (stat)
        *stat = SCPE_OPENERR;
    return INVALID_HANDLE;
    }

port = sim_open_os_serial (savname);

if (port == INVALID_HANDLE) {
    if (stat)
        *stat = SCPE_OPENERR;
    return port;
    }

status = sim_config_serial (port, config);              /* set serial configuration */

if (status != SCPE_OK) {                                /* port configuration error? */
    sim_close_serial (port);                            /* close the port */
    if (stat)
        *stat = status;
    port = INVALID_HANDLE;                              /* report error */
    }

if ((port != INVALID_HANDLE) && (*config) && (lp)) {
    lp->serconfig = (char *)realloc (lp->serconfig, 1 + strlen (config));
    strcpy (lp->serconfig, config);
    }
if (port != INVALID_HANDLE)
    _serial_add_to_open_list (port, lp, savname, config);

return port;
}

void sim_close_serial (SERHANDLE port)
{
sim_close_os_serial (port);
_serial_remove_from_open_list (port);
}

t_stat sim_config_serial  (SERHANDLE port, CONST char *sconfig)
{
CONST char *pptr;
CONST char *sptr, *tptr;
SERCONFIG config = { 0 };
t_bool arg_error = FALSE;
t_stat r;
struct open_serial_device *dev;

if ((sconfig == NULL) || (*sconfig == '\0'))
    sconfig = "9600-8N1";                               /* default settings */
pptr = sconfig;

config.baudrate = (uint32)strtotv (pptr, &sptr, 10);    /* parse baud rate */
arg_error = (pptr == sptr);                             /* check for bad argument */

if (*sptr)                                              /* separator present? */
    sptr++;                                             /* skip it */

config.charsize = (uint32)strtotv (sptr, &tptr, 10);    /* parse character size */
arg_error = arg_error || (sptr == tptr);                /* check for bad argument */

if (*tptr)                                              /* parity character present? */
    config.parity = (char)toupper (*tptr++);            /* save parity character */

config.stopbits = (uint32)strtotv (tptr, &sptr, 10);    /* parse number of stop bits */
arg_error = arg_error || (tptr == sptr);                /* check for bad argument */

if (arg_error)                                          /* bad conversions? */
    return SCPE_ARG;                                    /* report argument error */
if (strcmp (sptr, ".5") == 0)                           /* 1.5 stop bits requested? */
    config.stopbits = 0;                                /* code request */

r = sim_config_os_serial (port, config);
dev = _get_open_device (port);
if (dev) {
    dev->line->serconfig = (char *)realloc (dev->line->serconfig, 1 + strlen (sconfig));
    strcpy (dev->line->serconfig, sconfig);
    }
return r;
}

#if defined (_WIN32)

/* Windows serial implementation */

/* Enumerate the available serial ports.

   The serial port names are extracted from the appropriate place in the 
   windows registry (HKLM\HARDWARE\DEVICEMAP\SERIALCOMM\).  The resulting
   list is sorted alphabetically by device name (COMn).  The device description 
   is set to the OS internal name for the COM device.

*/

struct SERPORT {
    HANDLE hPort;
    DWORD dwEvtMask;
    OVERLAPPED oReadSync;
    OVERLAPPED oWriteReady;
    OVERLAPPED oWriteSync;
    };

static int sim_serial_os_devices (int max, SERIAL_LIST* list)
{
int ports = 0;
HKEY hSERIALCOMM;

memset(list, 0, max*sizeof(*list));
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hSERIALCOMM) == ERROR_SUCCESS) {
    DWORD dwIndex = 0;
    DWORD dwType;
    DWORD dwValueNameSize = sizeof(list[ports].desc);
    DWORD dwDataSize = sizeof(list[ports].name);

    /* Enumerate all the values underneath HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM */
    while (RegEnumValueA(hSERIALCOMM, dwIndex, list[ports].desc, &dwValueNameSize, NULL, &dwType, (BYTE *)list[ports].name, &dwDataSize) == ERROR_SUCCESS) {
        /* String values with non-zero size are the interesting ones */
        if ((dwType == REG_SZ) && (dwDataSize > 0)) {
            if (ports < max)
                ++ports;
            else
                break;
            }
        /* Besure to clear the working entry before trying again */
        memset(list[ports].name, 0, sizeof(list[ports].name));
        memset(list[ports].desc, 0, sizeof(list[ports].desc));
        dwValueNameSize = sizeof(list[ports].desc);
        dwDataSize = sizeof(list[ports].name);
        ++dwIndex;
        }
    RegCloseKey(hSERIALCOMM);
    }
return ports;
}

/* Open a serial port.

   The serial port designated by "name" is opened, and the handle to the port is
   returned.  If an error occurs, INVALID_HANDLE is returned instead.  After
   opening, the port is configured with the default communication parameters
   established by the system, and the timeouts are set for immediate return on a
   read request to enable polling.

   Implementation notes:

    1. We call "GetDefaultCommConfig" to obtain the default communication
       parameters for the specified port.  If the name does not refer to a
       communications port (serial or parallel), the function fails.

    2. There is no way to limit "CreateFile" just to serial ports, so we must
       check after the port is opened.  The "GetCommState" routine will return
       an error if the handle does not refer to a serial port.

    3. Calling "GetDefaultCommConfig" for a serial port returns a structure
       containing a DCB.  This contains the default parameters.  However, some
       of the DCB fields are not set correctly, so we cannot use this directly
       in a call to "SetCommState".  Instead, we must copy the fields of
       interest to a DCB retrieved from a call to "GetCommState".
*/

static SERHANDLE sim_open_os_serial (char *name)
{
HANDLE hPort;
SERHANDLE port;
DCB dcb;
COMMCONFIG commdefault;
DWORD error;
DWORD commsize = sizeof (commdefault);
COMMTIMEOUTS cto;

if (!GetDefaultCommConfig (name, &commdefault, &commsize)) {    /* get default comm parameters */
    error = GetLastError ();                                    /* function failed; get error */

    if (error != ERROR_INVALID_PARAMETER)                       /* not a communications port name? */
        sim_error_serial ("GetDefaultCommConfig", (int) error); /* no, so report unexpected error */

    return INVALID_HANDLE;                                      /* indicate bad port name */
    }

hPort = CreateFile (name, GENERIC_READ | GENERIC_WRITE, /* open the port */
                   0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

if (hPort == INVALID_HANDLE_VALUE) {                    /* open failed? */
    error = GetLastError ();                            /* get error code */

    if ((error != ERROR_FILE_NOT_FOUND) &&              /* bad filename? */
        (error != ERROR_ACCESS_DENIED))                 /* already open? */
        sim_error_serial ("CreateFile", (int) error);   /* no, so report unexpected error */

    return INVALID_HANDLE;                              /* indicate bad port name */
    }

port = (SERHANDLE)calloc (1, sizeof(*port));            /* instantiate the SERHANDLE */
port->hPort = hPort;

if (!GetCommState (port->hPort, &dcb)) {                /* get the current comm parameters */
    error = GetLastError ();                            /* function failed; get error */

    if (error != ERROR_INVALID_PARAMETER)               /* not a serial port name? */
        sim_error_serial ("GetCommState", (int) error); /* no, so report unexpected error */

    sim_close_os_serial (port);                         /* close port */
    return INVALID_HANDLE;                              /*   and indicate bad port name */
    }

dcb.BaudRate = commdefault.dcb.BaudRate;                /* copy default parameters of interest */
dcb.Parity   = commdefault.dcb.Parity;
dcb.ByteSize = commdefault.dcb.ByteSize;
dcb.StopBits = commdefault.dcb.StopBits;
dcb.fOutX    = commdefault.dcb.fOutX;
dcb.fInX     = commdefault.dcb.fInX;

dcb.fDtrControl = DTR_CONTROL_DISABLE;                  /* disable DTR initially until poll connects */

if (!SetCommState (port->hPort, &dcb)) {                /* configure the port with default parameters */
    sim_error_serial ("SetCommState",                   /* function failed; report unexpected error */
                      (int) GetLastError ());
    sim_close_os_serial (port);                         /* close port */
    return INVALID_HANDLE;                              /*   and indicate failure to caller */
    }

cto.ReadIntervalTimeout         = MAXDWORD;             /* set port to return immediately on read */
cto.ReadTotalTimeoutMultiplier  = 0;                    /* i.e., to enable polling */
cto.ReadTotalTimeoutConstant    = 0;
cto.WriteTotalTimeoutMultiplier = 0;
cto.WriteTotalTimeoutConstant   = 0;

if (!SetCommTimeouts (port->hPort, &cto)) {             /* configure port timeouts */
    sim_error_serial ("SetCommTimeouts",                /* function failed; report unexpected error */
                      (int) GetLastError ());
    sim_close_os_serial (port);                         /* close port */
    return INVALID_HANDLE;                              /*   and indicate failure to caller */
    }

/* Create an event object for use by WaitCommEvent. */

port->oWriteReady.hEvent = CreateEvent(NULL,            /* default security attributes */
                                       TRUE,            /* manual-reset event */
                                       TRUE,            /* signaled */
                                       NULL);           /* no name */
if (port->oWriteReady.hEvent == NULL) {
    sim_error_serial ("CreateEvent",                    /* function failed; report unexpected error */
                      (int) GetLastError ());
    sim_close_os_serial (port);                         /* close port */
    return INVALID_HANDLE;                              /*   and indicate failure to caller */
    }

port->oReadSync.hEvent = CreateEvent(NULL,              /* default security attributes */
                                     TRUE,              /* manual-reset event */
                                     FALSE,             /* not signaled */
                                     NULL);             /* no name */
if (port->oReadSync.hEvent == NULL) {
    sim_error_serial ("CreateEvent",                    /* function failed; report unexpected error */
                      (int) GetLastError ());
    sim_close_os_serial (port);                         /* close port */
    return INVALID_HANDLE;                              /*   and indicate failure to caller */
    }

port->oWriteSync.hEvent = CreateEvent(NULL,             /* default security attributes */
                                      TRUE,             /* manual-reset event */
                                      FALSE,            /* not signaled */
                                      NULL);            /* no name */
if (port->oWriteSync.hEvent == NULL) {
    sim_error_serial ("CreateEvent",                    /* function failed; report unexpected error */
                      (int) GetLastError ());
    sim_close_os_serial (port);                         /* close port */
    return INVALID_HANDLE;                              /*   and indicate failure to caller */
    }

if (!SetCommMask (port->hPort, EV_TXEMPTY)) {
    sim_error_serial ("SetCommMask",                    /* function failed; report unexpected error */
                      (int) GetLastError ());
    sim_close_os_serial (port);                         /* close port */
    return INVALID_HANDLE;                              /*   and indicate failure to caller */
    }

return port;                                            /* return port handle on success */
}


/* Configure a serial port.

   Port parameters are configured as specified in the "config" structure.  If
   "config" contains an invalid configuration value, or if the host system
   rejects the configuration (e.g., by requesting an unsupported combination of
   character size and stop bits), SCPE_ARG is returned to the caller.  If an
   unexpected error occurs, SCPE_IOERR is returned.  If the configuration
   succeeds, SCPE_OK is returned.

   Implementation notes:

    1. We do not enable input parity checking, as the multiplexer library has no
       way of communicating parity errors back to the target simulator.

    2. A zero value for the "stopbits" field of the "config" structure implies
       1.5 stop bits.
*/

static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config)
{
static const struct {
    char parity;
    BYTE parity_code;
    } parity_map [] =
        { { 'E', EVENPARITY }, { 'M', MARKPARITY  }, { 'N', NOPARITY },
          { 'O', ODDPARITY  }, { 'S', SPACEPARITY } };

static const int32 parity_count = sizeof (parity_map) / sizeof (parity_map [0]);

DCB dcb;
DWORD error;
int32 i;

if (!GetCommState (port->hPort, &dcb)) {                /* get the current comm parameters */
    sim_error_serial ("GetCommState",                   /* function failed; report unexpected error */
                      (int) GetLastError ());
    return SCPE_IOERR;                                  /* return failure status */
    }

dcb.BaudRate = config.baudrate;                         /* assign baud rate */

if (config.charsize >= 5 && config.charsize <= 8)       /* character size OK? */
    dcb.ByteSize = (BYTE)config.charsize;               /* assign character size */
else
    return SCPE_ARG;                                    /* not a valid size */

for (i = 0; i < parity_count; i++)                      /* assign parity */
    if (config.parity == parity_map [i].parity) {       /* match mapping value? */
        dcb.Parity = parity_map [i].parity_code;        /* assign corresponding code */
        break;
        }

if (i == parity_count)                                  /* parity assigned? */
    return SCPE_ARG;                                    /* not a valid parity specifier */

if (config.stopbits == 1)                               /* assign stop bits */
    dcb.StopBits = ONESTOPBIT;
else if (config.stopbits == 2)
    dcb.StopBits = TWOSTOPBITS;
else if (config.stopbits == 0)                          /* 0 implies 1.5 stop bits */
    dcb.StopBits = ONE5STOPBITS;
else
    return SCPE_ARG;                                    /* not a valid number of stop bits */

if (!SetCommState (port->hPort, &dcb)) {                /* set the configuration */
    error = GetLastError ();                            /* check for error */

    if (error == ERROR_INVALID_PARAMETER)               /* invalid configuration? */
        return SCPE_ARG;                                /* report as argument error */

    sim_error_serial ("SetCommState", (int) error);     /* function failed; report unexpected error */
    return SCPE_IOERR;                                  /* return failure status */
    }

return SCPE_OK;                                         /* return success status */
}


/* Control a serial port.

   The DTR and RTS line of the serial port is set or cleared as indicated in 
   the respective bits_to_set or bits_to_clear parameters.  If the 
   incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, 
   DSR and CTS are returned.

   If unreasonable or nonsense bits_to_set or bits_to_clear bits are 
   specified, then the return status is SCPE_ARG;
   If an error occurs, SCPE_IOERR is returned.
*/

t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
{
if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) ||         /* Assure only settable bits */
    (bits_to_clear & ~(TMXR_MDM_OUTGOING)) ||
    (bits_to_set & bits_to_clear))                  /* and can't set and clear the same bits */
    return SCPE_ARG;
if (bits_to_set&TMXR_MDM_DTR)
    if (!EscapeCommFunction (port->hPort, SETDTR)) {
        sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
        return SCPE_IOERR;
        }
if (bits_to_clear&TMXR_MDM_DTR)
    if (!EscapeCommFunction (port->hPort, CLRDTR)) {
        sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
        return SCPE_IOERR;
        }
if (bits_to_set&TMXR_MDM_RTS)
    if (!EscapeCommFunction (port->hPort, SETRTS)) {
        sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
        return SCPE_IOERR;
        }
if (bits_to_clear&TMXR_MDM_RTS)
    if (!EscapeCommFunction (port->hPort, CLRRTS)) {
        sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
        return SCPE_IOERR;
        }
if (incoming_bits) {
    DWORD ModemStat;
    if (GetCommModemStatus (port->hPort, &ModemStat)) {
        sim_error_serial ("GetCommModemStatus", (int) GetLastError ());
        return SCPE_IOERR;
        }
    *incoming_bits = ((ModemStat&MS_CTS_ON)  ? TMXR_MDM_CTS : 0) |
                     ((ModemStat&MS_DSR_ON)  ? TMXR_MDM_DSR : 0) |
                     ((ModemStat&MS_RING_ON) ? TMXR_MDM_RNG : 0) |
                     ((ModemStat&MS_RLSD_ON) ? TMXR_MDM_DCD : 0);
    }
return SCPE_OK;
}


/* Read from a serial port.

   The port is checked for available characters.  If any are present, they are
   copied to the passed buffer, and the count of characters is returned.  If no
   characters are available, 0 is returned.  If an error occurs, -1 is returned.
   If a BREAK is detected on the communications line, the corresponding flag in
   the "brk" array is set.

   Implementation notes:

    1. The "ClearCommError" function will set the CE_BREAK flag in the returned
       errors value if a BREAK has occurred.  However, we do not know where in
       the serial stream it happened, as CE_BREAK isn't associated with a
       specific character.  Because the "brk" array does want a flag associated
       with a specific character, we guess at the proper location by setting
       the "brk" entry corresponding to the first NUL in the character stream.
       If no NUL is present, then the "brk" entry associated with the first
       character is set.
*/

int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk)
{
DWORD read;
DWORD commerrors;
COMSTAT cs;
char *bptr;

if (!ClearCommError (port->hPort, &commerrors, &cs)) {  /* get the comm error flags  */
    sim_error_serial ("ClearCommError",                 /* function failed; report unexpected error */
                      (int) GetLastError ());
    return -1;                                          /* return failure to caller */
    }

if (!ReadFile (port->hPort, (LPVOID) buffer,            /* read any available characters */
               (DWORD) count, &read, &port->oReadSync)) {
    sim_error_serial ("ReadFile",                       /* function failed; report unexpected error */
                      (int) GetLastError ());
    return -1;                                          /* return failure to caller */
    }

if (commerrors & CE_BREAK) {                            /* was a BREAK detected? */
    bptr = (char *) memchr (buffer, 0, read);           /* search for the first NUL in the buffer */

    if (bptr)                                           /* was one found? */
        brk = brk + (bptr - buffer);                    /* calculate corresponding position */

    *brk = 1;                                           /* set the BREAK flag */
    }

return read;                                            /* return the number of characters read */
}


/* Write to a serial port.

   "Count" characters are written from "buffer" to the serial port.  The actual
   number of characters written to the port is returned.  If an error occurred
   on writing, -1 is returned.
*/

int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
{
if (WaitForSingleObject (port->oWriteReady.hEvent, 0) == WAIT_TIMEOUT)
    return 0;
if ((!WriteFile (port->hPort, (LPVOID) buffer,   /* write the buffer to the serial port */
                 (DWORD) count, NULL, &port->oWriteSync)) &&
    (GetLastError () != ERROR_IO_PENDING)) {
    sim_error_serial ("WriteFile",              /* function failed; report unexpected error */
                      (int) GetLastError ());
    return -1;                                  /* return failure to caller */
    }
if ((!WaitCommEvent (port->hPort, &port->dwEvtMask, &port->oWriteReady)) &&
    (GetLastError () != ERROR_IO_PENDING)) {
    sim_error_serial ("WaitCommEvent",          /* function failed; report unexpected error */
                      (int) GetLastError ());
    return -1;                                  /* return failure to caller */
    }
return count;                                   /* return number of characters written/queued */
}


/* Close a serial port.

   The serial port is closed.  Errors are ignored.
*/

static void sim_close_os_serial (SERHANDLE port)
{
if (port->oWriteReady.hEvent)
    CloseHandle (port->oWriteReady.hEvent);               /* close the event handle */
if (port->oReadSync.hEvent)
    CloseHandle (port->oReadSync.hEvent);               /* close the event handle */
if (port->oWriteSync.hEvent)
    CloseHandle (port->oWriteSync.hEvent);              /* close the event handle */
if (port->hPort)
    CloseHandle (port->hPort);                          /* close the port */
free (port);
}



#elif defined (__unix__) || defined(__APPLE__) || defined(__hpux)

struct SERPORT {
    int port;
    };

#if defined(__linux) || defined(__linux__)
#include <dirent.h>
#include <libgen.h>
#include <unistd.h>
#include <sys/stat.h>
#endif /* __linux__ */

/* UNIX implementation */

/* Enumerate the available serial ports.

   The serial port names generated by attempting to open /dev/ttyS0 thru
   /dev/ttyS63 and /dev/ttyUSB0 thru /dev/ttyUSB63 and /dev/tty.serial0
   thru /dev/tty.serial63.  Ones we can open and are ttys (as determined 
   by isatty()) are added to the list.  The list is sorted alphabetically 
   by device name.

*/

static int sim_serial_os_devices (int max, SERIAL_LIST* list)
{
int i;
int port;
int ports = 0;

memset(list, 0, max*sizeof(*list));
#if defined(__linux) || defined(__linux__)
if (1) {
    struct dirent **namelist;
    struct stat st;

    i = scandir("/sys/class/tty/", &namelist, NULL, NULL);

    while (i--) {
        if (strcmp(namelist[i]->d_name, ".") &&
            strcmp(namelist[i]->d_name, "..")) {
            char path[1024], devicepath[1024], driverpath[1024];

            sprintf (path, "/sys/class/tty/%s", namelist[i]->d_name);
            sprintf (devicepath, "/sys/class/tty/%s/device", namelist[i]->d_name);
            sprintf (driverpath, "/sys/class/tty/%s/device/driver", namelist[i]->d_name);
            if ((lstat(devicepath, &st) == 0) && S_ISLNK(st.st_mode)) {
                char buffer[1024];

                memset (buffer, 0, sizeof(buffer));
                if (readlink(driverpath, buffer, sizeof(buffer)) > 0) {
                    sprintf (list[ports].name, "/dev/%s", basename (path));
                    port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */
                    if (port != -1) {                   /* open OK? */
                        if (isatty (port))              /* is device a TTY? */
                            ++ports;
                        close (port);
                        }
                    }
                }
            }
        free (namelist[i]);
        }
    free (namelist);
    }
#elif defined(__hpux)
for (i=0; (ports < max) && (i < 64); ++i) {
    sprintf (list[ports].name, "/dev/tty%dp%d", i/8, i%8);
    port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */
    if (port != -1) {                                   /* open OK? */
        if (isatty (port))                              /* is device a TTY? */
            ++ports;
        close (port);
        }
    }
#else /* Non Linux/HP-UX, just try some well known device names */
for (i=0; (ports < max) && (i < 64); ++i) {
    sprintf (list[ports].name, "/dev/ttyS%d", i);
    port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */
    if (port != -1) {                                   /* open OK? */
        if (isatty (port))                              /* is device a TTY? */
            ++ports;
        close (port);
        }
    }
for (i=0; (ports < max) && (i < 64); ++i) {
    sprintf (list[ports].name, "/dev/ttyUSB%d", i);
    port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */
    if (port != -1) {                                   /* open OK? */
        if (isatty (port))                              /* is device a TTY? */
            ++ports;
        close (port);
        }
    }
for (i=1; (ports < max) && (i < 64); ++i) {
    sprintf (list[ports].name, "/dev/tty.serial%d", i);
    port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */
    if (port != -1) {                                   /* open OK? */
        if (isatty (port))                              /* is device a TTY? */
            ++ports;
        close (port);
        }
    }
for (i=0; (ports < max) && (i < 64); ++i) {
    sprintf (list[ports].name, "/dev/tty%02d", i);
    port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */
    if (port != -1) {                                   /* open OK? */
        if (isatty (port))                              /* is device a TTY? */
            ++ports;
        close (port);
        }
    }
for (i=0; (ports < max) && (i < 8); ++i) {
    sprintf (list[ports].name, "/dev/ttyU%d", i);
    port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */
    if (port != -1) {                                   /* open OK? */
        if (isatty (port))                              /* is device a TTY? */
            ++ports;
        close (port);
        }
    }
#endif
return ports;
}

/* Open a serial port.

   The serial port designated by "name" is opened, and the handle to the port is
   returned.  If an error occurs, INVALID_HANDLE is returned instead.  After
   opening, the port is configured to "raw" mode.

   Implementation notes:

    1. We use a non-blocking open to allow for polling during reads.

    2. There is no way to limit "open" just to serial ports, so we must check
       after the port is opened.  We do this with a combination of "isatty" and
       "tcgetattr".

    3. We configure with PARMRK set and IGNBRK and BRKINT cleared.  This will
       mark a communication line BREAK condition in the input stream with the
       three-character sequence \377 \000 \000.  This is detected during
       reading.
*/

static SERHANDLE sim_open_os_serial (char *name)
{
static const tcflag_t i_clear = IGNBRK |                /* ignore BREAK */
                                BRKINT |                /* signal on BREAK */
                                INPCK  |                /* enable parity checking */
                                ISTRIP |                /* strip character to 7 bits */
                                INLCR  |                /* map NL to CR */
                                IGNCR  |                /* ignore CR */
                                ICRNL  |                /* map CR to NL */
                                IXON   |                /* enable XON/XOFF output control */
                                IXOFF;                  /* enable XON/XOFF input control */

static const tcflag_t i_set   = PARMRK |                /* mark parity errors and line breaks */
                                IGNPAR;                 /* ignore parity errors */

static const tcflag_t o_clear = OPOST;                  /* post-process output */

static const tcflag_t o_set   = 0;

static const tcflag_t c_clear = HUPCL;                  /* hang up line on last close */

static const tcflag_t c_set   = CREAD |                 /* enable receiver */
                                CLOCAL;                 /* ignore modem status lines */

static const tcflag_t l_clear = ISIG    |               /* enable signals */
                                ICANON  |               /* canonical input */
                                ECHO    |               /* echo characters */
                                ECHOE   |               /* echo ERASE as an error correcting backspace */
                                ECHOK   |               /* echo KILL */
                                ECHONL  |               /* echo NL */
                                NOFLSH  |               /* disable flush after interrupt */
                                TOSTOP  |               /* send SIGTTOU for background output */
                                IEXTEN;                 /* enable extended functions */

static const tcflag_t l_set   = 0;
int port;
SERHANDLE serport;
struct termios tio;

port = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK);     /* open the port */

if (port == -1) {                                       /* open failed? */
    if (errno != ENOENT && errno != EACCES)             /* file not found or can't open? */
        sim_error_serial ("open", errno);               /* no, so report unexpected error */

    return INVALID_HANDLE;                              /* indicate failure to caller */
    }

if (!isatty (port)) {                                   /* is device a TTY? */
    close (port);                                       /* no, so close it */
    return INVALID_HANDLE;                              /*   and return failure to caller */
    }

if (tcgetattr (port, &tio)) {                           /* get the terminal attributes */
    sim_error_serial ("tcgetattr", errno);              /* function failed; report unexpected error */
    close (port);                                       /* close the port */
    return INVALID_HANDLE;                              /*   and return failure to caller */
    }

// which of these methods is best?

#if 1

tio.c_iflag = (tio.c_iflag & ~i_clear) | i_set;           /* configure the serial line for raw mode */
tio.c_oflag = (tio.c_oflag & ~o_clear) | o_set;
tio.c_cflag = (tio.c_cflag & ~c_clear) | c_set;
tio.c_lflag = (tio.c_lflag & ~l_clear) | l_set;
#ifdef VMIN
tio.c_cc[VMIN] = 1;
#endif
#ifdef VTIME
tio.c_cc[VTIME] = 0;
#endif

#elif 0

tio.c_iflag &= ~(IGNBRK | BRKINT | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF);
tio.c_iflag |= PARMRK | IGNPAR;
tio.c_oflag &= ~(OPOST);
tio.c_cflag &= ~(HUPCL);
tio.c_cflag |= CREAD | CLOCAL;
tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | TOSTOP | IEXTEN);

#elif 0

tio.c_iflag = PARMRK | IGNPAR;
tio.c_oflag = 0;
tio.c_cflag = tio.c_cflag | CLOCAL | CREAD;
tio.c_lflag = 0;

#endif

if (tcsetattr (port, TCSANOW, &tio)) {                  /* set the terminal attributes */
    sim_error_serial ("tcsetattr", errno);              /* function failed; report unexpected error */
    close (port);                                       /* close the port */
    return INVALID_HANDLE;                              /*   and return failure to caller */
    }

serport = (SERHANDLE)calloc (1, sizeof(*serport));
serport->port = port;
return serport;                                         /* return port fd for success */
}


/* Configure a serial port.

   Port parameters are configured as specified in the "config" structure.  If
   "config" contains an invalid configuration value, or if the host system
   rejects the configuration (e.g., by requesting an unsupported combination of
   character size and stop bits), SCPE_ARG is returned to the caller.  If an
   unexpected error occurs, SCPE_IOERR is returned.  If the configuration
   succeeds, SCPE_OK is returned.

   Implementation notes:

    1. 1.5 stop bits is not a supported configuration.

*/

static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config)
{
struct termios tio;
int32 i;

static const struct {
    uint32  rate;
    speed_t rate_code;
    } baud_map [] =
        { { 50,     B50     }, { 75,     B75     }, { 110,    B110    }, {  134,   B134   },
          { 150,    B150    }, { 200,    B200    }, { 300,    B300    }, {  600,   B600   },
          { 1200,   B1200   }, { 1800,   B1800   }, { 2400,   B2400   }, {  4800,  B4800  },
          { 9600,   B9600   }, { 19200,  B19200  }, { 38400,  B38400  }, {  57600, B57600 },
          { 115200, B115200 } };

static const int32 baud_count = sizeof (baud_map) / sizeof (baud_map [0]);

static const tcflag_t charsize_map [4] = { CS5, CS6, CS7, CS8 };


if (tcgetattr (port->port, &tio)) {                     /* get the current configuration */
    sim_error_serial ("tcgetattr", errno);              /* function failed; report unexpected error */
    return SCPE_IOERR;                                  /* return failure status */
    }

for (i = 0; i < baud_count; i++)                        /* assign baud rate */
    if (config.baudrate == baud_map [i].rate) {         /* match mapping value? */
        cfsetispeed(&tio, baud_map [i].rate_code);      /* set input rate */
        cfsetospeed(&tio, baud_map [i].rate_code);      /* set output rate */
        break;
        }

if (i == baud_count)                                    /* baud rate assigned? */
    return SCPE_ARG;                                    /* invalid rate specified */

if ((config.charsize >= 5) && (config.charsize <= 8))   /* character size OK? */
    tio.c_cflag = (tio.c_cflag & ~CSIZE) |              /* replace character size code */
                charsize_map [config.charsize - 5];
else
    return SCPE_ARG;                                    /* not a valid size */

switch (config.parity) {                                /* assign parity */
    case 'E':
        tio.c_cflag = (tio.c_cflag & ~PARODD) | PARENB; /* set for even parity */
        break;

    case 'N':
        tio.c_cflag = tio.c_cflag & ~PARENB;            /* set for no parity */
        break;

    case 'O':
        tio.c_cflag = tio.c_cflag | PARODD | PARENB;    /* set for odd parity */
        break;

    default:
        return SCPE_ARG;                                /* not a valid parity specifier */
    }

if (config.stopbits == 1)                               /* one stop bit? */
    tio.c_cflag = tio.c_cflag & ~CSTOPB;                /* clear two-bits flag */
else if (config.stopbits == 2)                          /* two stop bits? */
    tio.c_cflag = tio.c_cflag | CSTOPB;                 /* set two-bits flag */
else                                                    /* some other number? */
    return SCPE_ARG;                                    /* not a valid number of stop bits */

if (tcsetattr (port->port, TCSAFLUSH, &tio)) {          /* set the new configuration */
    sim_error_serial ("tcsetattr", errno);              /* function failed; report unexpected error */
    return SCPE_IERR;                                   /* return failure status */
    }

return SCPE_OK;                                         /* configuration set successfully */
}


/* Control a serial port.

   The DTR and RTS line of the serial port is set or cleared as indicated in 
   the respective bits_to_set or bits_to_clear parameters.  If the 
   incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, 
   DSR and CTS are returned.

   If unreasonable or nonsense bits_to_set or bits_to_clear bits are 
   specified, then the return status is SCPE_ARG;
   If an error occurs, SCPE_IOERR is returned.
*/

t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
{
int bits;

if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) ||         /* Assure only settable bits */
    (bits_to_clear & ~(TMXR_MDM_OUTGOING)) ||
    (bits_to_set & bits_to_clear))                  /* and can't set and clear the same bits */
    return SCPE_ARG;
if (bits_to_set) {
    bits = ((bits_to_set&TMXR_MDM_DTR) ? TIOCM_DTR : 0) |
           ((bits_to_set&TMXR_MDM_RTS) ? TIOCM_RTS : 0);
    if (ioctl (port->port, TIOCMBIS, &bits)) {      /* set the desired bits */
        sim_error_serial ("ioctl", errno);          /* report unexpected error */
        return SCPE_IOERR;                          /* return failure status */
        }
    }
if (bits_to_clear) {
    bits = ((bits_to_clear&TMXR_MDM_DTR) ? TIOCM_DTR : 0) |
           ((bits_to_clear&TMXR_MDM_RTS) ? TIOCM_RTS : 0);
    if (ioctl (port->port, TIOCMBIC, &bits)) {      /* clear the desired bits */
        sim_error_serial ("ioctl", errno);          /* report unexpected error */
        return SCPE_IOERR;                          /* return failure status */
        }
    }
if (incoming_bits) {
    if (ioctl (port->port, TIOCMGET, &bits)) {      /* get the modem bits */
        sim_error_serial ("ioctl", errno);          /* report unexpected error */
        return SCPE_IOERR;                          /* return failure status */
        }
    *incoming_bits = ((bits&TIOCM_CTS) ? TMXR_MDM_CTS : 0) |
                     ((bits&TIOCM_DSR) ? TMXR_MDM_DSR : 0) |
                     ((bits&TIOCM_RNG) ? TMXR_MDM_RNG : 0) |
                     ((bits&TIOCM_CAR) ? TMXR_MDM_DCD : 0);
    }

return SCPE_OK;
}


/* Read from a serial port.

   The port is checked for available characters.  If any are present, they are
   copied to the passed buffer, and the count of characters is returned.  If no
   characters are available, 0 is returned.  If an error occurs, -1 is returned.
   If a BREAK is detected on the communications line, the corresponding flag in
   the "brk" array is set.

   Implementation notes:

    1. A character with a framing or parity error is indicated in the input
       stream by the three-character sequence \377 \000 \ccc, where "ccc" is the
       bad character.  A communications line BREAK is indicated by the sequence
       \377 \000 \000.  A received \377 character is indicated by the
       two-character sequence \377 \377.  If we find any of these sequences,
       they are replaced by the single intended character by sliding the
       succeeding characters backward by one or two positions.  If a BREAK
       sequence was encountered, the corresponding location in the "brk" array
       is determined, and the flag is set.  Note that there may be multiple
       sequences in the buffer.
*/

int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk)
{
int read_count;
char *bptr, *cptr;
int32 remaining;

read_count = read (port->port, (void *) buffer, (size_t) count);/* read from the serial port */

if (read_count == -1)                                       /* read error? */
    if (errno == EAGAIN)                                    /* no characters available? */
        return 0;                                           /* return 0 to indicate */
    else                                                    /* some other problem */
        sim_error_serial ("read", errno);                   /* report unexpected error */

else {                                                      /* read succeeded */
    cptr = buffer;                                          /* point at start of buffer */
    remaining = read_count - 1;                             /* stop search one char from end of string */

    while (remaining > 0 &&                                 /* still characters to search? */
           (bptr = (char*)memchr (cptr, '\377', remaining))) {/* search for start of PARMRK sequence */
        remaining = remaining - (bptr - cptr) - 1;          /* calc characters remaining */

        if (*(bptr + 1) == '\377') {                        /* is it a \377 \377 sequence? */
            memmove (bptr + 1, bptr + 2, remaining);        /* slide string backward to leave first \377 */
            remaining = remaining - 1;                      /* drop remaining count */
            read_count = read_count - 1;                    /*   and read count by char eliminated */
            }

        else if (remaining > 0 && *(bptr + 1) == '\0') {    /* is it a \377 \000 \ccc sequence? */
            memmove (bptr, bptr + 2, remaining);            /* slide string backward to leave \ccc */
            remaining = remaining - 2;                      /* drop remaining count */
            read_count = read_count - 2;                    /*   and read count by chars eliminated */

            if (*bptr == '\0')                              /* is it a BREAK sequence? */
                *(brk + (bptr - buffer)) = 1;               /* set corresponding BREAK flag */
            }

        cptr = bptr + 1;                                    /* point at remainder of string */
        }
    }

return (int32) read_count;                                  /* return the number of characters read */
}


/* Write to a serial port.

   "Count" characters are written from "buffer" to the serial port.  The actual
   number of characters written to the port is returned.  If an error occurred
   on writing, -1 is returned.
*/

int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
{
int written;

written = write (port->port, (void *) buffer, (size_t) count);/* write the buffer to the serial port */

if (written == -1) {
    if (errno == EWOULDBLOCK)
        written = 0;                                        /* not an error, but nothing written */
#if defined(EAGAIN)
    else if (errno == EAGAIN)
        written = 0;                                        /* not an error, but nothing written */
#endif
    else                                                    /* unexpected error? */
        sim_error_serial ("write", errno);                  /* report it */
    }

return (int32) written;                                     /* return number of characters written */
}


/* Close a serial port.

   The serial port is closed.  Errors are ignored.
*/

static void sim_close_os_serial (SERHANDLE port)
{
close (port->port);                                           /* close the port */
free (port);
}


#elif defined (VMS)

/* VMS implementation */

#if defined(__VAX)
#define sys$assign SYS$ASSIGN
#define sys$qio SYS$QIO
#define sys$qiow SYS$QIOW
#define sys$dassgn SYS$DASSGN
#define sys$device_scan SYS$DEVICE_SCAN
#define sys$getdviw SYS$GETDVIW
#endif

#include <descrip.h>
#include <ttdef.h>
#include <tt2def.h>
#include <iodef.h>
#include <ssdef.h>
#include <dcdef.h>
#include <dvsdef.h>
#include <dvidef.h>
#include <starlet.h>
#include <unistd.h>

typedef struct {
    unsigned short sense_count;
    unsigned char sense_first_char;
    unsigned char sense_reserved;
    unsigned int stat;
    unsigned int stat2; } SENSE_BUF;

typedef struct {
    unsigned short status;
    unsigned short count;
    unsigned int dev_status; } IOSB;

typedef struct {
    unsigned short buffer_size;
    unsigned short item_code;
    void *buffer_address;
    void *return_length_address;
    } ITEM;

struct SERPORT {
    uint32 port;
    IOSB write_iosb;
    };

/* Enumerate the available serial ports.

   The serial port names generated by attempting to open /dev/ttyS0 thru
   /dev/ttyS53 and /dev/ttyUSB0 thru /dev/ttyUSB0.  Ones we can open and
   are ttys (as determined by isatty()) are added to the list.  The list 
   is sorted alphabetically by device name.

*/

static int sim_serial_os_devices (int max, SERIAL_LIST* list)
{
$DESCRIPTOR (wild, "*");
char devstr[sizeof(list[0].name)];
$DESCRIPTOR (device, devstr);
int ports;
IOSB iosb;
uint32 status;
uint32 devsts;
#define UCB$M_TEMPLATE 0x2000       /* Device is a template device */
#define UCB$M_ONLINE   0x0010       /* Device is online */
uint32 devtype;
uint32 devdepend;
#define DEV$M_RTM 0x20000000
uint32 devnamlen = 0;
t_bool done = FALSE;
uint32 context[2];
uint32 devclass = DC$_TERM; /* Only interested in terminal devices */
ITEM select_items[] = { {sizeof (devclass), DVS$_DEVCLASS, &devclass, NULL},
                        {                  0,               0,        NULL, NULL}};
ITEM valid_items[] =  { {    sizeof (devsts),        DVI$_STS,     &devsts, NULL},
                        {     sizeof(devstr),     DVI$_DEVNAM,      devstr, &devnamlen},
                        {    sizeof(devtype),    DVI$_DEVTYPE,    &devtype, NULL},
                        {  sizeof(devdepend),  DVI$_DEVDEPEND,  &devdepend, NULL},
                        {                  0,               0,        NULL, NULL}};

memset(context, 0, sizeof(context));
memset(devstr, 0, sizeof(devstr));
memset(list, 0, max*sizeof(*list));
for (ports=0; (ports < max); ++ports) {
    device.dsc$w_length = sizeof (devstr) - 1;
    status = sys$device_scan (&device,
                              &device.dsc$w_length,
                              &wild,
                              select_items,
                              &context);
    switch (status) {
        case SS$_NOSUCHDEV:
        case SS$_NOMOREDEV:
            done = TRUE;
            break;
        default:
            if (0 == (status&1))
                done = TRUE;
            else {
                status = sys$getdviw (0, 0, &device, valid_items, &iosb, NULL, 0, NULL);
                if (status == SS$_NORMAL)
                    status = iosb.status;
                if (status != SS$_NORMAL) {
                    done = TRUE;
                    break;
                    }
                device.dsc$w_length = devnamlen;
                if ((0 == (devsts & UCB$M_TEMPLATE)) &&
                    (0 != (devsts & UCB$M_ONLINE)) &&
                    (0 == (devdepend & DEV$M_RTM))) {
                    devstr[device.dsc$w_length] = '\0';
                    strcpy (list[ports].name, devstr);
                    while (list[ports].name[0] == '_')
                        strcpy (list[ports].name, list[ports].name+1);
                    }
                else
                    --ports;
                }
            break;
        }
    if (done)
        break;
    }
return ports;
}

/* Open a serial port.

   The serial port designated by "name" is opened, and the handle to the port is
   returned.  If an error occurs, INVALID_HANDLE is returned instead.  After
   opening, the port is configured to "raw" mode.

   Implementation notes:

    1. We use a non-blocking open to allow for polling during reads.

    2. There is no way to limit "open" just to serial ports, so we must check
       after the port is opened.  We do this with sys$getdvi.

*/

static SERHANDLE sim_open_os_serial (char *name)
{
uint32 status;
uint32 chan = 0;
IOSB iosb;
$DESCRIPTOR (devnam, name);
uint32 devclass;
ITEM items[] = { {sizeof (devclass), DVI$_DEVCLASS, &devclass, NULL},
                 {                0,             0,      NULL, NULL}};
SENSE_BUF start_mode = { 0 };
SENSE_BUF run_mode = { 0 };
SERHANDLE port;

devnam.dsc$w_length = strlen (devnam.dsc$a_pointer);
status = sys$assign (&devnam, &chan, 0, 0);
if (status != SS$_NORMAL) 
    return INVALID_HANDLE;
status = sys$getdviw (0, chan, NULL, items, &iosb, NULL, 0, NULL);
if ((status != SS$_NORMAL)      || 
    (iosb.status != SS$_NORMAL) ||
    (devclass != DC$_TERM)) {
    sys$dassgn (chan);
    return INVALID_HANDLE;
    }
status = sys$qiow (0, chan, IO$_SENSEMODE, &iosb, 0, 0,
    &start_mode, sizeof (start_mode), 0, 0, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) {
    sys$dassgn (chan);
    return INVALID_HANDLE;
    }
run_mode = start_mode;
run_mode.stat = start_mode.stat | TT$M_NOECHO & ~(TT$M_HOSTSYNC | TT$M_TTSYNC | TT$M_HALFDUP);
run_mode.stat2 = start_mode.stat2 | TT2$M_PASTHRU;
status = sys$qiow (0, chan, IO$_SETMODE, &iosb, 0, 0,
    &run_mode, sizeof (run_mode), 0, 0, 0, 0);
if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) {
    sys$dassgn (chan);
    return INVALID_HANDLE;
    }
port = (SERHANDLE)calloc (1, sizeof(*port));
port->port = chan;
port->write_iosb.status = 1;
return port;                                            /* return channel for success */
}


/* Configure a serial port.

   Port parameters are configured as specified in the "config" structure.  If
   "config" contains an invalid configuration value, or if the host system
   rejects the configuration (e.g., by requesting an unsupported combination of
   character size and stop bits), SCPE_ARG is returned to the caller.  If an
   unexpected error occurs, SCPE_IOERR is returned.  If the configuration
   succeeds, SCPE_OK is returned.

   Implementation notes:

    1. 1.5 stop bits is not a supported configuration.

*/

static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config)
{
int32 i;
SENSE_BUF sense;
uint32 status, speed, parity, charsize, stopbits;
IOSB iosb;
static const struct {
    uint32  rate;
    uint32  rate_code;
    } baud_map [] =
        { { 50,     TT$C_BAUD_50     }, { 75,     TT$C_BAUD_75     }, { 110,    TT$C_BAUD_110    }, {  134,   TT$C_BAUD_134   },
          { 150,    TT$C_BAUD_150    }, { 300,    TT$C_BAUD_300    }, {  600,   TT$C_BAUD_600    }, {  1200,  TT$C_BAUD_1200  },
          { 1800,   TT$C_BAUD_1800   }, { 2000,   TT$C_BAUD_2000   }, { 2400,   TT$C_BAUD_2400   }, {  3600,  TT$C_BAUD_3600  },
          { 4800,   TT$C_BAUD_4800   }, { 7200,   TT$C_BAUD_7200   }, { 9600,   TT$C_BAUD_9600   }, { 19200,  TT$C_BAUD_19200 },
          { 38400,  TT$C_BAUD_38400  }, { 57600,  TT$C_BAUD_57600  }, { 76800,  TT$C_BAUD_76800  }, { 115200, TT$C_BAUD_115200} };

static const int32 baud_count = sizeof (baud_map) / sizeof (baud_map [0]);

status = sys$qiow (0, port->port, IO$_SENSEMODE, &iosb, 0, 0, &sense, sizeof(sense), 0, NULL, 0, 0);
if (status == SS$_NORMAL)
    status = iosb.status;
if (status != SS$_NORMAL) {
    sim_error_serial ("config-SENSEMODE", status);      /* report unexpected error */
    return SCPE_IOERR;
    }

for (i = 0; i < baud_count; i++)                        /* assign baud rate */
    if (config.baudrate == baud_map [i].rate) {         /* match mapping value? */
        speed = baud_map [i].rate_code << 8 |           /* set input rate */
                baud_map [i].rate_code;                 /* set output rate */
        break;
        }

if (i == baud_count)                                    /* baud rate assigned? */
    return SCPE_ARG;                                    /* invalid rate specified */

if (config.charsize >= 5 && config.charsize <= 8)       /* character size OK? */
    charsize = TT$M_ALTFRAME | config.charsize;         /* set character size */
else
    return SCPE_ARG;                                    /* not a valid size */

switch (config.parity) {                                /* assign parity */
    case 'E':
        parity = TT$M_ALTRPAR | TT$M_PARITY;            /* set for even parity */
        break;

    case 'N':
        parity = TT$M_ALTRPAR;                          /* set for no parity */
        break;

    case 'O':
        parity = TT$M_ALTRPAR | TT$M_PARITY | TT$M_ODD; /* set for odd parity */
        break;

    default:
        return SCPE_ARG;                                /* not a valid parity specifier */
    }


switch (config.stopbits) {
    case 1:                                             /* one stop bit? */
        stopbits = 0;
        break;
    case 2:                                             /* two stop bits? */
        if ((speed & 0xff) <= TT$C_BAUD_150) {          /* Only valid for */
            stopbits = TT$M_TWOSTOP;                    /* speeds 150baud or less */
            break;
            }
    default:
        return SCPE_ARG;                                /* not a valid number of stop bits */
    }

status = sys$qiow (0, port->port, IO$_SETMODE, &iosb, 0, 0,
    &sense, sizeof (sense), speed, 0, parity | charsize | stopbits, 0);
if (status == SS$_NORMAL)
    status = iosb.status;
if (status != SS$_NORMAL) {
    sim_error_serial ("config-SETMODE", status);        /* report unexpected error */
    return SCPE_IOERR;
    }
return SCPE_OK;                                         /* configuration set successfully */
}


/* Control a serial port.

   The DTR and RTS line of the serial port is set or cleared as indicated in 
   the respective bits_to_set or bits_to_clear parameters.  If the 
   incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, 
   DSR and CTS are returned.

   If unreasonable or nonsense bits_to_set or bits_to_clear bits are 
   specified, then the return status is SCPE_ARG;
   If an error occurs, SCPE_IOERR is returned.
*/

t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
{
uint32 status;
IOSB iosb;
uint32 bits[2] = {0, 0};

if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) ||         /* Assure only settable bits */
    (bits_to_clear & ~(TMXR_MDM_OUTGOING)) ||
    (bits_to_set & bits_to_clear))                  /* and can't set and clear the same bits */
    return SCPE_ARG;
if (bits_to_set)
    bits[0] |= (((bits_to_set&TMXR_MDM_DTR) ? TT$M_DS_DTR : 0) |
                ((bits_to_set&TMXR_MDM_RTS) ? TT$M_DS_RTS : 0)) << 16;
if (bits_to_clear)
    bits[0] |= (((bits_to_clear&TMXR_MDM_DTR) ? TT$M_DS_DTR : 0) |
                ((bits_to_clear&TMXR_MDM_RTS) ? TT$M_DS_RTS : 0)) << 24;
if (bits_to_set || bits_to_clear) {
    status = sys$qiow (0, port->port, IO$_SETMODE|IO$M_SET_MODEM|IO$M_MAINT, &iosb, 0, 0,
                       bits, 0, 0, 0, 0, 0);
    if (status == SS$_NORMAL)
        status = iosb.status;
    if (status != SS$_NORMAL) {
        sim_error_serial ("control-SETMODE", status);      /* report unexpected error */
        return SCPE_IOERR;
        }
    }
if (incoming_bits) {
    uint32 modem;

    status = sys$qiow (0, port->port, IO$_SENSEMODE|IO$M_RD_MODEM, &iosb, 0, 0,
                       bits, 0, 0, 0, 0, 0);
    if (status == SS$_NORMAL)
        status = iosb.status;
    if (status != SS$_NORMAL) {
        sim_error_serial ("control-SENSEMODE", status);      /* report unexpected error */
        return SCPE_IOERR;
        }
    modem = bits[0] >> 16;
    *incoming_bits = ((modem&TT$M_DS_CTS)     ? TMXR_MDM_CTS : 0) |
                     ((modem&TT$M_DS_DSR)     ? TMXR_MDM_DSR : 0) |
                     ((modem&TT$M_DS_RING)    ? TMXR_MDM_RNG : 0) |
                     ((modem&TT$M_DS_CARRIER) ? TMXR_MDM_DCD : 0);
    }

return SCPE_OK;
}


/* Read from a serial port.

   The port is checked for available characters.  If any are present, they are
   copied to the passed buffer, and the count of characters is returned.  If no
   characters are available, 0 is returned.  If an error occurs, -1 is returned.
   If a BREAK is detected on the communications line, the corresponding flag in
   the "brk" array is set.

   Implementation notes:

    1. A character with a framing or parity error is indicated in the input
       stream by the three-character sequence \377 \000 \ccc, where "ccc" is the
       bad character.  A communications line BREAK is indicated by the sequence
       \377 \000 \000.  A received \377 character is indicated by the
       two-character sequence \377 \377.  If we find any of these sequences,
       they are replaced by the single intended character by sliding the
       succeeding characters backward by one or two positions.  If a BREAK
       sequence was encountered, the corresponding location in the "brk" array
       is determined, and the flag is set.  Note that there may be multiple
       sequences in the buffer.
*/

int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk)
{
int read_count = 0;
uint32 status;
static uint32 term[2] = {0, 0};
unsigned char buf[4];
IOSB iosb;
SENSE_BUF sense;

status = sys$qiow (0, port->port, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb,
    0, 0, &sense, 8, 0, term, 0, 0);
if (status == SS$_NORMAL)
    status = iosb.status;
if (status != SS$_NORMAL) {
    sim_error_serial ("read", status);                      /* report unexpected error */
    return -1;
    }
if (sense.sense_count == 0)                                 /* no characters available? */
    return 0;                                               /* return 0 to indicate */
status = sys$qiow (0, port->port, IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO, 
                   &iosb, 0, 0, buffer, (count < sense.sense_count) ? count : sense.sense_count, 0, term, 0, 0);
if (status == SS$_NORMAL)
    status = iosb.status;
if (status != SS$_NORMAL) {
    sim_error_serial ("read", status);                      /* report unexpected error */
    return -1;
    }
return (int32)iosb.count;                                   /* return the number of characters read */
}


/* Write to a serial port.

   "Count" characters are written from "buffer" to the serial port.  The actual
   number of characters written to the port is returned.  If an error occurred
   on writing, -1 is returned.
*/

int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
{
uint32 status;

if (port->write_iosb.status == 0)           /* Prior write not done yet? */
    return 0;
status = sys$qio (0, port->port, IO$_WRITELBLK | IO$M_NOFORMAT,
                  &port->write_iosb, 0, 0, buffer, count, 0, 0, 0, 0);
if (status != SS$_NORMAL) {
    sim_error_serial ("write", status);                 /* report unexpected error */
    return -1;
    }
return (int32)count;                                    /* return number of characters written */
}


/* Close a serial port.

   The serial port is closed.  Errors are ignored.
*/

static void sim_close_os_serial (SERHANDLE port)
{
sys$dassgn (port->port);                                /* close the port */
free (port);
}

#else

/* Non-implemented stubs */

/* Enumerate the available serial ports. */

static int sim_serial_os_devices (int max, SERIAL_LIST* list)
{
return 0;
}

/* Open a serial port */

static SERHANDLE sim_open_os_serial (char *name)
{
return INVALID_HANDLE;
}


/* Configure a serial port */

static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config)
{
return SCPE_IERR;
}


/* Control a serial port */

t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
{
return SCPE_NOFNC;
}


/* Read from a serial port */

int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk)
{
return -1;
}


/* Write to a serial port */

int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
{
return -1;
}


/* Close a serial port */

static void sim_close_os_serial (SERHANDLE port)
{
}



#endif                                                  /* end else !implemented */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_serial.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/* sim_serial.h: OS-dependent serial port routines header file

   Copyright (c) 2008, J. David Bryan

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the author shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from the author.

   07-Oct-08    JDB     [serial] Created file
*/


#ifndef SIM_SERIAL_H_
#define SIM_SERIAL_H_    0

#ifdef  __cplusplus
extern "C" {
#endif

#ifndef SIMH_SERHANDLE_DEFINED
#define SIMH_SERHANDLE_DEFINED 0
typedef struct SERPORT *SERHANDLE;
#endif /* SERHANDLE_DEFINED */

#if defined (_WIN32)                        /* Windows definitions */

/* We need the basic Win32 definitions, but including "windows.h" also includes
   "winsock.h" as well.  However, "sim_sock.h" explicitly includes "winsock2.h,"
   and this file cannot coexist with "winsock.h".  So we set a guard definition
   that prevents "winsock.h" from being included.
*/

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#if !defined(INVALID_HANDLE)
#define INVALID_HANDLE  (SERHANDLE)INVALID_HANDLE_VALUE
#endif /* !defined(INVALID_HANDLE) */

#elif defined (__unix__) || defined (__APPLE__) || defined (__hpux) /* UNIX definitions */

#include <fcntl.h>
#ifdef __hpux
#include <sys/modem.h>
#endif
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>

#if !defined(INVALID_HANDLE)
#define INVALID_HANDLE  ((SERHANDLE)(void *)-1)
#endif /* !defined(INVALID_HANDLE) */

#elif defined (VMS)                             /* VMS definitions */
#if !defined(INVALID_HANDLE)
#define INVALID_HANDLE  ((SERHANDLE)(void *)-1)
#endif /* !defined(INVALID_HANDLE) */

#else                                           /* Non-implemented definitions */

#if !defined(INVALID_HANDLE)
#define INVALID_HANDLE  ((SERHANDLE)(void *)-1)
#endif /* !defined(INVALID_HANDLE) */

#endif  /* OS variants */


/* Common definitions */

/* Global routines */
#include "sim_tmxr.h"                           /* need TMLN definition and modem definitions */

extern SERHANDLE sim_open_serial    (char *name, TMLN *lp, t_stat *status);
extern t_stat    sim_config_serial  (SERHANDLE port, CONST char *config);
extern t_stat    sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits);
extern int32     sim_read_serial    (SERHANDLE port, char *buffer, int32 count, char *brk);
extern int32     sim_write_serial   (SERHANDLE port, char *buffer, int32 count);
extern void      sim_close_serial   (SERHANDLE port);
extern t_stat    sim_show_serial    (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc);

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































Deleted src/sim_sock.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
/* sim_sock.c: OS-dependent socket routines

   Copyright (c) 2001-2010, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   15-Oct-12    MP      Added definitions needed to detect possible tcp 
                        connect failures
   25-Sep-12    MP      Reworked for RFC3493 interfaces supporting IPv6 and IPv4
   22-Jun-10    RMS     Fixed types in sim_accept_conn (from Mark Pizzolato)
   19-Nov-05    RMS     Added conditional for OpenBSD (from Federico G. Schwindt)
   16-Aug-05    RMS     Fixed spurious SIGPIPE signal error in Unix
   14-Apr-05    RMS     Added WSAEINPROGRESS test (from Tim Riker)
   09-Jan-04    RMS     Fixed typing problem in Alpha Unix (found by Tim Chapman)
   17-Apr-03    RMS     Fixed non-implemented version of sim_close_sock
                        (found by Mark Pizzolato)
   17-Dec-02    RMS     Added sim_connect_socket, sim_create_socket
   08-Oct-02    RMS     Revised for .NET compatibility
   22-Aug-02    RMS     Changed calling sequence for sim_accept_conn
   22-May-02    RMS     Added OS2 EMX support from Holger Veit
   06-Feb-02    RMS     Added VMS support from Robert Alan Byer
   16-Sep-01    RMS     Added Macintosh support from Peter Schorn
   02-Sep-01    RMS     Fixed UNIX bugs found by Mirian Lennox and Tom Markson
*/

#ifdef  __cplusplus
extern "C" {
#endif

#include "sim_sock.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

#if defined(AF_INET6) && defined(_WIN32)
#include <ws2tcpip.h>
#endif

#ifdef HAVE_DLOPEN
#include <dlfcn.h>
#endif

#ifndef WSAAPI
#define WSAAPI
#endif

#if defined(SHUT_RDWR) && !defined(SD_BOTH)
#define SD_BOTH SHUT_RDWR
#endif

#ifndef   NI_MAXHOST
#define   NI_MAXHOST 1025
#endif

/* OS dependent routines

   sim_master_sock      create master socket
   sim_connect_sock     connect a socket to a remote destination
   sim_connect_sock_ex  connect a socket to a remote destination
   sim_accept_conn      accept connection
   sim_read_sock        read from socket
   sim_write_sock       write from socket
   sim_close_sock       close socket
   sim_setnonblock      set socket non-blocking
*/

/* First, all the non-implemented versions */

#if defined (__OS2__) && !defined (__EMX__)

void sim_init_sock (void)
{
}

void sim_cleanup_sock (void)
{
}

SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags)
{
return INVALID_SOCKET;
}

SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags)
{
return INVALID_SOCKET;
}

SOCKET sim_accept_conn (SOCKET master, char **connectaddr);
{
return INVALID_SOCKET;
}

int sim_read_sock (SOCKET sock, char *buf, int nbytes)
{
return -1;
}

int sim_write_sock (SOCKET sock, char *msg, int nbytes)
{
return 0;
}

void sim_close_sock (SOCKET sock)
{
return;
}

#else                                                   /* endif unimpl */

/* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */

static struct sock_errors {
    int value;
    const char *text;
    } sock_errors[] = {
        {WSAEWOULDBLOCK,  "Operation would block"},
        {WSAENAMETOOLONG, "File name too long"},
        {WSAEINPROGRESS,  "Operation now in progress "},
        {WSAETIMEDOUT,    "Connection timed out"},
        {WSAEISCONN,      "Transport endpoint is already connected"},
        {WSAECONNRESET,   "Connection reset by peer"},
        {WSAECONNREFUSED, "Connection refused"},
        {WSAECONNABORTED, "Connection aborted"},
        {WSAEHOSTUNREACH, "No route to host"},
        {WSAEADDRINUSE,   "Address already in use"},
#if defined (WSAEAFNOSUPPORT)
        {WSAEAFNOSUPPORT, "Address family not supported by protocol"},
#endif
        {WSAEACCES,       "Permission denied"},
        {0, NULL}
    };


const char *sim_get_err_sock (const char *emsg)
{
int err = WSAGetLastError ();
int i;
static char err_buf[512];

for (i=0; (sock_errors[i].text) && (sock_errors[i].value != err); i++)
    ;
if (sock_errors[i].value == err)
    sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, sock_errors[i].text);
else
#if defined(_WIN32)
    sprintf (err_buf, "Sockets: %s error %d\n", emsg, err);
#else
    sprintf (err_buf, "Sockets: %s error %d - %s\n", emsg, err, strerror(err));
#endif
return err_buf;
}

SOCKET sim_err_sock (SOCKET s, const char *emsg)
{
sim_printf ("%s", sim_get_err_sock (emsg));
if (s != INVALID_SOCKET) {
    int err = WSAGetLastError ();
    sim_close_sock (s);
    WSASetLastError (err);      /* Retain Original socket error value */
    }
return INVALID_SOCKET;
}

typedef void    (WSAAPI *freeaddrinfo_func) (struct addrinfo *ai);
static freeaddrinfo_func p_freeaddrinfo;

typedef int     (WSAAPI *getaddrinfo_func) (const char *hostname,
                                 const char *service,
                                 const struct addrinfo *hints,
                                 struct addrinfo **res);
static getaddrinfo_func p_getaddrinfo;

#if defined(VMS)
typedef size_t socklen_t;
#if !defined(EAI_OVERFLOW)
#define EAI_OVERFLOW EAI_FAIL
#endif
#endif

#if defined(__hpux)
#if !defined(EAI_OVERFLOW)
#define EAI_OVERFLOW EAI_FAIL
#endif
#endif

typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
static getnameinfo_func p_getnameinfo;

static void    WSAAPI s_freeaddrinfo (struct addrinfo *ai)
{
struct addrinfo *a, *an;

for (a=ai; a != NULL; a=an) {
    an = a->ai_next;
    free (a->ai_canonname);
    free (a->ai_addr);
    free (a);
    }
}

static int     WSAAPI s_getaddrinfo (const char *hostname,
                                     const char *service,
                                     const struct addrinfo *hints,
                                     struct addrinfo **res)
{
struct hostent *he;
struct servent *se = NULL;
struct sockaddr_in *sin;
struct addrinfo *result = NULL;
struct addrinfo *ai, *lai = NULL;
struct addrinfo dhints;
struct in_addr ipaddr;
struct in_addr *fixed[2];
struct in_addr **ips = NULL;
struct in_addr **ip;
const char *cname = NULL;
int port = 0;

// Validate parameters
if ((hostname == NULL) && (service == NULL))
    return EAI_NONAME;

if (hints) {
    if ((hints->ai_family != PF_INET) && (hints->ai_family != PF_UNSPEC))
        return EAI_FAMILY;
    switch (hints->ai_socktype)
        {
        default:
            return EAI_SOCKTYPE;
        case SOCK_DGRAM:
        case SOCK_STREAM:
        case 0:
            break;
        }
    }
else {
    hints = &dhints;
    memset(&dhints, 0, sizeof(dhints));
    dhints.ai_family = PF_UNSPEC;
    }
if (service) {
    char *c;

    port = strtoul(service, &c, 10);
    if ((port == 0) || (*c != '\0')) {
        switch (hints->ai_socktype)
            {
            case SOCK_DGRAM:
                se = getservbyname(service, "udp");
                break;
            case SOCK_STREAM:
            case 0:
                se = getservbyname(service, "tcp");
                break;
            }
        if (NULL == se)
            return EAI_SERVICE;
        port = se->s_port;
        }
    }

if (hostname) {
    if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) || 
        (0 == strcmp("255.255.255.255", hostname))) {
        fixed[0] = &ipaddr;
        fixed[1] = NULL;
        }
    else {
        if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) || 
            (0 == strcmp("255.255.255.255", hostname))) {
            fixed[0] = &ipaddr;
            fixed[1] = NULL;
            if ((hints->ai_flags & AI_CANONNAME) && !(hints->ai_flags & AI_NUMERICHOST)) {
                he = gethostbyaddr((char *)&ipaddr, 4, AF_INET);
                if (NULL != he)
                    cname = he->h_name;
                else
                    cname = hostname;
                }
            ips = fixed;
            }
        else {
            if (hints->ai_flags & AI_NUMERICHOST)
                return EAI_NONAME;
            he = gethostbyname(hostname);
            if (he) {
                ips = (struct in_addr **)he->h_addr_list;
                if (hints->ai_flags & AI_CANONNAME)
                    cname = he->h_name;
                }
            else {
                switch (h_errno)
                    {
                    case HOST_NOT_FOUND:
                    case NO_DATA:
                        return EAI_NONAME;
                    case TRY_AGAIN:
                        return EAI_AGAIN;
                    default:
                        return EAI_FAIL;
                    }
                }
            }
        }
    }
else {
    if (hints->ai_flags & AI_PASSIVE)
        ipaddr.s_addr = htonl(INADDR_ANY);
    else
        ipaddr.s_addr = htonl(INADDR_LOOPBACK);
    fixed[0] = &ipaddr;
    fixed[1] = NULL;
    ips = fixed;
    }
for (ip=ips; (ip != NULL) && (*ip != NULL); ++ip) {
    ai = (struct addrinfo *)calloc(1, sizeof(*ai));
    if (NULL == ai) {
        s_freeaddrinfo(result);
        return EAI_MEMORY;
        }
    ai->ai_family = PF_INET;
    ai->ai_socktype = hints->ai_socktype;
    ai->ai_protocol = hints->ai_protocol;
    ai->ai_addr = NULL;
    ai->ai_addrlen = sizeof(struct sockaddr_in);
    ai->ai_canonname = NULL;
    ai->ai_next = NULL;
    ai->ai_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in));
    if (NULL == ai->ai_addr) {
        free(ai);
        s_freeaddrinfo(result);
        return EAI_MEMORY;
        }
    sin = (struct sockaddr_in *)ai->ai_addr;
    sin->sin_family = PF_INET;
    sin->sin_port = (unsigned short)port;
    memcpy(&sin->sin_addr, *ip, sizeof(sin->sin_addr));
    if (NULL == result)
        result = ai;
    else
        lai->ai_next = ai;
    lai = ai;
    }
if (cname) {
    result->ai_canonname = (char *)calloc(1, strlen(cname)+1);
    if (NULL == result->ai_canonname) {
        s_freeaddrinfo(result);
        return EAI_MEMORY;
        }
    strcpy(result->ai_canonname, cname);
    }
*res = result;
return 0;
}

#ifndef EAI_OVERFLOW
#define EAI_OVERFLOW WSAENAMETOOLONG
#endif

static int     WSAAPI s_getnameinfo (const struct sockaddr *sa, socklen_t salen,
                                     char *host, size_t hostlen,
                                     char *serv, size_t servlen,
                                     int flags)
{
struct hostent *he;
struct servent *se = NULL;
const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;

if (sin->sin_family != PF_INET)
    return EAI_FAMILY;
if ((NULL == host) && (NULL == serv))
    return EAI_NONAME;
if ((serv) && (servlen > 0)) {
    if (flags & NI_NUMERICSERV)
        se = NULL;
    else
        if (flags & NI_DGRAM)
            se = getservbyport(sin->sin_port, "udp");
        else
            se = getservbyport(sin->sin_port, "tcp");
    if (se) {
        if (servlen <= strlen(se->s_name))
            return EAI_OVERFLOW;
        strcpy(serv, se->s_name);
        }
    else {
        char buf[16];

        sprintf(buf, "%d", ntohs(sin->sin_port));
        if (servlen <= strlen(buf))
            return EAI_OVERFLOW;
        strcpy(serv, buf);
        }
    }
if ((host) && (hostlen > 0)) {
    if (flags & NI_NUMERICHOST)
        he = NULL;
    else
        he = gethostbyaddr((const char *)&sin->sin_addr, 4, AF_INET);
    if (he) {
        if (hostlen < strlen(he->h_name)+1)
            return EAI_OVERFLOW;
        strcpy(host, he->h_name);
        }
    else {
        if (flags & NI_NAMEREQD)
            return EAI_NONAME;
        if (hostlen < strlen(inet_ntoa(sin->sin_addr))+1)
            return EAI_OVERFLOW;
        strcpy(host, inet_ntoa(sin->sin_addr));
        }
    }
return 0;
}

#if defined(_WIN32) || defined(__CYGWIN__)

#if !defined(IPV6_V6ONLY)           /* Older XP environments may not define IPV6_V6ONLY */
#define IPV6_V6ONLY           27    /* Treat wildcard bind as AF_INET6-only. */
#endif
/* Dynamic DLL load variables */
#ifdef _WIN32
static HINSTANCE hLib = 0;                      /* handle to DLL */
#else
static void *hLib = NULL;                       /* handle to Library */
#endif
static int lib_loaded = 0;                      /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */
static const char* lib_name = "Ws2_32.dll";

/* load function pointer from DLL */
typedef int (*_func)();

static void load_function(const char* function, _func* func_ptr) {
#ifdef _WIN32
    *func_ptr = (_func)GetProcAddress(hLib, function);
#else
    *func_ptr = (_func)dlsym(hLib, function);
#endif
    if (*func_ptr == 0) {
    sim_printf ("Sockets: Failed to find function '%s' in %s\r\n", function, lib_name);
    lib_loaded = 3;
  }
}

/* load Ws2_32.dll as required */
int load_ws2(void) {
  switch(lib_loaded) {
    case 0:                  /* not loaded */
            /* attempt to load DLL */
#ifdef _WIN32
      hLib = LoadLibraryA(lib_name);
#else
      hLib = dlopen(lib_name, RTLD_NOW);
#endif
      if (hLib == 0) {
        /* failed to load DLL */
        sim_printf ("Sockets: Failed to load %s\r\n", lib_name);
        lib_loaded = 2;
        break;
      } else {
        /* library loaded OK */
        lib_loaded = 1;
      }

      /* load required functions; sets dll_load=3 on error */
      load_function("getaddrinfo",       (_func *) &p_getaddrinfo);
      load_function("getnameinfo",       (_func *) &p_getnameinfo);
      load_function("freeaddrinfo",      (_func *) &p_freeaddrinfo);

      if (lib_loaded != 1) {
        /* unsuccessful load, connect stubs */
        p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo;
        p_getnameinfo = (getnameinfo_func)s_getnameinfo;
        p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo;
      }
      break;
    default:                /* loaded or failed */
      break;
  }
  return (lib_loaded == 1) ? 1 : 0;
}
#endif

/* OS independent routines

   sim_parse_addr       parse a hostname/ipaddress from port and apply defaults and 
                        optionally validate an address match
*/

/* sim_parse_addr       host:port

   Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
   If the host field contains one or more colon characters (i.e. it is an IPv6 address), 
   the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)

   Inputs:
        cptr    =       pointer to input string
        default_host
                =       optional pointer to default host if none specified
        host_len =      length of host buffer
        default_port
                =       optional pointer to default port if none specified
        port_len =      length of port buffer
        validate_addr = optional name/addr which is checked to be equivalent
                        to the host result of parsing the other input.  This
                        address would usually be returned by sim_accept_conn.
   Outputs:
        host    =       pointer to buffer for IP address (may be NULL), 0 = none
        port    =       pointer to buffer for IP port (may be NULL), 0 = none
        result  =       status (0 on complete success or -1 if 
                        parsing can't happen due to bad syntax, a value is 
                        out of range, a result can't fit into a result buffer, 
                        a service name doesn't exist, or a validation name 
                        doesn't match the parsed host)
*/

int sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr)
{
char gbuf[CBUFSIZE], default_pbuf[CBUFSIZE];
const char *hostp;
char *portp;
char *endc;
unsigned long portval;

if ((host != NULL) && (host_len != 0))
    memset (host, 0, host_len);
if ((port != NULL) && (port_len != 0))
    memset (port, 0, port_len);
if ((cptr == NULL) || (*cptr == 0)) {
    if (((default_host == NULL) || (*default_host == 0)) || ((default_port == NULL) || (*default_port == 0)))
        return -1;
    if ((host == NULL) || (port == NULL))
        return -1;                                  /* no place */
    if ((strlen(default_host) >= host_len) || (strlen(default_port) >= port_len))
        return -1;                                  /* no room */
    strcpy (host, default_host);
    strcpy (port, default_port);
    return 0;
    }
memset (default_pbuf, 0, sizeof(default_pbuf));
if (default_port)
    strncpy (default_pbuf, default_port, sizeof(default_pbuf)-1);
gbuf[sizeof(gbuf)-1] = '\0';
strncpy (gbuf, cptr, sizeof(gbuf)-1);
hostp = gbuf;                                           /* default addr */
portp = NULL;
if ((portp = strrchr (gbuf, ':')) &&                    /* x:y? split */
    (NULL == strchr (portp, ']'))) {
    *portp++ = 0;
    if (*portp == '\0')
        portp = default_pbuf;
    }
else {                                                  /* No colon in input */
    portp = gbuf;                                       /* Input is the port specifier */
    hostp = (const char *)default_host;                 /* host is defaulted if provided */
    }
if (portp != NULL) {
    portval = strtoul(portp, &endc, 10);
    if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
        return -1;                                      /* numeric value too big */
    if (*endc != '\0') {
        struct servent *se = getservbyname(portp, "tcp");

        if (se == NULL)
            return -1;                                  /* invalid service name */
        }
    }
if (port)                                               /* port wanted? */
    if (portp != NULL) {
        if (strlen(portp) >= port_len)
            return -1;                                  /* no room */
        else
            strcpy (port, portp);
        }
if (hostp != NULL) {
    if (']' == hostp[strlen(hostp)-1]) {
        if ('[' != hostp[0])
            return -1;                                  /* invalid domain literal */
        /* host may be the const default_host so move to temp buffer before modifying */
        strncpy(gbuf, hostp+1, sizeof(gbuf)-1);         /* remove brackets from domain literal host */
        gbuf[strlen(gbuf)-1] = '\0';
        hostp = gbuf;
        }
    }
if (host) {                                             /* host wanted? */
    if (hostp != NULL) {
        if (strlen(hostp) >= host_len)
            return -1;                                  /* no room */
        else
            if (('\0' != hostp[0]) || (default_host == NULL))
                strcpy (host, hostp);
            else
                if (strlen(default_host) >= host_len)
                    return -1;                          /* no room */
                else
                    strcpy (host, default_host);
        }
    else {
        if (default_host) {
            if (strlen(default_host) >= host_len)
                return -1;                              /* no room */
            else
                strcpy (host, default_host);
            }
        }
    }
if (validate_addr) {
    struct addrinfo *ai_host, *ai_validate, *ai, *aiv;
    int status;

    if (hostp == NULL)
        return -1;
    if (p_getaddrinfo(hostp, NULL, NULL, &ai_host))
        return -1;
    if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) {
        p_freeaddrinfo (ai_host);
        return -1;
        }
    status = -1;
    for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
        for (aiv = ai_validate; aiv != NULL; aiv = aiv->ai_next) {
            if ((ai->ai_addrlen == aiv->ai_addrlen) &&
                (ai->ai_family == aiv->ai_family) &&
                (0 == memcmp (ai->ai_addr, aiv->ai_addr, ai->ai_addrlen))) {
                status = 0;
                break;
                }
            }
        }
    if (status != 0) {
        /* be generous and allow successful validations against variations of localhost addresses */
        if (((0 == strcmp("127.0.0.1", hostp)) && 
             (0 == strcmp("::1", validate_addr))) ||
            ((0 == strcmp("127.0.0.1", validate_addr)) && 
             (0 == strcmp("::1", hostp))))
            status = 0;
        }
    p_freeaddrinfo (ai_host);
    p_freeaddrinfo (ai_validate);
    return status;
    }
return 0;
}

/* sim_parse_addr_ex    localport:host:port

   Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
   If the host field contains one or more colon characters (i.e. it is an IPv6 address), 
   the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)

        llll:w.x.y.z:rrrr
        llll:name.domain.com:rrrr
        llll::rrrr
        rrrr
        w.x.y.z:rrrr
        [w.x.y.z]:rrrr
        name.domain.com:rrrr

   Inputs:
        cptr    =       pointer to input string
        default_host
                =       optional pointer to default host if none specified
        host_len =      length of host buffer
        default_port
                =       optional pointer to default port if none specified
        port_len =      length of port buffer

   Outputs:
        host    =       pointer to buffer for IP address (may be NULL), 0 = none
        port    =       pointer to buffer for IP port (may be NULL), 0 = none
        localport
                =       pointer to buffer for local IP port (may be NULL), 0 = none
        result  =       status (SCPE_OK on complete success or SCPE_ARG if 
                        parsing can't happen due to bad syntax, a value is 
                        out of range, a result can't fit into a result buffer, 
                        a service name doesn't exist, or a validation name 
                        doesn't match the parsed host)
*/
int sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t localport_len, const char *default_port)
{
const char *hostp;

if ((localport != NULL) && (localport_len != 0))
    memset (localport, 0, localport_len);
hostp = strchr (cptr, ':');
if ((hostp != NULL) && ((hostp[1] == '[') || (NULL != strchr (hostp+1, ':')))) {
    if ((localport != NULL) && (localport_len != 0)) {
        localport_len -= 1;
        if (localport_len > (size_t)(hostp-cptr))
            localport_len = (size_t)(hostp-cptr);
        memcpy (localport, cptr, localport_len);
        }
    return sim_parse_addr (hostp+1, host, hostlen, default_host, port, port_len, default_port, NULL);
    }
return sim_parse_addr (cptr, host, hostlen, default_host, port, port_len, default_port, NULL);
}


void sim_init_sock (void)
{
#if defined (_WIN32)
int err;
WORD wVersionRequested; 
WSADATA wsaData; 
wVersionRequested = MAKEWORD (2, 2);

err = WSAStartup (wVersionRequested, &wsaData);         /* start Winsock */ 
if (err != 0)
    sim_printf ("Winsock: startup error %d\n", err);
#if defined(AF_INET6)
load_ws2 ();
#endif                                                  /* endif AF_INET6 */
#else                                                   /* Use native addrinfo APIs */
#if defined(AF_INET6)
    p_getaddrinfo = (getaddrinfo_func)getaddrinfo;
    p_getnameinfo = (getnameinfo_func)getnameinfo;
    p_freeaddrinfo = (freeaddrinfo_func)freeaddrinfo;
#else
    /* Native APIs not available, connect stubs */
    p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo;
    p_getnameinfo = (getnameinfo_func)s_getnameinfo;
    p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo;
#endif                                                  /* endif AF_INET6 */
#endif                                                  /* endif _WIN32 */
#if defined (SIGPIPE)
signal (SIGPIPE, SIG_IGN);                              /* no pipe signals */
#endif
}

void sim_cleanup_sock (void)
{
#if defined (_WIN32)
WSACleanup ();
#endif
}

#if defined (_WIN32)                                    /* Windows */
static int sim_setnonblock (SOCKET sock)
{
unsigned long non_block = 1;

return ioctlsocket (sock, FIONBIO, &non_block);         /* set nonblocking */
}

#elif defined (VMS)                                     /* VMS */
static int sim_setnonblock (SOCKET sock)
{
int non_block = 1;

return ioctl (sock, FIONBIO, &non_block);               /* set nonblocking */
}

#else                                                   /* Mac, Unix, OS/2 */
static int sim_setnonblock (SOCKET sock)
{
int fl, sta;

fl = fcntl (sock, F_GETFL,0);                           /* get flags */
if (fl == -1)
    return SOCKET_ERROR;
sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK);           /* set nonblock */
if (sta == -1)
    return SOCKET_ERROR;
#if !defined (macintosh) && !defined (__EMX__) && \
    !defined (__HAIKU__)                                /* Unix only */
sta = fcntl (sock, F_SETOWN, getpid());                 /* set ownership */
if (sta == -1)
    return SOCKET_ERROR;
#endif
return 0;
}

#endif                                                  /* endif !Win32 && !VMS */

static int sim_setnodelay (SOCKET sock)
{
int nodelay = 1;
int sta;

/* disable Nagle algorithm */
sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));
if (sta == -1)
    return SOCKET_ERROR;

#if defined(TCP_NODELAYACK)
/* disable delayed ack algorithm */
sta = setsockopt (sock, IPPROTO_TCP, TCP_NODELAYACK, (char *)&nodelay, sizeof(nodelay));
if (sta == -1)
    return SOCKET_ERROR;
#endif

#if defined(TCP_QUICKACK)
/* disable delayed ack algorithm */
sta = setsockopt (sock, IPPROTO_TCP, TCP_QUICKACK, (char *)&nodelay, sizeof(nodelay));
if (sta == -1)
    return SOCKET_ERROR;
#endif

return sta;
}

static SOCKET sim_create_sock (int af, int opt_flags)
{
SOCKET newsock;
int err;

newsock = socket (af, ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM), 0);/* create socket */
if (newsock == INVALID_SOCKET) {                        /* socket error? */
    err = WSAGetLastError ();
#if defined(WSAEAFNOSUPPORT)
    if (err == WSAEAFNOSUPPORT)                         /* expected error, just return */
        return newsock;
#endif
    return sim_err_sock (newsock, "socket");            /* report error and return */
    }
return newsock;
}

/*
   Some platforms and/or network stacks have varying support for listening on 
   an IPv6 socket and receiving connections from both IPv4 and IPv6 client 
   connections.  This is known as IPv4-Mapped.  Some platforms claim such 
   support (i.e. some Windows versions), but it doesn't work in all cases.
*/

SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags)
{
SOCKET newsock = INVALID_SOCKET;
int sta;
char host[CBUFSIZE], port[CBUFSIZE];
int r;
struct addrinfo hints;
struct addrinfo *result = NULL, *preferred;

r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL);
if (parse_status)
    *parse_status = r;
if (r)
    return newsock;

memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) {
    if (parse_status)
        *parse_status = -1;
    return newsock;
    }
preferred = result;
#ifdef IPV6_V6ONLY
/*
    When we can create a dual stack socket, be sure to find the IPv6 addrinfo 
    to bind to.
*/
for (; preferred != NULL; preferred = preferred->ai_next) {
    if (preferred->ai_family == AF_INET6)
        break;
    }
if (preferred == NULL)
    preferred = result;
#endif
retry:
newsock = sim_create_sock (preferred->ai_family, 0);    /* create socket */
if (newsock == INVALID_SOCKET) {                        /* socket error? */
#ifndef IPV6_V6ONLY
    if (preferred->ai_next) {
        preferred = preferred->ai_next;
        goto retry;
        }
#else
    if ((preferred->ai_family == AF_INET6) &&
        (preferred != result)) {
        preferred = result;
        goto retry;
        }
#endif
    p_freeaddrinfo(result);
    return newsock;
    }
#ifdef IPV6_V6ONLY
if (preferred->ai_family == AF_INET6) {
    int off = 0;
    sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off));
    }
#endif
if (opt_flags & SIM_SOCK_OPT_REUSEADDR) {
    int on = 1;

    sta = setsockopt (newsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
    }
#if defined (SO_EXCLUSIVEADDRUSE)
else {
    int on = 1;

    sta = setsockopt (newsock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&on, sizeof(on));
    }
#endif
sta = bind (newsock, preferred->ai_addr, preferred->ai_addrlen);
p_freeaddrinfo(result);
if (sta == SOCKET_ERROR)                                /* bind error? */
    return sim_err_sock (newsock, "bind");
if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
    sta = sim_setnonblock (newsock);                    /* set nonblocking */
    if (sta == SOCKET_ERROR)                            /* fcntl error? */
        return sim_err_sock (newsock, "fcntl");
    }
sta = listen (newsock, 1);                              /* listen on socket */
if (sta == SOCKET_ERROR)                                /* listen error? */
    return sim_err_sock (newsock, "listen");
return newsock;                                         /* got it! */
}

SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags)
{
SOCKET newsock = INVALID_SOCKET;
int sta;
char host[CBUFSIZE], port[CBUFSIZE];
struct addrinfo hints;
struct addrinfo *result = NULL, *source = NULL;

if (sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL))
    return INVALID_SOCKET;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM);
if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result))
    return INVALID_SOCKET;

if (sourcehostport) {

    /* Validate the local/source side address which we'll bind to */
    if (sim_parse_addr (sourcehostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL)) {
        p_freeaddrinfo (result);
        return INVALID_SOCKET;
        }

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = result->ai_family;                /* Same family as connect destination */
    hints.ai_protocol = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? IPPROTO_UDP : IPPROTO_TCP);
    hints.ai_socktype = ((opt_flags & SIM_SOCK_OPT_DATAGRAM) ? SOCK_DGRAM : SOCK_STREAM);
    if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &source)) {
        p_freeaddrinfo (result);
        return INVALID_SOCKET;
        }

    newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */
    if (newsock == INVALID_SOCKET) {                    /* socket error? */
        p_freeaddrinfo (result);
        p_freeaddrinfo (source);
        return newsock;
        }

    sta = bind (newsock, source->ai_addr, source->ai_addrlen);
    p_freeaddrinfo(source);
    source = NULL;
    if (sta == SOCKET_ERROR) {                          /* bind error? */
        p_freeaddrinfo (result);
        return sim_err_sock (newsock, "bind");
        }
    }

if (newsock == INVALID_SOCKET) {                        /* socket error? */
    newsock = sim_create_sock (result->ai_family, opt_flags & SIM_SOCK_OPT_DATAGRAM);/* create socket */
    if (newsock == INVALID_SOCKET) {                    /* socket error? */
        p_freeaddrinfo (result);
        return newsock;
        }
    }

if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
    sta = sim_setnonblock (newsock);                    /* set nonblocking */
    if (sta == SOCKET_ERROR) {                          /* fcntl error? */
        p_freeaddrinfo (result);
        return sim_err_sock (newsock, "fcntl");
        }
    }
if ((!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) && (opt_flags & SIM_SOCK_OPT_NODELAY)) {
    sta = sim_setnodelay (newsock);                     /* set nodelay */
    if (sta == SOCKET_ERROR) {                          /* setsock error? */
        p_freeaddrinfo (result);
        return sim_err_sock (newsock, "setnodelay");
        }
    }
if (!(opt_flags & SIM_SOCK_OPT_DATAGRAM)) {
    int keepalive = 1;

    /* enable TCP Keep Alives */
    sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
    if (sta == -1) 
        return sim_err_sock (newsock, "setsockopt KEEPALIVE");
    }
sta = connect (newsock, result->ai_addr, result->ai_addrlen);
p_freeaddrinfo (result);
if (sta == SOCKET_ERROR) {
    if (opt_flags & SIM_SOCK_OPT_BLOCKING) {
        if ((WSAGetLastError () == WSAETIMEDOUT)    ||                        /* expected errors after a connect failure */
            (WSAGetLastError () == WSAEHOSTUNREACH) ||
            (WSAGetLastError () == WSAECONNREFUSED) ||
            (WSAGetLastError () == WSAECONNABORTED) ||
            (WSAGetLastError () == WSAECONNRESET)) {
            sim_close_sock (newsock);
            newsock = INVALID_SOCKET;
            }
        else
            return sim_err_sock (newsock, "connect");
        }
    else    /* Non Blocking case won't return errors until some future read */
        if ((WSAGetLastError () != WSAEWOULDBLOCK) &&
            (WSAGetLastError () != WSAEINPROGRESS))
            return sim_err_sock (newsock, "connect");
    }
return newsock;                                         /* got it! */
}

SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, int opt_flags)
{
int sta = 0, err;
int keepalive = 1;
#if defined (macintosh) || defined (__linux) || defined (__linux__) || \
    defined (__APPLE__) || defined (__OpenBSD__) || \
    defined(__NetBSD__) || defined(__FreeBSD__) || \
    (defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)) || \
    defined (__HAIKU__)
socklen_t size;
#elif defined (_WIN32) || defined (__EMX__) || \
     (defined (__ALPHA) && defined (__unix__)) || \
     defined (__hpux)
int size;
#else 
size_t size; 
#endif
SOCKET newsock;
struct sockaddr_storage clientname;

if (master == 0)                                        /* not attached? */
    return INVALID_SOCKET;
size = sizeof (clientname);
memset (&clientname, 0, sizeof(clientname));
newsock = accept (master, (struct sockaddr *) &clientname, &size);
if (newsock == INVALID_SOCKET) {                        /* error? */
    err = WSAGetLastError ();
    if (err != WSAEWOULDBLOCK)
        sim_err_sock(newsock, "accept");
    return INVALID_SOCKET;
    }
if (connectaddr != NULL) {
    *connectaddr = (char *)calloc(1, NI_MAXHOST+1);
#ifdef AF_INET6
    p_getnameinfo((struct sockaddr *)&clientname, size, *connectaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
    if (0 == memcmp("::ffff:", *connectaddr, 7))        /* is this a IPv4-mapped IPv6 address? */
        memmove(*connectaddr, 7+*connectaddr,           /* prefer bare IPv4 address */
                strlen(*connectaddr) - 7 + 1);          /* length to include terminating \0 */
#else
    strcpy(*connectaddr, inet_ntoa(((struct sockaddr_in *)&connectaddr)->s_addr));
#endif
    }

if (!(opt_flags & SIM_SOCK_OPT_BLOCKING)) {
    sta = sim_setnonblock (newsock);                    /* set nonblocking */
    if (sta == SOCKET_ERROR)                            /* fcntl error? */
        return sim_err_sock (newsock, "fcntl");
    }

if ((opt_flags & SIM_SOCK_OPT_NODELAY)) {
    sta = sim_setnodelay (newsock);                     /* set nonblocking */
    if (sta == SOCKET_ERROR)                            /* setsockopt error? */
        return sim_err_sock (newsock, "setnodelay");
    }

/* enable TCP Keep Alives */
sta = setsockopt (newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(keepalive));
if (sta == -1) 
    return sim_err_sock (newsock, "setsockopt KEEPALIVE");

return newsock;
}

int sim_check_conn (SOCKET sock, int rd)
{
fd_set rw_set, er_set;
fd_set *rw_p = &rw_set;
fd_set *er_p = &er_set;
struct timeval zero;
struct sockaddr_storage peername;
#if defined (macintosh) || defined (__linux) || defined (__linux__) || \
    defined (__APPLE__) || defined (__OpenBSD__) || \
    defined(__NetBSD__) || defined(__FreeBSD__) || \
    (defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)) || \
    defined (__HAIKU__)
socklen_t peernamesize = (socklen_t)sizeof(peername);
#elif defined (_WIN32) || defined (__EMX__) || \
     (defined (__ALPHA) && defined (__unix__)) || \
     defined (__hpux)
int peernamesize = (int)sizeof(peername);
#else 
size_t peernamesize = sizeof(peername); 
#endif

memset (&zero, 0, sizeof(zero));
FD_ZERO (rw_p);
FD_ZERO (er_p);
FD_SET (sock, rw_p);
FD_SET (sock, er_p);
if (rd)
    (void)select ((int) sock + 1, rw_p, NULL, er_p, &zero);
else
    (void)select ((int) sock + 1, NULL, rw_p, er_p, &zero);
if (FD_ISSET (sock, er_p))
    return -1;
if (FD_ISSET (sock, rw_p)) {
    if (0 == getpeername (sock, (struct sockaddr *)&peername, &peernamesize))
        return 1;
    else
        return -1;
    }
return 0;
}

static int _sim_getaddrname (struct sockaddr *addr, size_t addrsize, char *hostnamebuf, char *portnamebuf)
{
#if defined (macintosh) || defined (__linux) || defined (__linux__) || \
    defined (__APPLE__) || defined (__OpenBSD__) || \
    defined(__NetBSD__) || defined(__FreeBSD__) || \
    (defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)) || \
    defined (__HAIKU__)
socklen_t size = (socklen_t)addrsize;
#elif defined (_WIN32) || defined (__EMX__) || \
     (defined (__ALPHA) && defined (__unix__)) || \
     defined (__hpux)
int size = (int)addrsize;
#else 
size_t size = addrsize; 
#endif
int ret = 0;

#ifdef AF_INET6
*hostnamebuf = '\0';
*portnamebuf = '\0';
ret = p_getnameinfo(addr, size, hostnamebuf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if (0 == memcmp("::ffff:", hostnamebuf, 7))        /* is this a IPv4-mapped IPv6 address? */
    memmove(hostnamebuf, 7+hostnamebuf,            /* prefer bare IPv4 address */
            strlen(hostnamebuf) + 7 - 1);          /* length to include terminating \0 */
if (!ret)
    ret = p_getnameinfo(addr, size, NULL, 0, portnamebuf, NI_MAXSERV, NI_NUMERICSERV);
#else
strcpy(hostnamebuf, inet_ntoa(((struct sockaddr_in *)addr)->s_addr));
sprintf(portnamebuf, "%d", (int)ntohs(((struct sockaddr_in *)addr)->s_port)));
#endif
return ret;
}

int sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf)
{
struct sockaddr_storage sockname, peername;
#if defined (macintosh) || defined (__linux) || defined (__linux__) || \
    defined (__APPLE__) || defined (__OpenBSD__) || \
    defined(__NetBSD__) || defined(__FreeBSD__) || \
    (defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)) || \
    defined (__HAIKU__)
socklen_t socknamesize = (socklen_t)sizeof(sockname);
socklen_t peernamesize = (socklen_t)sizeof(peername);
#elif defined (_WIN32) || defined (__EMX__) || \
     (defined (__ALPHA) && defined (__unix__)) || \
     defined (__hpux)
int socknamesize = (int)sizeof(sockname);
int peernamesize = (int)sizeof(peername);
#else 
size_t socknamesize = sizeof(sockname); 
size_t peernamesize = sizeof(peername); 
#endif
char hostbuf[NI_MAXHOST+1];
char portbuf[NI_MAXSERV+1];

if (socknamebuf)
    *socknamebuf = (char *)calloc(1, NI_MAXHOST+NI_MAXSERV+4);
if (peernamebuf)
    *peernamebuf = (char *)calloc(1, NI_MAXHOST+NI_MAXSERV+4);
(void)getsockname (sock, (struct sockaddr *)&sockname, &socknamesize);
(void)getpeername (sock, (struct sockaddr *)&peername, &peernamesize);
if (socknamebuf != NULL) {
    _sim_getaddrname ((struct sockaddr *)&sockname, (size_t)socknamesize, hostbuf, portbuf);
    sprintf(*socknamebuf, "[%s]:%s", hostbuf, portbuf);
    }
if (peernamebuf != NULL) {
    _sim_getaddrname ((struct sockaddr *)&peername, (size_t)peernamesize, hostbuf, portbuf);
    sprintf(*peernamebuf, "[%s]:%s", hostbuf, portbuf);
    }
return 0;
}


int sim_read_sock (SOCKET sock, char *buf, int nbytes)
{
int rbytes, err;

rbytes = recv (sock, buf, nbytes, 0);
if (rbytes == 0)                                        /* disconnect */
    return -1;
if (rbytes == SOCKET_ERROR) {
    err = WSAGetLastError ();
    if (err == WSAEWOULDBLOCK)                          /* no data */
        return 0;
#if defined(EAGAIN)
    if (err == EAGAIN)                                  /* no data */
        return 0;
#endif
    if ((err != WSAETIMEDOUT) &&                        /* expected errors after a connect failure */
        (err != WSAEHOSTUNREACH) &&
        (err != WSAECONNREFUSED) &&
        (err != WSAECONNABORTED) &&
        (err != WSAECONNRESET) &&
        (err != WSAEINTR))                              /* or a close of a blocking read */
        sim_err_sock (INVALID_SOCKET, "read");
    return -1;
    }
return rbytes;
}

int sim_write_sock (SOCKET sock, const char *msg, int nbytes)
{
int err, sbytes = send (sock, msg, nbytes, 0);

if (sbytes == SOCKET_ERROR) {
    err = WSAGetLastError ();
    if (err == WSAEWOULDBLOCK)                          /* no data */
        return 0;
#if defined(EAGAIN)
    if (err == EAGAIN)                                  /* no data */
        return 0;
#endif
    }
return sbytes;
}

void sim_close_sock (SOCKET sock)
{
shutdown(sock, SD_BOTH);
closesocket (sock);
}

#endif                                                  /* end else !implemented */

#ifdef  __cplusplus
}
#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_sock.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* sim_sock.h: OS-dependent socket routines header file

   Copyright (c) 2001-2008, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   15-Oct-12    MP      Added definitions needed to detect possible tcp 
                        connect failures
   25-Sep-12    MP      Reworked for RFC3493 interfaces supporting IPv6 and IPv4
   04-Jun-08    RMS     Addes sim_create_sock, for IBM 1130
   14-Apr-05    RMS     Added WSAEINPROGRESS (from Tim Riker)
   20-Aug-04    HV      Added missing definition for OS/2 (from Holger Veit)
   22-Oct-03    MP      Changed WIN32 winsock include to use winsock2.h to
                        avoid a conflict if sim_sock.h and sim_ether.h get
                        included by the same module.
   20-Mar-03    RMS     Added missing timerclear definition for VMS (from
                        Robert Alan Byer)
   15-Feb-03    RMS     Added time.h for EMX (from Holger Veit)
   17-Dec-02    RMS     Added sim_connect_sock
   08-Oct-02    RMS     Revised for .NET compatibility
   20-Aug-02    RMS     Changed calling sequence for sim_accept_conn
   30-Apr-02    RMS     Changed VMS stropts include to ioctl
   06-Feb-02    RMS     Added VMS support from Robert Alan Byer
   16-Sep-01    RMS     Added Macintosh support from Peter Schorn
*/

#ifndef SIM_SOCK_H_
#define SIM_SOCK_H_    0

#ifdef  __cplusplus
extern "C" {
#endif

#if defined (_WIN32)                                    /* Windows */
#include <winsock2.h>

#elif !defined (__OS2__) || defined (__EMX__)           /* VMS, Mac, Unix, OS/2 EMX */
#include <sys/types.h>                                  /* for fcntl, getpid */
#include <sys/socket.h>                                 /* for sockets */
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>                                 /* for sockaddr_in */
#include <netinet/tcp.h>                                /* for TCP_NODELAY */
#include <arpa/inet.h>                                  /* for inet_addr and inet_ntoa */
#include <netdb.h>
#include <sys/time.h>                                   /* for EMX */

#define WSAGetLastError()       errno                   /* Windows macros */
#define WSASetLastError(err) errno = err
#define closesocket     close 
#define SOCKET          int
#if defined(__hpux)
#define WSAEWOULDBLOCK  EAGAIN
#else
#define WSAEWOULDBLOCK  EWOULDBLOCK
#endif
#define WSAENAMETOOLONG ENAMETOOLONG
#define WSAEINPROGRESS  EINPROGRESS
#define WSAETIMEDOUT    ETIMEDOUT
#define WSAEISCONN      EISCONN
#define WSAECONNRESET   ECONNRESET
#define WSAECONNREFUSED ECONNREFUSED
#define WSAECONNABORTED ECONNABORTED
#define WSAEHOSTUNREACH EHOSTUNREACH
#define WSAEADDRINUSE   EADDRINUSE
#if defined(EAFNOSUPPORT)
#define WSAEAFNOSUPPORT EAFNOSUPPORT
#endif
#define WSAEACCES       EACCES
#define WSAEINTR        EINTR
#define INVALID_SOCKET  ((SOCKET)-1) 
#define SOCKET_ERROR    -1
#endif

#if defined (VMS)                                       /* VMS unique */
#include <ioctl.h>                                      /* for ioctl */
#if !defined (AI_NUMERICHOST)
#define AI_NUMERICHOST 0
#endif
#if defined (__VAX)
#define sockaddr_storage sockaddr
#endif
#endif

#if !defined(CBUFSIZE)
#define CBUFSIZE 1024
#define sim_printf printf
#endif

int sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr);
int sim_parse_addr_ex (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, char *localport, size_t local_port_len, const char *default_port);
#define SIM_SOCK_OPT_REUSEADDR      0x0001
#define SIM_SOCK_OPT_DATAGRAM       0x0002
#define SIM_SOCK_OPT_NODELAY        0x0004
#define SIM_SOCK_OPT_BLOCKING       0x0008
SOCKET sim_master_sock_ex (const char *hostport, int *parse_status, int opt_flags);
#define sim_master_sock(hostport, parse_status) sim_master_sock_ex(hostport, parse_status, ((sim_switches & SWMASK ('U')) ? SIM_SOCK_OPT_REUSEADDR : 0))
SOCKET sim_connect_sock_ex (const char *sourcehostport, const char *hostport, const char *default_host, const char *default_port, int opt_flags);
#define sim_connect_sock(hostport, default_host, default_port) sim_connect_sock_ex(NULL, hostport, default_host, default_port, 0)
SOCKET sim_accept_conn_ex (SOCKET master, char **connectaddr, int opt_flags);
#define sim_accept_conn(master, connectaddr) sim_accept_conn_ex(master, connectaddr, 0)
int sim_check_conn (SOCKET sock, int rd);
int sim_read_sock (SOCKET sock, char *buf, int nbytes);
int sim_write_sock (SOCKET sock, const char *msg, int nbytes);
void sim_close_sock (SOCKET sock);
const char *sim_get_err_sock (const char *emsg);
SOCKET sim_err_sock (SOCKET sock, const char *emsg);
int sim_getnames_sock (SOCKET sock, char **socknamebuf, char **peernamebuf);
void sim_init_sock (void);
void sim_cleanup_sock (void);

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































Deleted src/sim_tape.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
/* sim_tape.c: simulator tape support library

   Copyright (c) 1993-2008, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   Ultimately, this will be a place to hide processing of various tape formats,
   as well as OS-specific direct hardware access.

   23-Jan-12    MP      Added support for Logical EOT detection while positioning
   05-Feb-11    MP      Refactored to prepare for SIM_ASYNC_IO support
                        Added higher level routines:
                            sim_tape_wreomrw    - erase remainder of tape & rewind
                            sim_tape_sprecsf    - skip records
                            sim_tape_spfilef    - skip files
                            sim_tape_sprecsr    - skip records rev
                            sim_tape_spfiler    - skip files rev
                            sim_tape_position   - general purpose position
                        These routines correspond to natural tape operations 
                        and will align better when physical tape support is 
                        included here.
   08-Jun-08    JDB     Fixed signed/unsigned warning in sim_tape_set_fmt
   23-Jan-07    JDB     Fixed backspace over gap at BOT
   22-Jan-07    RMS     Fixed bug in P7B format read reclnt rev (found by Rich Cornwell)
   15-Dec-06    RMS     Added support for small capacity tapes
   30-Aug-06    JDB     Added erase gap support
   14-Feb-06    RMS     Added variable tape capacity
   23-Jan-06    JDB     Fixed odd-byte-write problem in sim_tape_wrrecf
   17-Dec-05    RMS     Added write support for Paul Pierce 7b format
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   02-May-05    RMS     Added support for Pierce 7b format
   28-Jul-04    RMS     Fixed bug in writing error records (found by Dave Bryan)
                RMS     Fixed incorrect error codes (found by Dave Bryan)
   05-Jan-04    RMS     Revised for file I/O library
   25-Apr-03    RMS     Added extended file support
   28-Mar-03    RMS     Added E11 and TPC format support

   Public routines:

   sim_tape_attach      attach tape unit
   sim_tape_detach      detach tape unit
   sim_tape_attach_help help routine for attaching tapes
   sim_tape_rdrecf      read tape record forward
   sim_tape_rdrecr      read tape record reverse
   sim_tape_wrrecf      write tape record forward
   sim_tape_sprecf      space tape record forward
   sim_tape_sprecr      space tape record reverse
   sim_tape_wrtmk       write tape mark
   sim_tape_wreom       erase remainder of tape
   sim_tape_wreomrw     erase remainder of tape & rewind
   sim_tape_wrgap       write erase gap
   sim_tape_sprecsf     space records forward
   sim_tape_spfilef     space files forward 
   sim_tape_sprecsr     space records reverse
   sim_tape_spfiler     space files reverse
   sim_tape_position    generalized position
   sim_tape_rewind      rewind
   sim_tape_reset       reset unit
   sim_tape_bot         TRUE if at beginning of tape
   sim_tape_eot         TRUE if at or beyond end of tape
   sim_tape_wrp         TRUE if write protected
   sim_tape_set_fmt     set tape format
   sim_tape_show_fmt    show tape format
   sim_tape_set_capac   set tape capacity
   sim_tape_show_capac  show tape capacity
   sim_tape_set_dens    set tape density
   sim_tape_show_dens   show tape density
   sim_tape_set_async   enable asynchronous operation
   sim_tape_clr_async   disable asynchronous operation
*/

#include "sim_defs.h"
#include "sim_tape.h"
#include <ctype.h>

#if defined SIM_ASYNCH_IO
#include <pthread.h>
#endif

struct sim_tape_fmt {
    const char          *name;                          /* name */
    int32               uflags;                         /* unit flags */
    t_addr              bot;                            /* bot test */
    };

static struct sim_tape_fmt fmts[MTUF_N_FMT] = {
    { "SIMH", 0,       sizeof (t_mtrlnt) - 1 },
    { "E11",  0,       sizeof (t_mtrlnt) - 1 },
    { "TPC",  UNIT_RO, sizeof (t_tpclnt) - 1 },
    { "P7B",  0,       0 },
/*  { "TPF",  UNIT_RO, 0 }, */
    { NULL,   0,       0 }
    };

static const uint32 bpi [] = {                          /* tape density table, indexed by MT_DENS constants */
    0,                                                  /*   0 = MT_DENS_NONE -- density not set */
    200,                                                /*   1 = MT_DENS_200  -- 200 bpi NRZI */
    556,                                                /*   2 = MT_DENS_556  -- 556 bpi NRZI */
    800,                                                /*   3 = MT_DENS_800  -- 800 bpi NRZI */
    1600,                                               /*   4 = MT_DENS_1600 -- 1600 bpi PE */
    6250                                                /*   5 = MT_DENS_6250 -- 6250 bpi GCR */
    };

#define BPI_COUNT       (sizeof (bpi) / sizeof (bpi [0]))   /* count of density table entries */

static t_stat sim_tape_ioerr (UNIT *uptr);
static t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat);
static uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map, uint32 mapsize);
static t_stat sim_tape_simh_check (UNIT *uptr);
static t_stat sim_tape_e11_check (UNIT *uptr);
static t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map);
static void sim_tape_data_trace (UNIT *uptr, const uint8 *data, size_t len, const char* txt, int detail, uint32 reason);
static t_stat tape_erase_fwd (UNIT *uptr, t_mtrlnt gap_size);
static t_stat tape_erase_rev (UNIT *uptr, t_mtrlnt gap_size);


struct tape_context {
    DEVICE              *dptr;              /* Device for unit (access to debug flags) */
    uint32              dbit;               /* debugging bit for trace */
    uint32              auto_format;        /* Format determined dynamically */
#if defined SIM_ASYNCH_IO
    int                 asynch_io;          /* Asynchronous Interrupt scheduling enabled */
    int                 asynch_io_latency;  /* instructions to delay pending interrupt */
    pthread_mutex_t     lock;
    pthread_t           io_thread;          /* I/O Thread Id */
    pthread_mutex_t     io_lock;
    pthread_cond_t      io_cond;
    pthread_cond_t      io_done;
    pthread_cond_t      startup_cond;
    int                 io_top;
    uint8               *buf;
    uint32              *bc;
    uint32              *fc;
    uint32              vbc;
    uint32              max;
    uint32              gaplen;
    uint32              bpi;
    uint32              *objupdate;
    TAPE_PCALLBACK      callback;
    t_stat              io_status;
#endif
    };
#define tape_ctx up8                        /* Field in Unit structure which points to the tape_context */

#if defined SIM_ASYNCH_IO
#define AIO_CALLSETUP                                                   \
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;       \
                                                                        \
if (ctx == NULL)                                                        \
    return sim_messagef (SCPE_IERR, "Bad Attach\n");                    \
if ((!callback) || !ctx->asynch_io)

#define AIO_CALL(op, _buf, _bc, _fc, _max, _vbc, _gaplen, _bpi, _obj, _callback)\
    if (ctx->asynch_io) {                                               \
        struct tape_context *ctx =                                      \
                      (struct tape_context *)uptr->tape_ctx;            \
                                                                        \
        pthread_mutex_lock (&ctx->io_lock);                             \
                                                                        \
        sim_debug (ctx->dbit, ctx->dptr,                                \
      "sim_tape AIO_CALL(op=%d, unit=%d)\n", op, (int)(uptr-ctx->dptr->units));\
                                                                        \
        if (ctx->callback)                                              \
            abort(); /* horrible mistake, stop */                       \
        ctx->io_top = op;                                               \
        ctx->buf = _buf;                                                \
        ctx->bc = _bc;                                                  \
        ctx->fc = _fc;                                                  \
        ctx->max = _max;                                                \
        ctx->vbc = _vbc;                                                \
        ctx->gaplen = _gaplen;                                          \
        ctx->bpi = _bpi;                                                \
        ctx->objupdate = _obj;                                          \
        ctx->callback = _callback;                                      \
        pthread_cond_signal (&ctx->io_cond);                            \
        pthread_mutex_unlock (&ctx->io_lock);                           \
        }                                                               \
    else                                                                \
        if (_callback)                                                  \
            (_callback) (uptr, r);
#define TOP_DONE  0             /* close */
#define TOP_RDRF  1             /* sim_tape_rdrecf_a */
#define TOP_RDRR  2             /* sim_tape_rdrecr_a */
#define TOP_WREC  3             /* sim_tape_wrrecf_a */
#define TOP_WTMK  4             /* sim_tape_wrtmk_a */
#define TOP_WEOM  5             /* sim_tape_wreom_a */
#define TOP_WEMR  6             /* sim_tape_wreomrw_a */
#define TOP_WGAP  7             /* sim_tape_wrgap_a */
#define TOP_SPRF  8             /* sim_tape_sprecf_a */
#define TOP_SRSF  9             /* sim_tape_sprecsf_a */
#define TOP_SPRR 10             /* sim_tape_sprecr_a */
#define TOP_SRSR 11             /* sim_tape_sprecsr_a */
#define TOP_SPFF 12             /* sim_tape_spfilef */
#define TOP_SFRF 13             /* sim_tape_spfilebyrecf */
#define TOP_SPFR 14             /* sim_tape_spfiler */
#define TOP_SFRR 15             /* sim_tape_spfilebyrecr */
#define TOP_RWND 16             /* sim_tape_rewind_a */
#define TOP_POSN 17             /* sim_tape_position_a */

static void *
_tape_io(void *arg)
{
UNIT* volatile uptr = (UNIT*)arg;
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

    /* Boost Priority for this I/O thread vs the CPU instruction execution 
       thread which in general won't be readily yielding the processor when 
       this thread needs to run */
    sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

    sim_debug (ctx->dbit, ctx->dptr, "_tape_io(unit=%d) starting\n", (int)(uptr-ctx->dptr->units));

    pthread_mutex_lock (&ctx->io_lock);
    pthread_cond_signal (&ctx->startup_cond);   /* Signal we're ready to go */
    while (1) {
        pthread_cond_wait (&ctx->io_cond, &ctx->io_lock);
        if (ctx->io_top == TOP_DONE)
            break;
        pthread_mutex_unlock (&ctx->io_lock);
        switch (ctx->io_top) {
            case TOP_RDRF:
                ctx->io_status = sim_tape_rdrecf (uptr, ctx->buf, ctx->bc, ctx->max);
                break;
            case TOP_RDRR:
                ctx->io_status = sim_tape_rdrecr (uptr, ctx->buf, ctx->bc, ctx->max);
                break;
            case TOP_WREC:
                ctx->io_status = sim_tape_wrrecf (uptr, ctx->buf, ctx->vbc);
                break;
            case TOP_WTMK:
                ctx->io_status = sim_tape_wrtmk (uptr);
                break;
            case TOP_WEOM:
                ctx->io_status = sim_tape_wreom (uptr);
                break;
            case TOP_WEMR:
                ctx->io_status = sim_tape_wreomrw (uptr);
                break;
            case TOP_WGAP:
                ctx->io_status = sim_tape_wrgap (uptr, ctx->gaplen);
                break;
            case TOP_SPRF:
                ctx->io_status = sim_tape_sprecf (uptr, ctx->bc);
                break;
            case TOP_SRSF:
                ctx->io_status = sim_tape_sprecsf (uptr, ctx->vbc, ctx->bc);
                break;
            case TOP_SPRR:
                ctx->io_status = sim_tape_sprecr (uptr, ctx->bc);
                break;
            case TOP_SRSR:
                ctx->io_status = sim_tape_sprecsr (uptr, ctx->vbc, ctx->bc);
                break;
            case TOP_SPFF:
                ctx->io_status = sim_tape_spfilef (uptr, ctx->vbc, ctx->bc);
                break;
            case TOP_SFRF:
                ctx->io_status = sim_tape_spfilebyrecf (uptr, ctx->vbc, ctx->bc, ctx->fc, ctx->max);
                break;
            case TOP_SPFR:
                ctx->io_status = sim_tape_spfiler (uptr, ctx->vbc, ctx->bc);
                break;
            case TOP_SFRR:
                ctx->io_status = sim_tape_spfilebyrecr (uptr, ctx->vbc, ctx->bc, ctx->fc);
                break;
            case TOP_RWND:
                ctx->io_status = sim_tape_rewind (uptr);
                break;
            case TOP_POSN:
                ctx->io_status = sim_tape_position (uptr, ctx->vbc, ctx->gaplen, ctx->bc, ctx->bpi, ctx->fc, ctx->objupdate);
                break;
            }
        pthread_mutex_lock (&ctx->io_lock);
        ctx->io_top = TOP_DONE;
        pthread_cond_signal (&ctx->io_done);
        sim_activate (uptr, ctx->asynch_io_latency);
    }
    pthread_mutex_unlock (&ctx->io_lock);

    sim_debug (ctx->dbit, ctx->dptr, "_tape_io(unit=%d) exiting\n", (int)(uptr-ctx->dptr->units));

    return NULL;
}

/* This routine is called in the context of the main simulator thread before 
   processing events for any unit. It is only called when an asynchronous 
   thread has called sim_activate() to activate a unit.  The job of this 
   routine is to put the unit in proper condition to digest what may have
   occurred in the asynchronous thread.
   
   Since tape processing only handles a single I/O at a time to a 
   particular tape device, we have the opportunity to possibly detect 
   improper attempts to issue multiple concurrent I/O requests. */
static void _tape_completion_dispatch (UNIT *uptr)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
TAPE_PCALLBACK callback = ctx->callback;

sim_debug (ctx->dbit, ctx->dptr, "_tape_completion_dispatch(unit=%d, top=%d, callback=%p)\n", (int)(uptr-ctx->dptr->units), ctx->io_top, ctx->callback);

if (ctx->io_top != TOP_DONE)
    abort();                                            /* horribly wrong, stop */

if (ctx->callback && ctx->io_top == TOP_DONE) {
    ctx->callback = NULL;
    callback (uptr, ctx->io_status);
    }
}

static t_bool _tape_is_active (UNIT *uptr)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

if (ctx) {
    sim_debug (ctx->dbit, ctx->dptr, "_tape_is_active(unit=%d, top=%d)\n", (int)(uptr-ctx->dptr->units), ctx->io_top);
    return (ctx->io_top != TOP_DONE);
    }
return FALSE;
}

static t_bool _tape_cancel (UNIT *uptr)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

if (ctx) {
    sim_debug (ctx->dbit, ctx->dptr, "_tape_cancel(unit=%d, top=%d)\n", (int)(uptr-ctx->dptr->units), ctx->io_top);
    if (ctx->asynch_io) {
        pthread_mutex_lock (&ctx->io_lock);
        while (ctx->io_top != TOP_DONE)
            pthread_cond_wait (&ctx->io_done, &ctx->io_lock);
        pthread_mutex_unlock (&ctx->io_lock);
        }
    }
return FALSE;
}
#else
#define AIO_CALLSETUP                                                       \
    if (uptr->tape_ctx == NULL)                                             \
        return sim_messagef (SCPE_IERR, "Bad Attach\n");
#define AIO_CALL(op, _buf, _fc, _bc, _max, _vbc, _gaplen, _bpi, _obj, _callback) \
    if (_callback)                                                    \
        (_callback) (uptr, r);
#endif


/* Enable asynchronous operation */

t_stat sim_tape_set_async (UNIT *uptr, int latency)
{
#if !defined(SIM_ASYNCH_IO)
sim_printf ("Tape: can't operate asynchronously\r\n");
return SCPE_NOFNC;
#else
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
pthread_attr_t attr;

ctx->asynch_io = sim_asynch_enabled;
ctx->asynch_io_latency = latency;
if (ctx->asynch_io) {
    pthread_mutex_init (&ctx->io_lock, NULL);
    pthread_cond_init (&ctx->io_cond, NULL);
    pthread_cond_init (&ctx->io_done, NULL);
    pthread_cond_init (&ctx->startup_cond, NULL);
    pthread_attr_init(&attr);
    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_mutex_lock (&ctx->io_lock);
    pthread_create (&ctx->io_thread, &attr, _tape_io, (void *)uptr);
    pthread_attr_destroy(&attr);
    pthread_cond_wait (&ctx->startup_cond, &ctx->io_lock); /* Wait for thread to stabilize */
    pthread_mutex_unlock (&ctx->io_lock);
    pthread_cond_destroy (&ctx->startup_cond);
    }
uptr->a_check_completion = _tape_completion_dispatch;
uptr->a_is_active = _tape_is_active;
uptr->cancel = _tape_cancel;
return SCPE_OK;
#endif
}

/* Disable asynchronous operation */

t_stat sim_tape_clr_async (UNIT *uptr)
{
#if !defined(SIM_ASYNCH_IO)
return SCPE_NOFNC;
#else
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

/* make sure device exists */
if (!ctx) return SCPE_UNATT;

if (ctx->asynch_io) {
    pthread_mutex_lock (&ctx->io_lock);
    ctx->asynch_io = 0;
    pthread_cond_signal (&ctx->io_cond);
    pthread_mutex_unlock (&ctx->io_lock);
    pthread_join (ctx->io_thread, NULL);
    pthread_mutex_destroy (&ctx->io_lock);
    pthread_cond_destroy (&ctx->io_cond);
    pthread_cond_destroy (&ctx->io_done);
    }
return SCPE_OK;
#endif
}

/* 
   This routine is called when the simulator stops and any time
   the asynch mode is changed (enabled or disabled)
*/
static void _sim_tape_io_flush (UNIT *uptr)
{
#if defined (SIM_ASYNCH_IO)
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

sim_tape_clr_async (uptr);
if (sim_asynch_enabled)
    sim_tape_set_async (uptr, ctx->asynch_io_latency);
#endif
fflush (uptr->fileref);
}

/* Attach tape unit */

t_stat sim_tape_attach (UNIT *uptr, CONST char *cptr)
{
DEVICE *dptr;

if ((dptr = find_dev_from_unit (uptr)) == NULL)
    return SCPE_NOATT;
return sim_tape_attach_ex (uptr, cptr, (dptr->flags & DEV_DEBUG) ? 0xFFFFFFFF : 0, 0);
}

t_stat sim_tape_attach_ex (UNIT *uptr, const char *cptr, uint32 dbit, int completion_delay)
{
struct tape_context *ctx;
uint32 objc;
DEVICE *dptr;
char gbuf[CBUFSIZE];
t_stat r;
t_bool auto_format = FALSE;

if ((dptr = find_dev_from_unit (uptr)) == NULL)
    return SCPE_NOATT;
if (sim_switches & SWMASK ('F')) {                      /* format spec? */
    cptr = get_glyph (cptr, gbuf, 0);                   /* get spec */
    if (*cptr == 0)                                     /* must be more */
        return SCPE_2FARG;
    if (sim_tape_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK)
        return sim_messagef (SCPE_ARG, "Invalid Tape Format: %s\n", gbuf);
    sim_switches = sim_switches & ~(SWMASK ('F'));      /* Record Format specifier already processed */
    auto_format = TRUE;
    }
if (MT_GET_FMT (uptr) == MTUF_F_TPC)
    sim_switches |= SWMASK ('R');                       /* Force ReadOnly attach for TPC tapes */
r = attach_unit (uptr, (CONST char *)cptr);             /* attach unit */
if (r != SCPE_OK)                                       /* error? */
    return sim_messagef (r, "Can't open tape image: %s\n", cptr);
switch (MT_GET_FMT (uptr)) {                            /* case on format */

    case MTUF_F_STD:                                    /* SIMH */
        if (SCPE_OK != sim_tape_simh_check (uptr)) {
            sim_tape_detach (uptr);
            return SCPE_FMT;                            /* yes, complain */
            }
        break;

    case MTUF_F_E11:                                    /* E11 */
        if (SCPE_OK != sim_tape_e11_check (uptr)) {
            sim_tape_detach (uptr);
            return SCPE_FMT;                            /* yes, complain */
            }
        break;

    case MTUF_F_TPC:                                    /* TPC */
        objc = sim_tape_tpc_map (uptr, NULL, 0);        /* get # objects */
        if (objc == 0) {                                /* tape empty? */
            sim_tape_detach (uptr);
            return SCPE_FMT;                            /* yes, complain */
            }
        uptr->filebuf = calloc (objc + 1, sizeof (t_addr));
        if (uptr->filebuf == NULL) {                    /* map allocated? */
            sim_tape_detach (uptr);
            return SCPE_MEM;                            /* no, complain */
            }
        uptr->hwmark = objc + 1;                        /* save map size */
        sim_tape_tpc_map (uptr, (t_addr *) uptr->filebuf, objc);/* fill map */
        break;

    default:
        break;
        }

uptr->tape_ctx = ctx = (struct tape_context *)calloc(1, sizeof(struct tape_context));
ctx->dptr = dptr;                                       /* save DEVICE pointer */
ctx->dbit = dbit;                                       /* save debug bit */
ctx->auto_format = auto_format;                         /* save that we auto selected format */

sim_tape_rewind (uptr);

#if defined (SIM_ASYNCH_IO)
sim_tape_set_async (uptr, completion_delay);
#endif
uptr->io_flush = _sim_tape_io_flush;

return SCPE_OK;
}

/* Detach tape unit */

t_stat sim_tape_detach (UNIT *uptr)
{
struct tape_context *ctx;
uint32 f;
t_stat r;
t_bool auto_format = FALSE;

if (uptr == NULL)
    return SCPE_IERR;
ctx = (struct tape_context *)uptr->tape_ctx;
f = MT_GET_FMT (uptr);
if ((ctx == NULL) || !(uptr->flags & UNIT_ATT))
    return SCPE_IERR;

if (uptr->io_flush)
    uptr->io_flush (uptr);                              /* flush buffered data */
if (ctx)
    auto_format = ctx->auto_format;

sim_tape_clr_async (uptr);

r = detach_unit (uptr);                                 /* detach unit */
if (r != SCPE_OK)
    return r;
switch (f) {                                            /* case on format */

    case MTUF_F_TPC:                                    /* TPC */
        if (uptr->filebuf)                              /* free map */
            free (uptr->filebuf);
        uptr->filebuf = NULL;
        uptr->hwmark = 0;
        break;

    default:
        break;
        }

sim_tape_rewind (uptr);
free (uptr->tape_ctx);
uptr->tape_ctx = NULL;
uptr->io_flush = NULL;
if (auto_format)    /* format was determined or specified at attach time? */
    sim_tape_set_fmt (uptr, 0, "SIMH", NULL);   /* restore default format */
return SCPE_OK;
}

t_stat sim_tape_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "%s Tape Attach Help\n\n", dptr->name);
if (0 == (uptr-dptr->units)) {
    if (dptr->numunits > 1) {
        uint32 i;

        for (i=0; i < dptr->numunits; ++i)
            if (dptr->units[i].flags & UNIT_ATTABLE)
                fprintf (st, "  sim> ATTACH {switches} %s%d tapefile\n\n", dptr->name, i);
        }
    else
        fprintf (st, "  sim> ATTACH {switches} %s tapefile\n\n", dptr->name);
    }
else
    fprintf (st, "  sim> ATTACH {switches} %s tapefile\n\n", dptr->name);
fprintf (st, "Attach command switches\n");
fprintf (st, "    -R          Attach Read Only.\n");
fprintf (st, "    -E          Must Exist (if not specified an attempt to create the indicated\n");
fprintf (st, "                virtual tape will be attempted).\n");
fprintf (st, "    -F          Open the indicated tape container in a specific format (default\n");
fprintf (st, "                is SIMH, alternatives are E11, TPC and P7B)\n");
return SCPE_OK;
}

static void sim_tape_data_trace(UNIT *uptr, const uint8 *data, size_t len, const char* txt, int detail, uint32 reason)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

if (ctx == NULL)
    return;
if (sim_deb && (ctx->dptr->dctrl & reason))
    sim_data_trace(ctx->dptr, uptr, (detail ? data : NULL), "", len, txt, reason);
}

/* Read record length forward (internal routine)

   Inputs:
        uptr    =       pointer to tape unit
        bc      =       pointer to returned record length
   Outputs:
        status  =       operation status

   exit condition       tape position
   ------------------   -----------------------------------------------------
   unit unattached      unchanged
   read error           unchanged, PNU set
   end of file/medium   updated if a gap precedes, else unchanged and PNU set
   tape mark            updated
   tape runaway         updated
   data record          updated, sim_fread will read record forward

   This routine is called to set up a record read or spacing in the forward
   direction.  On return, status is MTSE_OK and the tape is positioned at the
   first data byte if a record was encountered, or status is an MTSE error code
   giving the reason that the operation did not succeed and the tape position is
   as indicated above.

   The ANSI standards for magnetic tape recording (X3.32, X3.39, and X3.54) and
   the equivalent ECMA standard (ECMA-62) specify a maximum erase gap length of
   25 feet (7.6 meters).  While gaps of any length may be written, gaps longer
   than this are non-standard and may indicate that an unrecorded or erased tape
   is being read.

   If the tape density has been set via a previous "sim_tape_set_dens" call,
   then the length is monitored when skipping over erase gaps.  If the length
   reaches 25 feet, motion is terminated, and MTSE_RUNAWAY status is returned.
   Runaway status is also returned if an end-of-medium marker or the physical
   end of file is encountered while spacing over a gap; however, MTSE_EOM is
   returned if the tape is positioned at the EOM on entry.

   If the density has not been set, then a gap of any length is skipped, and
   MTSE_RUNAWAY status is never returned.  In effect, erase gaps present in the
   tape image file will be transparent to the caller.

   Erase gaps are currently supported only in SIMH (MTUF_F_STD) tape format.
   Because gaps may be partially overwritten with data records, gap metadata
   must be examined marker-by-marker.  To reduce the number of file read calls,
   a buffer of metadata elements is used.  The buffer size is initially
   established at 256 elements but may be set to any size desired.  To avoid a
   large read for the typical case where an erase gap is not present, the first
   read is of a single metadatum marker.  If that is a gap marker, then
   additional buffered reads are performed.

   See the notes at "sim_tape_wrgap" regarding the erase gap implementation.

   Implementation notes:

    1. For programming convenience, erase gap processing is performed for both
       SIMH standard and E11 tape formats, although the latter will never
       contain erase gaps, as the "sim_tape_wrgap" call takes no action for the
       E11 format.

    2. The "feof" call cannot return a non-zero value on the first pass through
       the loop, because the "sim_fseek" call resets the internal end-of-file
       indicator.  Subsequent passes only occur if an erase gap is present, so
       a non-zero return indicates an EOF was seen while reading through a gap.

    3. The dynamic start/stop test of the HP 3000 magnetic tape diagnostic
       heavily exercises the erase gap scanning code.  Sample test execution
       times for various buffer sizes on a 2 GHz host platform are:

         buffer size    execution time
         (elements)     (CPU seconds)
         -----------    --------------
               1             7200
              32              783
             128              237
             256              203
             512              186
            1024              171

    4. Because an erase gap may precede the logical end-of-medium, represented
       either by the physical end-of-file or by an EOM marker, the "position not
       updated" flag is set only if the tape is positioned at the EOM when the
       routine is entered.  If at least one gap marker precedes the EOM, then
       the PNU flag is not set.  This ensures that a backspace-and-retry
       sequence will work correctly in both cases.
*/

static t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
uint8 c;
t_bool all_eof;
uint32 f = MT_GET_FMT (uptr);
t_mtrlnt sbc;
t_tpclnt tpcbc;
t_mtrlnt buffer [256];                                  /* local tape buffer */
uint32 bufcntr, bufcap;                                 /* buffer counter and capacity */
int32 runaway_counter, sizeof_gap;                      /* bytes remaining before runaway and bytes per gap */
t_stat r = MTSE_OK;

MT_CLR_PNU (uptr);                                      /* clear the position-not-updated flag */

if ((uptr->flags & UNIT_ATT) == 0)                      /* if the unit is not attached */
    return MTSE_UNATT;                                  /*   then quit with an error */
if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */

sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);         /* set the initial tape position */

switch (f) {                                            /* the read method depends on the tape format */

    case MTUF_F_STD:
    case MTUF_F_E11:
        runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)]; /* set the largest legal gap size in bytes */

        if (runaway_counter == 0) {                     /* if tape density has not been not set */
            sizeof_gap = 0;                             /*   then disable runaway detection */
            runaway_counter = INT_MAX;                  /*     to allow gaps of any size */
            }
        else                                            /* otherwise */
            sizeof_gap = sizeof (t_mtrlnt);             /*   set the size of the gap */

        bufcntr = 0;                                    /* force an initial read */
        bufcap = 0;                                     /*   but of just one metadata marker */

        do {                                            /* loop until a record, gap, or error is seen */
            if (bufcntr == bufcap) {                    /* if the buffer is empty then refill it */
                if (feof (uptr->fileref)) {             /* if we hit the EOF while reading a gap */
                    if (sizeof_gap > 0)                 /*   then if detection is enabled */
                        r = MTSE_RUNAWAY;               /*     then report a tape runaway */
                    else                                /*   otherwise report the physical EOF */
                        r = MTSE_EOM;                   /*     as the end-of-medium */
                    break;
                    }

                else if (bufcap == 0)                   /* otherwise if this is the initial read */
                    bufcap = 1;                         /*   then start with just one marker */

                else                                    /* otherwise reset the capacity */
                    bufcap = sizeof (buffer)            /*   to the full size of the buffer */
                               / sizeof (buffer [0]);

                bufcap = sim_fread (buffer,             /* fill the buffer */
                                    sizeof (t_mtrlnt),  /*   with tape metadata */
                                    bufcap,
                                    uptr->fileref);

                if (ferror (uptr->fileref)) {           /* if a file I/O error occurred */
                    if (bufcntr == 0)                   /*   then if this is the initial read */
                        MT_SET_PNU (uptr);              /*     then set position not updated */

                    r = sim_tape_ioerr (uptr);          /* report the error and quit */
                    break;
                    }

                else if (bufcap == 0                    /* otherwise if positioned at the physical EOF */
                  || buffer [0] == MTR_EOM)             /*   or at the logical EOM */
                    if (bufcntr == 0) {                 /*     then if this is the initial read */
                        MT_SET_PNU (uptr);              /*       then set position not updated */
                        r = MTSE_EOM;                   /*         and report the end-of-medium and quit */
                        break;
                        }

                    else {                              /*     otherwise some gap has already been skipped */
                        if (sizeof_gap > 0)             /*       so if detection is enabled */
                            r = MTSE_RUNAWAY;           /*         then report a tape runaway */
                        else                            /*       otherwise report the physical EOF */
                            r = MTSE_EOM;               /*         as the end-of-medium */
                        break;
                        }

                else                                    /* otherwise reset the index */
                    bufcntr = 0;                        /*   to the start of the buffer */
                }

            *bc = buffer [bufcntr++];                   /* store the metadata marker value */

            if (*bc == MTR_EOM) {                       /* if an end-of-medium marker is seen */
                if (sizeof_gap > 0)                     /*   then if detection is enabled */
                    r = MTSE_RUNAWAY;                   /*     then report a tape runaway */
                else                                    /*   otherwise report the physical EOF */
                    r = MTSE_EOM;                       /*     as the end-of-medium */
                break;
                }

            uptr->pos = uptr->pos + sizeof (t_mtrlnt);  /* space over the marker */

            if (*bc == MTR_TMK) {                       /* if the value is a tape mark */
                r = MTSE_TMK;                           /*   then quit with tape mark status */
                break;
                }

            else if (*bc == MTR_GAP)                    /* otherwise if the value is a full gap */
                runaway_counter -= sizeof_gap;          /*   then decrement the gap counter */

            else if (*bc == MTR_FHGAP) {                        /* otherwise if the value if a half gap */
                uptr->pos = uptr->pos - sizeof (t_mtrlnt) / 2;  /*   then back up */
                sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /*     to resync */
                bufcntr = bufcap;                               /* mark the buffer as invalid to force a read */

                *bc = MTR_GAP;                                  /* reset the marker */
                runaway_counter -= sizeof_gap / 2;              /*   and decrement the gap counter */
                }

            else {                                                  /* otherwise it's a record marker */
                if (bufcntr < bufcap)                               /* if the position is within the buffer */
                    sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /*   then seek to the data area */

                sbc = MTR_L (*bc);                                  /* extract the record length */
                uptr->pos = uptr->pos + sizeof (t_mtrlnt)           /* position to the start */
                  + (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc);       /*   of the record */
                }
            }
        while (*bc == MTR_GAP && runaway_counter > 0);  /* continue until data or runaway occurs */

        if (r == MTSE_OK && runaway_counter <= 0)       /* if a tape runaway occurred */
            r = MTSE_RUNAWAY;                           /*   then report it */

        break;                                          /* otherwise the operation succeeded */

    case MTUF_F_TPC:
        sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
        *bc = tpcbc;                                    /* save rec lnt */
        if (ferror (uptr->fileref)) {                   /* error? */
            MT_SET_PNU (uptr);                          /* pos not upd */
            return sim_tape_ioerr (uptr);
            }
        if (feof (uptr->fileref)) {                     /* eof? */
            MT_SET_PNU (uptr);                          /* pos not upd */
            r = MTSE_EOM;
            break;
            }
        uptr->pos = uptr->pos + sizeof (t_tpclnt);      /* spc over reclnt */
        if (tpcbc == TPC_TMK)                           /* tape mark? */
            r = MTSE_TMK;
        uptr->pos = uptr->pos + ((tpcbc + 1) & ~1);     /* spc over record */
        break;

    case MTUF_F_P7B:
        for (sbc = 0, all_eof = 1; ; sbc++) {           /* loop thru record */
            sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
            if (ferror (uptr->fileref)) {               /* error? */
                MT_SET_PNU (uptr);                      /* pos not upd */
                return sim_tape_ioerr (uptr);
                }
            if (feof (uptr->fileref)) {                 /* eof? */
                if (sbc == 0)                           /* no data? eom */
                    return MTSE_EOM;
                break;                                  /* treat like eor */
                }
            if ((sbc != 0) && (c & P7B_SOR))            /* next record? */
                break;
            if ((c & P7B_DPAR) != P7B_EOF)
                all_eof = 0;
            }
        *bc = sbc;                                      /* save rec lnt */
        sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
        uptr->pos = uptr->pos + sbc;                    /* spc over record */
        if (all_eof)                                    /* tape mark? */
            r = MTSE_TMK;
        break;

    default:
        return MTSE_FMT;
        }
sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", r, *bc, uptr->pos);
return r;
}

/* Read record length reverse (internal routine)

   Inputs:
        uptr    =       pointer to tape unit
        bc      =       pointer to returned record length
   Outputs:
        status  =       operation status

   exit condition       tape position
   ------------------   -------------------------------------------
   unit unattached      unchanged
   beginning of tape    unchanged
   read error           unchanged
   end of file          unchanged
   end of medium        updated
   tape mark            updated
   tape runaway         updated
   data record          updated, sim_fread will read record forward

   This routine is called to set up a record read or spacing in the reverse
   direction.  On return, status is MTSE_OK and the tape is positioned at the
   first data byte if a record was encountered, or status is an MTSE error code
   giving the reason that the operation did not succeed and the tape position is
   as indicated above.

   See the notes at "sim_tape_rdlntf" and "sim_tape_wrgap" regarding tape
   runaway and the erase gap implementation, respectively.
*/

static t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
uint8 c;
t_bool all_eof;
uint32 f = MT_GET_FMT (uptr);
t_addr ppos;
t_mtrlnt sbc;
t_tpclnt tpcbc;
t_mtrlnt buffer [256];                                  /* local tape buffer */
uint32 bufcntr, bufcap;                                 /* buffer counter and capacity */
int32 runaway_counter, sizeof_gap;                      /* bytes remaining before runaway and bytes per gap */
t_stat r = MTSE_OK;

MT_CLR_PNU (uptr);                                      /* clear the position-not-updated flag */

if ((uptr->flags & UNIT_ATT) == 0)                      /* if the unit is not attached */
    return MTSE_UNATT;                                  /*   then quit with an error */
if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */

if (sim_tape_bot (uptr))                                /* if the unit is positioned at the BOT */
    return MTSE_BOT;                                    /*   then reading backward is not possible */

switch (f) {                                            /* the read method depends on the tape format */

    case MTUF_F_STD:
    case MTUF_F_E11:
        runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)]; /* set largest legal gap size in bytes */

        if (runaway_counter == 0) {                     /* if tape density has not been not set */
            sizeof_gap = 0;                             /*   then disable runaway detection */
            runaway_counter = INT_MAX;                  /*     to allow gaps of any size */
            }

        else                                            /* otherwise */
            sizeof_gap = sizeof (t_mtrlnt);             /*   set the size of the gap */

        bufcntr = 0;                                    /* force an initial read */
        bufcap = 1;                                     /*   but of just one metadata marker */

        do {                                            /* loop until a record, gap, or error seen */
            if (bufcntr == 0) {                         /* if the buffer is empty then refill it */
                if (sim_tape_bot (uptr)) {              /* if the search has backed into the BOT */
                    r = MTSE_BOT;                       /*   then quit with an error */
                    break;
                    }

                else if (uptr->pos < sizeof (buffer))   /* if less than a full buffer remains */
                    bufcap = (uint32) uptr->pos         /*   then reduce the capacity accordingly */
                               / sizeof (t_mtrlnt);

                sim_fseek (uptr->fileref,                           /* seek back to the location */
                           uptr->pos - bufcap * sizeof (t_mtrlnt),  /*   corresponding to the start */
                           SEEK_SET);                               /*     of the buffer */

                bufcntr = sim_fread (buffer, sizeof (t_mtrlnt),     /* fill the buffer */
                                     bufcap, uptr->fileref);        /*   with tape metadata */

                if (ferror (uptr->fileref)) {           /* if a file I/O error occurred */
                    MT_SET_PNU (uptr);                  /*   then set position not updated */
                    r = sim_tape_ioerr (uptr);          /*     report the error and quit */
                    break;
                    }

                else                                    /* otherwise reset the capacity */
                    bufcap = sizeof (buffer)            /*   to the full size of the buffer */
                               / sizeof (buffer [0]);
                }

            *bc = buffer [--bufcntr];                   /* store the metadata marker value */

            uptr->pos = uptr->pos - sizeof (t_mtrlnt);  /* backspace over the marker */

            if (*bc == MTR_TMK) {                       /* if the marker is a tape mark */
                r = MTSE_TMK;                           /*   then quit with tape mark status */
                break;
                }

            else if (*bc == MTR_GAP)                    /* otherwise if the marker is a full gap */
                runaway_counter -= sizeof_gap;          /*   then decrement the gap counter */

            else if ((*bc & MTR_M_RHGAP) == MTR_RHGAP           /* otherwise if the marker */
              || *bc == MTR_RRGAP) {                            /*   is a half gap */
                uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2;  /*     then position forward to resync */
                bufcntr = 0;                                    /* mark the buffer as invalid to force a read */

                *bc = MTR_GAP;                                  /* reset the marker */
                runaway_counter -= sizeof_gap / 2;              /*   and decrement the gap counter */
                }

            else {                                              /* otherwise it's a record marker */
                sbc = MTR_L (*bc);                              /* extract the record length */
                uptr->pos = uptr->pos - sizeof (t_mtrlnt)       /* position to the start */
                  - (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc);   /*   of the record */
                sim_fseek (uptr->fileref,                       /* seek to the data area */
                           uptr->pos + sizeof (t_mtrlnt), SEEK_SET);
                }
            }
        while (*bc == MTR_GAP && runaway_counter > 0);  /* continue until data or runaway occurs */

        if (r == MTSE_OK && runaway_counter <= 0)       /* if a tape runaway occurred */
            r = MTSE_RUNAWAY;                           /*   then report it */

        break;                                          /* otherwise the operation succeeded */

    case MTUF_F_TPC:
        ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf); /* find prev rec */
        sim_fseek (uptr->fileref, ppos, SEEK_SET);      /* position */
        sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
        *bc = tpcbc;                                    /* save rec lnt */
        if (ferror (uptr->fileref))                     /* error? */
            return sim_tape_ioerr (uptr);
        if (feof (uptr->fileref)) {                     /* eof? */
            r = MTSE_EOM;
            break;
            }
        uptr->pos = ppos;                               /* spc over record */
        if (*bc == MTR_TMK) {                           /* tape mark? */
            r = MTSE_TMK;
            break;
            }
        sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET);
        break;

    case MTUF_F_P7B:
        for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) {
            sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET);
            sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
            if (ferror (uptr->fileref))                 /* error? */
                return sim_tape_ioerr (uptr);
            if (feof (uptr->fileref)) {                 /* eof? */
                r = MTSE_EOM;
                break;
                }
            if ((c & P7B_DPAR) != P7B_EOF)
                all_eof = 0;
            if (c & P7B_SOR)                            /* start of record? */
                break;
            }
        uptr->pos = uptr->pos - sbc;                    /* update position */
        *bc = sbc;                                      /* save rec lnt */
        sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
        if (all_eof)                                    /* tape mark? */
            r = MTSE_TMK;
        break;

    default:
        return MTSE_FMT;
        }
sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", r, *bc, uptr->pos);
return r;
}

/* Read record forward

   Inputs:
        uptr    =       pointer to tape unit
        buf     =       pointer to buffer
        bc      =       pointer to returned record length
        max     =       maximum record size
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   read error           unchanged, PNU set
   end of file/medium   unchanged, PNU set
   invalid record       unchanged, PNU set
   tape mark            updated
   data record          updated
   data record error    updated
*/

t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
uint32 f = MT_GET_FMT (uptr);
t_mtrlnt i, tbc, rbc;
t_addr opos;
t_stat st;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecf(unit=%d, buf=%p, max=%d)\n", (int)(uptr-ctx->dptr->units), buf, max);

opos = uptr->pos;                                       /* old position */
if (MTSE_OK != (st = sim_tape_rdlntf (uptr, &tbc)))     /* read rec lnt */
    return st;
*bc = rbc = MTR_L (tbc);                                /* strip error flag */
if (rbc > max) {                                        /* rec out of range? */
    MT_SET_PNU (uptr);
    uptr->pos = opos;
    return MTSE_INVRL;
    }
i = (t_mtrlnt)sim_fread (buf, sizeof (uint8), rbc, uptr->fileref);/* read record */
if (ferror (uptr->fileref)) {                           /* error? */
    MT_SET_PNU (uptr);
    uptr->pos = opos;
    return sim_tape_ioerr (uptr);
    }
for ( ; i < rbc; i++)                                   /* fill with 0's */
    buf[i] = 0;
if (f == MTUF_F_P7B)                                    /* p7b? strip SOR */
    buf[0] = buf[0] & P7B_DPAR;
sim_tape_data_trace(uptr, buf, rbc, "Record Read", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
}

t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback)
{
t_stat r = SCPE_OK;
AIO_CALLSETUP
    r = sim_tape_rdrecf (uptr, buf, bc, max);
AIO_CALL(TOP_RDRF, buf, bc, NULL, max, 0, 0, 0, NULL, callback);
return r;
}


/* Read record reverse

   Inputs:
        uptr    =       pointer to tape unit
        buf     =       pointer to buffer
        bc      =       pointer to returned record length
        max     =       maximum record size
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   read error           unchanged
   end of file          unchanged
   end of medium        updated
   invalid record       unchanged
   tape mark            updated
   data record          updated
   data record error    updated
*/

t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
uint32 f = MT_GET_FMT (uptr);
t_mtrlnt i, rbc, tbc;
t_stat st;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rdrecr(unit=%d, buf=%p, max=%d)\n", (int)(uptr-ctx->dptr->units), buf, max);

if (MTSE_OK != (st = sim_tape_rdlntr (uptr, &tbc)))     /* read rec lnt */
    return st;
*bc = rbc = MTR_L (tbc);                                /* strip error flag */
if (rbc > max)                                          /* rec out of range? */
    return MTSE_INVRL;
i = (t_mtrlnt)sim_fread (buf, sizeof (uint8), rbc, uptr->fileref);/* read record */
if (ferror (uptr->fileref))                             /* error? */
    return sim_tape_ioerr (uptr);
for ( ; i < rbc; i++)                                   /* fill with 0's */
    buf[i] = 0;
if (f == MTUF_F_P7B)                                    /* p7b? strip SOR */
    buf[0] = buf[0] & P7B_DPAR;
sim_tape_data_trace(uptr, buf, rbc, "Record Read Reverse", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
}

t_stat sim_tape_rdrecr_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback)
{
t_stat r = SCPE_OK;
AIO_CALLSETUP
    r = sim_tape_rdrecr (uptr, buf, bc, max);
AIO_CALL(TOP_RDRR, buf, bc, NULL, max, 0, 0, 0, NULL, callback);
return r;
}

/* Write record forward

   Inputs:
        uptr    =       pointer to tape unit
        buf     =       pointer to buffer
        bc      =       record length
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   write protect        unchanged
   write error          unchanged, PNU set
   data record          updated
*/

t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
uint32 f = MT_GET_FMT (uptr);
t_mtrlnt sbc;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrrecf(unit=%d, buf=%p, bc=%d)\n", (int)(uptr-ctx->dptr->units), buf, bc);

sim_tape_data_trace(uptr, buf, bc, "Record Write", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
MT_CLR_PNU (uptr);
sbc = MTR_L (bc);
if ((uptr->flags & UNIT_ATT) == 0)                      /* not attached? */
    return MTSE_UNATT;
if (sim_tape_wrp (uptr))                                /* write prot? */
    return MTSE_WRP;
if (sbc == 0)                                           /* nothing to do? */
    return MTSE_OK;
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);         /* set pos */
switch (f) {                                            /* case on format */

    case MTUF_F_STD:                                    /* standard */
        sbc = MTR_L ((bc + 1) & ~1);                    /* pad odd length */
    case MTUF_F_E11:                                    /* E11 */
        sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
        sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
        sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
        if (ferror (uptr->fileref)) {                   /* error? */
            MT_SET_PNU (uptr);
            return sim_tape_ioerr (uptr);
            }
        uptr->pos = uptr->pos + sbc + (2 * sizeof (t_mtrlnt));  /* move tape */
        break;

    case MTUF_F_P7B:                                    /* Pierce 7B */
        buf[0] = buf[0] | P7B_SOR;                      /* mark start of rec */
        sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
        sim_fwrite (buf, sizeof (uint8), 1, uptr->fileref); /* delimit rec */
        if (ferror (uptr->fileref)) {                   /* error? */
            MT_SET_PNU (uptr);
            return sim_tape_ioerr (uptr);
            }
        uptr->pos = uptr->pos + sbc;                    /* move tape */
        break;
        }
sim_tape_data_trace(uptr, buf, sbc, "Record Written", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR);
return MTSE_OK;
}

t_stat sim_tape_wrrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt bc, TAPE_PCALLBACK callback)
{
t_stat r = SCPE_OK;
AIO_CALLSETUP
    r = sim_tape_wrrecf (uptr, buf, bc);
AIO_CALL(TOP_WREC, buf, 0, NULL, 0, bc, 0, 0, NULL, callback);
return r;
}

/* Write metadata forward (internal routine) */

static t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

MT_CLR_PNU (uptr);
if ((uptr->flags & UNIT_ATT) == 0)                      /* not attached? */
    return MTSE_UNATT;
if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
if (sim_tape_wrp (uptr))                                /* write prot? */
    return MTSE_WRP;
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);         /* set pos */
sim_fwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref);
if (ferror (uptr->fileref)) {                           /* error? */
    MT_SET_PNU (uptr);
    return sim_tape_ioerr (uptr);
    }
sim_debug (MTSE_DBG_STR, ctx->dptr, "wr_lnt: lnt: %d, pos: %" T_ADDR_FMT "u\n", dat, uptr->pos);
uptr->pos = uptr->pos + sizeof (t_mtrlnt);              /* move tape */
return MTSE_OK;
}

/* Write tape mark */

t_stat sim_tape_wrtmk (UNIT *uptr)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrtmk(unit=%d)\n", (int)(uptr-ctx->dptr->units));
if (MT_GET_FMT (uptr) == MTUF_F_P7B) {                  /* P7B? */
    uint8 buf = P7B_EOF;                                /* eof mark */
    return sim_tape_wrrecf (uptr, &buf, 1);             /* write char */
    }
return sim_tape_wrdata (uptr, MTR_TMK);
}

t_stat sim_tape_wrtmk_a (UNIT *uptr, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_wrtmk (uptr);
AIO_CALL(TOP_WTMK, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback);
return r;
}

/* Write end of medium */

t_stat sim_tape_wreom (UNIT *uptr)
{
t_stat result;
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreom(unit=%d)\n", (int)(uptr-ctx->dptr->units));
if (MT_GET_FMT (uptr) == MTUF_F_P7B)                    /* cant do P7B */
    return MTSE_FMT;

result = sim_tape_wrdata (uptr, MTR_EOM);               /* write the EOM marker */

uptr->pos = uptr->pos - sizeof (t_mtrlnt);              /* restore original tape position */
MT_SET_PNU (uptr);                                      /* indicate that position was not updated */

return result;
}

t_stat sim_tape_wreom_a (UNIT *uptr, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_wreom (uptr);
AIO_CALL(TOP_WEOM, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback);
return r;
}

/* Write end of medium-rewind */

t_stat sim_tape_wreomrw (UNIT *uptr)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat r;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wreomrw(unit=%d)\n", (int)(uptr-ctx->dptr->units));
if (MT_GET_FMT (uptr) == MTUF_F_P7B)                    /* cant do P7B */
    return MTSE_FMT;
r = sim_tape_wrdata (uptr, MTR_EOM);
if (r == MTSE_OK)
    r = sim_tape_rewind (uptr);
return r;
}

t_stat sim_tape_wreomrw_a (UNIT *uptr, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_wreomrw (uptr);
AIO_CALL(TOP_WEMR, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback);
return r;
}

/* Write erase gap

   Inputs:
        uptr    = pointer to tape unit
        gaplen  = length of gap in tenths of an inch

   Outputs:
        status  = operation status

   exit condition       position
   ------------------   ------------------
   unit unattached      unchanged
   unsupported format   unchanged
   write protected      unchanged
   read error           unchanged, PNU set
   write error          unchanged, PNU set
   gap written          updated


   An erase gap is represented in the tape image file by a special metadata
   value.  This value is chosen so that it is still recognizable even if it has
   been "cut in half" by a subsequent data overwrite that does not end on a
   metadatum-sized boundary.  In addition, a range of metadata values are
   reserved for detection in the reverse direction.  Erase gaps are currently
   supported only in SIMH (MTUF_F_STD) tape format.

   This implementation supports erasing gaps in the middle of a populated tape
   image and will always produce a valid image.  It also produces valid images
   when overwriting gaps with data records, with one exception: a data write
   that leaves only two bytes of gap remaining will produce an invalid tape.
   This limitation is deemed acceptable, as it is analogous to the existing
   limitation that data records cannot overwrite other data records without
   producing an invalid tape.

   Because SIMH tape images do not carry physical parameters (e.g., recording
   density), overwriting a tape image file containing gap metadata is
   problematic if the density setting is not the same as that used during
   recording.  There is no way to establish a gap of a certain length
   unequivocally in an image file, so this implementation establishes a gap of a
   certain number of bytes that reflect the desired gap length at the tape
   density in bits per inch used during writing.

   To write an erase gap, the implementation uses one of two approaches,
   depending on whether or not the current tape position is at EOM.  Erasing at
   EOM presents no special difficulties; gap metadata markers are written for
   the prescribed number of bytes.  If the tape is not at EOM, then erasing must
   take into account the existing record structure to ensure that a valid tape
   image is maintained.

   The general approach is to erase for the nominal number of bytes but to
   increase that length, if necessary, to ensure that a partially overwritten
   data record at the end of the gap can be altered to maintain validity.
   Because the smallest legal tape record requires space for two metadata
   markers plus two data bytes, an erasure that would leave less than that
   is increased to consume the entire record.  Otherwise, the final record is
   truncated appropriately by rewriting the leading and trailing length words
   appropriately.

   When reading in either direction, gap metadata markers are ignored (skipped)
   until a record length header, EOF marker, EOM marker, or physical EOF is
   encountered.  Thus, tape images containing gap metadata are transparent to
   the calling simulator (unless tape runaway support is enabled -- see the
   notes at "sim_tape_rdlntf" for details).

   The permissibility of data record lengths that are not multiples of the
   metadatum size presents a difficulty when reading.  If such an "odd length"
   record is written over a gap, half of a metadata marker will exist
   immediately after the trailing record length.

   This condition is detected when reading forward by the appearance of a
   "reversed" marker.  The value appears reversed because the value is made up
   of half of one marker and half of the next.  This is handled by seeking
   forward two bytes to resync (the stipulation above that the overwrite cannot
   leave only two bytes of gap means that at least one "whole" metadata marker
   will follow).  Reading in reverse presents a more complex problem, because
   half of the marker is from the preceding trailing record length marker and
   therefore could be any of a range of values.  However, that range is
   restricted by the SIMH tape specification requirement that record length
   metadata values must have bits 30:24 set to zero.  This allows unambiguous
   detection of the condition.

   The value chosen for gap metadata and the values reserved for "half-gap"
   detection are:

     0xFFFFFFFE            - primary gap value
     0xFFFEFFFF            - reserved (indicates half-gap in forward reads)
     0xFFFF0000:0xFFFF00FF - reserved (indicates half-gap in reverse reads)
     0xFFFF8000:0xFFFF80FF - reserved (indicates half-gap in reverse reads)

   If the tape density has been set via a previous sim_tape_set_dens call, and
   the tape format is set to SIMH format, then this routine will write a gap of
   the appropriate size.  If the density has not been set, then no action will
   be taken, and either MTSE_IOERR or MTSE_OK status will be returned, depending
   on whether SIMH or another format is selected, respectively.  A simulator
   that calls this routine must set the density beforehand; failure to do so is
   an error.  However, calling while another format is enabled is OK and is
   treated as a no-operation.  This allows a device simulator that supports
   writing erase gaps to use the same code without worrying about the tape
   format currently selected by the user.
*/

t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat st;
t_mtrlnt meta, sbc, new_len, rec_size;
t_addr gap_pos = uptr->pos;
uint32 file_size, marker_count, tape_density;
int32 gap_needed;
uint32 gap_alloc = 0;                                   /* gap currently allocated from the tape */
const uint32 format = MT_GET_FMT (uptr);                /* tape format */
const uint32 meta_size = sizeof (t_mtrlnt);             /* bytes per metadatum */
const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2;  /* smallest data record size */

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_wrgap(unit=%d, gaplen=%u)\n", (int)(uptr-ctx->dptr->units), gaplen);

MT_CLR_PNU (uptr);

if ((uptr->flags & UNIT_ATT) == 0)                      /* if the unit is not attached */
    return MTSE_UNATT;                                  /*   then we cannot proceed */

else if (sim_tape_wrp (uptr))                           /* otherwise if the unit is write protected */
    return MTSE_WRP;                                    /*   then we cannot write */

tape_density = bpi [MT_DENS (uptr->dynflags)];          /* get the density of the tape */

if (format != MTUF_F_STD)                               /* if erase gaps aren't supported by the format */
    return MTSE_OK;                                     /*   then take no action */
else if (tape_density == 0)                             /* otherwise if the density is not set */
    return MTSE_IOERR;                                  /*   then report an I/O error */
else                                                    /* otherwise */
    gap_needed = (gaplen * tape_density) / 10;          /*   determine the gap size needed in bytes */

file_size = sim_fsize (uptr->fileref);                  /* get file size */
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);         /* position tape */

/* Read tape records and allocate to gap until amount required is consumed.

   Read next metadatum from tape:
    - EOF or EOM: allocate remainder of bytes needed.
    - TMK or GAP: allocate sizeof(metadatum) bytes.
    - Reverse GAP: allocate sizeof(metadatum) / 2 bytes.
    - Data record: see below.

   Loop until bytes needed = 0.
*/

do {
    sim_fread (&meta, meta_size, 1, uptr->fileref);     /* read metadatum */

    if (ferror (uptr->fileref)) {                       /* read error? */
        uptr->pos = gap_pos;                            /* restore original position */
        MT_SET_PNU (uptr);                              /* position not updated */
        return sim_tape_ioerr (uptr);                   /* translate error */
        }
    else
        uptr->pos = uptr->pos + meta_size;              /* move tape over datum */

    if (feof (uptr->fileref) || (meta == MTR_EOM)) {    /* at eof or eom? */
        gap_alloc = gap_alloc + gap_needed;             /* allocate remainder */
        gap_needed = 0;
        }

    else if ((meta == MTR_GAP) || (meta == MTR_TMK)) {  /* gap or tape mark? */
        gap_alloc = gap_alloc + meta_size;              /* allocate marker space */
        gap_needed = gap_needed - meta_size;            /* reduce requirement */
        }

    else if (meta == MTR_FHGAP) {                       /* half gap? */
        uptr->pos = uptr->pos - meta_size / 2;          /* backup to resync */
        sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */
        gap_alloc = gap_alloc + meta_size / 2;          /* allocate marker space */
        gap_needed = gap_needed - meta_size / 2;        /* reduce requirement */
        }

    else if (uptr->pos +
             MTR_L (meta) + meta_size > file_size) {    /* rec len out of range? */
        gap_alloc = gap_alloc + gap_needed;             /* presume overwritten tape */
        gap_needed = 0;                                 /* allocate remainder */
        }

/* Allocate a data record:
    - Determine record size in bytes (including metadata)
    - If record size - bytes needed < smallest allowed record size,
      allocate entire record to gap, else allocate needed amount and
      truncate data record to reflect remainder.
*/
    else {                                              /* data record */
        sbc = MTR_L (meta);                             /* get record data length */
        rec_size = ((sbc + 1) & ~1) + meta_size * 2;    /* overall size in bytes */

        if (rec_size < gap_needed + min_rec_size) {         /* rec too small? */
            uptr->pos = uptr->pos - meta_size + rec_size;   /* position past record */
            sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* move tape */
            gap_alloc = gap_alloc + rec_size;               /* allocate record */
            gap_needed = gap_needed - rec_size;             /* reduce requirement */
            }

        else {                                              /* record size OK */
            uptr->pos = uptr->pos - meta_size + gap_needed; /* position to end of gap */
            new_len = MTR_F (meta) | (sbc - gap_needed);    /* truncate to new len */
            st = sim_tape_wrdata (uptr, new_len);           /* write new rec len */

            if (st != MTSE_OK) {                            /* write OK? */
                uptr->pos = gap_pos;                        /* restore orig pos */
                return st;                                  /* PNU was set by wrdata */
                }

            uptr->pos = uptr->pos + sbc - gap_needed;       /* position to end of data */
            st = sim_tape_wrdata (uptr, new_len);           /* write new rec len */

            if (st != MTSE_OK) {                            /* write OK? */
                uptr->pos = gap_pos;                        /* restore orig pos */
                return st;                                  /* PNU was set by wrdata */
                }

            gap_alloc = gap_alloc + gap_needed;             /* allocate remainder */
            gap_needed = 0;
            }
        }
    }
while (gap_needed > 0);

uptr->pos = gap_pos;                                    /* reposition to gap start */

if (gap_alloc & (meta_size - 1)) {                      /* gap size "odd?" */
    st = sim_tape_wrdata (uptr, MTR_FHGAP);             /* write half gap marker */
    if (st != MTSE_OK) {                                /* write OK? */
        uptr->pos = gap_pos;                            /* restore orig pos */
        return st;                                      /* PNU was set by wrdata */
        }
    uptr->pos = uptr->pos - meta_size / 2;              /* realign position */
    gap_alloc = gap_alloc - 2;                          /* decrease gap to write */
    }

marker_count = gap_alloc / meta_size;                   /* count of gap markers */

do {
    st = sim_tape_wrdata (uptr, MTR_GAP);               /* write gap markers */
    if (st != MTSE_OK) {                                /* write OK? */
        uptr->pos = gap_pos;                            /* restore orig pos */
        return st;                                      /* PNU was set by wrdata */
        }
    }
while (--marker_count > 0);

return MTSE_OK;
}

t_stat sim_tape_wrgap_a (UNIT *uptr, uint32 gaplen, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_wrgap (uptr, gaplen);
AIO_CALL(TOP_RDRR, NULL, NULL, NULL, 0, 0, gaplen, 0, NULL, callback);
return r;
}

/* Erase a record forward.

   An erase gap is written in the forward direction on the tape unit specified
   by "uptr" for a length corresponding to a record containing the number of
   bytes specified by "bc", and the status of the operation is returned.  The
   resulting gap will occupy "bc" bytes plus the size of the record length
   metadata.  This function may be used to erase a record of length "n" in place
   by requesting a gap of length "n".  After erasure, the tape will be
   positioned at the end of the gap.
*/

t_stat sim_tape_errecf (UNIT *uptr, t_mtrlnt bc)
{
const t_mtrlnt meta_size = sizeof (t_mtrlnt);           /* the number of bytes per metadatum */
const t_mtrlnt gap_size = bc + 2 * meta_size;           /* the requested gap size in bytes */

return MTSE_IOERR;                 /* stub return */
}

/* Erase a record reverse.

   An erase gap is written in the reverse direction on the tape unit specified
   by "uptr" for a length corresponding to a record containing the number of
   bytes specified by "bc", and the status of the operation is returned.  The
   resulting gap will occupy "bc" bytes plus the size of the record length
   metadata.  This function may be used to erase a record of length "n" in place
   by requesting a gap of length "n".  After erasure, the tape will be
   positioned at the start of the gap.
*/

t_stat sim_tape_errecr (UNIT *uptr, t_mtrlnt bc)
{
const t_mtrlnt meta_size = sizeof (t_mtrlnt);           /* the number of bytes per metadatum */
const t_mtrlnt gap_size = bc + 2 * meta_size;           /* the requested gap size in bytes */

return MTSE_IOERR;                 /* stub return */
}

/* Space record forward

   Inputs:
        uptr    =       pointer to tape unit
        bc      =       pointer to size of record skipped
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   read error           unchanged, PNU set
   end of file/medium   unchanged, PNU set
   tape mark            updated
   data record          updated
   data record error    updated
*/

t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat st;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecf(unit=%d)\n", (int)(uptr-ctx->dptr->units));

st = sim_tape_rdlntf (uptr, bc);                        /* get record length */
*bc = MTR_L (*bc);
return st;
}

t_stat sim_tape_sprecf_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_sprecf (uptr, bc);
AIO_CALL(TOP_SPRF, NULL, bc, NULL, 0, 0, 0, 0, NULL, callback);
return r;
}

/* Space records forward

   Inputs:
        uptr    =       pointer to tape unit
        count   =       count of records to skip
        skipped =       pointer to number of records actually skipped
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   read error           unchanged, PNU set
   end of file/medium   unchanged, PNU set
   tape mark            updated
   data record          updated
   data record error    updated
*/

t_stat sim_tape_sprecsf (UNIT *uptr, uint32 count, uint32 *skipped)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat st;
t_mtrlnt tbc;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsf(unit=%d, count=%d)\n", (int)(uptr-ctx->dptr->units), count);

*skipped = 0;
while (*skipped < count) {                              /* loopo */
    st = sim_tape_sprecf (uptr, &tbc);                  /* spc rec */
    if (st != MTSE_OK)
        return st;
    *skipped = *skipped + 1;                            /* # recs skipped */
    }
return MTSE_OK;
}

t_stat sim_tape_sprecsf_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_sprecsf (uptr, count, skipped);
AIO_CALL(TOP_SRSF, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback);
return r;
}

/* Space record reverse

   Inputs:
        uptr    =       pointer to tape unit
        bc      =       pointer to size of records skipped
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   beginning of tape    unchanged
   read error           unchanged
   end of file          unchanged
   end of medium        updated
   tape mark            updated
   data record          updated
*/

t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat st;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecr(unit=%d)\n", (int)(uptr-ctx->dptr->units));

if (MT_TST_PNU (uptr)) {
    MT_CLR_PNU (uptr);
    *bc = 0;
    return MTSE_OK;
    }
st = sim_tape_rdlntr (uptr, bc);                        /* get record length */
*bc = MTR_L (*bc);
return st;
}

t_stat sim_tape_sprecr_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_sprecr (uptr, bc);
AIO_CALL(TOP_SPRR, NULL, bc, NULL, 0, 0, 0, 0, NULL, callback);
return r;
}

/* Space records reverse

   Inputs:
        uptr    =       pointer to tape unit
        count   =       count of records to skip
        skipped =       pointer to number of records actually skipped
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   beginning of tape    unchanged
   read error           unchanged
   end of file          unchanged
   end of medium        updated
   tape mark            updated
   data record          updated
*/

t_stat sim_tape_sprecsr (UNIT *uptr, uint32 count, uint32 *skipped)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat st;
t_mtrlnt tbc;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_sprecsr(unit=%d, count=%d)\n", (int)(uptr-ctx->dptr->units), count);

*skipped = 0;
while (*skipped < count) {                              /* loopo */
    st = sim_tape_sprecr (uptr, &tbc);                  /* spc rec rev */
    if (st != MTSE_OK)
        return st;
    *skipped = *skipped + 1;                            /* # recs skipped */
    }
return MTSE_OK;
}

t_stat sim_tape_sprecsr_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_sprecsr (uptr, count, skipped);
AIO_CALL(TOP_SRSR, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback);
return r;
}

/* Space files forward by record

   Inputs:
        uptr    =       pointer to tape unit
        count   =       count of files to skip
        skipped =       pointer to number of files actually skipped
        recsskipped =   pointer to number of records skipped
        check_leot =    flag to detect and stop skip between two successive tape marks
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   read error           unchanged, PNU set
   end of file/medium   unchanged, PNU set
   tape mark            updated
   data record          updated
   data record error    updated
*/

t_stat sim_tape_spfilebyrecf (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat st;
t_bool last_tapemark = FALSE;
uint32 filerecsskipped;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecf(unit=%d, count=%d, check_leot=%d)\n", (int)(uptr-ctx->dptr->units), count, check_leot);

if (check_leot) {
    t_mtrlnt rbc;

    st = sim_tape_rdlntr (uptr, &rbc);
    last_tapemark = (MTSE_TMK == st);
    if ((st == MTSE_OK) || (st == MTSE_TMK))
        sim_tape_rdlntf (uptr, &rbc);
    }
*skipped = 0;
*recsskipped = 0;
while (*skipped < count) {                              /* loopo */
    while (1) {
        st = sim_tape_sprecsf (uptr, 0x1ffffff, &filerecsskipped);/* spc recs */
        *recsskipped += filerecsskipped;
        if (st != MTSE_OK)
            break;
        }
    if (st == MTSE_TMK) {
        *skipped = *skipped + 1;                        /* # files skipped */
        if (check_leot && (filerecsskipped == 0) && last_tapemark) {
            uint32 filefileskipped;
            sim_tape_spfilebyrecr (uptr, 1, &filefileskipped, &filerecsskipped);
            *skipped = *skipped - 1;                    /* adjust # files skipped */
            return MTSE_LEOT;
            }
        last_tapemark = TRUE;
        }
    else
        return st;
    }
return MTSE_OK;
}

t_stat sim_tape_spfilebyrecf_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_spfilebyrecf (uptr, count, skipped, recsskipped, check_leot);
AIO_CALL(TOP_SFRF, NULL, skipped, recsskipped, check_leot, count, 0, 0, NULL, callback);
return r;
}

/* Space files forward

   Inputs:
        uptr    =       pointer to tape unit
        count   =       count of files to skip
        skipped =       pointer to number of files actually skipped
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   read error           unchanged, PNU set
   end of file/medium   unchanged, PNU set
   tape mark            updated
   data record          updated
   data record error    updated
*/

t_stat sim_tape_spfilef (UNIT *uptr, uint32 count, uint32 *skipped)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
uint32 totalrecsskipped;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilef(unit=%d, count=%d)\n", (int)(uptr-ctx->dptr->units), count);

return sim_tape_spfilebyrecf (uptr, count, skipped, &totalrecsskipped, FALSE);
}

t_stat sim_tape_spfilef_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_spfilef (uptr, count, skipped);
AIO_CALL(TOP_SPFF, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback);
return r;
}

/* Space files reverse by record

   Inputs:
        uptr    =       pointer to tape unit
        count   =       count of files to skip
        skipped =       pointer to number of files actually skipped
        recsskipped =   pointer to number of records skipped
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   beginning of tape    unchanged
   read error           unchanged
   end of file          unchanged
   end of medium        updated
   tape mark            updated
   data record          updated
*/

t_stat sim_tape_spfilebyrecr (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat st;
uint32 filerecsskipped;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfilebyrecr(unit=%d, count=%d)\n", (int)(uptr-ctx->dptr->units), count);

*skipped = 0;
*recsskipped = 0;
while (*skipped < count) {                              /* loopo */
    while (1) {
        st = sim_tape_sprecsr (uptr, 0x1ffffff, &filerecsskipped);/* spc recs rev */
        *recsskipped += filerecsskipped;
        if (st != MTSE_OK)
            break;
        }
    if (st == MTSE_TMK)
        *skipped = *skipped + 1;                        /* # files skipped */
    else
        return st;
    }
return MTSE_OK;
}

t_stat sim_tape_spfilebyrecr_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_spfilebyrecr (uptr, count, skipped, recsskipped);
AIO_CALL(TOP_SPFR, NULL, skipped, recsskipped, 0, count, 0, 0, NULL, callback);
return r;
}

/* Space files reverse

   Inputs:
        uptr    =       pointer to tape unit
        count   =       count of files to skip
        skipped =       pointer to number of files actually skipped
   Outputs:
        status  =       operation status

   exit condition       position

   unit unattached      unchanged
   beginning of tape    unchanged
   read error           unchanged
   end of file          unchanged
   end of medium        updated
   tape mark            updated
   data record          updated
*/

t_stat sim_tape_spfiler (UNIT *uptr, uint32 count, uint32 *skipped)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
uint32 totalrecsskipped;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_spfiler(unit=%d, count=%d)\n", (int)(uptr-ctx->dptr->units), count);

return sim_tape_spfilebyrecr (uptr, count, skipped, &totalrecsskipped);
}

t_stat sim_tape_spfiler_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_spfiler (uptr, count, skipped);
AIO_CALL(TOP_SPFR, NULL, skipped, NULL, 0, count, 0, 0, NULL, callback);
return r;
}

/* Rewind tape */

t_stat sim_tape_rewind (UNIT *uptr)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

if (uptr->flags & UNIT_ATT) {
    if (ctx == NULL)                                    /* if not properly attached? */
        return sim_messagef (SCPE_IERR, "Bad Attach\n");/*   that's a problem */
    sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rewind(unit=%d)\n", (int)(uptr-ctx->dptr->units));
    }
uptr->pos = 0;
MT_CLR_PNU (uptr);
return MTSE_OK;
}

t_stat sim_tape_rewind_a (UNIT *uptr, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_rewind (uptr);
AIO_CALL(TOP_RWND, NULL, NULL, NULL, 0, 0, 0, 0, NULL, callback);
return r;
}

/* Position Tape */

t_stat sim_tape_position (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recsskipped, uint32 files, uint32 *filesskipped, uint32 *objectsskipped)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
t_stat r = MTSE_OK;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_position(unit=%d, flags=0x%X, recs=%d, files=%d)\n", (int)(uptr-ctx->dptr->units), flags, recs, files);

*recsskipped = *filesskipped = *objectsskipped = 0;
if (flags & MTPOS_M_REW)
    r = sim_tape_rewind (uptr);
if (r != MTSE_OK)
    return r;
if (flags & MTPOS_M_OBJ) {
    uint32 objs = recs;
    uint32 skipped;
    uint32 objsremaining = objs;

    while (*objectsskipped < objs) {                       /* loopo */
        if (flags & MTPOS_M_REV)                        /* reverse? */
            r = sim_tape_sprecsr (uptr, objsremaining, &skipped);
        else
            r = sim_tape_sprecsf (uptr, objsremaining, &skipped);
        objsremaining = objsremaining - (skipped + ((r == MTSE_TMK) ? 1 : 0));
        if ((r == MTSE_TMK) || (r == MTSE_OK))
            *objectsskipped = *objectsskipped + skipped + ((r == MTSE_TMK) ? 1 : 0);
        else
            return r;
        }
    r = MTSE_OK;
    }
else {
    uint32 fileskiprecs;

    if (flags & MTPOS_M_REV)                            /* reverse? */
        r = sim_tape_spfilebyrecr (uptr, files, filesskipped, &fileskiprecs);
    else
        r = sim_tape_spfilebyrecf (uptr, files, filesskipped, &fileskiprecs, (flags & MTPOS_M_DLE));
    if (r != MTSE_OK)
        return r;
    if (flags & MTPOS_M_REV)                            /* reverse? */
        r = sim_tape_sprecsr (uptr, recs, recsskipped);
    else
        r = sim_tape_sprecsf (uptr, recs, recsskipped);
    if (r == MTSE_TMK)
        *filesskipped = *filesskipped + 1;
    *objectsskipped = fileskiprecs + *filesskipped + *recsskipped;
    }
return r;
}

t_stat sim_tape_position_a (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recsskipped, uint32 files, uint32 *filesskipped, uint32 *objectsskipped, TAPE_PCALLBACK callback)
{
t_stat r = MTSE_OK;
AIO_CALLSETUP
    r = sim_tape_position (uptr, flags, recs, recsskipped, files, filesskipped, objectsskipped);
AIO_CALL(TOP_POSN, NULL, recsskipped, filesskipped, 0, flags, recs, files, objectsskipped, callback);
return r;
}

/* Reset tape */

t_stat sim_tape_reset (UNIT *uptr)
{
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;

MT_CLR_PNU (uptr);
if (!(uptr->flags & UNIT_ATT))                          /* attached? */
    return SCPE_OK;

if (ctx == NULL)                                        /* if not properly attached? */
    return sim_messagef (SCPE_IERR, "Bad Attach\n");    /*   that's a problem */
sim_debug (ctx->dbit, ctx->dptr, "sim_tape_reset(unit=%d)\n", (int)(uptr-ctx->dptr->units));

_sim_tape_io_flush(uptr);
AIO_VALIDATE;
AIO_UPDATE_QUEUE;
return SCPE_OK;
}

/* Test for BOT */

t_bool sim_tape_bot (UNIT *uptr)
{
uint32 f = MT_GET_FMT (uptr);

return (uptr->pos <= fmts[f].bot)? TRUE: FALSE;
}

/* Test for end of tape */

t_bool sim_tape_eot (UNIT *uptr)
{
return (uptr->capac && (uptr->pos >= uptr->capac))? TRUE: FALSE;
}

/* Test for write protect */

t_bool sim_tape_wrp (UNIT *uptr)
{
return ((uptr->flags & MTUF_WRP) || (MT_GET_FMT (uptr) == MTUF_F_TPC))? TRUE: FALSE;
}

/* Process I/O error */

static t_stat sim_tape_ioerr (UNIT *uptr)
{
sim_printf ("%s: Magtape library I/O error: %s\n", sim_uname (uptr), strerror (errno));
clearerr (uptr->fileref);
return MTSE_IOERR;
}

/* Set tape format */

t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 f;

if (uptr == NULL)
    return SCPE_IERR;
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;
if (cptr == NULL)
    return SCPE_ARG;
for (f = 0; f < MTUF_N_FMT; f++) {
    if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) {
        uptr->flags = (uptr->flags & ~MTUF_FMT) |
            (f << MTUF_V_FMT) | fmts[f].uflags;
        return SCPE_OK;
        }
    }
return SCPE_ARG;
}

/* Show tape format */

t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 f = MT_GET_FMT (uptr);

if (fmts[f].name)
    fprintf (st, "%s format", fmts[f].name);
else fprintf (st, "invalid format");
return SCPE_OK;
}

/* Map a TPC format tape image */

static uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map, uint32 mapsize)
{
t_addr tpos, leot;
t_addr tape_size;
t_tpclnt bc, last_bc = 0xFFFF;
uint32 had_double_tape_mark = 0;
size_t i;
uint32 objc, sizec;
uint32 *countmap = NULL;
uint8 *recbuf = NULL;
DEVICE *dptr = find_dev_from_unit (uptr);

if ((uptr == NULL) || (uptr->fileref == NULL))
    return 0;
countmap = (uint32 *)calloc (65536, sizeof(*countmap));
recbuf = (uint8 *)malloc (65536);
tape_size = (t_addr)sim_fsize (uptr->fileref);
sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape_size: %" T_ADDR_FMT "u\n", tape_size);
for (objc = 0, sizec = 0, tpos = 0;; ) {
    sim_fseek (uptr->fileref, tpos, SEEK_SET);
    i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref);
    if (i == 0)     /* past or at eof? */
        break;
    if (countmap[bc] == 0)
        sizec++;
    ++countmap[bc];
    if (map && (objc < mapsize))
        map[objc] = tpos;
    if (bc) {
        sim_debug (MTSE_DBG_STR, dptr, "tpc_map: %d byte count at pos: %" T_ADDR_FMT "u\n", bc, tpos);
        if (sim_deb && (dptr->dctrl & MTSE_DBG_STR)) {
            sim_fread (recbuf, 1, bc, uptr->fileref);
            sim_data_trace(dptr, uptr, ((dptr->dctrl & MTSE_DBG_DAT) ? recbuf : NULL), "", bc, "Data Record", MTSE_DBG_STR);
            }
        }
    else
        sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape mark at pos: %" T_ADDR_FMT "u\n", tpos);
    objc++;
    tpos = tpos + ((bc + 1) & ~1) + sizeof (t_tpclnt);
    if ((bc == 0) && (last_bc == 0)) {  /* double tape mark? */
        had_double_tape_mark = objc;
        leot = tpos;
        }
    last_bc = bc;
    }
sim_debug (MTSE_DBG_STR, dptr, "tpc_map: objc: %u, different record sizes: %u\n", objc, sizec);
for (i=0; i<65535; i++) {
    if (countmap[i]) {
        if (i == 0)
            sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u tape marks\n", countmap[i]);
        else
            sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u %d byte record%s\n", countmap[i], (int)i, (countmap[i] > 1) ? "s" : "");
        }
    }
if (((last_bc != 0xffff) && 
     (tpos > tape_size) &&
     (!had_double_tape_mark))    ||
    (!had_double_tape_mark)      ||
    ((objc == countmap[0]) && 
     (countmap[0] != 2))) {     /* Unreasonable format? */
    if (last_bc != 0xffff)
        sim_debug (MTSE_DBG_STR, dptr, "tpc_map: ERROR unexpected EOT byte count: %d\n", last_bc);
    if (tpos > tape_size)
        sim_debug (MTSE_DBG_STR, dptr, "tpc_map: ERROR next record position %" T_ADDR_FMT "u beyond EOT: %" T_ADDR_FMT "u\n", tpos, tape_size);
    if (objc == countmap[0])
        sim_debug (MTSE_DBG_STR, dptr, "tpc_map: ERROR tape cnly contains tape marks\n");
    free (countmap);
    free (recbuf);
    return 0;
    }

if ((last_bc != 0xffff) && (tpos > tape_size)) {
    sim_debug (MTSE_DBG_STR, dptr, "tpc_map: WARNING unexpected EOT byte count: %d, double tape mark before %" T_ADDR_FMT "u provides logical EOT\n", last_bc, leot);
    objc = had_double_tape_mark;
    tpos = leot;
    }
if (map)
    map[objc] = tpos;
sim_debug (MTSE_DBG_STR, dptr, "tpc_map: OK objc: %d\n", objc);
free (countmap);
free (recbuf);
return objc;
}

/* Check the basic structure of a SIMH format tape image */

static t_stat sim_tape_simh_check (UNIT *uptr)
{
return SCPE_OK;
}

/* Check the basic structure of a E11 format tape image */

static t_stat sim_tape_e11_check (UNIT *uptr)
{
return SCPE_OK;
}

/* Find the preceding record in a TPC file */

static t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map)
{
uint32 lo, hi, p;


if (map == NULL)
    return 0;
lo = 0;
hi = uptr->hwmark - 1;
do {
    p = (lo + hi) >> 1;
    if (uptr->pos == map[p])
        return ((p == 0)? map[p]: map[p - 1]);
    else if (uptr->pos < map[p])
        hi = p - 1;
    else lo = p + 1;
    }
while (lo <= hi);
return ((p == 0)? map[p]: map[p - 1]);
}

/* Set tape capacity */

t_stat sim_tape_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_addr cap;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_ARG;
if (uptr->flags & UNIT_ATT)
    return SCPE_ALATT;
cap = (t_addr) get_uint (cptr, 10, sim_taddr_64? 2000000: 2000, &r);
if (r != SCPE_OK)
    return SCPE_ARG;
uptr->capac = cap * ((t_addr) 1000000);
return SCPE_OK;
}

/* Show tape capacity */

t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (uptr->capac) {
    if (uptr->capac >= (t_addr) 1000000)
        fprintf (st, "capacity=%dMB", (uint32) (uptr->capac / ((t_addr) 1000000)));
    else {
        if (uptr->capac >= (t_addr) 1000)
            fprintf (st, "capacity=%dKB", (uint32) (uptr->capac / ((t_addr) 1000)));
        else
            fprintf (st, "capacity=%dB", (uint32) uptr->capac);
        }
    }
else
    fprintf (st, "unlimited capacity");
return SCPE_OK;
}

/* Set the tape density.

   Set the density of the specified tape unit either to the value supplied or to
   the value represented by the supplied character string.
   
   If "desc" is NULL, then "val" must be set to one of the MT_DENS_* constants
   in sim_tape.h other than MT_DENS_NONE; the supplied value is used as the tape
   density, and the character string is ignored.  Otherwise, "desc" must point
   at an int32 value containing a set of allowed densities constructed as a
   bitwise OR of the appropriate MT_*_VALID values.  In this case, the string
   pointed to by "cptr" will be parsed for a decimal value corresponding to the
   desired density in bits per inch and validated against the set of allowed
   values.

   In either case, SCPE_ARG is returned if the density setting is not valid or
   allowed.  If the setting is OK, the new density is set into the unit
   structure, and SCPE_OK is returned.
*/

t_stat sim_tape_set_dens (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
uint32 density, new_bpi;
t_stat result = SCPE_OK;

if (uptr == NULL)                                               /* if the unit pointer is null */
    return SCPE_IERR;                                           /*   then the caller has screwed up */

else if (desc == NULL)                                          /* otherwise if a validation set was not supplied */
    if (val > 0 && val < (int32) BPI_COUNT)                     /*   then if a valid density code was supplied */
        uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK)     /*     then insert the code */
                           | (val << UNIT_V_DF_TAPE);           /*       in the unit flags */
    else                                                        /*   otherwise the code is invalid */
        return SCPE_ARG;                                        /*     so report a bad argument */

else {                                                          /* otherwise a validation set was supplied */
    if (cptr == NULL || *cptr == 0)                             /*   but if no value is present */
        return SCPE_MISVAL;                                     /*     then report a missing value */

    new_bpi = (uint32) get_uint (cptr, 10, UINT_MAX, &result);  /* convert the string value */

    if (result != SCPE_OK)                                      /* if the conversion failed */
        result = SCPE_ARG;                                      /*   then report a bad argument */

    else for (density = 0; density < BPI_COUNT; density++)      /* otherwise validate the density */
        if (new_bpi == bpi [density]                            /* if it matches a value in the list */
          && ((1 << density) & *(const int32 *) desc)) {        /*   and it's an allowed value */
            uptr->dynflags = (uptr->dynflags & ~MTVF_DENS_MASK) /*     then store the index of the value */
                               | density << UNIT_V_DF_TAPE;     /*       in the unit flags */
            return SCPE_OK;                                     /*         and return success */
            }

    result = SCPE_ARG;                                          /* if no match, then report a bad argument */
    }

return result;                                                  /* return the result of the operation */
}

/* Show the tape density */

t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
uint32 tape_density;

if (uptr == NULL)                                       /* if the unit pointer is null */
    return SCPE_IERR;                                   /*   then the caller has screwed up */

else {                                                  /* otherwise get the density */
    tape_density = bpi [MT_DENS (uptr->dynflags)];      /*   of the tape from the unit flags */

    if (tape_density)                                   /* if it's set */
        fprintf (st, "density=%d bpi", tape_density);   /*   then report it */
    else                                                /* otherwise */
        fprintf (st, "density not set");                /*   it was never set by the caller */
    }

return SCPE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_tape.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* sim_tape.h: simulator tape support library definitions

   Copyright (c) 1993-2008, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   18-Jul-16    JDB     Added sim_tape_errecf, sim_tape_errecr functions
   15-Dec-14    JDB     Added tape density validity flags
   04-Nov-14    JDB     Added tape density flags
   11-Oct-14    JDB     Added reverse read half gap, set/show density
   22-Sep-14    JDB     Added tape runaway support
   23-Jan-12    MP      Added support for Logical EOT detection while positioning
   05-Feb-11    MP      Add Asynch I/O support
   30-Aug-06    JDB     Added erase gap support
   14-Feb-06    RMS     Added variable tape capacity
   17-Dec-05    RMS     Added write support for Paul Pierce 7b format
   02-May-05    RMS     Added support for Paul Pierce 7b format
*/

#ifndef SIM_TAPE_H_
#define SIM_TAPE_H_    0

#ifdef  __cplusplus
extern "C" {
#endif

/* SIMH/E11 tape format */

typedef uint32          t_mtrlnt;                       /* magtape rec lnt */

#define MTR_TMK         0x00000000                      /* tape mark */
#define MTR_EOM         0xFFFFFFFF                      /* end of medium */
#define MTR_GAP         0xFFFFFFFE                      /* primary gap */
#define MTR_RRGAP       0xFFFFFFFF                      /* reverse read half gap */
#define MTR_FHGAP       0xFFFEFFFF                      /* fwd half gap (overwrite) */
#define MTR_RHGAP       0xFFFF0000                      /* rev half gap (overwrite) */
#define MTR_M_RHGAP     (~0x000080FF)                   /* range mask for rev gap */
#define MTR_MAXLEN      0x00FFFFFF                      /* max len is 24b */
#define MTR_ERF         0x80000000                      /* error flag */
#define MTR_F(x)        ((x) & MTR_ERF)                 /* record error flg */
#define MTR_L(x)        ((x) & ~MTR_ERF)                /* record length */

/* TPC tape format */

typedef uint16          t_tpclnt;                       /* magtape rec lnt */

/* P7B tape format */

#define P7B_SOR         0x80                            /* start of record */
#define P7B_PAR         0x40                            /* parity */
#define P7B_DATA        0x3F                            /* data */
#define P7B_DPAR        (P7B_PAR|P7B_DATA)              /* data and parity */
#define P7B_EOF         0x0F                            /* eof character */

#define TPC_TMK         0x0000                          /* tape mark */

/* Unit flags */

#define MTUF_V_PNU      (UNIT_V_UF + 0)                 /* position not upd */
#define MTUF_V_WLK      (UNIT_V_UF + 1)                 /* write locked */
#define MTUF_V_FMT      (UNIT_V_UF + 2)                 /* tape file format */
#define MTUF_W_FMT      3                               /* 3b of formats */
#define MTUF_N_FMT      (1u << MTUF_W_FMT)              /* number of formats */
#define MTUF_M_FMT      ((1u << MTUF_W_FMT) - 1)
#define MTUF_F_STD       0                              /* SIMH format */
#define MTUF_F_E11       1                              /* E11 format */
#define MTUF_F_TPC       2                              /* TPC format */
#define MTUF_F_P7B       3                              /* P7B format */
#define MUTF_F_TDF       4                              /* TDF format */
#define MTUF_V_UF       (MTUF_V_FMT + MTUF_W_FMT)
#define MTUF_PNU        (1u << MTUF_V_PNU)
#define MTUF_WLK        (1u << MTUF_V_WLK)
#define MTUF_FMT        (MTUF_M_FMT << MTUF_V_FMT)
#define MTUF_WRP        (MTUF_WLK | UNIT_RO)

#define MT_F_STD        (MTUF_F_STD << MTUF_V_FMT)
#define MT_F_E11        (MTUF_F_E11 << MTUF_V_FMT)
#define MT_F_TPC        (MTUF_F_TPC << MTUF_V_FMT)
#define MT_F_P7B        (MTUF_F_P7B << MTUF_V_FMT)
#define MT_F_TDF        (MTUF_F_TDF << MTUF_V_FMT)

#define MT_SET_PNU(u)   (u)->flags = (u)->flags | MTUF_PNU
#define MT_CLR_PNU(u)   (u)->flags = (u)->flags & ~MTUF_PNU
#define MT_TST_PNU(u)   ((u)->flags & MTUF_PNU)
#define MT_GET_FMT(u)   (((u)->flags >> MTUF_V_FMT) & MTUF_M_FMT)

/* sim_tape_position Position Flags */
#define MTPOS_V_REW     3
#define MTPOS_M_REW     (1u << MTPOS_V_REW)            /* Rewind First */
#define MTPOS_V_REV     2
#define MTPOS_M_REV     (1u << MTPOS_V_REV)            /* Reverse Direction */
#define MTPOS_V_OBJ     1
#define MTPOS_M_OBJ     (1u << MTPOS_V_OBJ)            /* Objects vs Records/Files */
#define MTPOS_V_DLE     4
#define MTPOS_M_DLE     (1u << MTPOS_V_DLE)            /* Detect LEOT */

/* Tape density values */

#define MT_DENS_NONE    0                               /* density not set */
#define MT_DENS_200     1                               /* 200 bpi NRZI */
#define MT_DENS_556     2                               /* 556 bpi NRZI */
#define MT_DENS_800     3                               /* 800 bpi NRZI */
#define MT_DENS_1600    4                               /* 1600 bpi PE */
#define MT_DENS_6250    5                               /* 6250 bpi GCR */

#define MTVF_DENS_MASK  (((1u << UNIT_S_DF_TAPE) - 1) << UNIT_V_DF_TAPE)
#define MT_DENS(f)      (((f) & MTVF_DENS_MASK) >> UNIT_V_DF_TAPE)

#define MT_NONE_VALID   (1u << MT_DENS_NONE)            /* density not set is valid */
#define MT_200_VALID    (1u << MT_DENS_200)             /* 200 bpi is valid */
#define MT_556_VALID    (1u << MT_DENS_556)             /* 556 bpi is valid */
#define MT_800_VALID    (1u << MT_DENS_800)             /* 800 bpi is valid */
#define MT_1600_VALID   (1u << MT_DENS_1600)            /* 1600 bpi is valid */
#define MT_6250_VALID   (1u << MT_DENS_6250)            /* 6250 bpi is valid */

/* Return status codes */

#define MTSE_OK         0                               /* no error */
#define MTSE_TMK        1                               /* tape mark */
#define MTSE_UNATT      2                               /* unattached */
#define MTSE_IOERR      3                               /* IO error */
#define MTSE_INVRL      4                               /* invalid rec lnt */
#define MTSE_FMT        5                               /* invalid format */
#define MTSE_BOT        6                               /* beginning of tape */
#define MTSE_EOM        7                               /* end of medium */
#define MTSE_RECE       8                               /* error in record */
#define MTSE_WRP        9                               /* write protected */
#define MTSE_LEOT       10                              /* Logical End Of Tape */
#define MTSE_RUNAWAY    11                              /* tape runaway */

typedef void (*TAPE_PCALLBACK)(UNIT *unit, t_stat status);

/* Tape Internal Debug flags */

#define MTSE_DBG_DAT   0x0400000                        /* Debug Data */
#define MTSE_DBG_POS   0x0800000                        /* Debug Positioning activities */
#define MTSE_DBG_STR   0x1000000                        /* Debug Tape Structure */

/* Prototypes */

t_stat sim_tape_attach_ex (UNIT *uptr, const char *cptr, uint32 dbit, int completion_delay);
t_stat sim_tape_attach (UNIT *uptr, CONST char *cptr);
t_stat sim_tape_detach (UNIT *uptr);
t_stat sim_tape_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);
t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback);
t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);
t_stat sim_tape_rdrecr_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback);
t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc);
t_stat sim_tape_wrrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt bc, TAPE_PCALLBACK callback);
t_stat sim_tape_wrtmk (UNIT *uptr);
t_stat sim_tape_wrtmk_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_wreom (UNIT *uptr);
t_stat sim_tape_wreom_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_wreomrw (UNIT *uptr);
t_stat sim_tape_wreomrw_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen);
t_stat sim_tape_wrgap_a (UNIT *uptr, uint32 gaplen, TAPE_PCALLBACK callback);
t_stat sim_tape_errecf (UNIT *uptr, t_mtrlnt bc);
t_stat sim_tape_errecr (UNIT *uptr, t_mtrlnt bc);
t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc);
t_stat sim_tape_sprecf_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback);
t_stat sim_tape_sprecsf (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_sprecsf_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfilef (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_spfilef_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfilebyrecf (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot);
t_stat sim_tape_spfilebyrecf_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, t_bool check_leot, TAPE_PCALLBACK callback);
t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc);
t_stat sim_tape_sprecr_a (UNIT *uptr, t_mtrlnt *bc, TAPE_PCALLBACK callback);
t_stat sim_tape_sprecsr (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_sprecsr_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfiler (UNIT *uptr, uint32 count, uint32 *skipped);
t_stat sim_tape_spfiler_a (UNIT *uptr, uint32 count, uint32 *skipped, TAPE_PCALLBACK callback);
t_stat sim_tape_spfilebyrecr (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped);
t_stat sim_tape_spfilebyrecr_a (UNIT *uptr, uint32 count, uint32 *skipped, uint32 *recsskipped, TAPE_PCALLBACK callback);
t_stat sim_tape_rewind (UNIT *uptr);
t_stat sim_tape_rewind_a (UNIT *uptr, TAPE_PCALLBACK callback);
t_stat sim_tape_position (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recskipped, uint32 files, uint32 *fileskipped, uint32 *objectsskipped);
t_stat sim_tape_position_a (UNIT *uptr, uint32 flags, uint32 recs, uint32 *recsskipped, uint32 files, uint32 *filesskipped, uint32 *objectsskipped, TAPE_PCALLBACK callback);
t_stat sim_tape_reset (UNIT *uptr);
t_bool sim_tape_bot (UNIT *uptr);
t_bool sim_tape_wrp (UNIT *uptr);
t_bool sim_tape_eot (UNIT *uptr);
t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat sim_tape_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat sim_tape_set_dens (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat sim_tape_set_asynch (UNIT *uptr, int latency);
t_stat sim_tape_clr_asynch (UNIT *uptr);

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































































































































































































Deleted src/sim_timer.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
/* sim_timer.c: simulator timer library

   Copyright (c) 1993-2010, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   21-Oct-11    MP      Fixed throttling in several ways:
                         - Sleep for the observed clock tick size while throttling
                         - Recompute the throttling wait once every 10 seconds
                           to account for varying instruction mixes during
                           different phases of a simulator execution or to 
                           accommodate the presence of other load on the host 
                           system.
                         - Each of the pre-existing throttling modes (Kcps, 
                           Mcps, and %) all compute the appropriate throttling 
                           interval dynamically.  These dynamic computations
                           assume that 100% of the host CPU is dedicated to 
                           the current simulator during this computation.
                           This assumption may not always be true and under 
                           certain conditions may never provide a way to 
                           correctly determine the appropriate throttling 
                           wait.  An additional throttling mode has been added
                           which allows the simulator operator to explicitly
                           state the desired throttling wait parameters.
                           These are specified by: 
                                  SET THROT insts/delay
                           where 'insts' is the number of instructions to 
                           execute before sleeping for 'delay' milliseconds.
   22-Apr-11    MP      Fixed Asynch I/O support to reasonably account cycles
                        when an idle wait is terminated by an external event
   05-Jan-11    MP      Added Asynch I/O support
   29-Dec-10    MP      Fixed clock resolution determination for Unix platforms
   22-Sep-08    RMS     Added "stability threshold" for idle routine
   27-May-08    RMS     Fixed bug in Linux idle routines (from Walter Mueller)
   18-Jun-07    RMS     Modified idle to exclude counted delays
   22-Mar-07    RMS     Added sim_rtcn_init_all
   17-Oct-06    RMS     Added idle support (based on work by Mark Pizzolato)
                        Added throttle support
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   02-Jan-04    RMS     Split out from SCP

   This library includes the following routines:

   sim_timer_init -         initialize timing system
   sim_rtc_init -           initialize calibration
   sim_rtc_calb -           calibrate clock
   sim_idle -               virtual machine idle
   sim_os_msec  -           return elapsed time in msec
   sim_os_sleep -           sleep specified number of seconds
   sim_os_ms_sleep -        sleep specified number of milliseconds
   sim_idle_ms_sleep -      sleep specified number of milliseconds
                            or until awakened by an asynchronous
                            event
   sim_timespec_diff        subtract two timespec values
   sim_timer_activate_after schedule unit for specific time
   sim_timer_activate_time  determine activation time
   sim_timer_activate_time_usecs determine activation time in usecs
   sim_rom_read_with_delay  delay for default or specified delay
   sim_get_rom_delay_factor get current or initialize 1usec delay factor
   sim_set_rom_delay_factor set specific delay factor


   The calibration, idle, and throttle routines are OS-independent; the _os_
   routines are not.
*/

#define NOT_MUX_USING_CODE /* sim_tmxr library provider or agnostic */

#include "sim_defs.h"
#include <ctype.h>
#include <math.h>

#define SIM_INTERNAL_CLK (SIM_NTIMERS+(1<<30))
#define SIM_INTERNAL_UNIT sim_internal_timer_unit
#ifndef MIN
#define MIN(a,b)  (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b)  (((a) > (b)) ? (a) : (b))
#endif

uint32 sim_idle_ms_sleep (unsigned int msec);

/* MS_MIN_GRANULARITY exists here so that timing behavior for hosts systems  */
/* with slow clock ticks can be assessed and tested without actually having  */
/* that slow a clock tick on the development platform                        */
//#define MS_MIN_GRANULARITY 20   /* Uncomment to simulate 20ms host tick size.*/
                                /* some Solaris and BSD hosts come this way  */

#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
uint32 real_sim_idle_ms_sleep (unsigned int msec);
uint32 real_sim_os_msec (void);
uint32 real_sim_os_ms_sleep (unsigned int msec);
static uint32 real_sim_os_sleep_min_ms = 0;
static uint32 real_sim_os_sleep_inc_ms = 0;

uint32 sim_idle_ms_sleep (unsigned int msec)
{
uint32 real_start = real_sim_os_msec ();
uint32 start = (real_start / MS_MIN_GRANULARITY) * MS_MIN_GRANULARITY;
uint32 tick_left;

if (msec == 0)
    return 0;
if (real_start == start)
    tick_left = 0;
else
    tick_left = MS_MIN_GRANULARITY - (real_start - start);
if (msec <= tick_left)
    real_sim_idle_ms_sleep (tick_left);
else
    real_sim_idle_ms_sleep (((msec + MS_MIN_GRANULARITY - 1) / MS_MIN_GRANULARITY) * MS_MIN_GRANULARITY);

return (sim_os_msec () - start);
}

uint32 sim_os_msec (void)
{
return (real_sim_os_msec ()/MS_MIN_GRANULARITY)*MS_MIN_GRANULARITY;
}

uint32 sim_os_ms_sleep (unsigned int msec)
{
msec = MS_MIN_GRANULARITY*((msec+MS_MIN_GRANULARITY-1)/MS_MIN_GRANULARITY);

return real_sim_os_ms_sleep (msec);
}

#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */

t_bool sim_idle_enab = FALSE;                       /* global flag */
volatile t_bool sim_idle_wait = FALSE;              /* global flag */

static int32 sim_calb_tmr = -1;                     /* the system calibrated timer */
static int32 sim_calb_tmr_last = -1;                /* shadow value when at sim> prompt */
static double sim_inst_per_sec_last = 0;            /* shadow value when at sim> prompt */

static uint32 sim_idle_rate_ms = 0;
static uint32 sim_os_sleep_min_ms = 0;
static uint32 sim_os_sleep_inc_ms = 0;
static uint32 sim_os_clock_resoluton_ms = 0;
static uint32 sim_os_tick_hz = 0;
static uint32 sim_idle_stable = SIM_IDLE_STDFLT;
static uint32 sim_idle_calib_pct = 0;
static uint32 sim_rom_delay = 0;
static uint32 sim_throt_ms_start = 0;
static uint32 sim_throt_ms_stop = 0;
static uint32 sim_throt_type = 0;
static uint32 sim_throt_val = 0;
static uint32 sim_throt_state = SIM_THROT_STATE_INIT;
static double sim_throt_cps;
static double sim_throt_inst_start;
static uint32 sim_throt_sleep_time = 0;
static int32 sim_throt_wait = 0;
static UNIT *sim_clock_unit[SIM_NTIMERS+1] = {NULL};
UNIT * volatile sim_clock_cosched_queue[SIM_NTIMERS+1] = {NULL};
static int32 sim_cosched_interval[SIM_NTIMERS+1];
static t_bool sim_catchup_ticks = TRUE;
#if defined (SIM_ASYNCH_CLOCKS) && !defined (SIM_ASYNCH_IO)
#undef SIM_ASYNCH_CLOCKS
#endif
t_bool sim_asynch_timer = FALSE;

#if defined (SIM_ASYNCH_CLOCKS)
UNIT * volatile sim_wallclock_queue = QUEUE_LIST_END;
UNIT * volatile sim_wallclock_entry = NULL;
#endif

#define sleep1Samples       100

static uint32 _compute_minimum_sleep (void)
{
uint32 i, tot, tim;

sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);
#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
real_sim_idle_ms_sleep (1);         /* Start sampling on a tick boundary */
for (i = 0, tot = 0; i < sleep1Samples; i++)
    tot += real_sim_idle_ms_sleep (1);
tim = tot / sleep1Samples;          /* Truncated average */
real_sim_os_sleep_min_ms = tim;
real_sim_idle_ms_sleep (1);         /* Start sampling on a tick boundary */
for (i = 0, tot = 0; i < sleep1Samples; i++)
    tot += real_sim_idle_ms_sleep (real_sim_os_sleep_min_ms + 1);
tim = tot / sleep1Samples;          /* Truncated average */
real_sim_os_sleep_inc_ms = tim - real_sim_os_sleep_min_ms;
#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */
sim_idle_ms_sleep (1);              /* Start sampling on a tick boundary */
for (i = 0, tot = 0; i < sleep1Samples; i++)
    tot += sim_idle_ms_sleep (1);
tim = tot / sleep1Samples;          /* Truncated average */
sim_os_sleep_min_ms = tim;
sim_idle_ms_sleep (1);              /* Start sampling on a tick boundary */
for (i = 0, tot = 0; i < sleep1Samples; i++)
    tot += sim_idle_ms_sleep (sim_os_sleep_min_ms + 1);
tim = tot / sleep1Samples;          /* Truncated average */
sim_os_sleep_inc_ms = tim - sim_os_sleep_min_ms;
sim_os_set_thread_priority (PRIORITY_NORMAL);
return sim_os_sleep_min_ms;
}

#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)

#define sim_idle_ms_sleep   real_sim_idle_ms_sleep 
#define sim_os_msec         real_sim_os_msec 
#define sim_os_ms_sleep     real_sim_os_ms_sleep

#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */

#if defined(SIM_ASYNCH_IO)
uint32 sim_idle_ms_sleep (unsigned int msec)
{
uint32 start_time = sim_os_msec();
struct timespec done_time;
t_bool timedout = FALSE;

clock_gettime(CLOCK_REALTIME, &done_time);
done_time.tv_sec += (msec/1000);
done_time.tv_nsec += 1000000*(msec%1000);
if (done_time.tv_nsec > 1000000000) {
  done_time.tv_sec += done_time.tv_nsec/1000000000;
  done_time.tv_nsec = done_time.tv_nsec%1000000000;
  }
pthread_mutex_lock (&sim_asynch_lock);
sim_idle_wait = TRUE;
if (!pthread_cond_timedwait (&sim_asynch_wake, &sim_asynch_lock, &done_time))
  sim_asynch_check = 0;                 /* force check of asynch queue now */
else
  timedout = TRUE;
sim_idle_wait = FALSE;
pthread_mutex_unlock (&sim_asynch_lock);
if (!timedout) {
    AIO_UPDATE_QUEUE;
    }
return sim_os_msec() - start_time;
}
#else
uint32 sim_idle_ms_sleep (unsigned int msec)
{
return sim_os_ms_sleep (msec);
}
#endif

/* Mark the need for the sim_os_set_thread_priority routine, */
/* allowing the feature and/or platform dependent code to provide it */
#define NEED_THREAD_PRIORITY

/* If we've got pthreads support then use pthreads mechanisms */
#if defined(USE_READER_THREAD)

#undef NEED_THREAD_PRIORITY

#if defined(_WIN32)
/* On Windows there are several potentially disjoint threading APIs */
/* in use (base win32 pthreads, libSDL provided threading, and direct */
/* calls to beginthreadex), so go directly to the Win32 threading APIs */
/* to manage thread priority */
t_stat sim_os_set_thread_priority (int below_normal_above)
{
const static int val[3] = {THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL};

if ((below_normal_above < -1) || (below_normal_above > 1))
    return SCPE_ARG;
SetThreadPriority (GetCurrentThread(), val[1 + below_normal_above]);
return SCPE_OK;
}
#else
/* Native pthreads priority implementation */
t_stat sim_os_set_thread_priority (int below_normal_above)
{
int sched_policy, min_prio, max_prio;
struct sched_param sched_priority;

if ((below_normal_above < -1) || (below_normal_above > 1))
    return SCPE_ARG;

pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
min_prio = sched_get_priority_min(sched_policy);
max_prio = sched_get_priority_max(sched_policy);
switch (below_normal_above) {
    case PRIORITY_BELOW_NORMAL:
        sched_priority.sched_priority = min_prio;
        break;
    case PRIORITY_NORMAL:
        sched_priority.sched_priority = (max_prio + min_prio) / 2;
        break;
    case PRIORITY_ABOVE_NORMAL:
        sched_priority.sched_priority = max_prio;
        break;
    }
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
return SCPE_OK;
}
#endif
#endif  /* defined(USE_READER_THREAD) */

/* OS-dependent timer and clock routines */

/* VMS */

#if defined (VMS)

#if defined (__VAX)
#define sys$gettim SYS$GETTIM
#define sys$setimr SYS$SETIMR
#define lib$emul LIB$EMUL
#define sys$waitfr SYS$WAITFR
#define lib$subx LIB$SUBX
#define lib$ediv LIB$EDIV
#endif

#include <starlet.h>
#include <lib$routines.h>
#include <unistd.h>

const t_bool rtc_avail = TRUE;

uint32 sim_os_msec (void)
{
uint32 quo, htod, tod[2];
int32 i;

sys$gettim (tod);                                       /* time 0.1usec */

/* To convert to msec, must divide a 64b quantity by 10000.  This is actually done
   by dividing the 96b quantity 0'time by 10000, producing 64b of quotient, the
   high 32b of which are discarded.  This can probably be done by a clever multiply...
*/

quo = htod = 0;
for (i = 0; i < 64; i++) {                              /* 64b quo */
    htod = (htod << 1) | ((tod[1] >> 31) & 1);          /* shift divd */
    tod[1] = (tod[1] << 1) | ((tod[0] >> 31) & 1);
    tod[0] = tod[0] << 1;
    quo = quo << 1;                                     /* shift quo */
    if (htod >= 10000) {                                /* divd work? */
        htod = htod - 10000;                            /* subtract */
        quo = quo | 1;                                  /* set quo bit */
        }
    }
return quo;
}

void sim_os_sleep (unsigned int sec)
{
sleep (sec);
return;
}

uint32 sim_os_ms_sleep_init (void)
{
return _compute_minimum_sleep ();
}

uint32 sim_os_ms_sleep (unsigned int msec)
{
uint32 stime = sim_os_msec ();
uint32 qtime[2];
int32 nsfactor = -10000;
static int32 zero = 0;

lib$emul (&msec, &nsfactor, &zero, qtime);
sys$setimr (2, qtime, 0, 0);
sys$waitfr (2);
return sim_os_msec () - stime;
}

#ifdef NEED_CLOCK_GETTIME
int clock_gettime(int clk_id, struct timespec *tp)
{
uint32 secs, ns, tod[2], unixbase[2] = {0xd53e8000, 0x019db1de};

if (clk_id != CLOCK_REALTIME)
  return -1;

sys$gettim (tod);                                       /* time 0.1usec */
lib$subx(tod, unixbase, tod);                           /* convert to unix base */
lib$ediv(&10000000, tod, &secs, &ns);                   /* isolate seconds & 100ns parts */
tp->tv_sec = secs;
tp->tv_nsec = ns*100;
return 0;
}
#endif /* CLOCK_REALTIME */

#elif defined (_WIN32)

/* Win32 routines */

const t_bool rtc_avail = TRUE;

uint32 sim_os_msec (void)
{
return timeGetTime ();
}

void sim_os_sleep (unsigned int sec)
{
Sleep (sec * 1000);
return;
}

void sim_timer_exit (void)
{
timeEndPeriod (sim_idle_rate_ms);
return;
}

uint32 sim_os_ms_sleep_init (void)
{
TIMECAPS timers;

if (timeGetDevCaps (&timers, sizeof (timers)) != TIMERR_NOERROR)
    return 0;
if (timers.wPeriodMin == 0)
    return 0;
if (timeBeginPeriod (timers.wPeriodMin) != TIMERR_NOERROR)
    return 0;
atexit (sim_timer_exit);
/* return measured actual minimum sleep time */
return _compute_minimum_sleep ();
}

uint32 sim_os_ms_sleep (unsigned int msec)
{
uint32 stime = sim_os_msec();

Sleep (msec);
return sim_os_msec () - stime;
}

#if defined(NEED_CLOCK_GETTIME)
int clock_gettime(int clk_id, struct timespec *tp)
{
t_uint64 now, unixbase;

if (clk_id != CLOCK_REALTIME)
    return -1;
unixbase = 116444736;
unixbase *= 1000000000;
GetSystemTimeAsFileTime((FILETIME*)&now);
now -= unixbase;
tp->tv_sec = (long)(now/10000000);
tp->tv_nsec = (now%10000000)*100;
return 0;
}
#endif

#elif defined (__OS2__)

/* OS/2 routines, from Bruce Ray */

const t_bool rtc_avail = FALSE;

uint32 sim_os_msec (void)
{
return 0;
}

void sim_os_sleep (unsigned int sec)
{
return;
}

uint32 sim_os_ms_sleep_init (void)
{
return 0;
}

uint32 sim_os_ms_sleep (unsigned int msec)
{
return 0;
}

/* Metrowerks CodeWarrior Macintosh routines, from Ben Supnik */

#elif defined (__MWERKS__) && defined (macintosh)

#include <Timer.h>
#include <Mactypes.h>
#include <sioux.h>
#include <unistd.h>
#include <siouxglobals.h>
#define NANOS_PER_MILLI     1000000
#define MILLIS_PER_SEC      1000

const t_bool rtc_avail = TRUE;

uint32 sim_os_msec (void)
{
unsigned long long micros;
UnsignedWide macMicros;
unsigned long millis;

Microseconds (&macMicros);
micros = *((unsigned long long *) &macMicros);
millis = micros / 1000LL;
return (uint32) millis;
}

void sim_os_sleep (unsigned int sec)
{
sleep (sec);
return;
}

uint32 sim_os_ms_sleep_init (void)
{
return _compute_minimum_sleep ();
}

uint32 sim_os_ms_sleep (unsigned int milliseconds)
{
uint32 stime = sim_os_msec ();
struct timespec treq;

treq.tv_sec = milliseconds / MILLIS_PER_SEC;
treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
(void) nanosleep (&treq, NULL);
return sim_os_msec () - stime;
}

#if defined(NEED_CLOCK_GETTIME)
int clock_gettime(int clk_id, struct timespec *tp)
{
struct timeval cur;

if (clk_id != CLOCK_REALTIME)
  return -1;
gettimeofday (&cur, NULL);
tp->tv_sec = cur.tv_sec;
tp->tv_nsec = cur.tv_usec*1000;
return 0;
}
#endif

#else

/* UNIX routines */

#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#define NANOS_PER_MILLI     1000000
#define MILLIS_PER_SEC      1000

const t_bool rtc_avail = TRUE;

uint32 sim_os_msec (void)
{
struct timeval cur;
struct timezone foo;
uint32 msec;

gettimeofday (&cur, &foo);
msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000);
return msec;
}

void sim_os_sleep (unsigned int sec)
{
sleep (sec);
return;
}

uint32 sim_os_ms_sleep_init (void)
{
return _compute_minimum_sleep ();
}

#if !defined(_POSIX_SOURCE)
#ifdef NEED_CLOCK_GETTIME
typedef int clockid_t;
int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
struct timeval cur;
struct timezone foo;

if (clk_id != CLOCK_REALTIME)
  return -1;
gettimeofday (&cur, &foo);
tp->tv_sec = cur.tv_sec;
tp->tv_nsec = cur.tv_usec*1000;
return 0;
}
#endif /* CLOCK_REALTIME */
#endif /* !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO) */

uint32 sim_os_ms_sleep (unsigned int milliseconds)
{
uint32 stime = sim_os_msec ();
struct timespec treq;

treq.tv_sec = milliseconds / MILLIS_PER_SEC;
treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
(void) nanosleep (&treq, NULL);
return sim_os_msec () - stime;
}

#if defined(NEED_THREAD_PRIORITY)
#undef NEED_THREAD_PRIORITY
#include <sys/time.h>
#include <sys/resource.h>

t_stat sim_os_set_thread_priority (int below_normal_above)
{
if ((below_normal_above < -1) || (below_normal_above > 1))
    return SCPE_ARG;

errno = 0;
switch (below_normal_above) {
    case PRIORITY_BELOW_NORMAL:
        if ((getpriority (PRIO_PROCESS, 0) <= 0) &&     /* at or above normal pri? */
            (errno == 0))
            setpriority (PRIO_PROCESS, 0, 10);
        break;
    case PRIORITY_NORMAL:
        if (getpriority (PRIO_PROCESS, 0) != 0)         /* at or above normal pri? */
            setpriority (PRIO_PROCESS, 0, 0);
        break;
    case PRIORITY_ABOVE_NORMAL:
        if ((getpriority (PRIO_PROCESS, 0) <= 0) &&     /* at or above normal pri? */
            (errno == 0))
            setpriority (PRIO_PROCESS, 0, -10);
        break;
    }
return SCPE_OK;
}
#endif  /* defined(NEED_THREAD_PRIORITY) */

#endif

/* If one hasn't been provided yet, then just stub it */
#if defined(NEED_THREAD_PRIORITY)
t_stat sim_os_set_thread_priority (int below_normal_above)
{
return SCPE_OK;
}
#endif

#if defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1)
/* Make sure to use the substitute routines */
#undef sim_idle_ms_sleep
#undef sim_os_msec
#undef sim_os_ms_sleep
#endif /* defined(MS_MIN_GRANULARITY) && (MS_MIN_GRANULARITY != 1) */

/* diff = min - sub */
void
sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub)
{
/* move the minuend value to the difference and operate there. */
*diff = *min;
/* Borrow as needed for the nsec value */
while (sub->tv_nsec > diff->tv_nsec) {
    --diff->tv_sec;
    diff->tv_nsec += 1000000000;
    }
diff->tv_nsec -= sub->tv_nsec;
diff->tv_sec -= sub->tv_sec;
/* Normalize the result */
while (diff->tv_nsec > 1000000000) {
    ++diff->tv_sec;
    diff->tv_nsec -= 1000000000;
    }
}

/* Forward declarations */

static double _timespec_to_double (struct timespec *time);
static void _double_to_timespec (struct timespec *time, double dtime);
static t_bool _rtcn_tick_catchup_check (int32 tmr, int32 time);
static void _rtcn_configure_calibrated_clock (int32 newtmr);
static t_bool _sim_coschedule_cancel (UNIT *uptr);
static t_bool _sim_wallclock_cancel (UNIT *uptr);
static t_bool _sim_wallclock_is_active (UNIT *uptr);
t_stat sim_timer_show_idle_mode (FILE* st, UNIT* uptr, int32 val, CONST void *  desc);


#if defined(SIM_ASYNCH_CLOCKS)
static int sim_timespec_compare (struct timespec *a, struct timespec *b)
{
while (a->tv_nsec > 1000000000) {
    a->tv_nsec -= 1000000000;
    ++a->tv_sec;
    }
while (b->tv_nsec > 1000000000) {
    b->tv_nsec -= 1000000000;
    ++b->tv_sec;
    }
if (a->tv_sec < b->tv_sec)
    return -1;
if (a->tv_sec > b->tv_sec)
    return 1;
if (a->tv_nsec < b->tv_nsec)
    return -1;
if (a->tv_nsec > b->tv_nsec)
    return 1;
else
    return 0;
}
#endif /* defined(SIM_ASYNCH_CLOCKS) */

/* OS independent clock calibration package */

static int32 rtc_ticks[SIM_NTIMERS+1] = { 0 };            /* ticks */
static uint32 rtc_hz[SIM_NTIMERS+1] = { 0 };              /* tick rate */
static uint32 rtc_last_hz[SIM_NTIMERS+1] = { 0 };         /* prior tick rate */
static uint32 rtc_rtime[SIM_NTIMERS+1] = { 0 };           /* real time */
static uint32 rtc_vtime[SIM_NTIMERS+1] = { 0 };           /* virtual time */
static double rtc_gtime[SIM_NTIMERS+1] = { 0 };           /* instruction time */
static uint32 rtc_nxintv[SIM_NTIMERS+1] = { 0 };          /* next interval */
static int32 rtc_based[SIM_NTIMERS+1] = { 0 };            /* base delay */
static int32 rtc_currd[SIM_NTIMERS+1] = { 0 };            /* current delay */
static int32 rtc_initd[SIM_NTIMERS+1] = { 0 };            /* initial delay */
static uint32 rtc_elapsed[SIM_NTIMERS+1] = { 0 };         /* sec since init */
static uint32 rtc_calibrations[SIM_NTIMERS+1] = { 0 };    /* calibration count */
static double rtc_clock_skew_max[SIM_NTIMERS+1] = { 0 };  /* asynchronous max skew */
static double rtc_clock_start_gtime[SIM_NTIMERS+1] = { 0 };/* reference instruction time for clock */
static double rtc_clock_tick_size[SIM_NTIMERS+1] = { 0 }; /* 1/hz */
static uint32 rtc_calib_initializations[SIM_NTIMERS+1] = { 0 };/* Initialization Count */
static double rtc_calib_tick_time[SIM_NTIMERS+1] = { 0 }; /* ticks time */
static double rtc_calib_tick_time_tot[SIM_NTIMERS+1] = { 0 };/* ticks time - total*/
static uint32 rtc_calib_ticks_acked[SIM_NTIMERS+1] = { 0 };/* ticks Acked */
static uint32 rtc_calib_ticks_acked_tot[SIM_NTIMERS+1] = { 0 };/* ticks Acked - total */
static uint32 rtc_clock_ticks[SIM_NTIMERS+1] = { 0 };/* ticks delivered since catchup base */
static uint32 rtc_clock_ticks_tot[SIM_NTIMERS+1] = { 0 };/* ticks delivered since catchup base - total */
static double rtc_clock_init_base_time[SIM_NTIMERS+1] = { 0 };/* reference time for clock initialization */
static double rtc_clock_tick_start_time[SIM_NTIMERS+1] = { 0 };/* reference time when ticking started */
static double rtc_clock_catchup_base_time[SIM_NTIMERS+1] = { 0 };/* reference time for catchup ticks */
static uint32 rtc_clock_catchup_ticks[SIM_NTIMERS+1] = { 0 };/* Record of catchups */
static uint32 rtc_clock_catchup_ticks_tot[SIM_NTIMERS+1] = { 0 };/* Record of catchups - total */
static t_bool rtc_clock_catchup_pending[SIM_NTIMERS+1] = { 0 };/* clock tick catchup pending */
static t_bool rtc_clock_catchup_eligible[SIM_NTIMERS+1] = { 0 };/* clock tick catchup eligible */
static uint32 rtc_clock_time_idled[SIM_NTIMERS+1] = { 0 };/* total time idled */
static uint32 rtc_clock_time_idled_last[SIM_NTIMERS+1] = { 0 };/* total time idled */
static uint32 rtc_clock_calib_skip_idle[SIM_NTIMERS+1] = { 0 };/* Calibrations skipped due to idling */
static uint32 rtc_clock_calib_gap2big[SIM_NTIMERS+1] = { 0 };/* Calibrations skipped Gap Too Big */
static uint32 rtc_clock_calib_backwards[SIM_NTIMERS+1] = { 0 };/* Calibrations skipped Clock Running Backwards */
static uint32 sim_idle_cyc_ms = 0;                      /* Cycles per millisecond while not idling */

UNIT sim_timer_units[SIM_NTIMERS+1];                    /* Clock assist units                         */
                                                        /* one for each timer and one for an internal */
                                                        /* clock if no clocks are registered.         */
UNIT sim_internal_timer_unit;                           /* Internal calibration timer */
UNIT sim_throttle_unit;                                 /* one for throttle */

t_stat sim_throt_svc (UNIT *uptr);
t_stat sim_timer_tick_svc (UNIT *uptr);

#define DBG_IDL       TIMER_DBG_IDLE        /* idling */
#define DBG_QUE       TIMER_DBG_QUEUE       /* queue activities */
#define DBG_MUX       TIMER_DBG_MUX         /* tmxr queue activities */
#define DBG_TRC       0x008                 /* tracing */
#define DBG_CAL       0x010                 /* calibration activities */
#define DBG_TIM       0x020                 /* timer thread activities */
#define DBG_THR       0x040                 /* throttle activities */
#define DBG_ACK       0x080                 /* interrupt acknowledgement activities */
#define DBG_CHK       0x100                 /* check scheduled activation time*/
DEBTAB sim_timer_debug[] = {
  {"TRACE",   DBG_TRC, "Trace routine calls"},
  {"IDLE",    DBG_IDL, "Idling activities"},
  {"QUEUE",   DBG_QUE, "Event queuing activities"},
  {"IACK",    DBG_ACK, "interrupt acknowledgement activities"},
  {"CALIB",   DBG_CAL, "Calibration activities"},
  {"TIME",    DBG_TIM, "Activation and scheduling activities"},
  {"THROT",   DBG_THR, "Throttling activities"},
  {"MUX",     DBG_MUX, "Tmxr scheduling activities"},
  {"CHECK",   DBG_CHK, "Check scheduled activation time"},
  {0}
};

/* Forward device declarations */
extern DEVICE sim_timer_dev;
extern DEVICE sim_throttle_dev;


void sim_rtcn_init_all (void)
{
int32 tmr;

for (tmr = 0; tmr <= SIM_NTIMERS; tmr++)
    if (rtc_initd[tmr] != 0)
        sim_rtcn_init (rtc_initd[tmr], tmr);
return;
}

int32 sim_rtcn_init (int32 time, int32 tmr)
{
return sim_rtcn_init_unit (NULL, time, tmr);
}

int32 sim_rtcn_init_unit (UNIT *uptr, int32 time, int32 tmr)
{
if (time == 0)
    time = 1;
if (tmr == SIM_INTERNAL_CLK)
    tmr = SIM_NTIMERS;
else {
    if ((tmr < 0) || (tmr >= SIM_NTIMERS))
        return time;
    }
/*
 * If we'd previously succeeded in calibrating a tick value, then use that
 * delay as a better default to setup when we're re-initialized.
 * Re-initializing happens on any boot or after any breakpoint/continue.
 */
if (rtc_currd[tmr])
    time = rtc_currd[tmr];
if (!uptr)
    uptr = sim_clock_unit[tmr];
sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_init_unit(unit=%s, time=%d, tmr=%d)\n", uptr ? sim_uname(uptr) : "", time, tmr);
if (uptr) {
    if (!sim_clock_unit[tmr])
        sim_register_clock_unit_tmr (uptr, tmr);
    }
rtc_clock_start_gtime[tmr] = sim_gtime();
rtc_rtime[tmr] = sim_os_msec ();
rtc_vtime[tmr] = rtc_rtime[tmr];
rtc_nxintv[tmr] = 1000;
rtc_ticks[tmr] = 0;
rtc_last_hz[tmr] = rtc_hz[tmr];
rtc_hz[tmr] = 0;
rtc_based[tmr] = time;
rtc_currd[tmr] = time;
rtc_initd[tmr] = time;
rtc_elapsed[tmr] = 0;
rtc_calibrations[tmr] = 0;
rtc_clock_ticks_tot[tmr] += rtc_clock_ticks[tmr];
rtc_clock_ticks[tmr] = 0;
rtc_calib_tick_time_tot[tmr] += rtc_calib_tick_time[tmr];
rtc_calib_tick_time[tmr] = 0;
rtc_clock_catchup_pending[tmr] = FALSE;
rtc_clock_catchup_eligible[tmr] = FALSE;
rtc_clock_catchup_ticks_tot[tmr] += rtc_clock_catchup_ticks[tmr];
rtc_clock_catchup_ticks[tmr] = 0;
rtc_calib_ticks_acked_tot[tmr] += rtc_calib_ticks_acked[tmr];
rtc_calib_ticks_acked[tmr] = 0;
++rtc_calib_initializations[tmr];
rtc_clock_init_base_time[tmr] = sim_timenow_double ();
_rtcn_configure_calibrated_clock (tmr);
return time;
}

int32 sim_rtcn_calb (int32 ticksper, int32 tmr)
{
uint32 new_rtime, delta_rtime, last_idle_pct;
int32 delta_vtime;
double new_gtime;
int32 new_currd;
int32 itmr;

if (tmr == SIM_INTERNAL_CLK)
    tmr = SIM_NTIMERS;
else {
    if ((tmr < 0) || (tmr >= SIM_NTIMERS))
        return 10000;
    }
if (rtc_hz[tmr] != ticksper) {                          /* changing tick rate? */
    if (rtc_hz[tmr] == 0)
        rtc_clock_tick_start_time[tmr] = sim_timenow_double ();
    rtc_last_hz[tmr] = rtc_hz[tmr];
    rtc_hz[tmr] = ticksper;
    _rtcn_configure_calibrated_clock (tmr);
    if (ticksper != 0) {
        rtc_clock_tick_size[tmr] = 1.0 / ticksper;
        rtc_currd[tmr] = (int32)(sim_timer_inst_per_sec () / ticksper);
        }
    }
if (ticksper == 0)                                      /* running? */
    return 10000;
if (sim_clock_unit[tmr] == NULL) {                      /* Not using TIMER units? */
    rtc_clock_ticks[tmr] += 1;
    rtc_calib_tick_time[tmr] += rtc_clock_tick_size[tmr];
    }
if (rtc_clock_catchup_pending[tmr]) {                   /* catchup tick? */
    ++rtc_clock_catchup_ticks[tmr];                     /* accumulating which were catchups */
    rtc_clock_catchup_pending[tmr] = FALSE;
    }
rtc_ticks[tmr] = rtc_ticks[tmr] + 1;                    /* count ticks */
if (rtc_ticks[tmr] < ticksper)                          /* 1 sec yet? */
    return rtc_currd[tmr];
rtc_ticks[tmr] = 0;                                     /* reset ticks */
rtc_elapsed[tmr] = rtc_elapsed[tmr] + 1;                /* count sec */
if (sim_throt_type != SIM_THROT_NONE) {
    rtc_gtime[tmr] = sim_gtime();                       /* save instruction time */
    rtc_currd[tmr] = (int32)(sim_throt_cps / ticksper); /* use throttle calibration */
    ++rtc_calibrations[tmr];                            /* count calibrations */
    sim_debug (DBG_CAL, &sim_timer_dev, "using throttle calibrated value - result: %d\n", rtc_currd[tmr]);
    return rtc_currd[tmr];
    }
if (!rtc_avail)                                         /* no timer? */
    return rtc_currd[tmr];
if (sim_calb_tmr != tmr) {
    rtc_currd[tmr] = (int32)(sim_timer_inst_per_sec()/ticksper);
    sim_debug (DBG_CAL, &sim_timer_dev, "calibrated calibrated tmr=%d against system tmr=%d, tickper=%d (result: %d)\n", tmr, sim_calb_tmr, ticksper, rtc_currd[tmr]);
    return rtc_currd[tmr];
    }
new_rtime = sim_os_msec ();                             /* wall time */
++rtc_calibrations[tmr];                                /* count calibrations */
sim_debug (DBG_TRC, &sim_timer_dev, "sim_rtcn_calb(ticksper=%d, tmr=%d)\n", ticksper, tmr);
if (new_rtime < rtc_rtime[tmr]) {                       /* time running backwards? */
    /* This happens when the value returned by sim_os_msec wraps (as an uint32) */
    /* Wrapping will happen initially sometime before a simulator has been running */
    /* for 49 days approximately every 49 days thereafter. */
    ++rtc_clock_calib_backwards[tmr];                   /* Count statistic */
    sim_debug (DBG_CAL, &sim_timer_dev, "time running backwards - OldTime: %u, NewTime: %u, result: %d\n", rtc_rtime[tmr], new_rtime, rtc_currd[tmr]);
    rtc_rtime[tmr] = new_rtime;                         /* reset wall time */
    return rtc_currd[tmr];                              /* can't calibrate */
    }
delta_rtime = new_rtime - rtc_rtime[tmr];               /* elapsed wtime */
rtc_rtime[tmr] = new_rtime;                             /* adv wall time */
rtc_vtime[tmr] = rtc_vtime[tmr] + 1000;                 /* adv sim time */
if (delta_rtime > 30000) {                              /* gap too big? */
    /* This simulator process has somehow been suspended for a significant */
    /* amount of time.  This will certainly happen if the host system has  */
    /* slept or hibernated.  It also might happen when a simulator         */
    /* developer stops the simulator at a breakpoint (a process, not simh  */
    /* breakpoint).  To accomodate this, we set the calibration state to   */
    /* ignore what happened and proceed from here.                         */
    ++rtc_clock_calib_gap2big[tmr];                     /* Count statistic */
    rtc_vtime[tmr] = rtc_rtime[tmr];                    /* sync virtual and real time */
    rtc_nxintv[tmr] = 1000;                             /* reset next interval */
    rtc_gtime[tmr] = sim_gtime();                       /* save instruction time */
    sim_debug (DBG_CAL, &sim_timer_dev, "gap too big: delta = %d - result: %d\n", delta_rtime, rtc_currd[tmr]);
    return rtc_currd[tmr];                              /* can't calibr */
    }
if (delta_rtime == 0)                                   /* avoid divide by zero  */
    last_idle_pct = 0;                                  /* force calibration */
else
    last_idle_pct = MIN(100, (uint32)(100.0 * (((double)(rtc_clock_time_idled[tmr] - rtc_clock_time_idled_last[tmr])) / ((double)delta_rtime))));
rtc_clock_time_idled_last[tmr] = rtc_clock_time_idled[tmr];
if (last_idle_pct > (100 - sim_idle_calib_pct)) {
    rtc_rtime[tmr] = new_rtime;                         /* save wall time */
    rtc_vtime[tmr] = rtc_vtime[tmr] + 1000;             /* adv sim time */
    rtc_gtime[tmr] = sim_gtime();                       /* save instruction time */
    ++rtc_clock_calib_skip_idle[tmr];
    sim_debug (DBG_CAL, &sim_timer_dev, "skipping calibration due to idling (%d%%) - result: %d\n", last_idle_pct, rtc_currd[tmr]);
    return rtc_currd[tmr];                              /* avoid calibrating idle checks */
    }
new_gtime = sim_gtime();
if ((last_idle_pct == 0) && (delta_rtime != 0))
    sim_idle_cyc_ms = (uint32)((new_gtime - rtc_gtime[tmr]) / delta_rtime);
if (sim_asynch_timer) {
    /* An asynchronous clock, merely needs to divide the number of */
    /* instructions actually executed by the clock rate. */
    new_currd = (int32)((new_gtime - rtc_gtime[tmr])/ticksper);
    /* avoid excessive swings in the calibrated result */
    if (new_currd > 10*rtc_currd[tmr])              /* don't swing big too fast */
        new_currd = 10*rtc_currd[tmr];
    else
        if (new_currd < rtc_currd[tmr]/10)          /* don't swing small too fast */
            new_currd = rtc_currd[tmr]/10;
    rtc_currd[tmr] = new_currd;
    rtc_gtime[tmr] = new_gtime;                     /* save instruction time */
    sim_debug (DBG_CAL, &sim_timer_dev, "asynch calibration result: %d\n", rtc_currd[tmr]);
    return rtc_currd[tmr];                          /* calibrated result */
    }
rtc_gtime[tmr] = new_gtime;                             /* save instruction time */
/* This self regulating algorithm depends directly on the assumption */
/* that this routine is called back after processing the number of */
/* instructions which was returned the last time it was called. */
if (delta_rtime == 0)                                   /* gap too small? */
    rtc_based[tmr] = rtc_based[tmr] * ticksper;         /* slew wide */
else
    rtc_based[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) /
                                ((double) delta_rtime));/* new base rate */
delta_vtime = rtc_vtime[tmr] - rtc_rtime[tmr];          /* gap */
if (delta_vtime > SIM_TMAX)                             /* limit gap */
    delta_vtime = SIM_TMAX;
else if (delta_vtime < -SIM_TMAX)
    delta_vtime = -SIM_TMAX;
rtc_nxintv[tmr] = 1000 + delta_vtime;                   /* next wtime */
rtc_currd[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) /
    1000.0);                                            /* next delay */
if (rtc_based[tmr] <= 0)                                /* never negative or zero! */
    rtc_based[tmr] = 1;
if (rtc_currd[tmr] <= 0)                                /* never negative or zero! */
    rtc_currd[tmr] = 1;
sim_debug (DBG_CAL, &sim_timer_dev, "calibrated tmr=%d, tickper=%d (base=%d, nxintv=%u, result: %d)\n", tmr, ticksper, rtc_based[tmr], rtc_nxintv[tmr], rtc_currd[tmr]);
/* Adjust calibration for other timers which depend on this timer's calibration */
for (itmr=0; itmr<=SIM_NTIMERS; itmr++)
    if ((itmr != tmr) && (rtc_hz[itmr] != 0))
        rtc_currd[itmr] = (rtc_currd[tmr] * ticksper) / rtc_hz[itmr];
AIO_SET_INTERRUPT_LATENCY(rtc_currd[tmr] * ticksper);   /* set interrrupt latency */
return rtc_currd[tmr];
}

/* Prior interfaces - default to timer 0 */

int32 sim_rtc_init (int32 time)
{
return sim_rtcn_init (time, 0);
}

int32 sim_rtc_calb (int32 ticksper)
{
return sim_rtcn_calb (ticksper, 0);
}

/* sim_timer_init - get minimum sleep time available on this host */

t_bool sim_timer_init (void)
{
int tmr;
uint32 clock_start, clock_last, clock_now;

sim_debug (DBG_TRC, &sim_timer_dev, "sim_timer_init()\n");
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
    sim_timer_units[tmr].action = &sim_timer_tick_svc;
    sim_timer_units[tmr].flags = UNIT_DIS | UNIT_IDLE;
    sim_clock_cosched_queue[tmr] = QUEUE_LIST_END;
    }
SIM_INTERNAL_UNIT.flags = UNIT_IDLE;
sim_register_internal_device (&sim_timer_dev);          /* Register Clock Assist device */
sim_throttle_unit.action = &sim_throt_svc;
sim_register_clock_unit_tmr (&SIM_INTERNAL_UNIT, SIM_INTERNAL_CLK);
sim_idle_enab = FALSE;                                  /* init idle off */
sim_idle_rate_ms = sim_os_ms_sleep_init ();             /* get OS timer rate */
sim_set_rom_delay_factor (sim_get_rom_delay_factor ()); /* initialize ROM delay factor */

clock_last = clock_start = sim_os_msec ();
sim_os_clock_resoluton_ms = 1000;
do {
    uint32 clock_diff;
    
    clock_now = sim_os_msec ();
    clock_diff = clock_now - clock_last;
    if ((clock_diff > 0) && (clock_diff < sim_os_clock_resoluton_ms))
        sim_os_clock_resoluton_ms = clock_diff;
    clock_last = clock_now;
    } while (clock_now < clock_start + 100);
sim_os_tick_hz = 1000/(sim_os_clock_resoluton_ms * (sim_idle_rate_ms/sim_os_clock_resoluton_ms));
return (sim_idle_rate_ms != 0);
}

/* sim_timer_idle_capable - tell if the host is Idle capable and what the host OS tick size is */

t_bool sim_timer_idle_capable (uint32 *host_ms_sleep_1, uint32 *host_tick_ms)
{
if (host_tick_ms)
    *host_tick_ms = sim_os_clock_resoluton_ms;
if (host_ms_sleep_1)
    *host_ms_sleep_1 = sim_os_sleep_min_ms;
return (sim_idle_rate_ms != 0);
}

/* sim_show_timers - show running timer information */
t_stat sim_show_timers (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
{
int tmr, clocks;
struct timespec now;
time_t time_t_now;
int32 calb_tmr = (sim_calb_tmr == -1) ? sim_calb_tmr_last : sim_calb_tmr;
double inst_per_sec = sim_timer_inst_per_sec ();

fprintf (st, "Minimum Host Sleep Time:       %d ms (%dHz)\n", sim_os_sleep_min_ms, sim_os_tick_hz);
if (sim_os_sleep_min_ms != sim_os_sleep_inc_ms)
    fprintf (st, "Minimum Host Sleep Incr Time:  %d ms\n", sim_os_sleep_inc_ms);
fprintf (st, "Host Clock Resolution:         %d ms\n", sim_os_clock_resoluton_ms);
fprintf (st, "Execution Rate:                %s instructions/sec\n", sim_fmt_numeric (inst_per_sec));
if (sim_idle_enab) {
    fprintf (st, "Idling:                        Enabled\n");
    fprintf (st, "Time before Idling starts:     %d seconds\n", sim_idle_stable);
    }
if (sim_throt_type != SIM_THROT_NONE) {
    sim_show_throt (st, NULL, uptr, val, desc);
    }
fprintf (st, "Calibrated Timer:              %s\n", (calb_tmr == -1) ? "Undetermined" : 
                                                    ((calb_tmr == SIM_NTIMERS) ? "Internal Timer" : 
                                                    (sim_clock_unit[calb_tmr] ? sim_uname(sim_clock_unit[calb_tmr]) : "")));
if (calb_tmr == SIM_NTIMERS)
    fprintf (st, "Catchup Ticks:                 %s for clocks ticking faster than %d Hz\n", sim_catchup_ticks ? "Enabled" : "Disabled", sim_os_tick_hz);
if (sim_idle_calib_pct == 0)
    fprintf (st, "Calibration:                   Always\n");
else
    fprintf (st, "Calibration:                   Skipped when Idle exceeds %d%%\n", sim_idle_calib_pct);
fprintf (st, "\n");
for (tmr=clocks=0; tmr<=SIM_NTIMERS; ++tmr) {
    if (0 == rtc_initd[tmr])
        continue;
    
    if (sim_clock_unit[tmr]) {
        ++clocks;
        fprintf (st, "%s clock device is %s%s%s\n", sim_name, 
                                                    (tmr == SIM_NTIMERS) ? "Internal Calibrated Timer(" : "", 
                                                    sim_uname(sim_clock_unit[tmr]), 
                                                    (tmr == SIM_NTIMERS) ? ")" : "");
        }

    fprintf (st, "%s%sTimer %d:\n", sim_asynch_timer ? "Asynchronous " : "", rtc_hz[tmr] ? "Calibrated " : "Uncalibrated ", tmr);
    if (rtc_hz[tmr]) {
        fprintf (st, "  Running at:                %d Hz\n", rtc_hz[tmr]);
        fprintf (st, "  Tick Size:                 %s\n", sim_fmt_secs (rtc_clock_tick_size[tmr]));
        fprintf (st, "  Ticks in current second:   %d\n",   rtc_ticks[tmr]);
        }
    fprintf (st, "  Seconds Running:           %s (%s)\n",   sim_fmt_numeric ((double)rtc_elapsed[tmr]), sim_fmt_secs ((double)rtc_elapsed[tmr]));
    if (tmr == calb_tmr) {
        fprintf (st, "  Calibration Opportunities: %s\n",   sim_fmt_numeric ((double)rtc_calibrations[tmr]));
        if (sim_idle_calib_pct)
            fprintf (st, "  Calib Skip Idle Thresh %%:  %u\n",   sim_idle_calib_pct);
        if (rtc_clock_calib_skip_idle[tmr])
            fprintf (st, "  Calibs Skip While Idle:    %u\n",   rtc_clock_calib_skip_idle[tmr]);
        if (rtc_clock_calib_backwards[tmr])
            fprintf (st, "  Calibs Skip Backwards:     %u\n",   rtc_clock_calib_backwards[tmr]);
        if (rtc_clock_calib_gap2big[tmr])
            fprintf (st, "  Calibs Skip Gap Too Big:   %u\n",   rtc_clock_calib_gap2big[tmr]);
        }
    if (rtc_gtime[tmr])
        fprintf (st, "  Instruction Time:          %.0f\n", rtc_gtime[tmr]);
    if ((!sim_asynch_timer) && (sim_throt_type == SIM_THROT_NONE)) {
        fprintf (st, "  Real Time:                 %u\n",   rtc_rtime[tmr]);
        fprintf (st, "  Virtual Time:              %u\n",   rtc_vtime[tmr]);
        fprintf (st, "  Next Interval:             %s\n",   sim_fmt_numeric ((double)rtc_nxintv[tmr]));
        fprintf (st, "  Base Tick Delay:           %s\n",   sim_fmt_numeric ((double)rtc_based[tmr]));
        fprintf (st, "  Initial Insts Per Tick:    %s\n",   sim_fmt_numeric ((double)rtc_initd[tmr]));
        }
    fprintf (st, "  Current Insts Per Tick:    %s\n",   sim_fmt_numeric ((double)rtc_currd[tmr]));
    fprintf (st, "  Initializations:           %d\n",   rtc_calib_initializations[tmr]);
    fprintf (st, "  Ticks:                     %s\n", sim_fmt_numeric ((double)(rtc_clock_ticks[tmr])));
    if (rtc_clock_ticks_tot[tmr]+rtc_clock_ticks[tmr] != rtc_clock_ticks[tmr])
        fprintf (st, "  Total Ticks:               %s\n", sim_fmt_numeric ((double)(rtc_clock_ticks_tot[tmr]+rtc_clock_ticks[tmr])));
    if (rtc_clock_skew_max[tmr] != 0.0)
        fprintf (st, "  Peak Clock Skew:           %s%s\n", sim_fmt_secs (fabs(rtc_clock_skew_max[tmr])), (rtc_clock_skew_max[tmr] < 0) ? " fast" : " slow");
    if (rtc_calib_ticks_acked[tmr])
        fprintf (st, "  Ticks Acked:               %s\n",   sim_fmt_numeric ((double)rtc_calib_ticks_acked[tmr]));
    if (rtc_calib_ticks_acked_tot[tmr]+rtc_calib_ticks_acked[tmr] != rtc_calib_ticks_acked[tmr])
        fprintf (st, "  Total Ticks Acked:         %s\n",   sim_fmt_numeric ((double)(rtc_calib_ticks_acked_tot[tmr]+rtc_calib_ticks_acked[tmr])));
    if (rtc_calib_tick_time[tmr])
        fprintf (st, "  Tick Time:                 %s\n",   sim_fmt_secs (rtc_calib_tick_time[tmr]));
    if (rtc_calib_tick_time_tot[tmr]+rtc_calib_tick_time[tmr] != rtc_calib_tick_time[tmr])
        fprintf (st, "  Total Tick Time:           %s\n",   sim_fmt_secs (rtc_calib_tick_time_tot[tmr]+rtc_calib_tick_time[tmr]));
    if (rtc_clock_catchup_ticks[tmr])
        fprintf (st, "  Catchup Ticks Sched:       %s\n",   sim_fmt_numeric ((double)rtc_clock_catchup_ticks[tmr]));
    if (rtc_clock_catchup_ticks_tot[tmr]+rtc_clock_catchup_ticks[tmr] != rtc_clock_catchup_ticks[tmr])
        fprintf (st, "  Total Catchup Ticks Sched: %s\n",   sim_fmt_numeric ((double)(rtc_clock_catchup_ticks_tot[tmr]+rtc_clock_catchup_ticks[tmr])));
    if (rtc_clock_init_base_time[tmr]) {
        _double_to_timespec (&now, rtc_clock_init_base_time[tmr]);
        time_t_now = (time_t)now.tv_sec;
        fprintf (st, "  Initialize Base Time:      %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
        }
    if (rtc_clock_tick_start_time[tmr]) {
        _double_to_timespec (&now, rtc_clock_tick_start_time[tmr]);
        time_t_now = (time_t)now.tv_sec;
        fprintf (st, "  Tick Start Time:           %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
        }
    clock_gettime (CLOCK_REALTIME, &now);
    time_t_now = (time_t)now.tv_sec;
    fprintf (st, "  Wall Clock Time Now:       %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
    if (rtc_clock_catchup_eligible[tmr]) {
        _double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]+rtc_calib_tick_time[tmr]);
        time_t_now = (time_t)now.tv_sec;
        fprintf (st, "  Catchup Tick Time:         %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
        _double_to_timespec (&now, rtc_clock_catchup_base_time[tmr]);
        time_t_now = (time_t)now.tv_sec;
        fprintf (st, "  Catchup Base Time:         %8.8s.%03d\n", 11+ctime(&time_t_now), (int)(now.tv_nsec/1000000));
        }
    if (rtc_clock_time_idled[tmr])
        fprintf (st, "  Total Time Idled:          %s\n",   sim_fmt_secs (rtc_clock_time_idled[tmr]/1000.0));
    }
if (clocks == 0)
    fprintf (st, "%s clock device is not specified, co-scheduling is unavailable\n", sim_name);
return SCPE_OK;
}

t_stat sim_show_clock_queues (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr)
{
int tmr;

#if defined (SIM_ASYNCH_CLOCKS)
pthread_mutex_lock (&sim_timer_lock);
if (sim_asynch_timer) {
    const char *tim;
    struct timespec due;
    time_t time_t_due;

    if (sim_wallclock_queue == QUEUE_LIST_END)
        fprintf (st, "%s wall clock event queue empty\n", sim_name);
    else {
        fprintf (st, "%s wall clock event queue status\n", sim_name);
        for (uptr = sim_wallclock_queue; uptr != QUEUE_LIST_END; uptr = uptr->a_next) {
            if ((dptr = find_dev_from_unit (uptr)) != NULL) {
                fprintf (st, "  %s", sim_dname (dptr));
                if (dptr->numunits > 1)
                    fprintf (st, " unit %d", (int32) (uptr - dptr->units));
                }
            else
                fprintf (st, "  Unknown");
            tim = sim_fmt_secs(uptr->a_usec_delay/1000000.0);
            _double_to_timespec (&due, uptr->a_due_time);
            time_t_due = (time_t)due.tv_sec;
            fprintf (st, " after %s due at %8.8s.%06d\n", tim, 11+ctime(&time_t_due), (int)(due.tv_nsec/1000));
            }
        }
    }
#endif /* SIM_ASYNCH_CLOCKS */
for (tmr=0; tmr<=SIM_NTIMERS; ++tmr) {
    if (sim_clock_unit[tmr] == NULL)
        continue;
    if (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
        int32 accum;

        fprintf (st, "%s clock (%s) co-schedule event queue status\n",
                 sim_name, sim_uname(sim_clock_unit[tmr]));
        accum = 0;
        for (uptr = sim_clock_cosched_queue[tmr]; uptr != QUEUE_LIST_END; uptr = uptr->next) {
            if ((dptr = find_dev_from_unit (uptr)) != NULL) {
                fprintf (st, "  %s", sim_dname (dptr));
                if (dptr->numunits > 1)
                    fprintf (st, " unit %d", (int32) (uptr - dptr->units));
                }
            else
                fprintf (st, "  Unknown");
            if (accum == 0)
                fprintf (st, " on next tick");
            else
                fprintf (st, " after %d tick%s", accum, (accum > 1) ? "s" : "");
            if (uptr->usecs_remaining)
                fprintf (st, " plus %.0f usecs", uptr->usecs_remaining);
            fprintf (st, "\n");
            accum = accum + uptr->time;
            }
        }
    }
#if defined (SIM_ASYNCH_IO)
pthread_mutex_unlock (&sim_timer_lock);
#endif /* SIM_ASYNCH_IO */
return SCPE_OK;
}

REG sim_timer_reg[] = {
    { DRDATAD (IDLE_CYC_MS,      sim_idle_cyc_ms,        32, "Cycles Per Millisecond"), PV_RSPC|REG_RO},
    { DRDATAD (ROM_DELAY,        sim_rom_delay,          32, "ROM memory reference delay"), PV_RSPC|REG_RO},
    { NULL }
    };

REG sim_throttle_reg[] = {
    { DRDATAD (THROT_MS_START,   sim_throt_ms_start,     32, ""), PV_RSPC|REG_RO},
    { DRDATAD (THROT_MS_STOP,    sim_throt_ms_stop,      32, ""), PV_RSPC|REG_RO},
    { DRDATAD (THROT_TYPE,       sim_throt_type,         32, ""), PV_RSPC|REG_RO},
    { DRDATAD (THROT_VAL,        sim_throt_val,          32, ""), PV_RSPC|REG_RO},
    { DRDATAD (THROT_STATE,      sim_throt_state,        32, ""), PV_RSPC|REG_RO},
    { DRDATAD (THROT_SLEEP_TIME, sim_throt_sleep_time,   32, ""), PV_RSPC|REG_RO},
    { DRDATAD (THROT_WAIT,       sim_throt_wait,         32, ""), PV_RSPC|REG_RO},
    { NULL }
    };

/* Clear, Set and show catchup */

/* Set/Clear catchup */

t_stat sim_timer_set_catchup (int32 flag, CONST char *cptr)
{
if (flag) {
    if (!sim_catchup_ticks)
        sim_catchup_ticks = TRUE;
    }
else {
    if (sim_catchup_ticks)
        sim_catchup_ticks = FALSE;
    }
return SCPE_OK;
}

t_stat sim_timer_show_catchup (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
fprintf (st, "Calibrated Ticks%s", sim_catchup_ticks ? " with Catchup Ticks" : "");
return SCPE_OK;
}

/* Set idle calibration threshold */

t_stat sim_timer_set_idle_pct (int32 flag, CONST char *cptr)
{
t_stat r;
int32 newpct;

if (cptr == NULL)
    return SCPE_ARG;
newpct = (int32) get_uint (cptr, 10, 100, &r);
if ((r != SCPE_OK) || (newpct == (int32)(sim_idle_calib_pct)))
    return r;
if (newpct == 0)
    return SCPE_ARG;
sim_idle_calib_pct = (uint32)newpct;
return SCPE_OK;
}

/* Set/Clear asynch */

t_stat sim_timer_set_async (int32 flag, CONST char *cptr)
{
if (flag) {
    if (sim_asynch_enabled && (!sim_asynch_timer)) {
        sim_asynch_timer = TRUE;
        sim_timer_change_asynch ();
        }
    }
else {
    if (sim_asynch_timer) {
        sim_asynch_timer = FALSE;
        sim_timer_change_asynch ();
        }
    }
return SCPE_OK;
}

static CTAB set_timer_tab[] = {
#if defined (SIM_ASYNCH_CLOCKS)
    { "ASYNCH",     &sim_timer_set_async, 1 },
    { "NOASYNCH",   &sim_timer_set_async, 0 },
#endif
    { "CATCHUP",    &sim_timer_set_catchup,  1 },
    { "NOCATCHUP",  &sim_timer_set_catchup,  0 },
    { "CALIB",      &sim_timer_set_idle_pct, 0 },
    { NULL, NULL, 0 }
    };

MTAB sim_timer_mod[] = {
  { 0 },
};

static t_stat sim_timer_clock_reset (DEVICE *dptr);

static const char *sim_timer_description (DEVICE *dptr)
{
return "Clock Assist facilities";
}

static const char *sim_int_timer_description (DEVICE *dptr)
{
return "Internal Timer";
}

static const char *sim_throttle_description (DEVICE *dptr)
{
return "Throttle facility";
}

DEVICE sim_timer_dev = {
    "INT-CLOCK", sim_timer_units, sim_timer_reg, sim_timer_mod, 
    SIM_NTIMERS+1, 0, 0, 0, 0, 0, 
    NULL, NULL, &sim_timer_clock_reset, NULL, NULL, NULL, 
    NULL, DEV_DEBUG | DEV_NOSAVE, 0, sim_timer_debug};

DEVICE sim_int_timer_dev = {
    "INT-TIMER", &sim_internal_timer_unit, NULL, NULL, 
    1, 0, 0, 0, 0, 0, 
    NULL, NULL, NULL, NULL, NULL, NULL, 
    NULL, DEV_NOSAVE};

DEVICE sim_throttle_dev = {
    "INT-THROTTLE", &sim_throttle_unit, sim_throttle_reg, NULL, 1};


/* SET CLOCK command */

t_stat sim_set_timers (int32 arg, CONST char *cptr)
{
char *cvptr, gbuf[CBUFSIZE];
CTAB *ctptr;
t_stat r;

if ((cptr == NULL) || (*cptr == 0))
    return SCPE_2FARG;
while (*cptr != 0) {                                    /* do all mods */
    cptr = get_glyph_nc (cptr, gbuf, ',');              /* get modifier */
    if ((cvptr = strchr (gbuf, '=')))                   /* = value? */
        *cvptr++ = 0;
    get_glyph (gbuf, gbuf, 0);                          /* modifier to UC */
    if ((ctptr = find_ctab (set_timer_tab, gbuf))) {    /* match? */
        r = ctptr->action (ctptr->arg, cvptr);          /* do the rest */
        if (r != SCPE_OK)
            return r;
        }
    else return SCPE_NOPARAM;
    }
return SCPE_OK;
}

/* sim_idle - idle simulator until next event or for specified interval

   Inputs:
        tmr =   calibrated timer to use

   Must solve the linear equation

        ms_to_wait = w * ms_per_wait

   Or
        w = ms_to_wait / ms_per_wait
*/

t_bool sim_idle (uint32 tmr, int sin_cyc)
{
uint32 w_ms, w_idle, act_ms;
int32 act_cyc;

if (rtc_clock_catchup_pending[tmr]) {                   /* Catchup clock tick pending? */
    sim_debug (DBG_CAL, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d) - accelerating pending catch-up tick before idling %s\n", tmr, sin_cyc, sim_uname (sim_clock_unit[tmr]));
    sim_activate_abs (&sim_timer_units[tmr], 0);
    sim_interval -= sin_cyc;
    return FALSE;
    }
if ((!sim_idle_enab)                             ||     /* idling disabled */
    ((sim_clock_queue == QUEUE_LIST_END) &&             /* or clock queue empty? */
     (!sim_asynch_timer))||                             /*     and not asynch? */
    ((sim_clock_queue != QUEUE_LIST_END) &&             /* or clock queue not empty */
     ((sim_clock_queue->flags & UNIT_IDLE) == 0))||     /*   and event not idle-able? */
    (rtc_elapsed[tmr] < sim_idle_stable)) {             /* or timer not stable? */
    sim_debug (DBG_IDL, &sim_timer_dev, "Can't idle: %s - elapsed: %d.%03d\n", !sim_idle_enab ? "idle disabled" : 
                                                                             ((rtc_elapsed[tmr] < sim_idle_stable) ? "not stable" : 
                                                                                                                     ((sim_clock_queue != QUEUE_LIST_END) ? sim_uname (sim_clock_queue) : 
                                                                                                                                                            "")), rtc_elapsed[tmr], rtc_ticks[tmr]);
    sim_interval -= sin_cyc;
    return FALSE;
    }
if (_rtcn_tick_catchup_check(tmr, 0)) {
    sim_debug (DBG_CAL, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d) - rescheduling catchup tick for %s\n", tmr, sin_cyc, sim_uname (sim_clock_unit[tmr]));
    sim_interval -= sin_cyc;
    return FALSE;
    }
/*
   When a simulator is in an instruction path (or under other conditions 
   which would indicate idling), the countdown of sim_interval will not 
   be happening at a pace which is consistent with the rate it happens 
   when not in the 'idle capable' state.  The consequence of this is that 
   the clock calibration may produce calibrated results which vary much 
   more than they do when not in the idle able state.  Sim_idle also uses 
   the calibrated tick size to approximate an adjustment to sim_interval
   to reflect the number of instructions which would have executed during 
   the actual idle time, so consistent calibrated numbers produce better 
   adjustments. 
   
   To negate this effect, we accumulate the time actually idled here.
   sim_rtcn_calb compares the accumulated idle time during the most recent 
   second and if it exceeds the percentage defined by and sim_idle_calib_pct
   calibration is suppressed. Thus recalibration only happens if things 
   didn't idle too much.

   we also check check sim_idle_enab above so that all simulators can avoid
   directly checking sim_idle_enab before calling sim_idle so that all of 
   the bookkeeping on sim_idle_idled is done here in sim_timer where it 
   means something, while not idling when it isn't enabled.  
   */
sim_debug (DBG_TRC, &sim_timer_dev, "sim_idle(tmr=%d, sin_cyc=%d)\n", tmr, sin_cyc);
if (sim_idle_cyc_ms == 0)
    sim_idle_cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000;/* cycles per msec */
if ((sim_idle_rate_ms == 0) || (sim_idle_cyc_ms == 0)) {/* not possible? */
    sim_interval -= sin_cyc;
    sim_debug (DBG_IDL, &sim_timer_dev, "not possible idle_rate_ms=%d - cyc/ms=%d\n", sim_idle_rate_ms, sim_idle_cyc_ms);
    return FALSE;
    }
w_ms = (uint32) sim_interval / sim_idle_cyc_ms;         /* ms to wait */
/* When the host system has a clock tick which is less frequent than the    */
/* simulated system's clock, idling will cause delays which will miss       */
/* simulated clock ticks.  To accomodate this, and still allow idling, if   */
/* the simulator acknowledges the processing of clock ticks, then catchup   */
/* ticks can be used to make up for missed ticks. */
if (rtc_clock_catchup_eligible[tmr])
    w_idle = (sim_interval * 1000) / rtc_currd[tmr];    /* 1000 * pending fraction of tick */
else
    w_idle = (w_ms * 1000) / sim_idle_rate_ms;          /* 1000 * intervals to wait */
if (w_idle < 500) {                                     /* shorter than 1/2 the interval? */
    sim_interval -= sin_cyc;
    sim_debug (DBG_IDL, &sim_timer_dev, "no wait\n");
    return FALSE;
    }
if (sim_clock_queue == QUEUE_LIST_END)
    sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event in %d instructions\n", w_ms, sim_interval);
else
    sim_debug (DBG_IDL, &sim_timer_dev, "sleeping for %d ms - pending event on %s in %d instructions\n", w_ms, sim_uname(sim_clock_queue), sim_interval);
act_ms = sim_idle_ms_sleep (w_ms);                      /* wait */
rtc_clock_time_idled[tmr] += act_ms;
act_cyc = act_ms * sim_idle_cyc_ms;
act_cyc += (sim_idle_cyc_ms * sim_idle_rate_ms) / 2;    /* account for half an interval's worth of cycles */
if (sim_interval > act_cyc)
    sim_interval = sim_interval - act_cyc;              /* count down sim_interval */
else
    sim_interval = 0;                                   /* or fire immediately */
if (sim_clock_queue == QUEUE_LIST_END)
    sim_debug (DBG_IDL, &sim_timer_dev, "slept for %d ms - pending event in %d instructions\n", act_ms, sim_interval);
else
    sim_debug (DBG_IDL, &sim_timer_dev, "slept for %d ms - pending event on %s in %d instructions\n", act_ms, sim_uname(sim_clock_queue), sim_interval);
return TRUE;
}

/* Set idling - implicitly disables throttling */

t_stat sim_set_idle (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_stat r;
uint32 v;

if (cptr && *cptr) {
    v = (uint32) get_uint (cptr, 10, SIM_IDLE_STMAX, &r);
    if ((r != SCPE_OK) || (v < SIM_IDLE_STMIN))
        return sim_messagef (SCPE_ARG, "Invalid Stability value: %s.  Valid values range from %d to %d.\n", cptr, SIM_IDLE_STMIN, SIM_IDLE_STMAX);
    sim_idle_stable = v;
    }
sim_idle_enab = TRUE;
if (sim_throt_type != SIM_THROT_NONE) {
    sim_set_throt (0, NULL);
    sim_printf ("Throttling disabled\n");
    }
return SCPE_OK;
}

/* Clear idling */

t_stat sim_clr_idle (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
sim_idle_enab = FALSE;
return SCPE_OK;
}

/* Show idling */

t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (sim_idle_enab)
    fprintf (st, "idle enabled");
else
    fprintf (st, "idle disabled");
if (sim_switches & SWMASK ('D'))
    fprintf (st, ", stability wait = %ds, minimum sleep resolution = %dms", sim_idle_stable, sim_os_sleep_min_ms);
return SCPE_OK;
}

/* Throttling package */

t_stat sim_set_throt (int32 arg, CONST char *cptr)
{
CONST char *tptr;
char c;
t_value val, val2 = 0;

if (arg == 0) {
    if ((cptr != NULL) && (*cptr != 0))
        return sim_messagef (SCPE_ARG, "Unexpected NOTHROTTLE argument: %s\n", cptr);
    sim_throt_type = SIM_THROT_NONE;
    sim_throt_cancel ();
    }
else if (sim_idle_rate_ms == 0) {
    return sim_messagef (SCPE_NOFNC, "Throttling is not available, Minimum OS sleep time is %dms\n", sim_os_sleep_min_ms);
    }
else {
    if (*cptr == '\0')
        return sim_messagef (SCPE_ARG, "Missing throttle mode specification\n");
    val = strtotv (cptr, &tptr, 10);
    if (cptr == tptr)
        return sim_messagef (SCPE_ARG, "Invalid throttle specification: %s\n", cptr);
    sim_throt_sleep_time = sim_idle_rate_ms;
    c = (char)toupper (*tptr++);
    if (c == '/') {
        val2 = strtotv (tptr, &tptr, 10);
        if ((*tptr != '\0') || (val == 0))
            return sim_messagef (SCPE_ARG, "Invalid throttle delay specifier: %s\n", cptr);
        }
    if (c == 'M') 
        sim_throt_type = SIM_THROT_MCYC;
    else if (c == 'K')
        sim_throt_type = SIM_THROT_KCYC;
    else if ((c == '%') && (val > 0) && (val < 100))
        sim_throt_type = SIM_THROT_PCT;
    else if ((c == '/') && (val2 != 0))
        sim_throt_type = SIM_THROT_SPC;
    else return sim_messagef (SCPE_ARG, "Invalid throttle specification: %s\n", cptr);
    if (sim_idle_enab) {
        sim_printf ("Idling disabled\n");
        sim_clr_idle (NULL, 0, NULL, NULL);
        }
    sim_throt_val = (uint32) val;
    if (sim_throt_type == SIM_THROT_SPC) {
        if (val2 >= sim_idle_rate_ms)
            sim_throt_sleep_time = (uint32) val2;
        else {
            if ((sim_idle_rate_ms % val2) == 0) {
                sim_throt_sleep_time = sim_idle_rate_ms;
                sim_throt_val = (uint32) (val * (sim_idle_rate_ms / val2));
                }
            else {
                sim_throt_sleep_time = sim_idle_rate_ms;
                sim_throt_val = (uint32) (val * (1 + (sim_idle_rate_ms / val2)));
                }
            }
        }
    }
sim_register_internal_device (&sim_throttle_dev);       /* Register Throttle Device */
sim_throt_cps = SIM_INITIAL_IPS;    /* Initial value while correct one is determined */
return SCPE_OK;
}

t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr)
{
if (sim_idle_rate_ms == 0)
    fprintf (st, "Throttling:                    Not Available\n");
else {
    switch (sim_throt_type) {

    case SIM_THROT_MCYC:
        fprintf (st, "Throttle:                      %d megacycles\n", sim_throt_val);
        if (sim_throt_wait)
            fprintf (st, "Throttling by sleeping for:    %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait);
        break;

    case SIM_THROT_KCYC:
        fprintf (st, "Throttle:                      %d kilocycles\n", sim_throt_val);
        if (sim_throt_wait)
            fprintf (st, "Throttling by sleeping for:    %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait);
        break;

    case SIM_THROT_PCT:
        fprintf (st, "Throttle:                      %d%%\n", sim_throt_val);
        if (sim_throt_wait)
            fprintf (st, "Throttling by sleeping for:    %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_wait);
        break;

    case SIM_THROT_SPC:
        fprintf (st, "Throttle:                      sleep %d ms every %d cycles\n", sim_throt_sleep_time, sim_throt_val);
        break;

    default:
        fprintf (st, "Throttling:                    Disabled\n");
        break;
        }
    if (sim_throt_type != SIM_THROT_NONE) {
        if (sim_throt_state != SIM_THROT_STATE_THROTTLE)
            fprintf (st, "Throttle State:                %s - wait: %d\n", (sim_throt_state == SIM_THROT_STATE_INIT) ? "Waiting for Init" : "Timing", sim_throt_wait);
        }
    }
return SCPE_OK;
}

void sim_throt_sched (void)
{
sim_throt_state = SIM_THROT_STATE_INIT;
if (sim_throt_type)
    sim_activate (&sim_throttle_unit, SIM_THROT_WINIT);
}

void sim_throt_cancel (void)
{
sim_cancel (&sim_throttle_unit);
}

/* Throttle service

   Throttle service has three distinct states used while dynamically
   determining a throttling interval:

       SIM_THROT_STATE_INIT     take initial measurement
       SIM_THROT_STATE_TIME     take final measurement, calculate wait values
       SIM_THROT_STATE_THROTTLE periodic waits to slow down the CPU
*/
t_stat sim_throt_svc (UNIT *uptr)
{
int32 tmr;
uint32 delta_ms;
double a_cps, d_cps;

if (sim_throt_type == SIM_THROT_SPC) {                  /* Non dynamic? */
    sim_throt_state = SIM_THROT_STATE_THROTTLE;         /* force state */
    sim_throt_wait = sim_throt_val;
    }
switch (sim_throt_state) {

    case SIM_THROT_STATE_INIT:                          /* take initial reading */
        sim_idle_ms_sleep (sim_idle_rate_ms);           /* start on a tick boundart to calibrate */
        sim_throt_ms_start = sim_os_msec ();
        sim_throt_inst_start = sim_gtime();
        sim_throt_wait = SIM_THROT_WST;
        sim_throt_state = SIM_THROT_STATE_TIME;         /* next state */
        sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc(INIT) Starting.  Values wait = %d\n", sim_throt_wait);
        break;                                          /* reschedule */

    case SIM_THROT_STATE_TIME:                          /* take final reading */
        sim_throt_ms_stop = sim_os_msec ();
        delta_ms = sim_throt_ms_stop - sim_throt_ms_start;
        if (delta_ms < SIM_THROT_MSMIN) {               /* not enough time? */
            if (sim_throt_wait >= 100000000) {          /* too many inst? */
                sim_throt_state = SIM_THROT_STATE_INIT; /* fails in 32b! */
                sim_printf ("Can't throttle.  Host CPU is too fast with a minimum sleep time of %d ms\n", sim_idle_rate_ms);
                sim_set_throt (0, NULL);                /* disable throttling */
                return SCPE_OK;
                }
            sim_idle_ms_sleep (sim_idle_rate_ms);       /* start on a tick boundart to calibrate */
            sim_throt_wait = sim_throt_wait * SIM_THROT_WMUL;
            sim_throt_ms_start = sim_os_msec ();
            sim_throt_inst_start = sim_gtime();
            }
        else {                                          /* long enough */
            a_cps = ((double) sim_throt_wait) * 1000.0 / (double) delta_ms;
            if (sim_throt_type == SIM_THROT_MCYC)       /* calc desired cps */
                d_cps = (double) sim_throt_val * 1000000.0;
            else if (sim_throt_type == SIM_THROT_KCYC)
                d_cps = (double) sim_throt_val * 1000.0;
            else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0;
            if (d_cps >= a_cps) {
                sim_throt_state = SIM_THROT_STATE_INIT;
                sim_printf ("Host CPU is too slow to simulate %s instructions per second\n", sim_fmt_numeric(d_cps));
                sim_printf ("Throttling disabled.\n");
                sim_set_throt (0, NULL);
                return SCPE_OK;
                }
            while (1) {
                sim_throt_wait = (int32)                /* time between waits */
                    ((a_cps * d_cps * ((double) sim_throt_sleep_time)) /
                     (1000.0 * (a_cps - d_cps)));
                if (sim_throt_wait >= SIM_THROT_WMIN)   /* long enough? */
                    break;
                sim_throt_sleep_time += sim_os_sleep_inc_ms;
                sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Wait too small, increasing sleep time to %d ms.  Values a_cps = %f, d_cps = %f, wait = %d\n", 
                                                    sim_throt_sleep_time, a_cps, d_cps, sim_throt_wait);
                }
            sim_throt_ms_start = sim_throt_ms_stop;
            sim_throt_inst_start = sim_gtime();
            sim_throt_state = SIM_THROT_STATE_THROTTLE;
            sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Throttle values a_cps = %f, d_cps = %f, wait = %d, sleep = %d ms\n", 
                                                a_cps, d_cps, sim_throt_wait, sim_throt_sleep_time);
            sim_throt_cps = d_cps;                  /* save the desired rate */
            /* Run through all timers and adjust the calibration for each */
            /* one that is running to reflect the throttle rate */
            for (tmr=0; tmr<=SIM_NTIMERS; tmr++)
                if (rtc_hz[tmr]) {                                      /* running? */
                    rtc_gtime[tmr] = sim_gtime();                       /* save instruction time */
                    rtc_currd[tmr] = (int32)(sim_throt_cps / rtc_hz[tmr]);/* use throttle calibration */
                    }
            }
        break;

    case SIM_THROT_STATE_THROTTLE:                      /* throttling */
        sim_idle_ms_sleep (sim_throt_sleep_time);
        delta_ms = sim_os_msec () - sim_throt_ms_start;
        if (sim_throt_type != SIM_THROT_SPC) {          /* when not dynamic throttling */
            if (delta_ms >= 10000) {                    /* recompute every 10 sec */
                double delta_insts = sim_gtime() - sim_throt_inst_start;
                a_cps = (delta_insts * 1000.0) / (double) delta_ms;
                if (sim_throt_type == SIM_THROT_MCYC)   /* calc desired cps */
                    d_cps = (double) sim_throt_val * 1000000.0;
                else if (sim_throt_type == SIM_THROT_KCYC)
                    d_cps = (double) sim_throt_val * 1000.0;
                else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0;
                if (fabs(100.0 * (d_cps - a_cps) / a_cps) > (double)SIM_THROT_DRIFT_PCT) {
                    sim_throt_wait = sim_throt_val;
                    sim_throt_state = SIM_THROT_STATE_TIME;/* next state to recalibrate */
                    sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Recalibrating throttle based on values a_cps = %f, d_cps = %f\n", 
                                                        a_cps, d_cps);
                    }
                sim_throt_ms_start = sim_os_msec ();
                sim_throt_inst_start = sim_gtime();
                }
            }
        else                                            /* record instruction rate */
            sim_throt_cps = (int32)((1000.0 * sim_throt_val) / (double)delta_ms);
        break;
        }

sim_activate (uptr, sim_throt_wait);                    /* reschedule */
return SCPE_OK;
}

/* Clock assist activites */
t_stat sim_timer_tick_svc (UNIT *uptr)
{
int32 tmr = (int32)(uptr-sim_timer_units);
t_stat stat;

rtc_clock_ticks[tmr] += 1;
rtc_calib_tick_time[tmr] += rtc_clock_tick_size[tmr];
/*
 * Some devices may depend on executing during the same instruction or 
 * immediately after the clock tick event.  To satisfy this, we directly 
 * run the clock event here and if it completes successfully, schedule any
 * currently coschedule units to run now.  Ticks should never return a 
 * non-success status, while co-schedule activities might, so they are 
 * queued to run from sim_process_event
 */
sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_tick_svc(tmr=%d) - scheduling %s - cosched interval: %d\n", tmr, sim_uname (sim_clock_unit[tmr]), sim_cosched_interval[tmr]);
if (sim_clock_unit[tmr]->action == NULL)
    return SCPE_IERR;
stat = sim_clock_unit[tmr]->action (sim_clock_unit[tmr]);
--sim_cosched_interval[tmr];                    /* Countdown ticks */
if (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END)
    sim_clock_cosched_queue[tmr]->time = sim_cosched_interval[tmr];
if ((stat == SCPE_OK)                               && 
    (sim_cosched_interval[tmr] <= 0)                &&
    (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END)) {
    if (rtc_clock_catchup_eligible[tmr]) {      /* calibration started? */
        struct timespec now;
        double skew;

        clock_gettime(CLOCK_REALTIME, &now);
        skew = (_timespec_to_double(&now) - (rtc_calib_tick_time[tmr]+rtc_clock_catchup_base_time[tmr]));

        if (fabs(skew) > fabs(rtc_clock_skew_max[tmr]))
            rtc_clock_skew_max[tmr] = skew;
        }
    do {
        UNIT *cptr = sim_clock_cosched_queue[tmr];
        sim_clock_cosched_queue[tmr] = cptr->next;
        cptr->next = NULL;
        cptr->cancel = NULL;
        cptr->time = 0;
        if (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
            sim_clock_cosched_queue[tmr]->time += sim_cosched_interval[tmr];
            sim_cosched_interval[tmr] = sim_clock_cosched_queue[tmr]->time;
            }
        else
            sim_cosched_interval[tmr]  = 0;
        cptr->time = 0;
        sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_tick_svc(tmr=%d) - coactivating %s", tmr, sim_uname (cptr));
        if (cptr->usecs_remaining) {
            sim_debug (DBG_QUE, &sim_timer_dev, " remnant: %.0f - next %s after cosched interval: %d ticks\n", cptr->usecs_remaining, (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) ? sim_uname (sim_clock_cosched_queue[tmr]) : "", sim_cosched_interval[tmr]);
            sim_timer_activate_after (cptr, cptr->usecs_remaining);
            }
        else {
            sim_debug (DBG_QUE, &sim_timer_dev, " - next %s after cosched interval: %d ticks\n", (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) ? sim_uname (sim_clock_cosched_queue[tmr]) : "", sim_cosched_interval[tmr]);
            _sim_activate (cptr, 0);
            }
        } while ((sim_cosched_interval[tmr] <= 0) &&
             (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END));
    }
return stat;
}

void sim_rtcn_get_time (struct timespec *now, int tmr)
{
sim_debug (DBG_CAL, &sim_timer_dev, "sim_rtcn_get_time(tmr=%d)\n", tmr);
clock_gettime (CLOCK_REALTIME, now);
}

/* 
 * If the host system has a relatively large clock tick (as compared to
 * the desired simulated hz) ticks will naturally be scheduled late and
 * these delays will accumulate.  The net result will be unreasonably
 * slow ticks being delivered to the simulated system.
 * Additionally, when a simulator is idling and/or throttling, it will
 * deliberately call sim_os_ms_sleep and those sleep operations will be
 * variable and subject to the host system's minimum sleep resolution
 * which can exceed the desired sleep interval and add to the concept
 * of slow tick delivery to the simulated system.
 * We accomodate these problems and make up for lost ticks by injecting
 * catch-up ticks to the simulator.
 *
 * When necessary, catch-up ticks are scheduled to run under one 
 * of two conditions:
 *   1) after indicated number of instructions in a call by the simulator
 *      to sim_rtcn_tick_ack.  sim_rtcn_tick_ack exists to provide a 
 *      mechanism to inform the simh timer facilities when the simulated 
 *      system has accepted the most recent clock tick interrupt.
 *   2) immediately when the simulator calls sim_idle
 *
 * catchup ticks are only scheduled (eligible to happen) under these 
 * conditions after at least one tick has been acknowledged.
 */

/* _rtcn_tick_catchup_check - idle simulator until next event or for specified interval

   Inputs:
        tmr =   calibrated timer to check/schedule
        time =  instruction delay for next tick

   Returns TRUE if a catchup tick has been scheduled
*/

static t_bool _rtcn_tick_catchup_check (int32 tmr, int32 time)
{
if ((!sim_catchup_ticks) || 
    ((tmr < 0) || (tmr >= SIM_NTIMERS)))
    return FALSE;
if ((rtc_hz[tmr] > sim_os_tick_hz) &&           /* faster than host tick */
    (!rtc_clock_catchup_eligible[tmr]) &&       /* not eligible yet? */
    (time != -1)) {                             /* called from ack? */
    rtc_clock_catchup_base_time[tmr] = sim_timenow_double();
    rtc_clock_ticks_tot[tmr] += rtc_clock_ticks[tmr];
    rtc_clock_ticks[tmr] = 0;
    rtc_calib_tick_time_tot[tmr] += rtc_calib_tick_time[tmr];
    rtc_calib_tick_time[tmr] = 0.0;
    rtc_clock_catchup_ticks_tot[tmr] += rtc_clock_catchup_ticks[tmr];
    rtc_clock_catchup_ticks[tmr] = 0;
    rtc_calib_ticks_acked_tot[tmr] += rtc_calib_ticks_acked[tmr];
    rtc_calib_ticks_acked[tmr] = 0;
    rtc_clock_catchup_eligible[tmr] = TRUE;
    sim_debug (DBG_QUE, &sim_timer_dev, "_rtcn_tick_catchup_check() - Enabling catchup ticks for %s\n", sim_uname (sim_clock_unit[tmr]));
    return TRUE;
    }
if (rtc_clock_catchup_eligible[tmr])
    {
    double tnow = sim_timenow_double();

    if (tnow > (rtc_clock_catchup_base_time[tmr] + (rtc_calib_tick_time[tmr] + rtc_clock_tick_size[tmr]))) {
        sim_debug (DBG_QUE, &sim_timer_dev, "_rtcn_tick_catchup_check(%d) - scheduling catchup tick for %s which is behind %s\n", time, sim_uname (sim_clock_unit[tmr]), sim_fmt_secs (tnow > (rtc_clock_catchup_base_time[tmr] + (rtc_calib_tick_time[tmr] + rtc_clock_tick_size[tmr]))));
        rtc_clock_catchup_pending[tmr] = TRUE;
        sim_activate_abs (&sim_timer_units[tmr], (time < 0) ? 0 : time);
        return TRUE;
        }
    }
return FALSE;
}

t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr)
{
if ((tmr < 0) || (tmr >= SIM_NTIMERS))
    return SCPE_TIMER;
sim_debug (DBG_ACK, &sim_timer_dev, "sim_rtcn_tick_ack - for %s\n", sim_uname (sim_clock_unit[tmr]));
_rtcn_tick_catchup_check (tmr, (int32)time);
++rtc_calib_ticks_acked[tmr];
return SCPE_OK;
}


static double _timespec_to_double (struct timespec *time)
{
return ((double)time->tv_sec)+(double)(time->tv_nsec)/1000000000.0;
}

static void _double_to_timespec (struct timespec *time, double dtime)
{
time->tv_sec = (time_t)floor(dtime);
time->tv_nsec = (long)((dtime-floor(dtime))*1000000000.0);
}

double sim_timenow_double (void)
{
struct timespec now;

clock_gettime (CLOCK_REALTIME, &now);
return _timespec_to_double (&now);
}

#if defined(SIM_ASYNCH_CLOCKS)

pthread_t           sim_timer_thread;           /* Wall Clock Timing Thread Id */
pthread_cond_t      sim_timer_startup_cond;
t_bool              sim_timer_thread_running = FALSE;

static void *
_timer_thread(void *arg)
{
int sched_policy;
struct sched_param sched_priority;

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which, in general, won't be readily yielding the processor when 
   this thread needs to run */
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);

sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - starting\n");

pthread_mutex_lock (&sim_timer_lock);
pthread_cond_signal (&sim_timer_startup_cond);   /* Signal we're ready to go */
while (sim_asynch_timer && sim_is_running) {
    struct timespec start_time, stop_time;
    struct timespec due_time;
    double wait_usec;
    int32 inst_delay;
    double inst_per_sec;
    UNIT *uptr, *cptr, *prvptr;

    if (sim_wallclock_entry) {                          /* something to insert in queue? */

        sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - timing %s for %s\n", 
                   sim_uname(sim_wallclock_entry), sim_fmt_secs (sim_wallclock_entry->a_usec_delay/1000000.0));

        uptr = sim_wallclock_entry;
        sim_wallclock_entry = NULL;

        prvptr = NULL;
        for (cptr = sim_wallclock_queue; cptr != QUEUE_LIST_END; cptr = cptr->a_next) {
            if (uptr->a_due_time < cptr->a_due_time)
                break;
            prvptr = cptr;
            }
        if (prvptr == NULL) {                           /* insert at head */
            cptr = uptr->a_next = sim_wallclock_queue;
            sim_wallclock_queue = uptr;
            }
        else {
            cptr = uptr->a_next = prvptr->a_next;       /* insert at prvptr */
            prvptr->a_next = uptr;
            }
        }

    /* determine wait time */
    if (sim_wallclock_queue != QUEUE_LIST_END) {
        /* due time adjusted by 1/2 a minimal sleep interval */
        /* the goal being to let the last fractional part of the due time */
        /* be done by counting instructions */
        _double_to_timespec (&due_time, sim_wallclock_queue->a_due_time-(((double)sim_idle_rate_ms)*0.0005));
        }
    else {
        due_time.tv_sec = 0x7FFFFFFF;                   /* Sometime when 32 bit time_t wraps */
        due_time.tv_nsec = 0;
        }
    clock_gettime(CLOCK_REALTIME, &start_time);
    wait_usec = floor(1000000.0*(_timespec_to_double (&due_time) - _timespec_to_double (&start_time)));
    if (sim_wallclock_queue == QUEUE_LIST_END)
        sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting forever\n");
    else
        sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting for %.0f usecs until %.6f for %s\n", wait_usec, sim_wallclock_queue->a_due_time, sim_uname(sim_wallclock_queue));
    if ((wait_usec <= 0.0) || 
        (0 != pthread_cond_timedwait (&sim_timer_wake, &sim_timer_lock, &due_time))) {

        if (sim_wallclock_queue == QUEUE_LIST_END)      /* queue empty? */
            continue;                                   /* wait again */
        inst_per_sec = sim_timer_inst_per_sec ();

        uptr = sim_wallclock_queue;
        sim_wallclock_queue = uptr->a_next;
        uptr->a_next = NULL;                            /* hygiene */

        clock_gettime(CLOCK_REALTIME, &stop_time);
        if (1 != sim_timespec_compare (&due_time, &stop_time))
            inst_delay = 0;
        else
            inst_delay = (int32)(inst_per_sec*(_timespec_to_double(&due_time)-_timespec_to_double(&stop_time)));
        sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - slept %.0fms - activating(%s,%d)\n", 
                   1000.0*(_timespec_to_double (&stop_time)-_timespec_to_double (&start_time)), sim_uname(uptr), inst_delay);
        sim_activate (uptr, inst_delay);
        }
    else {/* Something wants to adjust the queue since the wait condition was signaled */
        }
    }
pthread_mutex_unlock (&sim_timer_lock);

sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - exiting\n");

return NULL;
}

#endif /* defined(SIM_ASYNCH_CLOCKS) */

/*
   In the event that there are no active clock devices, no instruction 
   rate calibration will be performed.  This is more likely on simpler
   simulators which don't have a full spectrum of standard devices or 
   possibly when a clock device exists but its use is optional.

   Additonally, when a host system has a natural clock tick (or minimal 
   sleep time) which is greater than the tick size that a simulator 
   wants to run a clock at, we run this clock at the rate implied by
   the host system's minimal sleep time or 50Hz.
   
   To solve this we merely run an internal clock at 10Hz.
 */

#define CLK_TPS 10
#define CLK_INIT (SIM_INITIAL_IPS/CLK_TPS)
static int32 sim_int_clk_tps;

static t_stat sim_timer_clock_tick_svc (UNIT *uptr)
{
sim_rtcn_calb (sim_int_clk_tps, SIM_INTERNAL_CLK);
sim_activate_after (uptr, 1000000/sim_int_clk_tps);     /* reactivate unit */
return SCPE_OK;
}

/* 
  This routine exists to assure that there is a single reliably calibrated 
  clock properly counting instruction execution relative to time.  The best 
  way to assure reliable calibration is to use a clock which ticks no 
  faster than the host system's clock.  This is optimal so that accurate 
  time measurements are taken.  If the simulated system doesn't have a 
  clock with an appropriate tick rate, an internal clock is run that meets 
  this requirement, 
 */
static void _rtcn_configure_calibrated_clock (int32 newtmr)
{
int32 tmr;

/* Look for a timer running slower than the host system clock */
sim_int_clk_tps = MIN(CLK_TPS, sim_os_tick_hz);
for (tmr=0; tmr<SIM_NTIMERS; tmr++) {
    if ((rtc_hz[tmr]) &&
        (rtc_hz[tmr] <= (uint32)sim_os_tick_hz) &&
        (sim_clock_unit[tmr]))
        break;
    }
if (tmr == SIM_NTIMERS) {                   /* None found? */
    if ((tmr != newtmr) && (!sim_is_active (&SIM_INTERNAL_UNIT))) {
        if ((sim_calb_tmr != SIM_NTIMERS) &&/* not internal timer? */
            (sim_calb_tmr != -1) &&         /* previously active? */
            (!rtc_hz[sim_calb_tmr])) {      /* now stopped? */
            sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Cleaning up stopped timer %s support\n", newtmr, sim_uname(sim_clock_unit[sim_calb_tmr]));
            /* Migrate any coscheduled devices to the standard queue */
            /* with appropriate usecs_remaining reflecting their currently */
            /* scheduled firing time.  sim_process_event() will coschedule */
            /* appropriately. */
            /* temporarily restore prior hz to get correct remaining time */
            rtc_hz[sim_calb_tmr] = rtc_last_hz[sim_calb_tmr];
            while (sim_clock_cosched_queue[sim_calb_tmr] != QUEUE_LIST_END) {
                UNIT *uptr = sim_clock_cosched_queue[sim_calb_tmr];
                double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1;

                _sim_coschedule_cancel (uptr);
                _sim_activate (uptr, 1);
                uptr->usecs_remaining = usecs_remaining;
                }
            rtc_hz[sim_calb_tmr] = 0;                           /* back to 0 */
            if (sim_clock_unit[sim_calb_tmr])
                sim_cancel (sim_clock_unit[sim_calb_tmr]);
            sim_cancel (&sim_timer_units[sim_calb_tmr]);
            }
        /* Start the internal timer */
        sim_calb_tmr = SIM_NTIMERS;
        sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Starting Internal Calibrated Timer at %dHz\n", newtmr, sim_int_clk_tps);
        SIM_INTERNAL_UNIT.action = &sim_timer_clock_tick_svc;
        SIM_INTERNAL_UNIT.flags = UNIT_IDLE;
        sim_register_internal_device (&sim_int_timer_dev);      /* Register Internal timer device */
        sim_rtcn_init_unit (&SIM_INTERNAL_UNIT, (CLK_INIT*CLK_TPS)/sim_int_clk_tps, SIM_INTERNAL_CLK);
        SIM_INTERNAL_UNIT.action (&SIM_INTERNAL_UNIT);          /* Force tick to activate timer */
        }
    return;
    }
if ((tmr == newtmr) && 
    (sim_calb_tmr == newtmr))               /* already set? */
    return;
if (sim_calb_tmr == SIM_NTIMERS) {      /* was old the internal timer? */
    sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Stopping Internal Calibrated Timer, New Timer = %d (%dHz)\n", newtmr, tmr, rtc_hz[tmr]);
    rtc_initd[SIM_NTIMERS] = 0;
    rtc_hz[SIM_NTIMERS] = 0;
    sim_register_clock_unit_tmr (NULL, SIM_INTERNAL_CLK);
    sim_cancel (&SIM_INTERNAL_UNIT);
    sim_cancel (&sim_timer_units[SIM_NTIMERS]);
    }
else {
    if ((sim_calb_tmr != -1) &&
        (rtc_hz[sim_calb_tmr] == 0)) {
        /* Migrate any coscheduled devices to the standard queue */
        /* with appropriate usecs_remaining reflecting their currently */
        /* scheduled firing time.  sim_process_event() will coschedule */
        /* appropriately. */
        /* temporarily restore prior hz to get correct remaining time */
        rtc_hz[sim_calb_tmr] = rtc_last_hz[sim_calb_tmr];
        while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
            UNIT *uptr = sim_clock_cosched_queue[tmr];
            double usecs_remaining = sim_timer_activate_time_usecs (uptr) - 1;

            _sim_coschedule_cancel (uptr);
            _sim_activate (uptr, 1);
            uptr->usecs_remaining = usecs_remaining;
            }
        rtc_hz[sim_calb_tmr] = 0;                           /* back to 0 */
        }
    sim_debug (DBG_CAL, &sim_timer_dev, "_rtcn_configure_calibrated_clock(newtmr=%d) - Changing Calibrated Timer from %d (%dHz) to %d (%dHz)\n", newtmr, sim_calb_tmr, rtc_hz[sim_calb_tmr], tmr, rtc_hz[tmr]);
    sim_calb_tmr = tmr;
    }
sim_calb_tmr = tmr;
}

static t_stat sim_timer_clock_reset (DEVICE *dptr)
{
sim_debug (DBG_TRC, &sim_timer_dev, "sim_timer_clock_reset()\n");
_rtcn_configure_calibrated_clock (sim_calb_tmr);
sim_timer_dev.description = &sim_timer_description;
sim_throttle_dev.description = &sim_throttle_description;
sim_int_timer_dev.description = &sim_int_timer_description;
if (sim_switches & SWMASK ('P')) {
    sim_cancel (&SIM_INTERNAL_UNIT);
    sim_calb_tmr = -1;
    }
return SCPE_OK;
}

void sim_start_timer_services (void)
{
sim_debug (DBG_TRC, &sim_timer_dev, "sim_start_timer_services()\n");
_rtcn_configure_calibrated_clock (sim_calb_tmr);
#if defined(SIM_ASYNCH_CLOCKS)
pthread_mutex_lock (&sim_timer_lock);
if (sim_asynch_timer) {
    pthread_attr_t attr;

    sim_debug (DBG_TRC, &sim_timer_dev, "sim_start_timer_services() - starting\n");
    pthread_cond_init (&sim_timer_startup_cond, NULL);
    pthread_attr_init (&attr);
    pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_create (&sim_timer_thread, &attr, _timer_thread, NULL);
    pthread_attr_destroy( &attr);
    pthread_cond_wait (&sim_timer_startup_cond, &sim_timer_lock); /* Wait for thread to stabilize */
    pthread_cond_destroy (&sim_timer_startup_cond);
    sim_timer_thread_running = TRUE;
    }
pthread_mutex_unlock (&sim_timer_lock);
#endif
}

void sim_stop_timer_services (void)
{
int tmr;

sim_debug (DBG_TRC, &sim_timer_dev, "sim_stop_timer_services()\n");

for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
    int32 accum;

    if (sim_clock_unit[tmr]) {
        int32 clock_time = _sim_activate_time (&sim_timer_units[tmr]);

        if (clock_time < 0)
            clock_time = 0;
        /* Stop clock assist unit and make sure the clock unit has a tick queued */
        sim_cancel (&sim_timer_units[tmr]);
        if (rtc_hz[tmr]) {
            sim_debug (DBG_QUE, &sim_timer_dev, "sim_stop_timer_services() - tmr=%d scheduling %s after %d\n", tmr, sim_uname (sim_clock_unit[tmr]), clock_time);
            _sim_activate (sim_clock_unit[tmr], clock_time);
            }
        /* Move coscheduled units to the standard event queue */
        accum = 0;
        while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
            UNIT *cptr = sim_clock_cosched_queue[tmr];
            double usecs_remaining = cptr->usecs_remaining;

            cptr->usecs_remaining = 0;
            sim_clock_cosched_queue[tmr] = cptr->next;
            cptr->next = NULL;
            cptr->cancel = NULL;
            accum += cptr->time;
            sim_debug (DBG_QUE, &sim_timer_dev, "sim_stop_timer_services() - tmr=%d scheduling %s after %d\n", tmr, sim_uname (cptr), clock_time + accum*rtc_currd[tmr]);
            _sim_activate (cptr, clock_time + accum*rtc_currd[tmr]);
            cptr->usecs_remaining = usecs_remaining;
            }
        sim_cosched_interval[tmr] = 0;
        }
    }
sim_cancel (&SIM_INTERNAL_UNIT);                    /* Make sure Internal Timer is stopped */
sim_cancel (&sim_timer_units[SIM_NTIMERS]);
sim_calb_tmr_last = sim_calb_tmr;                   /* Save calibrated timer value for display */
sim_inst_per_sec_last = sim_timer_inst_per_sec ();  /* Save execution rate for display */
sim_calb_tmr = -1;
#if defined(SIM_ASYNCH_CLOCKS)
pthread_mutex_lock (&sim_timer_lock);
if (sim_timer_thread_running) {
    sim_debug (DBG_TRC, &sim_timer_dev, "sim_stop_timer_services() - stopping\n");
    pthread_cond_signal (&sim_timer_wake);
    pthread_mutex_unlock (&sim_timer_lock);
    pthread_join (sim_timer_thread, NULL);
    sim_timer_thread_running = FALSE;
    /* Any wallclock queued events are now migrated to the normal event queue */
    while (sim_wallclock_queue != QUEUE_LIST_END) {
        UNIT *uptr = sim_wallclock_queue;
        double inst_delay_d = uptr->a_due_gtime - sim_gtime ();
        int32 inst_delay;

        uptr->cancel (uptr);
        if (inst_delay_d < 0.0)
            inst_delay_d = 0.0;
        /* Bound delay to avoid overflow.  */
        /* Long delays are usually canceled before they expire */
        if (inst_delay_d > (double)0x7FFFFFFF)
            inst_delay_d = (double)0x7FFFFFFF;
        inst_delay = (int32)inst_delay_d;
        if ((inst_delay == 0) && (inst_delay_d != 0.0))
            inst_delay = 1;     /* Minimum non-zero delay is 1 instruction */
        _sim_activate (uptr, inst_delay);            /* queue it now */
        }
    }
else
    pthread_mutex_unlock (&sim_timer_lock);
#endif
}

t_stat sim_timer_change_asynch (void)
{
#if defined(SIM_ASYNCH_CLOCKS)
if (sim_asynch_enabled && sim_asynch_timer)
    sim_start_timer_services ();
else
    sim_stop_timer_services ();
#endif
return SCPE_OK;
}

/* Instruction Execution rate. */
/*  returns a double since it is mostly used in double expressions and
    to avoid overflow if/when strange timing delays might produce unexpected results */

double sim_timer_inst_per_sec (void)
{
double inst_per_sec = sim_inst_per_sec_last;

if (sim_calb_tmr == -1)
    return inst_per_sec;
inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*rtc_hz[sim_calb_tmr];
if (0 == inst_per_sec)
    inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*sim_int_clk_tps;
return inst_per_sec;
}

t_stat sim_timer_activate (UNIT *uptr, int32 interval)
{
AIO_VALIDATE;
return sim_timer_activate_after (uptr, (double)((interval * 1000000.0) / sim_timer_inst_per_sec ()));
}

t_stat sim_timer_activate_after (UNIT *uptr, double usec_delay)
{
UNIT *ouptr = uptr;
int inst_delay, tmr;
double inst_delay_d, inst_per_usec;
t_stat stat;

AIO_VALIDATE;
/* If this is a clock unit, we need to schedule the related timer unit instead */
for (tmr=0; tmr<=SIM_NTIMERS; tmr++)
    if (sim_clock_unit[tmr] == uptr) {
        uptr = &sim_timer_units[tmr];
        break;
        }
if (sim_is_active (uptr))                               /* already active? */
    return SCPE_OK;
uptr->usecs_remaining = 0;
if (usec_delay <= 0.0) {
    sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - invalid usec value\n", 
               sim_uname(uptr), usec_delay);
    return SCPE_ARG;
    }
/* 
 * Handle long delays by aligning with the calibrated timer's calibration
 * activities.  Delays which would expire prior to the next calibration
 * are specifically scheduled directly based on the the current instruction
 * execution rate.  Longer delays are coscheduled to fire on the first tick
 * after the next calibration and at that time are either scheduled directly
 * or re-coscheduled for the next calibration time, repeating until the total
 * desired time has elapsed.
 */
inst_per_usec = sim_timer_inst_per_sec () / 1000000.0;
inst_delay_d = floor(inst_per_usec * usec_delay);
inst_delay = (int32)inst_delay_d;
if ((inst_delay == 0) && (usec_delay != 0))
    inst_delay_d = inst_delay = 1;  /* Minimum non-zero delay is 1 instruction */
if ((sim_calb_tmr != -1) && (rtc_hz[sim_calb_tmr])) {       /* Calibrated Timer available? */
    int32 inst_til_tick = sim_activate_time (&sim_timer_units[sim_calb_tmr]) - 1;
    int32 ticks_til_calib = rtc_hz[sim_calb_tmr] - rtc_ticks[sim_calb_tmr];
    int32 inst_til_calib = inst_til_tick + ((ticks_til_calib - 1) * rtc_currd[sim_calb_tmr]);
    uint32 usecs_til_calib = (uint32)ceil(inst_til_calib / inst_per_usec);

    if (uptr != &sim_timer_units[sim_calb_tmr]) {           /* Not scheduling calibrated timer? */
        if (inst_delay_d >= (double)inst_til_calib) {       /* long wait? */
            stat = sim_clock_coschedule_tmr (uptr, sim_calb_tmr, ticks_til_calib - 1);
            uptr->usecs_remaining = (stat == SCPE_OK) ? usec_delay - usecs_til_calib : 0.0;
            sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - coscheduling with with calibrated timer(%d), ticks=%d, usecs_remaining=%.0f usecs, inst_til_tick=%d\n", 
                       sim_uname(uptr), usec_delay, sim_calb_tmr, ticks_til_calib, uptr->usecs_remaining, inst_til_tick);
            sim_debug (DBG_CHK, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - result = %.0f usecs, %.0f usecs\n", 
                       sim_uname(uptr), usec_delay, sim_timer_activate_time_usecs (ouptr), sim_timer_activate_time_usecs (uptr));
            return stat;
            }
        }
    }
/* 
 * We're here to schedule if:
 * No Calibrated Timer, OR
 * Scheduling the Calibrated Timer OR
 * Short delay
 */
/*
 * Bound delay to avoid overflow.
 * Long delays are usually canceled before they expire, however bounding the 
 * delay will cause sim_activate_time to return inconsistent results when 
 * truncation has happened.
 */
if (inst_delay_d > (double)0x7fffffff)
    inst_delay_d = (double)0x7fffffff;              /* Bound delay to avoid overflow.  */
inst_delay = (int32)inst_delay_d;
#if defined(SIM_ASYNCH_CLOCKS)
if ((sim_asynch_timer) &&
    (usec_delay > sim_idle_rate_ms*1000.0)) {
    double d_now = sim_timenow_double ();
    UNIT *cptr, *prvptr;

    uptr->a_usec_delay = usec_delay;
    uptr->a_due_time = d_now + (usec_delay / 1000000.0);
    uptr->a_due_gtime = sim_gtime () + (sim_timer_inst_per_sec () * (usec_delay / 1000000.0));
    uptr->cancel = &_sim_wallclock_cancel;              /* bind cleanup method */
    uptr->a_is_active = &_sim_wallclock_is_active;
    if (tmr <= SIM_NTIMERS) {                            /* Timer Unit? */
        sim_clock_unit[tmr]->cancel = &_sim_wallclock_cancel;
        sim_clock_unit[tmr]->a_is_active = &_sim_wallclock_is_active;
        }

    sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - queueing wallclock addition at %.6f\n", 
               sim_uname(uptr), usec_delay, uptr->a_due_time);

    pthread_mutex_lock (&sim_timer_lock);
    for (cptr = sim_wallclock_queue, prvptr = NULL; cptr != QUEUE_LIST_END; cptr = cptr->a_next) {
        if (uptr->a_due_time < cptr->a_due_time)
            break;
        prvptr = cptr;
        }
    if (prvptr == NULL) {                           /* inserting at head */
        uptr->a_next = QUEUE_LIST_END;              /* Temporarily mark as active */
        while (sim_wallclock_entry) {               /* wait for any prior entry has been digested */
            sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - queue insert entry %s busy waiting for 1ms\n", 
                       sim_uname(uptr), usec_delay, sim_uname(sim_wallclock_entry));
            pthread_mutex_unlock (&sim_timer_lock);
            sim_os_ms_sleep (1);
            pthread_mutex_lock (&sim_timer_lock);
            }
        sim_wallclock_entry = uptr;
        pthread_mutex_unlock (&sim_timer_lock);
        pthread_cond_signal (&sim_timer_wake);      /* wake the timer thread to deal with it */
        return SCPE_OK;
        }
    else {                                          /* inserting at prvptr */
        uptr->a_next = prvptr->a_next;
        prvptr->a_next = uptr;
        pthread_mutex_unlock (&sim_timer_lock);
        return SCPE_OK;
        }
    }
#endif
stat = _sim_activate (uptr, inst_delay);                /* queue it now */
uptr->usecs_remaining = ((stat == SCPE_OK) && (0.0 < (usec_delay - ceil(inst_delay / inst_per_usec) ))) ? 
                            usec_delay - floor(inst_delay / inst_per_usec) :
                            0.0;
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - queue addition at %d - remnant: %.0f\n", 
           sim_uname(uptr), usec_delay, inst_delay, uptr->usecs_remaining);
sim_debug (DBG_CHK, &sim_timer_dev, "sim_timer_activate_after(%s, %.0f usecs) - result = %.0f usecs, %.0f usecs\n", 
           sim_uname(uptr), usec_delay, sim_timer_activate_time_usecs (ouptr), sim_timer_activate_time_usecs (uptr));
return stat;
}

/* Clock coscheduling routines */

t_stat sim_register_clock_unit_tmr (UNIT *uptr, int32 tmr)
{
if (tmr == SIM_INTERNAL_CLK)
    tmr = SIM_NTIMERS;
else {
    if ((tmr < 0) || (tmr > SIM_NTIMERS))
        return SCPE_IERR;
    }
if (NULL == uptr) {                         /* deregistering? */
    /* Migrate any coscheduled devices to the standard queue */
    /* they will fire and subsequently requeue themselves */
    while (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END) {
        UNIT *uptr = sim_clock_cosched_queue[tmr];
        double usecs_remaining = sim_timer_activate_time_usecs (uptr);

        _sim_coschedule_cancel (uptr);
        _sim_activate (uptr, 1);
        uptr->usecs_remaining = usecs_remaining;
        }
    if (sim_clock_unit[tmr]) {
        sim_cancel (sim_clock_unit[tmr]);
        sim_clock_unit[tmr]->dynflags &= ~UNIT_TMR_UNIT;
        }
    sim_clock_unit[tmr] = NULL;
    sim_cancel (&sim_timer_units[tmr]);
    return SCPE_OK;
    }
if (NULL == sim_clock_unit[tmr])
    sim_clock_cosched_queue[tmr] = QUEUE_LIST_END;
sim_clock_unit[tmr] = uptr;
uptr->dynflags |= UNIT_TMR_UNIT;
sim_timer_units[tmr].flags = ((tmr == SIM_NTIMERS) ? 0 : UNIT_DIS) | 
                             (sim_clock_unit[tmr] ? UNIT_IDLE : 0);
return SCPE_OK;
}

/* Default timer is 0, otherwise use a calibrated one if it exists */
int32 sim_rtcn_calibrated_tmr (void)
{
return ((rtc_currd[0] && rtc_hz[0]) ? 0 : ((sim_calb_tmr != -1) ? sim_calb_tmr : 0));
}

int32 sim_rtcn_tick_size (int32 tmr)
{
return (rtc_currd[tmr]) ? rtc_currd[tmr] : 10000;
}

t_stat sim_register_clock_unit (UNIT *uptr)
{
return sim_register_clock_unit_tmr (uptr, 0);
}

t_stat sim_clock_coschedule (UNIT *uptr, int32 interval)
{
int32 tmr = sim_rtcn_calibrated_tmr ();
int32 ticks = (interval + (sim_rtcn_tick_size (tmr)/2))/sim_rtcn_tick_size (tmr);/* Convert to ticks */

sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule(%s, interval=%d, ticks=%d)\n", sim_uname(uptr), interval, ticks);
return sim_clock_coschedule_tmr (uptr, tmr, ticks);
}

t_stat sim_clock_coschedule_abs (UNIT *uptr, int32 interval)
{
sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_abs(%s, interval=%d)\n", sim_uname(uptr), interval);
sim_cancel (uptr);
return sim_clock_coschedule (uptr, interval);
}

/* ticks - 0 means on the next tick, 1 means the second tick, etc.  */

t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks)
{
if (ticks < 0)
    return SCPE_ARG;
if (sim_is_active (uptr)) {
    sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule_tmr(%s, tmr=%d, ticks=%d) - already active\n", sim_uname (uptr), tmr, ticks);
    return SCPE_OK;
    }
if (tmr == SIM_INTERNAL_CLK)
    tmr = SIM_NTIMERS;
else {
    if ((tmr < 0) || (tmr > SIM_NTIMERS))
        return sim_activate (uptr, MAX(1, ticks) * 10000);
    }
if ((NULL == sim_clock_unit[tmr]) || (rtc_hz[tmr] == 0)) {
    sim_debug (DBG_TIM, &sim_timer_dev, "sim_clock_coschedule_tmr(%s, tmr=%d, ticks=%d) - no clock activating after %d instructions\n", sim_uname (uptr), tmr, ticks, ticks * (rtc_currd[tmr] ? rtc_currd[tmr] : rtc_currd[sim_rtcn_calibrated_tmr ()]));
    return sim_activate (uptr, ticks * (rtc_currd[tmr] ? rtc_currd[tmr] : rtc_currd[sim_rtcn_calibrated_tmr ()]));
    }
else {
    UNIT *cptr, *prvptr;
    int32 accum;

    if (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END)
        sim_clock_cosched_queue[tmr]->time = sim_cosched_interval[tmr];
    prvptr = NULL;
    accum = 0;
    for (cptr = sim_clock_cosched_queue[tmr]; cptr != QUEUE_LIST_END; cptr = cptr->next) {
        if (ticks < (accum + cptr->time))
            break;
        accum += cptr->time;
        prvptr = cptr;
        }
    if (prvptr == NULL) {
        cptr = uptr->next = sim_clock_cosched_queue[tmr];
        sim_clock_cosched_queue[tmr] = uptr;
        }
    else {
        cptr = uptr->next = prvptr->next;
        prvptr->next = uptr;
        }
    uptr->time = ticks - accum;
    if (cptr != QUEUE_LIST_END)
        cptr->time = cptr->time - uptr->time;
    uptr->cancel = &_sim_coschedule_cancel;             /* bind cleanup method */
    if (uptr == sim_clock_cosched_queue[tmr])
        sim_cosched_interval[tmr] = sim_clock_cosched_queue[tmr]->time;
    sim_debug (DBG_QUE, &sim_timer_dev, "sim_clock_coschedule_tmr(%s, tmr=%d, ticks=%d, hz=%d) - queueing for clock co-schedule, interval now: %d\n", sim_uname (uptr), tmr, ticks, rtc_hz[tmr], sim_cosched_interval[tmr]);
    }
return SCPE_OK;
}

t_stat sim_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 ticks)
{
sim_cancel (uptr);
return sim_clock_coschedule_tmr (uptr, tmr, ticks);
}

/* Cancel a unit on the coschedule queue */
static t_bool _sim_coschedule_cancel (UNIT *uptr)
{
AIO_UPDATE_QUEUE;
if (uptr->next) {                           /* On a queue? */
    int tmr;
    UNIT *nptr;

    for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
        if (sim_clock_unit[tmr]) {
            if (uptr == sim_clock_cosched_queue[tmr]) {
                nptr = sim_clock_cosched_queue[tmr] = uptr->next;
                uptr->next = NULL;
                }
            else {
                UNIT *cptr;

                for (cptr = sim_clock_cosched_queue[tmr];
                     (cptr != QUEUE_LIST_END);
                     cptr = cptr->next) {
                    if (cptr->next == uptr) {
                        nptr = cptr->next = (uptr)->next;
                        uptr->next = NULL;
                        break;
                        }
                    }
                }
            if (uptr->next == NULL) {           /* found? */
                uptr->cancel = NULL;
                uptr->usecs_remaining = 0;
                if (nptr != QUEUE_LIST_END)
                    nptr->time += uptr->time;
                sim_debug (DBG_QUE, &sim_timer_dev, "Canceled Clock Coscheduled Event for %s\n", sim_uname(uptr));
                return TRUE;
                }
            }
        }
    }
return FALSE;
}

t_bool sim_timer_is_active (UNIT *uptr)
{
int32 tmr;

if (!(uptr->dynflags & UNIT_TMR_UNIT))
    return FALSE;
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
    if (sim_clock_unit[tmr] == uptr)
        return sim_is_active (&sim_timer_units[tmr]);
    }
return FALSE;
}

t_bool sim_timer_cancel (UNIT *uptr)
{
int32 tmr;

if (!(uptr->dynflags & UNIT_TMR_UNIT))
    return SCPE_IERR;
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
    if (sim_clock_unit[tmr] == uptr)
        return sim_cancel (&sim_timer_units[tmr]);
    }
return SCPE_IERR;
}

#if defined(SIM_ASYNCH_CLOCKS)
static t_bool _sim_wallclock_cancel (UNIT *uptr)
{
int32 tmr;
t_bool b_return = FALSE;

AIO_UPDATE_QUEUE;
pthread_mutex_lock (&sim_timer_lock);
/* If this is a clock unit, we need to cancel both this and the related timer unit */
for (tmr=0; tmr<=SIM_NTIMERS; tmr++)
    if (sim_clock_unit[tmr] == uptr) {
        uptr = &sim_timer_units[tmr];
        break;
        }
if (uptr->a_next) {
    UNIT *cptr;

    if (uptr == sim_wallclock_entry) {  /* Pending on the queue? */
        sim_wallclock_entry = NULL;
        uptr->a_next = NULL;
        }
    else {
        if (uptr == sim_wallclock_queue) {
            sim_wallclock_queue = uptr->a_next;
            uptr->a_next = NULL;
            sim_debug (DBG_QUE, &sim_timer_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));
            pthread_cond_signal (&sim_timer_wake);
            }
        else {
            for (cptr = sim_wallclock_queue;
                (cptr != QUEUE_LIST_END);
                cptr = cptr->a_next) {
                if (cptr->a_next == (uptr)) {
                    cptr->a_next = (uptr)->a_next;
                    uptr->a_next = NULL;
                    sim_debug (DBG_QUE, &sim_timer_dev, "Canceled Timer Event for %s\n", sim_uname(uptr));
                    break;
                    }
                }
            }
        }
    if (uptr->a_next == NULL) {
        uptr->a_due_time = uptr->a_due_gtime = uptr->a_usec_delay = 0;
        uptr->cancel = NULL;
        uptr->a_is_active = NULL;
        if (tmr <= SIM_NTIMERS) {                        /* Timer Unit? */
            sim_clock_unit[tmr]->cancel = NULL;
            sim_clock_unit[tmr]->a_is_active = NULL;
            }
        b_return = TRUE;
        }
    }
pthread_mutex_unlock (&sim_timer_lock);
return b_return;
}

static t_bool _sim_wallclock_is_active (UNIT *uptr)
{
int32 tmr;

if (uptr->a_next)
    return TRUE;
/* If this is a clock unit, we need to examine the related timer unit instead */
for (tmr=0; tmr<=SIM_NTIMERS; tmr++)
    if (sim_clock_unit[tmr] == uptr)
        return (sim_timer_units[tmr].a_next != NULL);
return FALSE;
}
#endif /* defined(SIM_ASYNCH_CLOCKS) */

int32 _sim_timer_activate_time (UNIT *uptr)
{
UNIT *cptr;
int32 tmr;

#if defined(SIM_ASYNCH_CLOCKS)
if (uptr->a_is_active == &_sim_wallclock_is_active) {
    double d_result;

    pthread_mutex_lock (&sim_timer_lock);
    if (uptr == sim_wallclock_entry) {
        d_result = uptr->a_due_gtime - sim_gtime ();
        if (d_result < 0.0)
            d_result = 0.0;
        if (d_result > (double)0x7FFFFFFE)
            d_result = (double)0x7FFFFFFE;
        pthread_mutex_unlock (&sim_timer_lock);
        return ((int32)d_result) + 1;
        }
    for (cptr = sim_wallclock_queue;
         cptr != QUEUE_LIST_END;
         cptr = cptr->a_next)
        if (uptr == cptr) {
            d_result = uptr->a_due_gtime - sim_gtime ();
            if (d_result < 0.0)
                d_result = 0.0;
            if (d_result > (double)0x7FFFFFFE)
                d_result = (double)0x7FFFFFFE;
            pthread_mutex_unlock (&sim_timer_lock);
            return ((int32)d_result) + 1;
            }
    pthread_mutex_unlock (&sim_timer_lock);
    }
if (uptr->a_next)
    return uptr->a_event_time + 1;
#endif /* defined(SIM_ASYNCH_CLOCKS) */

if (uptr->cancel == &_sim_coschedule_cancel) {
    for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
        int32 accum = 0;

        for (cptr = sim_clock_cosched_queue[tmr]; cptr != QUEUE_LIST_END; cptr = cptr->next) {
            if (cptr == sim_clock_cosched_queue[tmr]) {
                if (sim_cosched_interval[tmr] > 0)
                    accum += sim_cosched_interval[tmr];
                }
            else
                accum += cptr->time;
            if (cptr == uptr)
                return (rtc_currd[tmr] * accum) + sim_activate_time (&sim_timer_units[tmr]);
            }
        }
    }
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
    if ((uptr == &sim_timer_units[tmr]) && (uptr->next)){
        return _sim_activate_time (&sim_timer_units[tmr]);
        }
    }
return -1;                                          /* Not found. */    
}

double sim_timer_activate_time_usecs (UNIT *uptr)
{
UNIT *cptr;
int32 tmr;
double result = -1.0;

/* If this is a clock unit, we need to return the related clock assist unit instead */
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
    if (sim_clock_unit[tmr] == uptr) {
        uptr = &sim_timer_units[tmr];
        break;
        }
    }

if (!sim_is_active (uptr)) {
    sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) - not active\n", sim_uname (uptr));
    return result;
    }
#if defined(SIM_ASYNCH_CLOCKS)
if (uptr->a_is_active == &_sim_wallclock_is_active) {
    pthread_mutex_lock (&sim_timer_lock);
    if (uptr == sim_wallclock_entry) {
        result = uptr->a_due_gtime - sim_gtime ();
        if (result < 0.0)
            result = 0.0;
        pthread_mutex_unlock (&sim_timer_lock);
        result = uptr->usecs_remaining + (1000000.0 * (result / sim_timer_inst_per_sec ())) + 1;
        sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) wallclock_entry - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ());
        return result;
        }
    for (cptr = sim_wallclock_queue;
         cptr != QUEUE_LIST_END;
         cptr = cptr->a_next)
        if (uptr == cptr) {
            result = uptr->a_due_gtime - sim_gtime ();
            if (result < 0.0)
                result = 0.0;
            pthread_mutex_unlock (&sim_timer_lock);
            result = uptr->usecs_remaining + (1000000.0 * (result / sim_timer_inst_per_sec ())) + 1;
            sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) wallclock - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ());
            return result;
            }
    pthread_mutex_unlock (&sim_timer_lock);
    }
if (uptr->a_next) {
    result = uptr->usecs_remaining + (1000000.0 * (uptr->a_event_time / sim_timer_inst_per_sec ())) + 1;
    sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) asynch - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ());
    return result;
    }
#endif /* defined(SIM_ASYNCH_CLOCKS) */

if (uptr->cancel == &_sim_coschedule_cancel) {
    for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
        int32 accum = 0;

        for (cptr = sim_clock_cosched_queue[tmr]; cptr != QUEUE_LIST_END; cptr = cptr->next) {
            if (cptr == sim_clock_cosched_queue[tmr]) {
                if (sim_cosched_interval[tmr] > 0)
                    accum += sim_cosched_interval[tmr];
                }
            else
                accum += cptr->time;
            if (cptr == uptr) {
                result = uptr->usecs_remaining + ceil(1000000.0 * ((rtc_currd[tmr] * accum) + sim_activate_time (&sim_timer_units[tmr]) - 1) / sim_timer_inst_per_sec ());
                sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) coscheduled - %.0f usecs, inst_per_sec=%.0f, tmr=%d, ticksize=%d, ticks=%d, inst_til_tick=%d\n", sim_uname (uptr), result, sim_timer_inst_per_sec (), tmr, rtc_currd[tmr], accum, sim_activate_time (&sim_timer_units[tmr]) - 1);
                return result;
                }
            }
        }
    }
for (tmr=0; tmr<=SIM_NTIMERS; tmr++) {
    if ((uptr == sim_clock_unit[tmr]) && (uptr->next)) {
        result = sim_clock_unit[tmr]->usecs_remaining + (1000000.0 * (sim_activate_time (&sim_timer_units[tmr]) - 1)) / sim_timer_inst_per_sec ();
        sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) clock - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ());
        return result;
        }
    if ((uptr == &sim_timer_units[tmr]) && (uptr->next)){
        result = uptr->usecs_remaining + (1000000.0 * (sim_activate_time (uptr) - 1)) / sim_timer_inst_per_sec ();
        sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) clock - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ());
        return result;
        }
    }
result = uptr->usecs_remaining + (1000000.0 * (sim_activate_time (uptr) - 1)) / sim_timer_inst_per_sec ();
sim_debug (DBG_QUE, &sim_timer_dev, "sim_timer_activate_time_usecs(%s) clock - %.0f usecs, inst_per_sec=%.0f\n", sim_uname (uptr), result, sim_timer_inst_per_sec ());
return result;                                          /* Not found. */    
}

/* read only memory delayed support

   Some simulation activities need a 'regulated' memory access
   time to meet timing assumptions in the code being executed.

   The default calibration determines a way to limit activities
   to 1Mhz for each call to sim_rom_read_with_delay().  If a 
   simulator needs a different delay factor, the 1 Mhz initial 
   value can be queried with sim_get_rom_delay_factor() and the 
   result can be adjusted as nessary and the operating delay
   can be set with sim_set_rom_delay_factor().
*/

SIM_NOINLINE static int32 _rom_swapb(int32 val)
{
return ((val << 24) & 0xff000000) | (( val << 8) & 0xff0000) |
    ((val >> 8) & 0xff00) | ((val >> 24) & 0xff);
}

static volatile int32 rom_loopval = 0;

SIM_NOINLINE int32 sim_rom_read_with_delay (int32 val)
{
uint32 i, l = sim_rom_delay;

for (i = 0; i < l; i++)
    rom_loopval |= (rom_loopval + val) ^ _rom_swapb (_rom_swapb (rom_loopval + val));
return val + rom_loopval;
}

SIM_NOINLINE uint32 sim_get_rom_delay_factor (void)
{
/* Calibrate the loop delay factor at startup.
   Do this 4 times and use the largest value computed. 
   The goal here is to come up with a delay factor which will throttle
   a 6 byte delay loop running from ROM address space to execute
   1 instruction per usec */

if (sim_rom_delay == 0) {
    uint32 i, ts, te, c = 10000, samples = 0;
    while (1) {
        c = c * 2;
        te = sim_os_msec();
        while (te == (ts = sim_os_msec ()));            /* align on ms tick */

/* This is merely a busy wait with some "work" that won't get optimized
   away by a good compiler. loopval always is zero.  To avoid smart compilers,
   the loopval variable is referenced in the function arguments so that the
   function expression is not loop invariant.  It also must be referenced
   by subsequent code to avoid the whole computation being eliminated. */

        for (i = 0; i < c; i++)
            rom_loopval |= (rom_loopval + ts) ^ _rom_swapb (_rom_swapb (rom_loopval + ts));
        te = sim_os_msec (); 
        if ((te - ts) < 50)                         /* sample big enough? */
            continue;
        if (sim_rom_delay < (rom_loopval + (c / (te - ts) / 1000) + 1))
            sim_rom_delay = rom_loopval + (c / (te - ts) / 1000) + 1;
        if (++samples >= 4)
            break;
        c = c / 2;
        }
    if (sim_rom_delay < 5)
        sim_rom_delay = 5;
    }
return sim_rom_delay;
}

void sim_set_rom_delay_factor (uint32 delay)
{
sim_rom_delay = delay;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_timer.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/* sim_timer.h: simulator timer library headers

   Copyright (c) 1993-2008, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   28-Apr-07    RMS     Added sim_rtc_init_all
   17-Oct-06    RMS     Added idle support
   02-Jan-04    RMS     Split out from SCP
*/

#ifndef SIM_TIMER_H_
#define SIM_TIMER_H_   0


#ifdef  __cplusplus
extern "C" {
#endif

/* Pick up a struct timespec definition if it is available */
#include <time.h>
#if defined(__struct_timespec_defined)
#define _TIMESPEC_DEFINED
#endif
#if defined(SIM_ASYNCH_IO) || defined(USE_READER_THREAD)
#include <pthread.h>
#endif

#if defined (__APPLE__)
#define HAVE_STRUCT_TIMESPEC 1   /* OSX defined the structure but doesn't tell us */
#endif

/* on HP-UX, CLOCK_REALTIME is enum, not preprocessor define */
#if !defined(CLOCK_REALTIME) && !defined(__hpux)
#define CLOCK_REALTIME 1
#define NEED_CLOCK_GETTIME 1
#if  defined(_MSC_VER)      /* Visual Studio/Visual C++ */
#if _MSC_VER >= 1900        /* Visual Studio Community (2015) */
#define HAVE_STRUCT_TIMESPEC 1
#define _TIMESPEC_DEFINED 1
#endif /* _MSC_VER >= 1900 */
#endif /* defined(_MSC_VER) */
#if !defined(HAVE_STRUCT_TIMESPEC)
#define HAVE_STRUCT_TIMESPEC 1
#if !defined(_TIMESPEC_DEFINED)
#define _TIMESPEC_DEFINED
struct timespec {
    time_t tv_sec;
    long   tv_nsec;
};
#endif /* !defined(_TIMESPEC_DEFINED) */
#endif /* !defined(HAVE_STRUCT_TIMESPEC) */
int clock_gettime(int clock_id, struct timespec *tp);
#endif


#define SIM_NTIMERS     8                           /* # timers */
#define SIM_TMAX        500                         /* max timer makeup */

#define SIM_INITIAL_IPS 500000                      /* uncalibrated assumption */
                                                    /* about instructions per second */

#define SIM_IDLE_CAL    10                          /* ms to calibrate */
#define SIM_IDLE_STMIN  2                           /* min sec for stability */
#define SIM_IDLE_STDFLT 20                          /* dft sec for stability */
#define SIM_IDLE_STMAX  600                         /* max sec for stability */

#define SIM_THROT_WINIT     1000                    /* cycles to skip */
#define SIM_THROT_WST       10000                   /* initial wait */
#define SIM_THROT_WMUL      4                       /* multiplier */
#define SIM_THROT_WMIN      50                      /* min wait */
#define SIM_THROT_DRIFT_PCT 5                       /* drift percentage for recalibrate */
#define SIM_THROT_MSMIN     10                      /* min for measurement */
#define SIM_THROT_NONE      0                       /* throttle parameters */
#define SIM_THROT_MCYC      1                       /* MegaCycles Per Sec */
#define SIM_THROT_KCYC      2                       /* KiloCycles Per Sec */
#define SIM_THROT_PCT       3                       /* Max Percent of host CPU */
#define SIM_THROT_SPC       4                       /* Specific periodic Delay */
#define SIM_THROT_STATE_INIT      0                 /* Starting */
#define SIM_THROT_STATE_TIME      1                 /* Checking Time */
#define SIM_THROT_STATE_THROTTLE  2                 /* Throttling  */

#define TIMER_DBG_IDLE  0x001                       /* Debug Flag for Idle Debugging */
#define TIMER_DBG_QUEUE 0x002                       /* Debug Flag for Asynch Queue Debugging */
#define TIMER_DBG_MUX   0x004                       /* Debug Flag for Asynch Queue Debugging */

t_bool sim_timer_init (void);
void sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub);
double sim_timenow_double (void);
int32 sim_rtcn_init (int32 time, int32 tmr);
int32 sim_rtcn_init_unit (UNIT *uptr, int32 time, int32 tmr);
void sim_rtcn_get_time (struct timespec *now, int tmr);
t_stat sim_rtcn_tick_ack (uint32 time, int32 tmr);
void sim_rtcn_init_all (void);
int32 sim_rtcn_calb (int32 ticksper, int32 tmr);
int32 sim_rtc_init (int32 time);
int32 sim_rtc_calb (int32 ticksper);
t_stat sim_set_timers (int32 arg, CONST char *cptr);
t_stat sim_show_timers (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc);
t_stat sim_show_clock_queues (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
t_bool sim_idle (uint32 tmr, int sin_cyc);
t_stat sim_set_throt (int32 arg, CONST char *cptr);
t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, CONST char *cptr);
t_stat sim_set_idle (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_clr_idle (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
void sim_throt_sched (void);
void sim_throt_cancel (void);
uint32 sim_os_msec (void);
void sim_os_sleep (unsigned int sec);
uint32 sim_os_ms_sleep (unsigned int msec);
uint32 sim_os_ms_sleep_init (void);
void sim_start_timer_services (void);
void sim_stop_timer_services (void);
t_stat sim_timer_change_asynch (void);
t_stat sim_timer_activate (UNIT *uptr, int32 interval);
t_stat sim_timer_activate_after (UNIT *uptr, double usec_delay);
int32 _sim_timer_activate_time (UNIT *uptr);
double sim_timer_activate_time_usecs (UNIT *uptr);
t_bool sim_timer_is_active (UNIT *uptr);
t_bool sim_timer_cancel (UNIT *uptr);
t_stat sim_register_clock_unit (UNIT *uptr);
t_stat sim_register_clock_unit_tmr (UNIT *uptr, int32 tmr);
t_stat sim_clock_coschedule (UNIT *uptr, int32 interval);
t_stat sim_clock_coschedule_abs (UNIT *uptr, int32 interval);
t_stat sim_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks);
t_stat sim_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 ticks);
double sim_timer_inst_per_sec (void);
int32 sim_rtcn_tick_size (int32 tmr);
int32 sim_rtcn_calibrated_tmr (void);
t_bool sim_timer_idle_capable (uint32 *host_ms_sleep_1, uint32 *host_tick_ms);
#define PRIORITY_BELOW_NORMAL  -1
#define PRIORITY_NORMAL         0
#define PRIORITY_ABOVE_NORMAL   1
t_stat sim_os_set_thread_priority (int below_normal_above);
uint32 sim_get_rom_delay_factor (void);
void sim_set_rom_delay_factor (uint32 delay);
int32 sim_rom_read_with_delay (int32 val);

extern t_bool sim_idle_enab;                        /* idle enabled flag */
extern volatile t_bool sim_idle_wait;               /* idle waiting flag */
extern t_bool sim_asynch_timer;
extern DEVICE sim_timer_dev;
extern UNIT * volatile sim_clock_cosched_queue[SIM_NTIMERS+1];
extern const t_bool rtc_avail;

#ifdef  __cplusplus
}
#endif

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































Deleted src/sim_tmxr.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
/* sim_tmxr.c: Telnet terminal multiplexer library

   Copyright (c) 2001-2011, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   Based on the original DZ11 simulator by Thord Nilson, as updated by
   Arthur Krewat.

   12-Oct-12    MP      Revised serial port support to not require changes to 
                        any code in TMXR library using code.  Added support
                        for per line listener ports and outgoing tcp connections.
   02-Jun-11    MP      Fixed telnet option negotiation loop with some clients
                        Added Option Negotiation and Debugging Support
   17-Jan-11    MP      Added Buffered line capabilities
   16-Jan-11    MP      Made option negotiation more reliable
   20-Nov-08    RMS     Added three new standardized SHOW routines
   05-Nov-08    JDB     Moved logging call after connection check in tmxr_putc_ln
   03-Nov-08    JDB     Added TMXR null check to tmxr_find_ldsc
   07-Oct-08    JDB     Added initial serial port support
   30-Sep-08    JDB     Reverted tmxr_find_ldsc to original implementation
   27-May-08    JDB     Added line connection order to tmxr_poll_conn,
                        added tmxr_set_lnorder and tmxr_show_lnorder
   14-May-08    JDB     Print device and line to which connection was made
   11-Apr-07    JDB     Worked around Telnet negotiation problem with QCTerm
   16-Aug-05    RMS     Fixed C++ declaration and cast problems
   29-Jun-05    RMS     Extended tmxr_dscln to support unit array devices
                        Fixed bug in SET LOG/NOLOG
   04-Jan-04    RMS     Changed TMXR ldsc to be pointer to linedesc array
                        Added tmxr_linemsg, circular output pointers, logging
                        (from Mark Pizzolato)
   29-Dec-03    RMS     Added output stall support
   01-Nov-03    RMS     Cleaned up attach routine
   09-Mar-03    RMS     Fixed bug in SHOW CONN
   22-Dec-02    RMS     Fixed bugs in IAC+IAC receive and transmit sequences
                        Added support for received break (all from by Mark Pizzolato)
                        Fixed bug in attach
   31-Oct-02    RMS     Fixed bug in 8b (binary) support
   22-Aug-02    RMS     Added tmxr_open_master, tmxr_close_master
   30-Dec-01    RMS     Added tmxr_fstats, tmxr_dscln, renamed tmxr_fstatus
   03-Dec-01    RMS     Changed tmxr_fconns for extended SET/SHOW
   20-Oct-01    RMS     Fixed bugs in read logic (found by Thord Nilson).
                        Added tmxr_rqln, tmxr_tqln

   This library includes:

   tmxr_poll_conn -                     poll for connection
   tmxr_reset_ln -                      reset line (drops Telnet/tcp and serial connections)
   tmxr_detach_ln -                     reset line and close per line listener and outgoing destination
   tmxr_getc_ln -                       get character for line
   tmxr_get_packet_ln -                 get packet from line
   tmxr_get_packet_ln_ex -              get packet from line with separater byte
   tmxr_poll_rx -                       poll receive
   tmxr_putc_ln -                       put character for line
   tmxr_put_packet_ln -                 put packet on line
   tmxr_put_packet_ln_ex -              put packet on line with separator byte
   tmxr_poll_tx -                       poll transmit
   tmxr_send_buffered_data -            transmit buffered data
   tmxr_set_modem_control_passthru -    enable modem control on a multiplexer
   tmxr_clear_modem_control_passthru -  disable modem control on a multiplexer
   tmxr_set_get_modem_bits -            set and/or get a line modem bits
   tmxr_set_line_loopback -             enable or disable loopback mode on a line
   tmxr_get_line_loopback -             returns the current loopback status of a line
   tmxr_set_line_halfduplex -           enable or disable halfduplex mode on a line
   tmxr_get_line_halfduplex -           returns the current halfduplex status of a line
   tmxr_set_config_line -               set port speed, character size, parity and stop bits
   tmxr_open_master -                   open master connection
   tmxr_close_master -                  close master connection
   tmxr_attach  -                       attach terminal multiplexor to listening port
   tmxr_detach  -                       detach terminal multiplexor to listening port
   tmxr_attach_help  -                  help routine for attaching multiplexer devices
   tmxr_set_line_unit -                 set the unit which polls for input for a given line
   tmxr_ex      -                       (null) examine
   tmxr_dep     -                       (null) deposit
   tmxr_msg     -                       send message to socket
   tmxr_linemsg -                       send message to line
   tmxr_linemsgf -                      send formatted message to line
   tmxr_fconns  -                       output connection status
   tmxr_fstats  -                       output connection statistics
   tmxr_set_log -                       enable logging for line
   tmxr_set_nolog -                     disable logging for line
   tmxr_show_log -                      show logging status for line
   tmxr_dscln   -                       disconnect line (SET routine)
   tmxr_rqln    -                       number of available characters for line
   tmxr_tqln    -                       number of buffered characters for line
   tmxr_tpqln    -                      number of buffered packet characters for line
   tmxr_tpbusyln -                      transmit packet busy status for line
   tmxr_set_lnorder -                   set line connection order
   tmxr_show_lnorder -                  show line connection order
   tmxr_show_summ -                     show connection summary
   tmxr_show_cstat -                    show line connections or status
   tmxr_show_lines -                    show number of lines
   tmxr_show_open_devices -             show info about all open tmxr devices 

   All routines are OS-independent.


    This library supports the simulation of multiple-line terminal multiplexers.
    It may also be used to create single-line "multiplexers" to provide
    additional terminals beyond the simulation console.  It may also be used to 
    create single-line or multi-line simulated synchronous (BiSync) devices.
    Multiplexer lines may be connected to terminal emulators supporting the 
    Telnet protocol via sockets, or to hardware terminals via host serial
    ports.  Concurrent Telnet and serial connections may be mixed on a given 
    multiplexer.

    When connecting via sockets, the simulated multiplexer is attached to a
    listening port on the host system:

      sim> attach MUX 23
      Listening on port 23

    Once attached, the listening port must be polled for incoming connections.
    When a connection attempt is received, it will be associated with the next
    multiplexer line in the user-specified line order, or with the next line in
    sequence if no order has been specified.  Individual lines may be connected
    to serial ports or remote systems via TCP (telnet or not as desired), OR 
    they may have separate listening TCP ports.

    Logging of Multiplexer Line output:
    
    The traffic going out multiplexer lines can be logged to files.  A single
    line multiplexer can log it's traffic with the following command:

        sim> atta MUX 23,Log=LogFileName
        sim> atta MUX Connect=ser0,Log=LogFileName

    Specifying a Log value for a multi-line multiplexer is specifying a 
    template filename.  The actual file name used for each line will be
    the indicated filename with _n appended (n being the line number).

    Buffered Multiplexer Line:

    A Multiplexer Line Buffering has been implemented.  A Buffered Line will 
    have a copy of the last 'buffer size' bytes of output retained in a line
    specific buffer.  The contents of this buffer will be transmitted out any
    new connection on that line when a new telnet session is established.

    This capability is most useful for the Console Telnet session.  When a
    Console Telnet session is Buffered, a simulator will start (via BOOT CPU 
    or whatever is appropriate for a particular simulator) without needing to 
    have an active telnet connection.  When a Telnet connection comes along 
    for the telnet port, the contents of the saved buffer (which wraps on 
    overflow) are presented on the telnet session as output before session 
    traffic.  This allows the connecting telnet client to see what happened 
    before he connected since the likely reason he might be connecting to the 
    console of a background simulator is to troubleshoot unusual behavior, 
    the details of which may have already been sent to the console.

    Serial Port support:

    Serial ports may be specified as an operating system specific device names
    or using simh generic serial names.  simh generic names are of the form 
    serN, where N is from 0 thru one less than the maximum number of serial 
    ports on the local system.  The mapping of simh generic port names to OS 
    specific names can be displayed using the following command:

        sim> show serial
        Serial devices:
         ser0   COM1 (\Device\Serial0)
         ser1   COM3 (Winachcf0)        

        sim> attach MUX Line=2,Connect=ser0

    or equivalently

        sim> attach MUX Line=2,Connect=COM1

    An optional configuration string may be present after the port name.  If
    present, it must be separated from the port name with a semicolon and has
    this form:

       <rate>-<charsize><parity><stopbits>

    where:

      rate     = communication rate in bits per second
      charsize = character size in bits (5-8, including optional parity)
      parity   = parity designator (N/E/O/M/S for no/even/odd/mark/space parity)
      stopbits = number of stop bits (1, 1.5, or 2)

     As an example:

        9600-8n1

    The supported rates, sizes, and parity options are host-specific.  If 
    a configuration string is not supplied, then the default of 9600-8N1 
    is used.

    An attachment to a serial port with the '-V' switch will cause a 
    connection message to be output to the connected serial port.
    This will help to confirm the correct port has been connected and 
    that the port settings are reasonable for the connected device.
    This would be done as:
     
        sim> attach -V MUX Connect=SerN
        

    Line specific tcp listening ports are supported.  These are configured 
    using commands of the form:
     
        sim> attach MUX Line=2,port{;notelnet}

    Direct computer to computer connections (Virutal Null Modem cables) may 
    be established using the telnet protocol or via raw tcp sockets.
     
        sim> attach MUX Line=2,Connect=host:port{;notelnet}

    Computer to computer virtual connections can be one way (as illustrated 
    above) or symmetric.  A symmetric connection is configured by combining 
    a one way connection with a tcp listening port on the same line:

        sim> attach MUX Line=2,Connect=host:port,listenport

    When symmetric virtual connections are configured, incoming connections 
    on the specified listening port are checked to assure that they actually 
    come from the specified connection destination host system.



     The command syntax for a single line device (MX) is:

        sim> attach MX port{;notelnet}
        sim> attach MX Connect=serN{;config}
        sim> attach MX Connect=COM9{;config}
        sim> attach MX Connect=host:port{;notelnet}

     The command syntax for ANY multi-line device is:

        sim> attach MX port{;notelnet}              ; Defines the master listening port for the mux and optionally allows non-telnet (i.e. raw socket) operation for all lines.
        sim> attach MX Line=n,port{;notelnet}       ; Defines a line specific listen port for a particular line. Each line can have a separate listen port and the mux can have its own as well.  Optionally disable telnet wire protocol (i.e. raw socket)
        sim> attach MX Line=n,Connect=serN{;config} ; Connects line n to simh generic serial port N (port list visible with the sim> SHOW SERIAL command), the optional ";config" data specifies the speed, parity and stop bits for the connection
                                                    ; DTR (and RTS) will be raised at attach time and will drop at detach/disconnect time
        sim> attach MX Line=n,Connect=host:port{;notelnet} ; Causes a connection to be established to the designated host:port.  The actual connection will happen in a non-blocking fashion and will be completed and/or re-established by the normal tmxr_poll_conn activities
     
     All connections configured for any multiplexer device are unconfigured by:

        sim> detach MX                              ; detaches ALL connections/ports/sessions on the MUX.

    Console serial connections are achieved by:

        sim> set console serial=serN{;config}
    or
        sim> set console serial=COM2{;config}

    A line specific listening port (12366) can be specified by the following:

        sim> attach MUX Line=2,12366

    A line specific remote telnet (or raw tcp) destination can be specified 
    by the following:

        sim> attach MUX Line=2,Connect=remotehost:port

    If a connection to a remotehost:port wants a raw binary data channel 
    (instead of a telnet session) the following would be used:

        sim> attach MUX Line=2,Connect=remotehost:port;notelnet

    A single line multiplexor can indicate any of the above line options 
    without specifying a line number:

        sim> attach MUX Connect=ser0;9600-8N1
        sim> attach MUX 12366
        sim> attach MUX Connect=remotehost:port
        sim> attach MUX Connect=remotehost:port;notelnet

    A multiplexor can disconnect all (telnet, serial and outgoing) previous
    attachments with:

        sim> detach MUX

   A device emulation may choose to implement a command interface to 
   disconnect specific individual lines.  This would usually be done via
   a Unit Modifier table entry (MTAB) which dispatches the command 
   "SET dev DISCONNECT[=line]" to tmxr_dscln.  This will cause a telnet 
   connection to be closed, but a serial port will normally have DTR 
   dropped for 500ms and raised again (thus hanging up a modem on that 
   serial port).

     sim> set MUX disconnect=2

   A line which is connected to a serial port can be manually closed by
   adding the -C switch to a disconnect command.

     sim> set -C MUX disconnect=2

    Full Modem Control serial port support.

    This library supports devices which wish to emulate full modem 
    control/signalling for serial ports.  Any device emulation which wishes 
    to support this functionality for attached serial ports must call
    "tmxr_set_modem_control_passthru" before any call to tmxr_attach.  
    This disables automatic DTR (&RTS) manipulation by this library.
    Responsibility for manipulating DTR falls on the simulated operating 
    system.  Calling tmxr_set_modem_control_passthru would usually be in 
    a device reset routine.  It may also be called by a device attach
    routine based on user specified options.
    Once support for full modem control has been declared by a device 
    emulation for a particular TMXR device, this library will make no 
    direct effort to manipulate modem bits while connected to serial ports.
    The "tmxr_set_get_modem_bits" API exists to allow the device emulation 
    layer to query and control modem signals.  The "tmxr_set_config_line" 
    API exists to allow the device emulation layer to change port settings 
    (baud rate, parity and stop bits).  A modem_control enabled line 
    merely passes the VM's port status bits, data and settings through to 
    and from the serial port.  

    The "tmxr_set_get_modem_bits" and "tmxr_set_config_line" APIs will 
    ONLY work on a modem control enabled TMXR device.

*/

#define NOT_MUX_USING_CODE /* sim_tmxr library define */

#include "sim_defs.h"
#include "sim_serial.h"
#include "sim_sock.h"
#include "sim_timer.h"
#include "sim_tmxr.h"
#include "scp.h"

#include <ctype.h>
#include <math.h>

/* Telnet protocol constants - negatives are for init'ing signed char data */

/* Commands */
#define TN_IAC          0xFFu /* -1 */                  /* protocol delim */
#define TN_DONT         0xFEu /* -2 */                  /* dont */
#define TN_DO           0xFDu /* -3 */                  /* do */
#define TN_WONT         0xFCu /* -4 */                  /* wont */
#define TN_WILL         0xFBu /* -5 */                  /* will */
#define TN_SB           0xFAu /* -6 */                  /* sub-option negotiation */
#define TN_GA           0xF9u /* -7 */                  /* go ahead */
#define TN_EL           0xF8u /* -8 */                  /* erase line */
#define TN_EC           0xF7u /* -9 */                  /* erase character */
#define TN_AYT          0xF6u /* -10 */                 /* are you there */
#define TN_AO           0xF5u /* -11 */                 /* abort output */
#define TN_IP           0xF4u /* -12 */                 /* interrupt process */
#define TN_BRK          0xF3u /* -13 */                 /* break */
#define TN_DATAMK       0xF2u /* -14 */                 /* data mark */
#define TN_NOP          0xF1u /* -15 */                 /* no operation */
#define TN_SE           0xF0u /* -16 */                 /* end sub-option negot */

/* Options */

#define TN_BIN            0                             /* bin */
#define TN_ECHO           1                             /* echo */
#define TN_SGA            3                             /* sga */
#define TN_STATUS         5                             /* option status query */
#define TN_TIMING         6                             /* Timing Mark */
#define TN_NAOCRD        10                             /* Output Carriage-Return Disposition */
#define TN_NAOHTS        11                             /* Output Horizontal Tab Stops */
#define TN_NAOHTD        12                             /* Output Horizontal Tab Stop Disposition */
#define TN_NAOFFD        13                             /* Output Forfeed Disposition */
#define TN_NAOVTS        14                             /* Output Vertical Tab Stop */
#define TN_NAOVTD        15                             /* Output Vertical Tab Stop Disposition */
#define TN_NAOLFD        16                             /* Output Linefeed Disposition */
#define TN_EXTEND        17                             /* Extended Ascii */
#define TN_LOGOUT        18                             /* Logout */
#define TN_BM            19                             /* Byte Macro */
#define TN_DET           20                             /* Data Entry Terminal */
#define TN_SENDLO        23                             /* Send Location */
#define TN_TERMTY        24                             /* Terminal Type */
#define TN_ENDREC        25                             /* Terminal Type */
#define TN_TUID          26                             /* TACACS User Identification */
#define TN_OUTMRK        27                             /* Output Marking */
#define TN_TTYLOC        28                             /* Terminal Location Number */
#define TN_3270          29                             /* 3270 Regime */
#define TN_X3PAD         30                             /* X.3 PAD */
#define TN_NAWS          31                             /* Negotiate About Window Size */
#define TN_TERMSP        32                             /* Terminal Speed */
#define TN_TOGFLO        33                             /* Remote Flow Control */
#define TN_LINE          34                             /* line mode */
#define TN_XDISPL        35                             /* X Display Location */
#define TN_ENVIRO        36                             /* Environment */
#define TN_AUTH          37                             /* Authentication */
#define TN_ENCRYP        38                             /* Data Encryption */
#define TN_NEWENV        39                             /* New Environment */
#define TN_TN3270        40                             /* TN3270 Enhancements */
#define TN_CHARST        42                             /* CHARSET */
#define TN_COMPRT        44                             /* Com Port Control */
#define TN_KERMIT        47                             /* KERMIT */

#define TN_CR           015                             /* carriage return */
#define TN_LF           012                             /* line feed */
#define TN_NUL          000                             /* null */

/* Telnet line states */

#define TNS_NORM        000                             /* normal */
#define TNS_IAC         001                             /* IAC seen */
#define TNS_WILL        002                             /* WILL seen */
#define TNS_WONT        003                             /* WONT seen */
#define TNS_SKIP        004                             /* skip next cmd */
#define TNS_CRPAD       005                             /* CR padding */
#define TNS_DO          006                             /* DO request pending rejection */

/* Telnet Option Sent Flags */

#define TNOS_DONT       001                             /* Don't has been sent */
#define TNOS_WONT       002                             /* Won't has been sent */

static BITFIELD tmxr_modem_bits[] = {
  BIT(DTR),                                 /* Data Terminal Ready */
  BIT(RTS),                                 /* Request To Send     */
  BIT(DCD),                                 /* Data Carrier Detect */
  BIT(RNG),                                 /* Ring Indicator      */
  BIT(CTS),                                 /* Clear To Send       */
  BIT(DSR),                                 /* Data Set Ready      */
  ENDBITS
};

static u_char mantra[] = {                  /* Telnet Option Negotiation Mantra */
    TN_IAC, TN_WILL, TN_LINE,
    TN_IAC, TN_WILL, TN_SGA,
    TN_IAC, TN_WILL, TN_ECHO,
    TN_IAC, TN_WILL, TN_BIN,
    TN_IAC, TN_DO, TN_BIN
    };

#define TMXR_GUARD  ((int32)(lp->serport ? 1 : sizeof(mantra)))/* buffer guard */

/* Local routines */

static void tmxr_add_to_open_list (TMXR* mux);

/* Initialize the line state.

   Reset the line state to represent an idle line.  Note that we do not clear
   all of the line structure members, so a connected line remains connected
   after this call.

   Because a line break is represented by a flag in the "receive break status"
   array, we must zero that array in order to clear any pending break
   indications.
*/

static void tmxr_init_line (TMLN *lp)
{
lp->tsta = 0;                                           /* init telnet state */
lp->xmte = 1;                                           /* enable transmit */
lp->dstb = 0;                                           /* default bin mode */
lp->rxbpr = lp->rxbpi = lp->rxcnt = lp->rxpcnt = 0;     /* init receive indexes */
if (!lp->txbfd || lp->notelnet)                         /* if not buffered telnet */
    lp->txbpr = lp->txbpi = lp->txcnt = lp->txpcnt = 0; /*   init transmit indexes */
lp->txdrp = 0;
tmxr_set_get_modem_bits (lp, 0, 0, NULL);
if ((!lp->mp->buffered) && (!lp->txbfd)) {
    lp->txbfd = 0;
    lp->txbsz = TMXR_MAXBUF;
    lp->txb = (char *)realloc (lp->txb, lp->txbsz);
    lp->rxbsz = TMXR_MAXBUF;
    lp->rxb = (char *)realloc(lp->rxb, lp->rxbsz);
    lp->rbr = (char *)realloc(lp->rbr, lp->rxbsz);
    }
if (lp->loopback) {
    lp->lpbsz = lp->rxbsz;
    lp->lpb = (char *)realloc(lp->lpb, lp->lpbsz);
    lp->lpbcnt = lp->lpbpi = lp->lpbpr = 0;
    }
if (lp->rxpb) {
    lp->rxpboffset = lp->rxpbsize = 0;
    free (lp->rxpb);
    lp->rxpb = NULL;
    }
if (lp->txpb) {
    lp->txpbsize = lp->txppsize = lp->txppoffset = 0;
    free (lp->txpb);
    lp->txpb = NULL;
    }
memset (lp->rbr, 0, lp->rxbsz);                         /* clear break status array */
return;
}


/* Report a connection to a line.

   If the indicated line (lp) is speaking the telnet wire protocol, a 
   notification of the form:

      Connected to the <sim> simulator <dev> device, line <n>

   is sent to the newly connected line.  If the device has only one line, the
   "line <n>" part is omitted.  If the device has not been defined, the "<dev>
   device" part is omitted.

*/

static void tmxr_report_connection (TMXR *mp, TMLN *lp)
{
int32 unwritten, psave;
char cmsg[80];
char dmsg[80] = "";
char lmsg[80] = "";
char msgbuf[256] = "";

if ((!lp->notelnet) || (sim_switches & SWMASK ('V'))) {
    sprintf (cmsg, "\n\r\nConnected to the %s simulator ", sim_name);

    if (mp->dptr) {                                     /* device defined? */
        sprintf (dmsg, "%s device",                     /* report device name */
                       sim_dname (mp->dptr));

        if (mp->lines > 1)                              /* more than one line? */
            sprintf (lmsg, ", line %d", (int)(lp-mp->ldsc));/* report the line number */
        }

    sprintf (msgbuf, "%s%s%s\r\n\n", cmsg, dmsg, lmsg);
    }

if (!mp->buffered) {
    lp->txbpi = 0;                                      /* init buf pointers */
    lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf));
    lp->rxcnt = lp->txcnt = lp->txdrp = 0;              /* init counters */
    lp->rxpcnt = lp->txpcnt = 0;
    }
else
    if (lp->txcnt > lp->txbsz)
        lp->txbpr = (lp->txbpi + 1) % lp->txbsz;
    else
        lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf));

psave = lp->txbpi;                                      /* save insertion pointer */
lp->txbpi = lp->txbpr;                                  /* insert connection message */
tmxr_linemsg (lp, msgbuf);                              /* beginning of buffer */
lp->txbpi = psave;                                      /* restore insertion pointer */

unwritten = tmxr_send_buffered_data (lp);               /* send the message */

if (unwritten == 0)                                     /* buffer now empty? */
    lp->xmte = 1;                                       /* reenable transmission if paused */

lp->txcnt -= (int32)strlen (msgbuf);                    /* adjust statistics */
return;
}


/* Report a disconnection to a line.

   A notification of the form:

      Disconnected from the <sim> simulator

   is sent to the line about to be disconnected.  We do not flush the buffer
   here, because the disconnect routines will do that just after calling us.
*/

static void tmxr_report_disconnection (TMLN *lp)
{
if (lp->notelnet)
    return;
tmxr_linemsgf (lp, "\r\nDisconnected from the %s simulator\r\n\n", sim_name);/* report disconnection */
return;
}

static int32 loop_write_ex (TMLN *lp, char *buf, int32 length, t_bool prefix_datagram)
{
int32 written = 0;
int32 loopfree = lp->lpbsz - lp->lpbcnt;

if (lp->datagram && prefix_datagram) {
    if ((size_t)loopfree < (size_t)(length + sizeof(length)))
        return written;
    loop_write_ex (lp, (char *)&length, sizeof(length), FALSE);
    }
while (length) {
    int32 chunksize;

    loopfree = lp->lpbsz - lp->lpbcnt;
    if (loopfree == 0)
        break;
    if (loopfree < length)
        length = loopfree;
    if (lp->lpbpi >= lp->lpbpr)
        chunksize = lp->lpbsz - lp->lpbpi;
    else
        chunksize = lp->lpbpr - lp->lpbpi;
    if (chunksize > length)
        chunksize = length;
    memcpy (&lp->lpb[lp->lpbpi], buf, chunksize);
    buf += chunksize;
    length -= chunksize;
    written += chunksize;
    lp->lpbpi = (lp->lpbpi + chunksize) % lp->lpbsz;
    }
lp->lpbcnt += written;
return written;
}

static int32 loop_write (TMLN *lp, char *buf, int32 length)
{
return loop_write_ex (lp, buf, length, TRUE);
}

static int32 loop_read_ex (TMLN *lp, char *buf, int32 bufsize)
{
int32 bytesread = 0;

while (bufsize > 0) {
    int32 chunksize;
    int32 loopused = lp->lpbcnt;

    if (loopused < bufsize)
        bufsize = loopused;
    if (loopused == 0)
        break;
    if (lp->lpbpi > lp->lpbpr)
        chunksize = lp->lpbpi - lp->lpbpr;
    else
        chunksize = lp->lpbsz - lp->lpbpr;
    if (chunksize > bufsize)
        chunksize = bufsize;
    memcpy (buf, &lp->lpb[lp->lpbpr], chunksize);
    buf += chunksize;
    bufsize -= chunksize;
    bytesread += chunksize;
    lp->lpbpr = (lp->lpbpr + chunksize) % lp->lpbsz;
    }
lp->lpbcnt -= bytesread;
return bytesread;
}

static int32 loop_read (TMLN *lp, char *buf, int32 bufsize)
{
if (lp->datagram) {
    int32 pktsize;

    if (lp->lpbcnt < (int32)sizeof(pktsize))
        return 0;
    if ((sizeof(pktsize) != loop_read_ex (lp, (char *)&pktsize, sizeof(pktsize))) ||
        (pktsize > bufsize))
        return -1;
    bufsize = pktsize;
    }
return loop_read_ex (lp, buf, bufsize);
}

/* Read from a line.

   Up to "length" characters are read into the character buffer associated with
   line "lp".  The actual number of characters read is returned.  If no
   characters are available, 0 is returned.  If an error occurred while reading,
   -1 is returned.

   If a line break was detected on serial input, the associated receive break
   status flag will be set.  Line break indication for Telnet connections is
   embedded in the Telnet protocol and must be determined externally.
*/

static int32 tmxr_read (TMLN *lp, int32 length)
{
int32 i = lp->rxbpi;

if (lp->loopback)
    return loop_read (lp, &(lp->rxb[i]), length);
if (lp->serport)                                        /* serial port connection? */
    return sim_read_serial (lp->serport, &(lp->rxb[i]), length, &(lp->rbr[i]));
else                                                    /* Telnet connection */
    return sim_read_sock (lp->sock, &(lp->rxb[i]), length);
}


/* Write to a line.

   Up to "length" characters are written from the character buffer associated
   with "lp".  The actual number of characters written is returned.  If an error
   occurred while writing, -1 is returned.
*/

static int32 tmxr_write (TMLN *lp, int32 length)
{
int32 written;
int32 i = lp->txbpr;

if (lp->loopback)
    return loop_write (lp, &(lp->txb[i]), length);

if (lp->serport) {                                      /* serial port connection? */
    if (sim_gtime () < lp->txnexttime)
        return 0;
    written = sim_write_serial (lp->serport, &(lp->txb[i]), length);
    if (written > 0)
        lp->txnexttime = floor (sim_gtime () + (lp->txdelta * sim_timer_inst_per_sec ()));
    return written;
    }
else {                                                  /* Telnet connection */
    written = sim_write_sock (lp->sock, &(lp->txb[i]), length);

    if (written == SOCKET_ERROR)                        /* did an error occur? */
        if (lp->datagram)
            return written;                             /* ignore errors on datagram sockets */
        else
            return -1;                                  /* return error indication */
    else
        return written;
    }
}


/* Remove a character from the read buffer.

   The character at position "p" in the read buffer associated with line "lp" is
   removed by moving all of the following received characters down one position.
   The receive break status array is adjusted accordingly.
*/

static void tmxr_rmvrc (TMLN *lp, int32 p)
{
for ( ; p < lp->rxbpi; p++) {                           /* work from "p" through end of buffer */
    lp->rxb[p] = lp->rxb[p + 1];                        /* slide following character down */
    lp->rbr[p] = lp->rbr[p + 1];                        /* adjust break status too */
    }

lp->rbr[p] = 0;                                         /* clear potential break from vacated slot */
lp->rxbpi = lp->rxbpi - 1;                              /* drop buffer insert index */
return;
}


/* Find a line descriptor indicated by unit or number.

   If "uptr" is NULL, then the line descriptor is determined by the line number
   passed in "val".  If "uptr" is not NULL, then it must point to a unit
   associated with a line, and the line descriptor is determined by the unit
   number, which is derived by the position of the unit in the device's unit
   array.

   Note: This routine may be called with a UNIT that does not belong to the
   device indicated in the TMXR structure.  That is, the multiplexer lines may
   belong to a device other than the one attached to the socket (the HP 2100 MUX
   device is one example).  Therefore, we must look up the device from the unit
   at each call, rather than depending on the DEVICE pointer stored in the TMXR.
*/

static TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, const TMXR *mp)
{
if (mp == NULL)                                         /* invalid multiplexer descriptor? */
    return NULL;                                        /* programming error! */
if (uptr) {                                             /* called from SET? */
    DEVICE *dptr = find_dev_from_unit (uptr);           /* find device */
    if (dptr == NULL)                                   /* what?? */
        return NULL;
    val = (int32) (uptr - dptr->units);                 /* implicit line # */
    }
if ((val < 0) || (val >= mp->lines))                    /* invalid line? */
    return NULL;
return mp->ldsc + val;                                  /* line descriptor */
}


/* Get a line descriptor indicated by a string or unit.

   A pointer to the line descriptor associated with multiplexer "mp" and unit
   "uptr" or specified by string "cptr" is returned.  If "uptr" is non-null,
   then the unit number within its associated device implies the line number.
   If "uptr" is null, then the string "cptr" is parsed for a decimal line
   number.  If the line number is missing, malformed, or outside of the range of
   line numbers associated with "mp", then NULL is returned with status set to
   SCPE_ARG.

   Implementation note:

    1. A return status of SCPE_IERR implies a programming error (passing an
       invalid pointer or an invalid unit).
*/

static TMLN *tmxr_get_ldsc (UNIT *uptr, const char *cptr, TMXR *mp, t_stat *status)
{
t_value  ln;
TMLN    *lp = NULL;
t_stat   code = SCPE_OK;

if (mp == NULL)                                         /* missing mux descriptor? */
    code = SCPE_IERR;                                   /* programming error! */

else if (uptr) {                                        /* implied line form? */
    lp = tmxr_find_ldsc (uptr, mp->lines, mp);          /* determine line from unit */

    if (lp == NULL)                                     /* invalid line number? */
        code = SCPE_IERR;                               /* programming error! */
    }

else if (cptr == NULL)                                  /* named line form, parameter supplied? */
    code = SCPE_MISVAL;                                 /* no, so report missing */

else {
    ln = get_uint (cptr, 10, mp->lines - 1, &code);     /* get line number */

    if (code == SCPE_OK)                                /* line number OK? */
        lp = mp->ldsc + (int32) ln;                     /* use as index to determine line */
    }

if (status)                                             /* return value pointer supplied? */
    *status = code;                                     /* store return status value */

return lp;                                              /* return pointer to line descriptor */
}

/* Generate the Attach string which will fully configure the multiplexer

   Inputs:
        old     =       pointer to the original configuration string which will be replaced
        *mp     =       pointer to multiplexer

   Output:
        a complete attach string for the current state of the multiplexer

*/
static char *growstring(char **string, size_t growth)
{
*string = (char *)realloc (*string, 1 + (*string ? strlen (*string) : 0) + growth);
return *string + strlen(*string);
}

static char *tmxr_mux_attach_string(char *old, TMXR *mp)
{
char* tptr = NULL;
int32 i;
TMLN *lp;

free (old);
tptr = (char *) calloc (1, 1);

if (tptr == NULL)                                       /* no more mem? */
    return tptr;

if (mp->port)                                           /* copy port */
    sprintf (growstring(&tptr, 13 + strlen (mp->port)), "%s%s", mp->port, mp->notelnet ? ";notelnet" : "");
if (mp->logfiletmpl[0])                                 /* logfile info */
    sprintf (growstring(&tptr, 7 + strlen (mp->logfiletmpl)), ",Log=%s", mp->logfiletmpl);
while ((*tptr == ',') || (*tptr == ' '))
    memmove (tptr, tptr+1, strlen(tptr+1)+1);
for (i=0; i<mp->lines; ++i) {
    char *lptr;
    lp = mp->ldsc + i;

    lptr = tmxr_line_attach_string(lp);
    if (lptr) {
        sprintf (growstring(&tptr, 10+strlen(lptr)), "%s%s", *tptr ? "," : "", lptr);
        free (lptr);
        }
    }
if (mp->lines == 1)
    while ((*tptr == ',') || (*tptr == ' '))
        memmove (tptr, tptr+1, strlen(tptr+1)+1);
if (*tptr == '\0') {
    free (tptr);
    tptr = NULL;
    }
return tptr;
}



/* Global routines */


/* Return the Line specific attach setup currently configured for a given line

   Inputs:
        *lp     =       pointer to terminal line descriptor
   Outputs:
        a string which can be used to reconfigure the line, 
        NULL if the line isn't configured

   Note: The returned string is dynamically allocated memory and must be freed 
         when it is no longer needed by calling free

*/

char *tmxr_line_attach_string(TMLN *lp)
{
char* tptr = NULL;

tptr = (char *) calloc (1, 1);

if (tptr == NULL)                                       /* no more mem? */
    return tptr;

if (lp->destination || lp->port || lp->txlogname) {
    if ((lp->mp->lines > 1) || (lp->port))
        sprintf (growstring(&tptr, 32), "Line=%d", (int)(lp-lp->mp->ldsc));
    if (lp->modem_control != lp->mp->modem_control)
        sprintf (growstring(&tptr, 32), ",%s", lp->modem_control ? "Modem" : "NoModem");
    if (lp->txbfd && (lp->txbsz != lp->mp->buffered))
        sprintf (growstring(&tptr, 32), ",Buffered=%d", lp->txbsz);
    if (!lp->txbfd && (lp->mp->buffered > 0))
        sprintf (growstring(&tptr, 32), ",UnBuffered");
    if (lp->mp->datagram != lp->datagram)
        sprintf (growstring(&tptr, 8), ",%s", lp->datagram ? "UDP" : "TCP");
    if (lp->mp->packet != lp->packet)
        sprintf (growstring(&tptr, 8), ",Packet");
    if (lp->port)
        sprintf (growstring(&tptr, 12 + strlen (lp->port)), ",%s%s", lp->port, ((lp->mp->notelnet != lp->notelnet) && (!lp->datagram)) ? (lp->notelnet ? ";notelnet" : ";telnet") : "");
    if (lp->destination) {
        if (lp->serport) {
            char portname[CBUFSIZE];

            get_glyph_nc (lp->destination, portname, ';');
            sprintf (growstring(&tptr, 25 + strlen (lp->destination)), ",Connect=%s%s%s", portname, strcmp("9600-8N1", lp->serconfig) ? ";" : "", strcmp("9600-8N1", lp->serconfig) ? lp->serconfig : "");
            }
        else
            sprintf (growstring(&tptr, 25 + strlen (lp->destination)), ",Connect=%s%s", lp->destination, ((lp->mp->notelnet != lp->notelnet) && (!lp->datagram)) ? (lp->notelnet ? ";notelnet" : ";telnet") : "");
        }
    if (lp->txlogname)
        sprintf (growstring(&tptr, 12 + strlen (lp->txlogname)), ",Log=%s", lp->txlogname);
    if (lp->loopback)
        sprintf (growstring(&tptr, 12 ), ",Loopback");
    }
if (*tptr == '\0') {
    free (tptr);
    tptr = NULL;
    }
return tptr;
}

/*

Set the connection polling interval

*/
t_stat tmxr_connection_poll_interval (TMXR *mp, uint32 seconds)
{
if (0 == seconds)
    return SCPE_ARG;
mp->poll_interval = seconds;
return SCPE_OK;
}

/* Poll for new connection

   Called from unit service routine to test for new connection

   Inputs:
        *mp     =       pointer to terminal multiplexer descriptor
   Outputs:
        line number activated, -1 if none

   If a connection order is defined for the descriptor, and the first value is
   not -1 (indicating default order), then the order array is used to find an
   open line.  Otherwise, a search is made of all lines in numerical sequence.

*/

int32 tmxr_poll_conn (TMXR *mp)
{
SOCKET newsock;
TMLN *lp;
int32 *op;
int32 i, j;
char *address;
char msg[512];
uint32 poll_time = sim_os_msec ();

if (mp->last_poll_time == 0) {                          /* first poll initializations */
    UNIT *uptr = mp->uptr;

    if (!uptr)                                          /* Attached ? */
        return -1;                                      /* No connections are possinle! */

    if (mp->poll_interval == 0)                         /* Assure reasonable polling interval */
        mp->poll_interval = TMXR_DEFAULT_CONNECT_POLL_INTERVAL;

    if (!(uptr->dynflags & TMUF_NOASYNCH)) {            /* if asynch not disabled */
        uptr->dynflags |= UNIT_TM_POLL;                 /* tag as polling unit */
        sim_cancel (uptr);
        }
    for (i=0; i < mp->lines; i++) {
        uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr;

        if (!(mp->uptr->dynflags & TMUF_NOASYNCH)) {    /* if asynch not disabled */
            uptr->dynflags |= UNIT_TM_POLL;             /* tag as polling unit */
            sim_cancel (uptr);
            }
        }
    }

if ((poll_time - mp->last_poll_time) < mp->poll_interval*1000)
    return -1;                                          /* too soon to try */

srand((unsigned int)poll_time);
tmxr_debug_trace (mp, "tmxr_poll_conn()");

mp->last_poll_time = poll_time;

/* Check for a pending Telnet/tcp connection */

if (mp->master) {
    if (mp->ring_sock != INVALID_SOCKET) {  /* Use currently 'ringing' socket if one is active */
        newsock = mp->ring_sock;
        mp->ring_sock = INVALID_SOCKET;
        address = mp->ring_ipad;
        mp->ring_ipad = NULL;
        }
    else
        newsock = sim_accept_conn_ex (mp->master, &address, (mp->packet ? SIM_SOCK_OPT_NODELAY : 0));/* poll connect */

    if (newsock != INVALID_SOCKET) {                    /* got a live one? */
        sprintf (msg, "tmxr_poll_conn() - Connection from %s", address);
        tmxr_debug_connect (mp, msg);
        op = mp->lnorder;                               /* get line connection order list pointer */
        i = mp->lines;                                  /* play it safe in case lines == 0 */
        ++mp->sessions;                                 /* count the new session */

        for (j = 0; j < mp->lines; j++, i++) {          /* find next avail line */
            if (op && (*op >= 0) && (*op < mp->lines))  /* order list present and valid? */
                i = *op++;                              /* get next line in list to try */
            else                                        /* no list or not used or range error */
                i = j;                                  /* get next sequential line */

            lp = mp->ldsc + i;                          /* get pointer to line descriptor */
            if ((lp->conn == FALSE) &&                  /* is the line available? */
                (lp->destination == NULL) &&
                (lp->master == 0) &&
                (lp->ser_connect_pending == FALSE) &&
                (lp->modem_control ? ((lp->modembits & TMXR_MDM_DTR) != 0) : TRUE))
                break;                                  /* yes, so stop search */
            }

        if (i >= mp->lines) {                           /* all busy? */
            int32 ringable_count = 0;

            for (j = 0; j < mp->lines; j++, i++) {      /* find next avail line */
                lp = mp->ldsc + j;                      /* get pointer to line descriptor */
                if ((lp->conn == FALSE) &&              /* is the line available? */
                    (lp->destination == NULL) &&
                    (lp->master == 0) &&
                    (lp->ser_connect_pending == FALSE) &&
                    ((lp->modembits & TMXR_MDM_DTR) == 0)) {
                    ++ringable_count;
                    tmxr_set_get_modem_bits (lp, TMXR_MDM_RNG, 0, NULL);
                    tmxr_debug_connect_line (lp, "tmxr_poll_conn() - Ringing line");
                    }
                }
            if (ringable_count > 0) {
                if (mp->ring_start_time == 0) {
                    mp->ring_start_time = poll_time;
                    mp->ring_sock = newsock;
                    mp->ring_ipad = address;
                    }
                else {
                    if ((poll_time - mp->ring_start_time) < TMXR_MODEM_RING_TIME*1000) {
                        mp->ring_sock = newsock;
                        mp->ring_ipad = address;
                        }
                    else {                                      /* Timeout waiting for DTR */
                        int ln;

                        /* turn off pending ring signals */
                        for (ln = 0; ln < lp->mp->lines; ln++) {
                            TMLN *tlp = lp->mp->ldsc + ln;
                            if (((tlp->destination == NULL) && (tlp->master == 0)) &&
                                (tlp->modembits & TMXR_MDM_RNG) && (tlp->conn == FALSE))
                                tlp->modembits &= ~TMXR_MDM_RNG;
                            }
                        mp->ring_start_time = 0;
                        tmxr_msg (newsock, "No answer on any connection\r\n");
                        tmxr_debug_connect (mp, "tmxr_poll_conn() - No Answer - All connections busy");
                        sim_close_sock (newsock);
                        free (address);
                        }
                    }
                }
            else {
                tmxr_msg (newsock, "All connections busy\r\n");
                tmxr_debug_connect (mp, "tmxr_poll_conn() - All connections busy");
                sim_close_sock (newsock);
                free (address);
                }
            }
        else {
            lp = mp->ldsc + i;                          /* get line desc */
            lp->conn = TRUE;                            /* record connection */
            lp->sock = newsock;                         /* save socket */
            lp->ipad = address;                         /* ip address */
            tmxr_init_line (lp);                        /* init line */
            lp->notelnet = mp->notelnet;                /* apply mux default telnet setting */
            if (!lp->notelnet) {
                sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
                tmxr_debug (TMXR_DBG_XMT, lp, "Sending", (char *)mantra, sizeof(mantra));
                lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
                memset (lp->telnet_sent_opts, 0, 256);
                }
            tmxr_report_connection (mp, lp);
            lp->cnms = sim_os_msec ();                  /* time of connection */
            return i;
            }
        }                                               /* end if newsock */
    }

/* Look for per line listeners or outbound connecting sockets */
for (i = 0; i < mp->lines; i++) {                       /* check each line in sequence */
    int j, r = rand();
    lp = mp->ldsc + i;                                  /* get pointer to line descriptor */

    /* Check for pending serial port connection notification */
    
    if (lp->ser_connect_pending) {
        lp->ser_connect_pending = FALSE;
        lp->conn = TRUE;
        return i;
        }

    /* Don't service network connections for loopbacked lines */

    if (lp->loopback)
        continue;

    /* If two simulators are configured with symmetric virtual null modem 
       cables pointing at each other, there may be a problem establishing 
       a connection if both systems happen to be checking for the success
       of their connections in the exact same order.  They can each observe
       success in their respective outgoing connections, which haven't 
       actually been 'accept'ed on the peer end of the connection.  
       We address this issue by checking for the success of an outgoing
       connection and the arrival of an incoming one in a random order.
     */
    for (j=0; j<2; j++)
        switch ((j+r)&1) {
            case 0:
                if (lp->connecting) {                           /* connecting? */
                    char *sockname, *peername;

                    switch (sim_check_conn(lp->connecting, FALSE))
                        {
                        case 1:                                 /* successful connection */
                            lp->conn = TRUE;                    /* record connection */
                            lp->sock = lp->connecting;          /* it now looks normal */
                            lp->connecting = 0;
                            lp->ipad = (char *)realloc (lp->ipad, 1+strlen (lp->destination));
                            strcpy (lp->ipad, lp->destination);
                            lp->cnms = sim_os_msec ();
                            sim_getnames_sock (lp->sock, &sockname, &peername);
                            sprintf (msg, "tmxr_poll_conn() - Outgoing Line Connection to %s (%s->%s) established", lp->destination, sockname, peername);
                            tmxr_debug_connect_line (lp, msg);
                            free (sockname);
                            free (peername);
                            return i;
                        case -1:                                /* failed connection */
                            sprintf (msg, "tmxr_poll_conn() - Outgoing Line Connection to %s failed", lp->destination);
                            tmxr_debug_connect_line (lp, msg);
                            tmxr_reset_ln (lp);                 /* retry */
                            break;
                        }
                    }
                break;
            case 1:
                if (lp->master) {                                   /* Check for a pending Telnet/tcp connection */
                    while (INVALID_SOCKET != (newsock = sim_accept_conn_ex (lp->master, &address, (lp->packet ? SIM_SOCK_OPT_NODELAY : 0)))) {/* got a live one? */
                        char *sockname, *peername;

                        sim_getnames_sock (newsock, &sockname, &peername);
                        sprintf (msg, "tmxr_poll_conn() - Incoming Line Connection from %s (%s->%s)", address, peername, sockname);
                        tmxr_debug_connect_line (lp, msg);
                        free (sockname);
                        free (peername);
                        ++mp->sessions;                             /* count the new session */

                        if (lp->destination) {                      /* Virtual Null Modem Cable? */
                            char host[CBUFSIZE];

                            if (sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL, address)) {
                                tmxr_msg (newsock, "Rejecting connection from unexpected source\r\n");
                                sprintf (msg, "tmxr_poll_conn() - Rejecting line connection from: %s, Expected: %s", address, host);
                                tmxr_debug_connect_line (lp, msg);
                                sim_close_sock (newsock);
                                free (address);
                                continue;                           /* Try for another connection */
                                }
                            if (lp->connecting) {
                                sprintf (msg, "tmxr_poll_conn() - aborting outgoing line connection attempt to: %s", lp->destination);
                                tmxr_debug_connect_line (lp, msg);
                                sim_close_sock (lp->connecting);    /* abort our as yet unconnnected socket */
                                lp->connecting = 0;
                                }
                            }
                        if (lp->conn == FALSE) {                    /* is the line available? */
                            if ((!lp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) {
                                lp->conn = TRUE;                    /* record connection */
                                lp->sock = newsock;                 /* save socket */
                                lp->ipad = address;                 /* ip address */
                                tmxr_init_line (lp);                /* init line */
                                if (!lp->notelnet) {
                                    sim_write_sock (newsock, (char *)mantra, sizeof(mantra));
                                    tmxr_debug (TMXR_DBG_XMT, lp, "Sending", (char *)mantra, sizeof(mantra));
                                    lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
                                    memset (lp->telnet_sent_opts, 0, 256);
                                    }
                                tmxr_report_connection (mp, lp);
                                lp->cnms = sim_os_msec ();          /* time of connection */
                                return i;
                                }
                            else {
                                tmxr_msg (newsock, "Line connection not available\r\n");
                                tmxr_debug_connect_line (lp, "tmxr_poll_conn() - Line connection not available");
                                sim_close_sock (newsock);
                                free (address);
                                }
                            }
                        else {
                            tmxr_msg (newsock, "Line connection busy\r\n");
                            tmxr_debug_connect_line (lp, "tmxr_poll_conn() - Line connection busy");
                            sim_close_sock (newsock);
                            free (address);
                            }
                        }
                    }
                break;
            }

    /* Check for needed outgoing connection initiation */

    if (lp->destination && (!lp->sock) && (!lp->connecting) && (!lp->serport) && 
        (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR))) {
        sprintf (msg, "tmxr_poll_conn() - establishing outgoing connection to: %s", lp->destination);
        tmxr_debug_connect_line (lp, msg);
        lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, (lp->datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | (lp->mp->packet ? SIM_SOCK_OPT_NODELAY : 0));
        }

    }

return -1;                                              /* no new connections made */
}

/* Reset a line.

   The telnet/tcp or serial session associated with multiplexer descriptor "mp" and
   line descriptor "lp" is disconnected.  An associated tcp socket is
   closed; a serial port is closed if the closeserial parameter is true, otherwise
   for non modem control serial lines DTR is dropped and raised again after 500ms 
   to signal the attached serial device.  
*/

static t_stat tmxr_reset_ln_ex (TMLN *lp, t_bool closeserial)
{
char msg[512];

tmxr_debug_trace_line (lp, "tmxr_reset_ln_ex()");

if (lp->txlog)
    fflush (lp->txlog);                                 /* flush log */

tmxr_send_buffered_data (lp);                           /* send any buffered data */

sprintf (msg, "tmxr_reset_ln_ex(%s)", closeserial ? "TRUE" : "FALSE");
tmxr_debug_connect_line (lp, msg);

if (lp->serport) {
    if (closeserial) {
        sim_close_serial (lp->serport);
        lp->serport = 0;
        lp->ser_connect_pending = FALSE;
        free (lp->destination);
        lp->destination = NULL;
        free (lp->serconfig);
        lp->serconfig = NULL;
        lp->cnms = 0;
        lp->xmte = 1;
        }
    else
        if (!lp->modem_control) {                       /* serial connection? */
            sim_control_serial (lp->serport, 0, TMXR_MDM_DTR|TMXR_MDM_RTS, NULL);/* drop DTR and RTS */
            sim_os_ms_sleep (TMXR_DTR_DROP_TIME);
            sim_control_serial (lp->serport, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL);/* raise DTR and RTS */
            }
    }
else                                                    /* Telnet connection */
    if (lp->sock) {
        sim_close_sock (lp->sock);                      /* close socket */
        free (lp->telnet_sent_opts);
        lp->telnet_sent_opts = NULL;
        lp->sock = 0;
        lp->conn = FALSE;
        lp->cnms = 0;
        lp->xmte = 1;
        }
free(lp->ipad);
lp->ipad = NULL;
if ((lp->destination) && (!lp->serport)) {
    if (lp->connecting) {
        sim_close_sock (lp->connecting);
        lp->connecting = 0;
        }
    if ((!lp->modem_control) || (lp->modembits & TMXR_MDM_DTR)) {
        sprintf (msg, "tmxr_reset_ln_ex() - connecting to %s", lp->destination);
        tmxr_debug_connect_line (lp, msg);
        lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, (lp->datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | (lp->mp->packet ? SIM_SOCK_OPT_NODELAY : 0));
        }
    }
tmxr_init_line (lp);                                /* initialize line state */
return SCPE_OK;
}

t_stat tmxr_close_ln (TMLN *lp)
{
tmxr_debug_trace_line (lp, "tmxr_close_ln()");
tmxr_debug_connect_line (lp, "tmxr_close_ln()");
return tmxr_reset_ln_ex (lp, TRUE);
}

t_stat tmxr_reset_ln (TMLN *lp)
{
tmxr_debug_trace_line (lp, "tmxr_reset_ln()");
return tmxr_reset_ln_ex (lp, FALSE);
}

/* Enable modem control pass thru

   Inputs:
        none
        
   Output:
        none

   Implementation note:

    1  Calling this API disables any actions on the part of this
       library to directly manipulate DTR (&RTS) on serial ports.

    2  Calling this API enables the tmxr_set_get_modem_bits and
       tmxr_set_config_line APIs.

*/
static t_stat tmxr_clear_modem_control_passthru_state (TMXR *mp, t_bool state)
{
int i;

if (mp->modem_control == state)
    return SCPE_OK;
if (mp->master)
    return SCPE_ALATT;
for (i=0; i<mp->lines; ++i) {
    TMLN *lp;

    lp = mp->ldsc + i;
    if ((lp->master)     || 
        (lp->sock)       || 
        (lp->connecting) ||
        (lp->serport))
        return SCPE_ALATT;
    }
mp->modem_control = state;
for (i=0; i<mp->lines; ++i)
    mp->ldsc[i].modem_control = state;
return SCPE_OK;
}

t_stat tmxr_set_modem_control_passthru (TMXR *mp)
{
return tmxr_clear_modem_control_passthru_state (mp, TRUE);
}

/* Disable modem control pass thru

   Inputs:
        none
        
   Output:
        none

   Implementation note:

    1  Calling this API enables this library's direct manipulation 
       of DTR (&RTS) on serial ports.

    2  Calling this API disables the tmxr_set_get_modem_bits and
       tmxr_set_config_line APIs.

    3  This API will only change the state of the modem control processing
       of this library if there are no listening ports, serial ports or 
       outgoing connecctions associated with the specified multiplexer

*/
t_stat tmxr_clear_modem_control_passthru (TMXR *mp)
{
return tmxr_clear_modem_control_passthru_state (mp, FALSE);
}

/* Manipulate the modem control bits of a specific line

   Inputs:
        *lp     =       pointer to terminal line descriptor
        bits_to_set     TMXR_MDM_DTR and/or TMXR_MDM_RTS as desired
        bits_to_clear   TMXR_MDM_DTR and/or TMXR_MDM_RTS as desired
        
   Output:
        incoming_bits   if non NULL, returns the current stat of DCD, 
                        RNG, CTS and DSR along with the current state
                        of DTR and RTS

   Implementation note:

       If a line is connected to a serial port, then these values affect 
       and reflect the state of the serial port.  If the line is connected
       to a network socket (or could be) then the network session state is
       set, cleared and/or returned.
*/
t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits)
{
int32 before_modem_bits, incoming_state;
DEVICE *dptr;

tmxr_debug_trace_line (lp, "tmxr_set_get_modem_bits()");

if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) ||         /* Assure only settable bits */
    (bits_to_clear & ~(TMXR_MDM_OUTGOING)) ||
    (bits_to_set & bits_to_clear))                  /* and can't set and clear the same bits */
    return SCPE_ARG;
before_modem_bits = lp->modembits;
lp->modembits |= bits_to_set;
lp->modembits &= ~(bits_to_clear | TMXR_MDM_INCOMING);
if ((lp->sock) || (lp->serport) || (lp->loopback)) {
    if (lp->modembits & TMXR_MDM_DTR) {
        incoming_state = TMXR_MDM_DSR;
        if (lp->modembits & TMXR_MDM_RTS)
            incoming_state |= TMXR_MDM_CTS;
        if (lp->halfduplex) {
            if (incoming_state & TMXR_MDM_CTS)
                incoming_state |= TMXR_MDM_DCD;
            }
        else
            incoming_state |= TMXR_MDM_DCD;
        }
    else
        incoming_state = TMXR_MDM_DCD | TMXR_MDM_DSR | ((lp->modembits & TMXR_MDM_DTR) ? 0 : TMXR_MDM_RNG);
    }
else {
    if (((before_modem_bits & TMXR_MDM_DTR) == 0) &&    /* Upward transition of DTR? */
        ((lp->modembits & TMXR_MDM_DTR) != 0)     &&
        (lp->conn == FALSE)                       &&    /* Not connected */ 
        (lp->modembits & TMXR_MDM_RNG)) {               /* and Ring Signal Present */
        if ((lp->destination == NULL) && 
            (lp->master == 0) &&
            (lp->mp && (lp->mp->ring_sock))) {
            int ln;
            
            lp->conn = TRUE;                            /* record connection */
            lp->sock = lp->mp->ring_sock;               /* save socket */
            lp->mp->ring_sock = INVALID_SOCKET;
            lp->ipad = lp->mp->ring_ipad;               /* ip address */
            lp->mp->ring_ipad = NULL;
            lp->mp->ring_start_time = 0;
            tmxr_init_line (lp);                        /* init line */
            lp->notelnet = lp->mp->notelnet;            /* apply mux default telnet setting */
            if (!lp->notelnet) {
                sim_write_sock (lp->sock, (char *)mantra, sizeof(mantra));
                tmxr_debug (TMXR_DBG_XMT, lp, "Sending", (char *)mantra, sizeof(mantra));
                lp->telnet_sent_opts = (uint8 *)realloc (lp->telnet_sent_opts, 256);
                memset (lp->telnet_sent_opts, 0, 256);
                }
            tmxr_report_connection (lp->mp, lp);
            lp->cnms = sim_os_msec ();                  /* time of connection */
            lp->modembits &= ~TMXR_MDM_RNG;             /* turn off ring on this line*/
            /* turn off other pending ring signals */
            for (ln = 0; ln < lp->mp->lines; ln++) {
                TMLN *tlp = lp->mp->ldsc + ln;
                if (((tlp->destination == NULL) && (tlp->master == 0)) &&
                    (tlp->modembits & TMXR_MDM_RNG) && (tlp->conn == FALSE))
                    tlp->modembits &= ~TMXR_MDM_RNG;
                }
            }
        }
    if ((lp->master) || (lp->mp && lp->mp->master) ||
        (lp->port && lp->destination))
        incoming_state = TMXR_MDM_DSR;
    else
        incoming_state = 0;
    }
lp->modembits |= incoming_state;
dptr = (lp->dptr ? lp->dptr : (lp->mp ? lp->mp->dptr : NULL));
if ((lp->modembits != before_modem_bits) && (sim_deb && lp->mp && dptr)) {
    sim_debug_bits (TMXR_DBG_MDM, dptr, tmxr_modem_bits, before_modem_bits, lp->modembits, FALSE);
    sim_debug (TMXR_DBG_MDM, dptr, " - Line %d - %p\n", (int)(lp-lp->mp->ldsc), lp->txb);
    }
if (incoming_bits)
    *incoming_bits = lp->modembits;
if (lp->mp && lp->modem_control) {                  /* This API ONLY works on modem_control enabled multiplexer lines */
    if (bits_to_set | bits_to_clear) {              /* Anything to do? */
        if (lp->loopback) {
            if ((lp->modembits ^ before_modem_bits) & TMXR_MDM_DTR) { /* DTR changed? */
                lp->ser_connect_pending = (lp->modembits & TMXR_MDM_DTR);
                lp->conn = !(lp->modembits & TMXR_MDM_DTR);
                }
            return SCPE_OK;
            }
        if (lp->serport)
            return sim_control_serial (lp->serport, bits_to_set, bits_to_clear, incoming_bits);
        if ((lp->sock) || (lp->connecting)) {
            if ((before_modem_bits & bits_to_clear & TMXR_MDM_DTR) != 0) { /* drop DTR? */
                if (lp->sock)
                    tmxr_report_disconnection (lp);     /* report closure */
                tmxr_reset_ln (lp);
                }
            }
        else {
            if ((lp->destination) &&                    /* Virtual Null Modem Cable */
                (bits_to_set & ~before_modem_bits &     /* and DTR being Raised */
                 TMXR_MDM_DTR)) {
                char msg[512];

                sprintf (msg, "tmxr_set_get_modem_bits() - establishing outgoing connection to: %s", lp->destination);
                tmxr_debug_connect_line (lp, msg);
                lp->connecting = sim_connect_sock_ex (lp->datagram ? lp->port : NULL, lp->destination, "localhost", NULL, (lp->datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | (lp->mp->packet ? SIM_SOCK_OPT_NODELAY : 0));
                }
            }
        }
    return SCPE_OK;
    }
if ((lp->sock) || (lp->connecting)) {
    if ((before_modem_bits & bits_to_clear & TMXR_MDM_DTR) != 0) { /* drop DTR? */
        if (lp->sock)
            tmxr_report_disconnection (lp);     /* report closure */
        tmxr_reset_ln (lp);
        }
    }
if ((lp->serport) && (!lp->loopback))
    sim_control_serial (lp->serport, 0, 0, incoming_bits);
return SCPE_INCOMP;
}

/* Enable or Disable loopback mode on a line

   Inputs:
        lp -                the line to change
        enable_loopback -   enable or disable flag

   Output:
        none

   Implementation note:

    1) When enabling loopback mode, this API will disconnect any currently 
       connected TCP or Serial session.
    2) When disabling loopback mode, prior network connections and/or 
       serial port connections will be restored.

*/
t_stat tmxr_set_line_loopback (TMLN *lp, t_bool enable_loopback)
{
if (lp->loopback == (enable_loopback != FALSE))
    return SCPE_OK;                 /* Nothing to do */
lp->loopback = (enable_loopback != FALSE);
if (lp->loopback) {
    lp->lpbsz = lp->rxbsz;
    lp->lpb = (char *)realloc(lp->lpb, lp->lpbsz);
    lp->lpbcnt = lp->lpbpi = lp->lpbpr = 0;
    if (!lp->conn)
        lp->ser_connect_pending = TRUE;
    }
else {
    free (lp->lpb);
    lp->lpb = NULL;
    lp->lpbsz = 0;
    }
return SCPE_OK;
}

t_bool tmxr_get_line_loopback (TMLN *lp)
{
return (lp->loopback != FALSE);
}

/* Enable or Disable halfduplex mode on a line

   Inputs:
        lp -                the line to change
        enable_halfduplex - enable or disable flag

   Output:
        none

   When a network connected line is in halfduplex mode, DCD modem signal
   track with CTS.  When not in halfduplex mode the DCD modem signal for
   network connected lines tracks with DSR.

*/
t_stat tmxr_set_line_halfduplex (TMLN *lp, t_bool enable_halfduplex)
{
if (lp->halfduplex == (enable_halfduplex != FALSE))
    return SCPE_OK;                 /* Nothing to do */
lp->halfduplex = (enable_halfduplex != FALSE);
return SCPE_OK;
}

t_bool tmxr_get_line_halfduplex (TMLN *lp)
{
return (lp->halfduplex != FALSE);
}

t_stat tmxr_set_config_line (TMLN *lp, CONST char *config)
{
t_stat r;

tmxr_debug_trace_line (lp, "tmxr_set_config_line()");
if (lp->serport)
    r = sim_config_serial (lp->serport, config);
else {
    lp->serconfig = (char *)realloc (lp->serconfig, 1 + strlen (config));
    strcpy (lp->serconfig, config);
    r = tmxr_set_line_speed (lp, lp->serconfig);;
    if (r != SCPE_OK) {
        free (lp->serconfig);
        lp->serconfig = NULL;
        }
    }
if ((r == SCPE_OK) && (lp->mp) && (lp->mp->uptr))   /* Record port state for proper restore */
    lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp);
return r;
}


/* Get character from specific line

   Inputs:
        *lp     =       pointer to terminal line descriptor
   Output:
        valid + char, 0 if line

   Implementation note:

    1. If a line break was detected coincident with the current character, the
       receive break status associated with the character is cleared, and
       SCPE_BREAK is ORed into the return value.
*/

int32 tmxr_input_pending_ln (TMLN *lp)
{
return (lp->rxbpi - lp->rxbpr);
}

int32 tmxr_getc_ln (TMLN *lp)
{
int32 j; 
t_stat val = 0;
uint32 tmp;

tmxr_debug_trace_line (lp, "tmxr_getc_ln()");
if ((lp->conn && lp->rcve) &&                           /* conn & enb & */
    ((!lp->rxbps) ||                                    /* (!rate limited || enough time passed)? */
     (sim_gtime () >= lp->rxnexttime))) {
    if (!sim_send_poll_data (&lp->send, &val)) {        /* injected input characters available? */
        j = lp->rxbpi - lp->rxbpr;                      /* # input chrs */
        if (j) {                                        /* any? */
            tmp = lp->rxb[lp->rxbpr];                   /* get char */
            val = TMXR_VALID | (tmp & 0377);            /* valid + chr */
            if (lp->rbr[lp->rxbpr]) {                   /* break? */
                lp->rbr[lp->rxbpr] = 0;                 /* clear status */
                val = val | SCPE_BREAK;                 /* indicate to caller */
                }
            lp->rxbpr = lp->rxbpr + 1;                  /* adv pointer */
            }
        }
    }                                                   /* end if conn */
if (lp->rxbpi == lp->rxbpr)                             /* empty? zero ptrs */
    lp->rxbpi = lp->rxbpr = 0;
if (lp->rxbps) {
    if (val)
        lp->rxnexttime = floor (sim_gtime () + ((lp->rxdelta * sim_timer_inst_per_sec ())/lp->rxbpsfactor));
    }
tmxr_debug_return(lp, val);
return val;
}

/* Get packet from specific line

   Inputs:
        *lp     =       pointer to terminal line descriptor
        **pbuf  =       pointer to pointer of packet contents
        *psize  =       pointer to packet size
        frame_byte -    byte which separates packets in the tcp stream
                        (0 means no separation character)

   Output:
        SCPE_LOST       link state lost
        SCPE_OK         Packet returned OR no packet available

   Implementation notes:

    1. If a packet is not yet available, then the pbuf address returned is
       NULL, but success (SCPE_OK) is returned
*/

t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize)
{
return tmxr_get_packet_ln_ex (lp, pbuf, psize, 0);
}

t_stat tmxr_get_packet_ln_ex (TMLN *lp, const uint8 **pbuf, size_t *psize, uint8 frame_byte)
{
int32 c;
size_t pktsize;
size_t fc_size = (frame_byte ? 1 : 0);

while (TMXR_VALID & (c = tmxr_getc_ln (lp))) {
    if (lp->rxpboffset + 3 > lp->rxpbsize) {
        lp->rxpbsize += 512;
        lp->rxpb = (uint8 *)realloc (lp->rxpb, lp->rxpbsize);
        }
    if ((lp->rxpboffset == 0) && (fc_size) && (c != frame_byte)) {
        tmxr_debug (TMXR_DBG_PRCV, lp, "Received Unexpected Framing Byte", (char *)&lp->rxpb[lp->rxpboffset], 1);
        continue;
        }
    if ((lp->datagram) && (lp->rxpboffset == fc_size)) {
        /* Datagram packet length is provided as a part of the natural datagram 
           delivery, for TCP lines, we read the packet length from the data stream.
           So, here we stuff packet size into head of packet buffer so it looks like
           it was delivered by TCP and the below return logic doesn't have to worry */
        lp->rxpb[lp->rxpboffset++] = (uint8)(((1 + lp->rxbpi - lp->rxbpr) >> 8) & 0xFF);
        lp->rxpb[lp->rxpboffset++] = (uint8)((1 + lp->rxbpi - lp->rxbpr) & 0xFF);
        }
    lp->rxpb[lp->rxpboffset++] = c & 0xFF;
    if (lp->rxpboffset >= (2 + fc_size)) {
        pktsize = (lp->rxpb[0+fc_size] << 8) | lp->rxpb[1+fc_size];
        if (pktsize == (lp->rxpboffset - 2)) {
            ++lp->rxpcnt;
            *pbuf = &lp->rxpb[2+fc_size];
            *psize = pktsize;
            lp->rxpboffset = 0;
            tmxr_debug (TMXR_DBG_PRCV, lp, "Received Packet", (char *)&lp->rxpb[2+fc_size], pktsize);
            return SCPE_OK;
            }
        }
    }
*pbuf = NULL;
*psize = 0;
if (lp->conn)
    return SCPE_OK;
return SCPE_LOST;
}

/* Poll for input

   Inputs:
        *mp     =       pointer to terminal multiplexer descriptor
   Outputs:     none
*/

void tmxr_poll_rx (TMXR *mp)
{
int32 i, nbytes, j;
TMLN *lp;

tmxr_debug_trace (mp, "tmxr_poll_rx()");
for (i = 0; i < mp->lines; i++) {                       /* loop thru lines */
    lp = mp->ldsc + i;                                  /* get line desc */
    if (!(lp->sock || lp->serport || lp->loopback) || 
        !(lp->rcve))                                    /* skip if not connected */
        continue;

    nbytes = 0;
    if (lp->rxbpi == 0)                                 /* need input? */
        nbytes = tmxr_read (lp,                         /* yes, read */
            lp->rxbsz - TMXR_GUARD);                    /* leave spc for Telnet cruft */
    else if (lp->tsta)                                  /* in Telnet seq? */
        nbytes = tmxr_read (lp,                         /* yes, read to end */
            lp->rxbsz - lp->rxbpi);

    if (nbytes < 0) {                                   /* line error? */
        if (!lp->datagram) {                            /* ignore errors reading UDP sockets */
            if (!lp->txbfd || lp->notelnet) 
                lp->txbpi = lp->txbpr = 0;              /* Drop the data we already know we can't send */
            tmxr_close_ln (lp);                         /* disconnect line */
            }
        }

    else if (nbytes > 0) {                              /* if data rcvd */

        tmxr_debug (TMXR_DBG_RCV, lp, "Received", &(lp->rxb[lp->rxbpi]), nbytes);

        j = lp->rxbpi;                                  /* start of data */
        lp->rxbpi = lp->rxbpi + nbytes;                 /* adv pointers */
        lp->rxcnt = lp->rxcnt + nbytes;

/* Examine new data, remove TELNET cruft before making input available */

        if (!lp->notelnet) {                            /* Are we looking for telnet interpretation? */
            for (; j < lp->rxbpi; ) {                   /* loop thru char */
                u_char tmp = (u_char)lp->rxb[j];        /* get char */
                switch (lp->tsta) {                     /* case tlnt state */

                case TNS_NORM:                          /* normal */
                    if (tmp == TN_IAC) {                /* IAC? */
                        lp->tsta = TNS_IAC;             /* change state */
                        tmxr_rmvrc (lp, j);             /* remove char */
                        break;
                        }
                    if ((tmp == TN_CR) && lp->dstb)     /* CR, no bin */
                        lp->tsta = TNS_CRPAD;           /* skip pad char */
                    j = j + 1;                          /* advance j */
                    break;

                case TNS_IAC:                           /* IAC prev */
                    if (tmp == TN_IAC) {                /* IAC + IAC */
                        lp->tsta = TNS_NORM;            /* treat as normal */
                        j = j + 1;                      /* advance j */
                        break;                          /* keep IAC */
                        }
                    if (tmp == TN_BRK) {                /* IAC + BRK? */
                        lp->tsta = TNS_NORM;            /* treat as normal */
                        lp->rxb[j] = 0;                 /* char is null */
                        lp->rbr[j] = 1;                 /* flag break */
                        j = j + 1;                      /* advance j */
                        break;
                        }
                    switch (tmp) {
                    case TN_WILL:                       /* IAC + WILL? */
                        lp->tsta = TNS_WILL;
                        break;
                    case TN_WONT:                       /* IAC + WONT? */
                        lp->tsta = TNS_WONT;
                        break;
                    case TN_DO:                         /* IAC + DO? */
                        lp->tsta = TNS_DO;
                        break;
                    case TN_DONT:                       /* IAC + DONT? */
                        lp->tsta = TNS_SKIP;            /* IAC + other */
                        break;
                    case TN_GA: case TN_EL:             /* IAC + other 2 byte types */
                    case TN_EC: case TN_AYT:    
                    case TN_AO: case TN_IP:
                    case TN_NOP: 
                        lp->tsta = TNS_NORM;            /* ignore */
                        break;
                    case TN_SB:                         /* IAC + SB sub-opt negotiation */
                    case TN_DATAMK:                     /* IAC + data mark */
                    case TN_SE:                         /* IAC + SE sub-opt end */
                        lp->tsta = TNS_NORM;            /* ignore */
                        break;
                        }
                    tmxr_rmvrc (lp, j);                 /* remove char */
                    break;

                case TNS_WILL:                          /* IAC+WILL prev */
                    if ((tmp == TN_STATUS) || 
                        (tmp == TN_TIMING) || 
                        (tmp == TN_NAOCRD) || 
                        (tmp == TN_NAOHTS) || 
                        (tmp == TN_NAOHTD) || 
                        (tmp == TN_NAOFFD) || 
                        (tmp == TN_NAOVTS) || 
                        (tmp == TN_NAOVTD) || 
                        (tmp == TN_NAOLFD) || 
                        (tmp == TN_EXTEND) || 
                        (tmp == TN_LOGOUT) || 
                        (tmp == TN_BM)     || 
                        (tmp == TN_DET)    || 
                        (tmp == TN_SENDLO) || 
                        (tmp == TN_TERMTY) || 
                        (tmp == TN_ENDREC) || 
                        (tmp == TN_TUID)   || 
                        (tmp == TN_OUTMRK) || 
                        (tmp == TN_TTYLOC) || 
                        (tmp == TN_3270)   || 
                        (tmp == TN_X3PAD)  || 
                        (tmp == TN_NAWS)   || 
                        (tmp == TN_TERMSP) || 
                        (tmp == TN_TOGFLO) || 
                        (tmp == TN_XDISPL) || 
                        (tmp == TN_ENVIRO) || 
                        (tmp == TN_AUTH)   || 
                        (tmp == TN_ENCRYP) || 
                        (tmp == TN_NEWENV) || 
                        (tmp == TN_TN3270) || 
                        (tmp == TN_CHARST) || 
                        (tmp == TN_COMPRT) || 
                        (tmp == TN_KERMIT)) {
                        /* Reject (DONT) these 'uninteresting' options only one time to avoid loops */
                        if (0 == (lp->telnet_sent_opts[tmp] & TNOS_DONT)) {
                            lp->notelnet = TRUE;                /* Temporarily disable so */
                            tmxr_putc_ln (lp, TN_IAC);          /* IAC gets injected bare */
                            lp->notelnet = FALSE;
                            tmxr_putc_ln (lp, TN_DONT); 
                            tmxr_putc_ln (lp, tmp); 
                            lp->telnet_sent_opts[tmp] |= TNOS_DONT;/* Record DONT sent */
                            }
                        }
                case TNS_WONT:           /* IAC+WILL/WONT prev */
                    if (tmp == TN_BIN) {                /* BIN? */
                        if (lp->tsta == TNS_WILL) {
                            lp->dstb = 0;
                            }
                        else {
                            lp->dstb = 1;
                            }
                        }
                    tmxr_rmvrc (lp, j);                 /* remove it */
                    lp->tsta = TNS_NORM;                /* next normal */
                    break;

                /* Negotiation with the HP terminal emulator "QCTerm" is not working.
                   QCTerm says "WONT BIN" but sends bare CRs.  RFC 854 says:

                     Note that "CR LF" or "CR NUL" is required in both directions
                     (in the default ASCII mode), to preserve the symmetry of the
                     NVT model.  ...The protocol requires that a NUL be inserted
                     following a CR not followed by a LF in the data stream.

                   Until full negotiation is implemented, we work around the problem
                   by checking the character following the CR in non-BIN mode and
                   strip it only if it is LF or NUL.  This should not affect
                   conforming clients.
                */

                case TNS_CRPAD:                         /* only LF or NUL should follow CR */
                    lp->tsta = TNS_NORM;                /* next normal */
                    if ((tmp == TN_LF) ||               /* CR + LF ? */
                        (tmp == TN_NUL))                /* CR + NUL? */
                        tmxr_rmvrc (lp, j);             /* remove it */
                    break;

                case TNS_DO:                            /* pending DO request */
                    if ((tmp == TN_STATUS) || 
                        (tmp == TN_TIMING) || 
                        (tmp == TN_NAOCRD) || 
                        (tmp == TN_NAOHTS) || 
                        (tmp == TN_NAOHTD) || 
                        (tmp == TN_NAOFFD) || 
                        (tmp == TN_NAOVTS) || 
                        (tmp == TN_NAOVTD) || 
                        (tmp == TN_NAOLFD) || 
                        (tmp == TN_EXTEND) || 
                        (tmp == TN_LOGOUT) || 
                        (tmp == TN_BM)     || 
                        (tmp == TN_DET)    || 
                        (tmp == TN_SENDLO) || 
                        (tmp == TN_TERMTY) || 
                        (tmp == TN_ENDREC) || 
                        (tmp == TN_TUID)   || 
                        (tmp == TN_OUTMRK) || 
                        (tmp == TN_TTYLOC) || 
                        (tmp == TN_3270)   || 
                        (tmp == TN_X3PAD)  || 
                        (tmp == TN_NAWS)   || 
                        (tmp == TN_TERMSP) || 
                        (tmp == TN_TOGFLO) || 
                        (tmp == TN_XDISPL) || 
                        (tmp == TN_ENVIRO) || 
                        (tmp == TN_AUTH)   || 
                        (tmp == TN_ENCRYP) || 
                        (tmp == TN_NEWENV) || 
                        (tmp == TN_TN3270) || 
                        (tmp == TN_CHARST) || 
                        (tmp == TN_COMPRT) || 
                        (tmp == TN_KERMIT)) {
                        /* Reject (WONT) these 'uninteresting' options only one time to avoid loops */
                        if (0 == (lp->telnet_sent_opts[tmp] & TNOS_WONT)) {
                            lp->notelnet = TRUE;                /* Temporarily disable so */
                            tmxr_putc_ln (lp, TN_IAC);          /* IAC gets injected bare */
                            lp->notelnet = FALSE;
                            tmxr_putc_ln (lp, TN_WONT); 
                            tmxr_putc_ln (lp, tmp); 
                            lp->telnet_sent_opts[tmp] |= TNOS_WONT;/* Record WONT sent */
                            }
                        }
                case TNS_SKIP: default:                 /* skip char */
                    tmxr_rmvrc (lp, j);                 /* remove char */
                    lp->tsta = TNS_NORM;                /* next normal */
                    break;
                    }                                   /* end case state */
                }                                       /* end for char */
            if (nbytes != (lp->rxbpi-lp->rxbpr)) {
                tmxr_debug (TMXR_DBG_RCV, lp, "Remaining", &(lp->rxb[lp->rxbpr]), lp->rxbpi-lp->rxbpr);
                }
            }
        }                                               /* end else nbytes */
    }                                                   /* end for lines */
for (i = 0; i < mp->lines; i++) {                       /* loop thru lines */
    lp = mp->ldsc + i;                                  /* get line desc */
    if (lp->rxbpi == lp->rxbpr)                         /* if buf empty, */
        lp->rxbpi = lp->rxbpr = 0;                      /* reset pointers */
    }                                                   /* end for */
return;
}


/* Return count of available characters for line */

int32 tmxr_rqln_bare (const TMLN *lp, t_bool speed)
{
if ((speed) && (lp->rxbps)) {                   /* consider speed and rate limiting? */
    if (sim_gtime () < lp->rxnexttime)          /* too soon? */
        return 0;
    else
        return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? lp->rxbsz : 0)) ? 1 : 0;
    }
return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? lp->rxbsz: 0));
}

int32 tmxr_rqln (const TMLN *lp)
{
return tmxr_rqln_bare (lp, TRUE);
}


/* Store character in line buffer

   Inputs:
        *lp     =       pointer to line descriptor
        chr     =       character
   Outputs:
        status  =       ok, connection lost, or stall

   Implementation note:

    1. If the line is not connected, SCPE_LOST is returned.
*/

t_stat tmxr_putc_ln (TMLN *lp, int32 chr)
{
if ((lp->conn == FALSE) &&                              /* no conn & not buffered telnet? */
    (!lp->txbfd || lp->notelnet)) {
    ++lp->txdrp;                                        /* lost */
    return SCPE_LOST;
    }
tmxr_debug_trace_line (lp, "tmxr_putc_ln()");
#define TXBUF_AVAIL(lp) ((lp->serport ? 2: lp->txbsz) - tmxr_tqln (lp))
#define TXBUF_CHAR(lp, c) {                               \
    lp->txb[lp->txbpi++] = (char)(c);                     \
    lp->txbpi %= lp->txbsz;                               \
    if (lp->txbpi == lp->txbpr)                           \
        lp->txbpr = (1+lp->txbpr)%lp->txbsz, ++lp->txdrp; \
    }
if ((lp->txbfd && !lp->notelnet) || (TXBUF_AVAIL(lp) > 1)) {/* room for char (+ IAC)? */
    if ((TN_IAC == (u_char) chr) && (!lp->notelnet))    /* char == IAC in telnet session? */
        TXBUF_CHAR (lp, TN_IAC);                        /* stuff extra IAC char */
    TXBUF_CHAR (lp, chr);                               /* buffer char & adv pointer */
    if ((!lp->txbfd) && (TXBUF_AVAIL (lp) <= TMXR_GUARD))/* near full? */
        lp->xmte = 0;                                   /* disable line */
    if (lp->txlog) {                                    /* log if available */
        extern TMLN *sim_oline;                         /* Make sure to avoid recursion */
        TMLN *save_oline = sim_oline;                   /* when logging to a socket */

        sim_oline = NULL;                               /* save output socket */
        fputc (chr, lp->txlog);                         /* log to actual file */
        sim_oline = save_oline;                         /* resture output socket */
        }
    sim_exp_check (&lp->expect, chr);                   /* process expect rules as needed */
    return SCPE_OK;                                     /* char sent */
    }
++lp->txdrp; lp->xmte = 0;                              /* no room, dsbl line */
return SCPE_STALL;                                      /* char not sent */
}

/* Store packet in line buffer

   Inputs:
        *lp     =       pointer to line descriptor
        *buf    =       pointer to packet data
        size    =       size of packet
        frame_char =    inter-packet franing character (0 means no frame character)

   Outputs:
        status  =       ok, connection lost, or stall

   Implementation notea:

    1. If the line is not connected, SCPE_LOST is returned.
    2. If prior packet transmission still in progress, SCPE_STALL is 
       returned and no packet data is stored.  The caller must retry later.
*/
t_stat tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size)
{
return tmxr_put_packet_ln_ex (lp, buf, size, 0);
}

t_stat tmxr_put_packet_ln_ex (TMLN *lp, const uint8 *buf, size_t size, uint8 frame_byte)
{
t_stat r;
size_t fc_size = (frame_byte ? 1 : 0);
size_t pktlen_size = (lp->datagram ? 0 : 2);

if ((!lp->conn) && (!lp->loopback))
    return SCPE_LOST;
if (lp->txppoffset < lp->txppsize) {
    tmxr_debug (TMXR_DBG_PXMT, lp, "Skipped Sending Packet - Transmit Busy", (char *)&lp->txpb[3], size);
    return SCPE_STALL;
    }
if (lp->txpbsize < size + pktlen_size + fc_size) {
    lp->txpbsize = size + pktlen_size + fc_size;
    lp->txpb = (uint8 *)realloc (lp->txpb, lp->txpbsize);
    }
lp->txpb[0] = frame_byte;
if (!lp->datagram) {
    lp->txpb[0+fc_size] = (size >> 8) & 0xFF;
    lp->txpb[1+fc_size] = size & 0xFF;
    }
memcpy (lp->txpb + pktlen_size + fc_size, buf, size);
lp->txppsize = size + pktlen_size + fc_size;
lp->txppoffset = 0;
tmxr_debug (TMXR_DBG_PXMT, lp, "Sending Packet", (char *)&lp->txpb[pktlen_size+fc_size], size);
++lp->txpcnt;
while ((lp->txppoffset < lp->txppsize) && 
       (SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset]))))
   ++lp->txppoffset;
tmxr_send_buffered_data (lp);
return (lp->conn || lp->loopback) ? SCPE_OK : SCPE_LOST;
}

/* Poll for output

   Inputs:
        *mp     =       pointer to terminal multiplexer descriptor
   Outputs:
        none
*/

void tmxr_poll_tx (TMXR *mp)
{
int32 i, nbytes;
TMLN *lp;

tmxr_debug_trace (mp, "tmxr_poll_tx()");
for (i = 0; i < mp->lines; i++) {                       /* loop thru lines */
    lp = mp->ldsc + i;                                  /* get line desc */
    if (!lp->conn)                                      /* skip if !conn */
        continue;
    nbytes = tmxr_send_buffered_data (lp);              /* buffered bytes */
    if (nbytes == 0) {                                  /* buf empty? enab line */
#if defined(SIM_ASYNCH_MUX)
        UNIT *ruptr = lp->uptr ? lp->uptr : lp->mp->uptr;
        if ((ruptr->dynflags & UNIT_TM_POLL) &&
            sim_asynch_enabled &&
            tmxr_rqln (lp))
            _sim_activate (ruptr, 0);
#endif
        lp->xmte = 1;                                   /* enable line transmit */
        }
    }                                                   /* end for */
return;
}


/* Send buffered data across network

   Inputs:
        *lp     =       pointer to line descriptor
   Outputs:
        returns number of bytes still buffered
*/

int32 tmxr_send_buffered_data (TMLN *lp)
{
int32 nbytes, sbytes;
t_stat r;

tmxr_debug_trace_line (lp, "tmxr_send_buffered_data()");
nbytes = tmxr_tqln(lp);                                 /* avail bytes */
if (nbytes) {                                           /* >0? write */
    if (lp->txbpr < lp->txbpi)                          /* no wrap? */
        sbytes = tmxr_write (lp, nbytes);               /* write all data */
    else
        sbytes = tmxr_write (lp, lp->txbsz - lp->txbpr);/* write to end buf */
    if (sbytes >= 0) {                                  /* ok? */
        tmxr_debug (TMXR_DBG_XMT, lp, "Sent", &(lp->txb[lp->txbpr]), sbytes);
        lp->txbpr = (lp->txbpr + sbytes);               /* update remove ptr */
        if (lp->txbpr >= lp->txbsz)                     /* wrap? */
            lp->txbpr = 0;
        lp->txcnt = lp->txcnt + sbytes;                 /* update counts */
        nbytes = nbytes - sbytes;
        if ((nbytes == 0) && (lp->datagram))            /* if Empty buffer on datagram line */
            lp->txbpi = lp->txbpr = 0;                  /* Start next packet at beginning of buffer */
        }
    if (sbytes < 0) {                                   /* I/O Error? */
        lp->txbpi = lp->txbpr = 0;                      /* Drop the data we already know we can't send */
        lp->rxpboffset = lp->txppoffset = lp->txppsize = 0;/* Drop the data we already know we can't send */
        tmxr_close_ln (lp);                             /*  close line/port on error */
        return nbytes;                                  /*  done now. */
        }
    if (nbytes && (lp->txbpr == 0))     {               /* more data and wrap? */
        sbytes = tmxr_write (lp, nbytes);
        if (sbytes > 0) {                               /* ok */
            tmxr_debug (TMXR_DBG_XMT, lp, "Sent", lp->txb, sbytes);
            lp->txbpr = (lp->txbpr + sbytes);           /* update remove ptr */
            if (lp->txbpr >= lp->txbsz)                 /* wrap? */
                lp->txbpr = 0;
            lp->txcnt = lp->txcnt + sbytes;             /* update counts */
            nbytes = nbytes - sbytes;
            }
        }
    }                                                   /* end if nbytes */
while ((lp->txppoffset < lp->txppsize) &&               /* buffered packet data? */
       (lp->txbsz > nbytes) &&                          /* and room in xmt buffer */
       (SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset]))))
   ++lp->txppoffset;
if ((nbytes == 0) && (tmxr_tqln(lp) > 0))
    return tmxr_send_buffered_data (lp);
return tmxr_tqln(lp) + tmxr_tpqln(lp);
}


/* Return count of buffered characters for line */

int32 tmxr_tqln (const TMLN *lp)
{
return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? lp->txbsz: 0));
}

/* Return count of buffered packet characters for line */

int32 tmxr_tpqln (const TMLN *lp)
{
return (lp->txppsize - lp->txppoffset);
}

/* Return transmit packet busy status for line */

t_bool tmxr_tpbusyln (const TMLN *lp)
{
return (0 != (lp->txppsize - lp->txppoffset));
}

static void _mux_detach_line (TMLN *lp, t_bool close_listener, t_bool close_connecting)
{
if (close_listener && lp->master) {
    sim_close_sock (lp->master);
    lp->master = 0;
    free (lp->port);
    lp->port = NULL;
    }
if (lp->sock) {                             /* if existing tcp, drop it */
    tmxr_report_disconnection (lp);         /* report disconnection */
    tmxr_reset_ln (lp);
    }
if (close_connecting) {
    free (lp->destination);
    lp->destination = NULL;
    if (lp->connecting) {                   /* if existing outgoing tcp, drop it */
        lp->sock = lp->connecting;
        lp->connecting = 0;
        tmxr_reset_ln (lp);
        }
    }
if (lp->serport) {                          /* close current serial connection */
    tmxr_reset_ln (lp);
    sim_control_serial (lp->serport, 0, TMXR_MDM_DTR|TMXR_MDM_RTS, NULL);/* drop DTR and RTS */
    sim_close_serial (lp->serport);
    lp->serport = 0;
    free (lp->serconfig);
    lp->serconfig = NULL;
    free (lp->destination);
    lp->destination = NULL;
    }
tmxr_set_line_loopback (lp, FALSE);
}

t_stat tmxr_detach_ln (TMLN *lp)
{
UNIT *uptr = NULL;

tmxr_debug_trace_line (lp, "tmxr_detach_ln()");
_mux_detach_line (lp, TRUE, TRUE);
if (lp->mp) {
    if (lp->uptr)
        uptr = lp->uptr;
    else
        uptr = lp->mp->uptr;
    }
if (uptr && uptr->filename) {
    /* Revise the unit's connect string to reflect the current attachments */
    uptr->filename = tmxr_mux_attach_string (uptr->filename, lp->mp);
    /* No connections or listeners exist, then we're equivalent to being fully detached.  We should reflect that */
    if (uptr->filename == NULL)
        tmxr_detach (lp->mp, uptr);
    }
return SCPE_OK;
}

static int32 _tmln_speed_delta (CONST char *cptr)
{
struct {
    const char *bps;
    int32 delta;
    } *spd, speeds[] = {
    {"50",      TMLN_SPD_50_BPS},
    {"75",      TMLN_SPD_75_BPS},
    {"110",     TMLN_SPD_110_BPS},
    {"134",     TMLN_SPD_134_BPS},
    {"150",     TMLN_SPD_150_BPS},
    {"300",     TMLN_SPD_300_BPS},
    {"600",     TMLN_SPD_600_BPS},
    {"1200",    TMLN_SPD_1200_BPS},
    {"1800",    TMLN_SPD_1800_BPS},
    {"2000",    TMLN_SPD_2000_BPS},
    {"2400",    TMLN_SPD_2400_BPS},
    {"3600",    TMLN_SPD_3600_BPS},
    {"4800",    TMLN_SPD_4800_BPS},
    {"7200",    TMLN_SPD_7200_BPS},
    {"9600",    TMLN_SPD_9600_BPS},
    {"19200",   TMLN_SPD_19200_BPS},
    {"38400",   TMLN_SPD_38400_BPS},
    {"57600",   TMLN_SPD_57600_BPS},
    {"76800",   TMLN_SPD_76800_BPS},
    {"115200",  TMLN_SPD_115200_BPS},
    {"0",       0}};                    /* End of List, last valid value */
int nspeed;
char speed[24];

nspeed = (uint32)strtotv (cptr, &cptr, 10);
if ((*cptr != '\0') && (*cptr != '-') && (*cptr != '*'))
    return -1;
sprintf (speed, "%d", nspeed);

spd = speeds;
while (1) {
    if (0 == strcmp(spd->bps, speed))
        return spd->delta;
    if (spd->delta == 0)
        break;
    ++spd;
    }
return -1;
}

t_stat tmxr_set_line_speed (TMLN *lp, CONST char *speed)
{
UNIT *uptr;
CONST char *cptr;
t_stat r;

if (!speed || !*speed)
    return SCPE_2FARG;
if (_tmln_speed_delta (speed) < 0)
    return SCPE_ARG;
lp->rxbps = (uint32)strtotv (speed, &cptr, 10);
if (*cptr == '*') {
    uint32 rxbpsfactor = (uint32) get_uint (cptr+1, 10, 32, &r);
    if (r != SCPE_OK)
        return r;
    lp->rxbpsfactor = TMXR_RX_BPS_UNIT_SCALE * rxbpsfactor;
    }
lp->rxdelta = _tmln_speed_delta (speed);
lp->rxnexttime = 0.0;
uptr = lp->uptr;
if ((!uptr) && (lp->mp))
    uptr = lp->mp->uptr;
if (uptr)
    uptr->wait = lp->rxdelta;
if (lp->rxbpsfactor == 0.0)
    lp->rxbpsfactor = TMXR_RX_BPS_UNIT_SCALE;
lp->txbps = lp->rxbps;
lp->txdelta = lp->rxdelta;
lp->txnexttime = lp->rxnexttime;
return SCPE_OK;
}


/* Open a master listening socket (and all of the other variances of connections).

   A listening socket for the port number described by "cptr" is opened for the
   multiplexer associated with descriptor "mp".  If the open is successful, all
   lines not currently otherwise connected (via serial, outgoing or direct 
   listener) are initialized for Telnet connections.

   Initialization for all connection styles (MUX wide listener, per line serial, 
   listener, outgoing, logging, buffering) are handled by this routine.

*/

t_stat tmxr_open_master (TMXR *mp, CONST char *cptr)
{
int32 i, line, nextline = -1;
char tbuf[CBUFSIZE], listen[CBUFSIZE], destination[CBUFSIZE], 
     logfiletmpl[CBUFSIZE], buffered[CBUFSIZE], hostport[CBUFSIZE], 
     port[CBUFSIZE], option[CBUFSIZE], speed[CBUFSIZE];
SOCKET sock;
SERHANDLE serport;
CONST char *tptr = cptr;
t_bool nolog, notelnet, listennotelnet, modem_control, loopback, datagram, packet;
TMLN *lp;
t_stat r = SCPE_OK;
t_bool not_quiet = (!sim_quiet) && (0 == (sim_switches & SWMASK ('Q')));

if (*tptr == '\0')
    return SCPE_ARG;
for (i = 0; i < mp->lines; i++) {               /* initialize lines */
    lp = mp->ldsc + i;
    lp->mp = mp;                                /* set the back pointer */
    lp->modem_control = mp->modem_control;
    if (lp->rxbpsfactor == 0.0)
        lp->rxbpsfactor = TMXR_RX_BPS_UNIT_SCALE;
    }
mp->ring_sock = INVALID_SOCKET;
free (mp->ring_ipad);
mp->ring_ipad = NULL;
mp->ring_start_time = 0;
tmxr_debug_trace (mp, "tmxr_open_master()");
while (*tptr) {
    line = nextline;
    memset(logfiletmpl, '\0', sizeof(logfiletmpl));
    memset(listen,      '\0', sizeof(listen));
    memset(destination, '\0', sizeof(destination));
    memset(buffered,    '\0', sizeof(buffered));
    memset(port,        '\0', sizeof(port));
    memset(option,      '\0', sizeof(option));
    memset(speed,       '\0', sizeof(speed));
    nolog = notelnet = listennotelnet = loopback = FALSE;
    datagram = mp->datagram;
    packet = mp->packet;
    if (mp->buffered)
        sprintf(buffered, "%d", mp->buffered);
    if (line != -1)
        notelnet = listennotelnet = mp->notelnet;
    modem_control = mp->modem_control;
    while (*tptr) {
        tptr = get_glyph_nc (tptr, tbuf, ',');
        if (!tbuf[0])
            break;
        cptr = tbuf;
        if (!isdigit(*cptr)) {
            char gbuf[CBUFSIZE];
            CONST char *init_cptr = cptr;

            cptr = get_glyph (cptr, gbuf, '=');
            if (0 == MATCH_CMD (gbuf, "LINE")) {
                if ((NULL == cptr) || ('\0' == *cptr))
                    return sim_messagef (SCPE_2FARG, "Missing Line Specifier\n");
                nextline = (int32) get_uint (cptr, 10, mp->lines-1, &r);
                if (r)
                    return sim_messagef (SCPE_ARG, "Invalid Line Specifier: %s\n", cptr);
                break;
                }
            if (0 == MATCH_CMD (gbuf, "LOG")) {
                if ((NULL == cptr) || ('\0' == *cptr))
                    return sim_messagef (SCPE_2FARG, "Missing Log Specifier\n");
                strncpy(logfiletmpl, cptr, sizeof(logfiletmpl)-1);
                continue;
                }
             if (0 == MATCH_CMD (gbuf, "LOOPBACK")) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected Loopback Specifier: %s\n", cptr);
                loopback = TRUE;
                continue;
                }
           if ((0 == MATCH_CMD (gbuf, "NOBUFFERED")) || 
                (0 == MATCH_CMD (gbuf, "UNBUFFERED"))) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected Unbuffered Specifier: %s\n", cptr);
                buffered[0] = '\0';
                continue;
                }
            if (0 == MATCH_CMD (gbuf, "BUFFERED")) {
                if ((NULL == cptr) || ('\0' == *cptr))
                    strcpy (buffered, "32768");
                else {
                    i = (int32) get_uint (cptr, 10, 1024*1024, &r);
                    if (r || (i == 0))
                        return sim_messagef (SCPE_ARG, "Invalid Buffered Specifier: %s\n", cptr);
                    sprintf(buffered, "%d", i);
                    }
                continue;
                }
            if (0 == MATCH_CMD (gbuf, "NOLOG")) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected NoLog Specifier: %s\n", cptr);
                nolog = TRUE;
                continue;
                }
            if (0 == MATCH_CMD (gbuf, "NOMODEM")) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected NoModem Specifier: %s\n", cptr);
                modem_control = FALSE;
                continue;
                }
            if (0 == MATCH_CMD (gbuf, "MODEM")) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected Modem Specifier: %s\n", cptr);
                modem_control = TRUE;
                continue;
                }
            if ((0 == MATCH_CMD (gbuf, "DATAGRAM")) || (0 == MATCH_CMD (gbuf, "UDP"))) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected Datagram Specifier: %s\n", cptr);
                notelnet = datagram = TRUE;
                continue;
                }
            if (0 == MATCH_CMD (gbuf, "PACKET")) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected Packet Specifier: %s\n", cptr);
                packet = TRUE;
                continue;
                }
            if ((0 == MATCH_CMD (gbuf, "STREAM")) || (0 == MATCH_CMD (gbuf, "TCP"))) {
                if ((NULL != cptr) && ('\0' != *cptr))
                    return sim_messagef (SCPE_2MARG, "Unexpected Stream Specifier: %s\n", cptr);
                datagram = FALSE;
                continue;
                }
            if (0 == MATCH_CMD (gbuf, "CONNECT")) {
                if ((NULL == cptr) || ('\0' == *cptr))
                    return sim_messagef (SCPE_2FARG, "Missing Connect Specifier\n");
                strncpy (destination, cptr, sizeof(destination)-1);
                continue;
                }
            if (0 == MATCH_CMD (gbuf, "SPEED")) {
                if ((NULL == cptr) || ('\0' == *cptr) || 
                    (_tmln_speed_delta (cptr) < 0))
                    return sim_messagef (SCPE_ARG, "Invalid Speed Specifier: %s\n", (cptr ? cptr : ""));
                strncpy (speed, cptr, sizeof(speed)-1);
                continue;
                }
            cptr = get_glyph (gbuf, port, ';');
            if (sim_parse_addr (port, NULL, 0, NULL, NULL, 0, NULL, NULL))
                return sim_messagef (SCPE_ARG, "Invalid Port Specifier: %s\n", port);
            if (cptr) {
                char *tptr = gbuf + (cptr - gbuf);
                get_glyph (cptr, tptr, 0);                  /* upcase this string */
                if (0 == MATCH_CMD (cptr, "NOTELNET"))
                    listennotelnet = TRUE;
                else
                    if (0 == MATCH_CMD (cptr, "TELNET"))
                        listennotelnet = FALSE;
                    else
                        return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", tptr);
                }
            cptr = init_cptr;
            }
        cptr = get_glyph_nc (cptr, port, ';');
        sock = sim_master_sock (port, &r);                      /* make master socket to validate port */
        if (r)
            return sim_messagef (SCPE_ARG, "Invalid Port Specifier: %s\n", port);
        if (sock == INVALID_SOCKET)                             /* open error */
            return sim_messagef (SCPE_OPENERR, "Can't open network port: %s\n", port);
        sim_close_sock (sock);
        sim_os_ms_sleep (2);                                    /* let the close finish (required on some platforms) */
        strcpy (listen, port);
        cptr = get_glyph (cptr, option, ';');
        if (option[0]) {
            if (0 == MATCH_CMD (option, "NOTELNET"))
                listennotelnet = TRUE;
            else
                if (0 == MATCH_CMD (option, "TELNET"))
                    listennotelnet = FALSE;
                else
                    return sim_messagef (SCPE_ARG, "Invalid Specifier: %s\n", option);
            }
        }
    if (destination[0]) {
        /* Validate destination */
        serport = sim_open_serial (destination, NULL, &r);
        if (serport != INVALID_HANDLE) {
            sim_close_serial (serport);
            if (strchr (destination, ';') && mp->modem_control && !(sim_switches & SIM_SW_REST))
                return sim_messagef (SCPE_ARG, "Serial line parameters must be set within simulated OS: %s\n", 1 + strchr (destination, ';'));
            }
        else {
            char *eptr;

            memset (hostport, '\0', sizeof(hostport));
            strncpy (hostport, destination, sizeof(hostport)-1);
            if ((eptr = strchr (hostport, ';')))
                *(eptr++) = '\0';
            if (eptr) {
                get_glyph (eptr, eptr, 0);          /* upcase this string */
                if (0 == MATCH_CMD (eptr, "NOTELNET"))
                    notelnet = TRUE;
                else
                    if (0 == MATCH_CMD (eptr, "TELNET"))
                        if (datagram)
                            return sim_messagef (SCPE_ARG, "Telnet invalid on Datagram socket\n");
                        else
                            notelnet = FALSE;
                    else
                        return sim_messagef (SCPE_ARG, "Unexpected specifier: %s\n", eptr);
                }
            sock = sim_connect_sock_ex (NULL, hostport, "localhost", NULL, (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | (packet ? SIM_SOCK_OPT_NODELAY : 0));
            if (sock != INVALID_SOCKET)
                sim_close_sock (sock);
            else
                return sim_messagef (SCPE_ARG, "Invalid destination: %s\n", hostport);
            }
        }
    if (line == -1) {
        if (modem_control != mp->modem_control)
            return SCPE_ARG;
        if (logfiletmpl[0]) {
            strncpy(mp->logfiletmpl, logfiletmpl, sizeof(mp->logfiletmpl)-1);
            for (i = 0; i < mp->lines; i++) {
                lp = mp->ldsc + i;
                sim_close_logfile (&lp->txlogref);
                lp->txlog = NULL;
                lp->txlogname = (char *)realloc(lp->txlogname, CBUFSIZE);
                if (mp->lines > 1)
                    sprintf(lp->txlogname, "%s_%d", mp->logfiletmpl, i);
                else
                    strcpy (lp->txlogname, mp->logfiletmpl);
                r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref);
                if (r != SCPE_OK) {
                    free (lp->txlogname);
                    lp->txlogname = NULL;
                    break;
                    }
                }
            }
        mp->buffered = atoi(buffered);
        for (i = 0; i < mp->lines; i++) { /* initialize line buffers */
            lp = mp->ldsc + i;
            if (mp->buffered) {
                lp->txbsz = mp->buffered;
                lp->txbfd = 1;
                lp->rxbsz = mp->buffered;
                }
            else {
                lp->txbsz = TMXR_MAXBUF;
                lp->txbfd = 0;
                lp->rxbsz = TMXR_MAXBUF;
                }
            lp->txbpi = lp->txbpr = 0;
            lp->txb = (char *)realloc(lp->txb, lp->txbsz);
            lp->rxb = (char *)realloc(lp->rxb, lp->rxbsz);
            lp->rbr = (char *)realloc(lp->rbr, lp->rxbsz);
            }
        if (nolog) {
            mp->logfiletmpl[0] = '\0';
            for (i = 0; i < mp->lines; i++) { /* close line logs */
                lp = mp->ldsc + i;
                free(lp->txlogname);
                lp->txlogname = NULL;
                if (lp->txlog) {
                    sim_close_logfile (&lp->txlogref);
                    lp->txlog = NULL;
                    }
                }
            }
        if ((listen[0]) && (!datagram)) {
            sock = sim_master_sock (listen, &r);            /* make master socket */
            if (r)
                return sim_messagef (SCPE_ARG, "Invalid network listen port: %s\n", listen);
            if (sock == INVALID_SOCKET)                     /* open error */
                return sim_messagef (SCPE_OPENERR, "Can't open network socket for listen port: %s\n", listen);
            if (mp->port) {                                 /* close prior listener */
                sim_close_sock (mp->master);
                mp->master = 0;
                free (mp->port);
                mp->port = NULL;
                }
            if (not_quiet)
                sim_printf ("Listening on port %s\n", listen);
            mp->port = (char *)realloc (mp->port, 1 + strlen (listen));
            strcpy (mp->port, listen);                      /* save port */
            mp->master = sock;                              /* save master socket */
            mp->ring_sock = INVALID_SOCKET;
            free (mp->ring_ipad);
            mp->ring_ipad = NULL;
            mp->ring_start_time = 0;
            mp->notelnet = listennotelnet;                  /* save desired telnet behavior flag */
            for (i = 0; i < mp->lines; i++) {               /* initialize lines */
                lp = mp->ldsc + i;
                lp->mp = mp;                                /* set the back pointer */
                lp->packet = mp->packet;

                if (lp->serport) {                          /* serial port attached? */
                    tmxr_reset_ln (lp);                     /* close current serial connection */
                    sim_control_serial (lp->serport, 0, TMXR_MDM_DTR|TMXR_MDM_RTS, NULL);/* drop DTR and RTS */
                    sim_close_serial (lp->serport);
                    lp->serport = 0;
                    free (lp->serconfig);
                    lp->serconfig = NULL;
                    }
                else {
                    if (speed[0])
                        tmxr_set_line_speed (lp, speed);
                    }
                tmxr_init_line (lp);                        /* initialize line state */
                lp->sock = 0;                               /* clear the socket */
                }
            }
        if (loopback) {
            if (mp->lines > 1)
                return sim_messagef (SCPE_ARG, "Ambiguous Loopback specification\n");
            if (not_quiet)
                sim_printf ("Operating in loopback mode\n");
            for (i = 0; i < mp->lines; i++) {
                lp = mp->ldsc + i;
                tmxr_set_line_loopback (lp, loopback);
                if (speed[0])
                    tmxr_set_line_speed (lp, speed);
                }
            }
        if (destination[0]) {
            if (mp->lines > 1)
                return sim_messagef (SCPE_ARG, "Ambiguous Destination specification\n");
            lp = &mp->ldsc[0];
            serport = sim_open_serial (destination, lp, &r);
            if (serport != INVALID_HANDLE) {
                _mux_detach_line (lp, TRUE, TRUE);
                if (lp->mp && lp->mp->master) {             /* if existing listener, close it */
                    sim_close_sock (lp->mp->master);
                    lp->mp->master = 0;
                    free (lp->mp->port);
                    lp->mp->port = NULL;
                    }
                lp->destination = (char *)malloc(1+strlen(destination));
                strcpy (lp->destination, destination);
                lp->mp = mp;
                lp->serport = serport;
                lp->ser_connect_pending = TRUE;
                lp->notelnet = TRUE;
                tmxr_init_line (lp);                        /* init the line state */
                if (!lp->mp->modem_control)                 /* raise DTR and RTS for non modem control lines */
                    sim_control_serial (lp->serport, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL);
                lp->cnms = sim_os_msec ();                  /* record time of connection */
                if (sim_switches & SWMASK ('V')) {          /* -V flag reports connection on port */
                    sim_os_ms_sleep (TMXR_DTR_DROP_TIME);
                    tmxr_report_connection (mp, lp);        /* report the connection to the line */
                    }
                }
            else {
                lp->datagram = datagram;
                if (datagram) {
                    if (listen[0]) {
                        lp->port = (char *)realloc (lp->port, 1 + strlen (listen));
                        strcpy (lp->port, listen);           /* save port */
                        }
                    else
                        return sim_messagef (SCPE_ARG, "Missing listen port for Datagram socket\n");
                    }
                lp->packet = packet;
                sock = sim_connect_sock_ex (datagram ? listen : NULL, hostport, "localhost", NULL, (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | (packet ? SIM_SOCK_OPT_NODELAY : 0));
                if (sock != INVALID_SOCKET) {
                    _mux_detach_line (lp, FALSE, TRUE);
                    lp->destination = (char *)malloc(1+strlen(hostport));
                    strcpy (lp->destination, hostport);
                    lp->mp = mp;
                    if (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR)) {
                        lp->connecting = sock;
                        lp->ipad = (char *)malloc (1 + strlen (lp->destination));
                        strcpy (lp->ipad, lp->destination);
                        }
                    else
                        sim_close_sock (sock);
                    lp->notelnet = notelnet;
                    tmxr_init_line (lp);                    /* init the line state */
                    if (speed[0] && (!datagram))
                        tmxr_set_line_speed (lp, speed);
                    return SCPE_OK;
                    }
                else
                    return sim_messagef (SCPE_ARG, "Can't open %s socket on %s%s%s\n", datagram ? "Datagram" : "Stream", datagram ? listen : "", datagram ? "<->" : "", hostport);
                }
            }
        }
    else {                                                  /* line specific attach */
        lp = &mp->ldsc[line];
        lp->mp = mp;
        if (logfiletmpl[0]) {
            sim_close_logfile (&lp->txlogref);
            lp->txlog = NULL;
            lp->txlogname = (char *)realloc (lp->txlogname, 1 + strlen (logfiletmpl));
            strcpy (lp->txlogname, logfiletmpl);
            r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref);
            if (r == SCPE_OK)
                setvbuf(lp->txlog, NULL, _IOFBF, 65536);
            else {
                free (lp->txlogname);
                lp->txlogname = NULL;
                return sim_messagef (r, "Can't open log file: %s\n", logfiletmpl);
                }
            }
        if (buffered[0] == '\0') {
            lp->rxbsz = lp->txbsz = TMXR_MAXBUF;
            lp->txbfd = 0;
            }
        else {
            lp->rxbsz = lp->txbsz = atoi(buffered);
            lp->txbfd = 1;
            }
        lp->txbpi = lp->txbpr = 0;
        lp->txb = (char *)realloc (lp->txb, lp->txbsz);
        lp->rxb = (char *)realloc(lp->rxb, lp->rxbsz);
        lp->rbr = (char *)realloc(lp->rbr, lp->rxbsz);
        lp->packet = packet;
        if (nolog) {
            free(lp->txlogname);
            lp->txlogname = NULL;
            if (lp->txlog) {
                sim_close_logfile (&lp->txlogref);
                lp->txlog = NULL;
                }
            }
        if ((listen[0]) && (!datagram)) {
            if ((mp->lines == 1) && (mp->master))
                return sim_messagef (SCPE_ARG, "Single Line MUX can have either line specific OR MUS listener but NOT both\n");
            sock = sim_master_sock (listen, &r);            /* make master socket */
            if (r)
                return sim_messagef (SCPE_ARG, "Invalid Listen Specification: %s\n", listen);
            if (sock == INVALID_SOCKET)                     /* open error */
                return sim_messagef (SCPE_OPENERR, "Can't listen on port: %s\n", listen);
            _mux_detach_line (lp, TRUE, FALSE);
            if (not_quiet)
                sim_printf ("Line %d Listening on port %s\n", line, listen);
            lp->port = (char *)realloc (lp->port, 1 + strlen (listen));
            strcpy (lp->port, listen);                       /* save port */
            lp->master = sock;                              /* save master socket */
            if (listennotelnet != mp->notelnet)
                lp->notelnet = listennotelnet;
            else
                lp->notelnet = mp->notelnet;
            }
        if (destination[0]) {
            serport = sim_open_serial (destination, lp, &r);
            if (serport != INVALID_HANDLE) {
                _mux_detach_line (lp, TRUE, TRUE);
                lp->destination = (char *)malloc(1+strlen(destination));
                strcpy (lp->destination, destination);
                lp->serport = serport;
                lp->ser_connect_pending = TRUE;
                lp->notelnet = TRUE;
                tmxr_init_line (lp);                        /* init the line state */
                if (!lp->mp->modem_control)                 /* raise DTR and RTS for non modem control lines */
                    sim_control_serial (lp->serport, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL);
                lp->cnms = sim_os_msec ();                  /* record time of connection */
                if (sim_switches & SWMASK ('V')) {          /* -V flag reports connection on port */
                    sim_os_ms_sleep (TMXR_DTR_DROP_TIME);
                    tmxr_report_connection (mp, lp);        /* report the connection to the line */
                    }
                }
            else {
                lp->datagram = datagram;
                if (datagram) {
                    if (listen[0]) {
                        lp->port = (char *)realloc (lp->port, 1 + strlen (listen));
                        strcpy (lp->port, listen);          /* save port */
                        }
                    else
                        return sim_messagef (SCPE_ARG, "Missing listen port for Datagram socket\n");
                    }
                sock = sim_connect_sock_ex (datagram ? listen : NULL, hostport, "localhost", NULL, (datagram ? SIM_SOCK_OPT_DATAGRAM : 0) | (packet ? SIM_SOCK_OPT_NODELAY : 0));
                if (sock != INVALID_SOCKET) {
                    _mux_detach_line (lp, FALSE, TRUE);
                    lp->destination = (char *)malloc(1+strlen(hostport));
                    strcpy (lp->destination, hostport);
                    if (!lp->modem_control || (lp->modembits & TMXR_MDM_DTR)) {
                        lp->connecting = sock;
                        lp->ipad = (char *)malloc (1 + strlen (lp->destination));
                        strcpy (lp->ipad, lp->destination);
                        }
                    else
                        sim_close_sock (sock);
                    lp->notelnet = notelnet;
                    tmxr_init_line (lp);                    /* init the line state */
                    }
                else
                    return sim_messagef (SCPE_ARG, "Can't open %s socket on %s%s%s\n", datagram ? "Datagram" : "Stream", datagram ? listen : "", datagram ? "<->" : "", hostport);
                }
            }
        if (loopback) {
            tmxr_set_line_loopback (lp, loopback);
            if (not_quiet)
                sim_printf ("Line %d operating in loopback mode\n", line);
            }
        lp->modem_control = modem_control;
        if (speed[0] && (!datagram) && (!lp->serport))
            tmxr_set_line_speed (lp, speed);
        r = SCPE_OK;
        }
    }
if (r == SCPE_OK)
    tmxr_add_to_open_list (mp);
return r;
}


/* Declare which unit polls for input 

   Inputs:
        *mp     =       the mux
        line    =       the line number
        *uptr_poll =    the unit which polls

   Outputs:
        none

   Implementation note:

        Only devices which poll on a unit different from the unit provided
        at MUX attach time need call this function.  Calling this API is
        necessary for asynchronous multiplexer support and unnecessary 
        otherwise.

*/

t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll)
{
if ((line < 0) || (line >= mp->lines))
    return SCPE_ARG;
mp->ldsc[line].uptr = uptr_poll;
return SCPE_OK;
}

/* Declare which unit polls for output 

   Inputs:
        *mp     =       the mux
        line    =       the line number
        *uptr_poll =    the unit which polls for output

   Outputs:
        none

   Implementation note:

        Only devices which poll on a unit different from the unit provided
        at MUX attach time need call this function ABD different from the
        unit which polls for input.  Calling this API is necessary for 
        asynchronous multiplexer support and unnecessary otherwise.

*/

t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll)
{
if ((line < 0) || (line >= mp->lines))
    return SCPE_ARG;
mp->ldsc[line].o_uptr = uptr_poll;
return SCPE_OK;
}

/* Declare which units are the console input and out devices

   Inputs:
        *rxuptr =    the console input unit
        *txuptr =    the console output unit

   Outputs:
        none

   Implementation note:

        This routine is exported by the tmxr library so that it gets 
        defined to code which uses it by including sim_tmxr.h.  Including
        sim_tmxr.h is necessary so that sim_activate is properly defined
        in the caller's code to actually call tmxr_activate.

*/

t_stat tmxr_set_console_units (UNIT *rxuptr, UNIT *txuptr)
{
extern TMXR sim_con_tmxr;

tmxr_set_line_unit (&sim_con_tmxr, 0, rxuptr);
tmxr_set_line_output_unit (&sim_con_tmxr, 0, txuptr);
return SCPE_OK;
}


static TMXR **tmxr_open_devices = NULL;
static int tmxr_open_device_count = 0;

#if defined(SIM_ASYNCH_MUX)
pthread_t           sim_tmxr_poll_thread;          /* Polling Thread Id */
#if defined(_WIN32) || defined(VMS)
pthread_t           sim_tmxr_serial_poll_thread;   /* Serial Polling Thread Id */
pthread_cond_t      sim_tmxr_serial_startup_cond;
#endif
pthread_mutex_t     sim_tmxr_poll_lock;
pthread_cond_t      sim_tmxr_poll_cond;
pthread_cond_t      sim_tmxr_startup_cond;
int32               sim_tmxr_poll_count = 0;
t_bool              sim_tmxr_poll_running = FALSE;

static void *
_tmxr_poll(void *arg)
{
struct timeval timeout;
int timeout_usec;
DEVICE *dptr = tmxr_open_devices[0]->dptr;
UNIT **units = NULL;
UNIT **activated = NULL;
SOCKET *sockets = NULL;
int wait_count = 0;

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which, in general, won't be readily yielding the processor when 
   this thread needs to run */
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_poll() - starting\n");

units = (UNIT **)calloc(FD_SETSIZE, sizeof(*units));
activated = (UNIT **)calloc(FD_SETSIZE, sizeof(*activated));
sockets = (SOCKET *)calloc(FD_SETSIZE, sizeof(*sockets));
timeout_usec = 1000000;
pthread_mutex_lock (&sim_tmxr_poll_lock);
pthread_cond_signal (&sim_tmxr_startup_cond);   /* Signal we're ready to go */
while (sim_asynch_enabled) {
    int i, j, status, select_errno;
    fd_set readfds, errorfds;
    int socket_count;
    SOCKET max_socket_fd;
    TMXR *mp;
    DEVICE *d;

    if ((tmxr_open_device_count == 0) || (!sim_is_running)) {
        for (j=0; j<wait_count; ++j) {
            d = find_dev_from_unit(activated[j]);
            sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Removing interest in %s. Other interest: %d\n", sim_uname(activated[j]), activated[j]->a_poll_waiter_count);
            --activated[j]->a_poll_waiter_count;
            --sim_tmxr_poll_count;
            }
        break;
        }
    /* If we started something we should wait for, let it finish before polling again */
    if (wait_count) {
        sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_poll() - waiting for %d units\n", wait_count);
        pthread_cond_wait (&sim_tmxr_poll_cond, &sim_tmxr_poll_lock);
        sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_poll() - continuing with timeout of %dms\n", timeout_usec/1000);
        }
    FD_ZERO (&readfds);
    FD_ZERO (&errorfds);
    for (i=max_socket_fd=socket_count=0; i<tmxr_open_device_count; ++i) {
        mp = tmxr_open_devices[i];
        if ((mp->master) && (mp->uptr->dynflags&UNIT_TM_POLL)) {
            units[socket_count] = mp->uptr;
            sockets[socket_count] = mp->master;
            FD_SET (mp->master, &readfds);
            FD_SET (mp->master, &errorfds);
            if (mp->master > max_socket_fd)
                max_socket_fd = mp->master;
            ++socket_count;
            }
        for (j=0; j<mp->lines; ++j) {
            if (mp->ldsc[j].sock) {
                units[socket_count] = mp->ldsc[j].uptr;
                if (units[socket_count] == NULL)
                    units[socket_count] = mp->uptr;
                sockets[socket_count] = mp->ldsc[j].sock;
                FD_SET (mp->ldsc[j].sock, &readfds);
                FD_SET (mp->ldsc[j].sock, &errorfds);
                if (mp->ldsc[j].sock > max_socket_fd)
                    max_socket_fd = mp->ldsc[j].sock;
                ++socket_count;
                }
#if !defined(_WIN32) && !defined(VMS)
            if (mp->ldsc[j].serport) {
                units[socket_count] = mp->ldsc[j].uptr;
                if (units[socket_count] == NULL)
                    units[socket_count] = mp->uptr;
                sockets[socket_count] = mp->ldsc[j].serport;
                FD_SET (mp->ldsc[j].serport, &readfds);
                FD_SET (mp->ldsc[j].serport, &errorfds);
                if (mp->ldsc[j].serport > max_socket_fd)
                    max_socket_fd = mp->ldsc[j].serport;
                ++socket_count;
                }
#endif
            if (mp->ldsc[j].connecting) {
                units[socket_count] = mp->uptr;
                sockets[socket_count] = mp->ldsc[j].connecting;
                FD_SET (mp->ldsc[j].connecting, &readfds);
                FD_SET (mp->ldsc[j].connecting, &errorfds);
                if (mp->ldsc[j].connecting > max_socket_fd)
                    max_socket_fd = mp->ldsc[j].connecting;
                ++socket_count;
                }
            if (mp->ldsc[j].master) {
                units[socket_count] = mp->uptr;
                sockets[socket_count] = mp->ldsc[j].master;
                FD_SET (mp->ldsc[j].master, &readfds);
                FD_SET (mp->ldsc[j].master, &errorfds);
                if (mp->ldsc[j].master > max_socket_fd)
                    max_socket_fd = mp->ldsc[j].master;
                ++socket_count;
                }
            }
        }
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
    if (timeout_usec > 1000000)
        timeout_usec = 1000000;
    timeout.tv_sec = timeout_usec/1000000;
    timeout.tv_usec = timeout_usec%1000000;
    select_errno = 0;
    if (socket_count == 0) {
        sim_os_ms_sleep (timeout_usec/1000);
        status = 0;
        }
    else
        status = select (1+(int)max_socket_fd, &readfds, NULL, &errorfds, &timeout);
    select_errno = errno;
    wait_count=0;
    pthread_mutex_lock (&sim_tmxr_poll_lock);
    switch (status) {
        case 0:     /* timeout */
            for (i=max_socket_fd=socket_count=0; i<tmxr_open_device_count; ++i) {
                mp = tmxr_open_devices[i];
                if (mp->master) {
                    if (!mp->uptr->a_polling_now) {
                        mp->uptr->a_polling_now = TRUE;
                        mp->uptr->a_poll_waiter_count = 0;
                        d = find_dev_from_unit(mp->uptr);
                        sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Activating %s to poll connect\n", sim_uname(mp->uptr));
                        pthread_mutex_unlock (&sim_tmxr_poll_lock);
                        _sim_activate (mp->uptr, 0);
                        pthread_mutex_lock (&sim_tmxr_poll_lock);
                        }
                    if (mp->txcount) {
                        timeout_usec = 10000; /* Wait 10ms next time (this gets doubled below) */
                        mp->txcount = 0;
                        }
                    }
                for (j=0; j<mp->lines; ++j) {
                    if ((mp->ldsc[j].conn) && (mp->ldsc[j].uptr)) {
                        if (tmxr_tqln(&mp->ldsc[j]) || tmxr_rqln (&mp->ldsc[j])) {
                            timeout_usec = 10000; /* Wait 10ms next time (this gets doubled below) */
                            /* More than one socket can be associated with the 
                               same unit.  Make sure to only activate it one time */
                            if (!mp->ldsc[j].uptr->a_polling_now) {
                                mp->ldsc[j].uptr->a_polling_now = TRUE;
                                mp->ldsc[j].uptr->a_poll_waiter_count = 0;
                                d = find_dev_from_unit(mp->ldsc[j].uptr);
                                sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Line %d Activating %s to poll data: %d/%d\n", 
                                    j, sim_uname(mp->ldsc[j].uptr), tmxr_tqln(&mp->ldsc[j]), tmxr_rqln (&mp->ldsc[j]));
                                pthread_mutex_unlock (&sim_tmxr_poll_lock);
                                _sim_activate (mp->ldsc[j].uptr, 0);
                                pthread_mutex_lock (&sim_tmxr_poll_lock);
                                }
                            }
                        }
                    }
                }
            sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_poll() - Poll Timeout - %dms\n", timeout_usec/1000);
            timeout_usec *= 2;     /* Double timeout time */  
            break;
        case SOCKET_ERROR:
            wait_count = 0;
            if (select_errno == EINTR)
                break;
            sim_printf ("select() returned -1, errno=%d - %s\r\n", select_errno, strerror(select_errno));
            abort();
            break;
        default:
            wait_count = 0;
            for (i=0; i<socket_count; ++i) {
                if (FD_ISSET(sockets[i], &readfds) || 
                    FD_ISSET(sockets[i], &errorfds)) {
                    /* More than one socket can be associated with the 
                       same unit.  Only activate one time */
                    for (j=0; j<wait_count; ++j)
                        if (activated[j] == units[i])
                            break;
                    if (j == wait_count) {
                        activated[j] = units[i];
                        ++wait_count;
                        if (!activated[j]->a_polling_now) {
                            activated[j]->a_polling_now = TRUE;
                            activated[j]->a_poll_waiter_count = 1;
                            d = find_dev_from_unit(activated[j]);
                            sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Activating for data %s\n", sim_uname(activated[j]));
                            pthread_mutex_unlock (&sim_tmxr_poll_lock);
                            _sim_activate (activated[j], 0);
                            pthread_mutex_lock (&sim_tmxr_poll_lock);
                            }
                        else {
                            d = find_dev_from_unit(activated[j]);
                            sim_debug (TMXR_DBG_ASY, d, "_tmxr_poll() - Already Activated %s%d %d times\n", sim_uname(activated[j]), activated[j]->a_poll_waiter_count);
                            ++activated[j]->a_poll_waiter_count;
                            }
                        }
                    }
                }
            if (wait_count)
                timeout_usec = 10000; /* Wait 10ms next time */
            break;
        }
    sim_tmxr_poll_count += wait_count;
    }
pthread_mutex_unlock (&sim_tmxr_poll_lock);
free(units);
free(activated);
free(sockets);

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_poll() - exiting\n");

return NULL;
}

#if defined(_WIN32)
static void *
_tmxr_serial_poll(void *arg)
{
int timeout_usec;
DEVICE *dptr = tmxr_open_devices[0]->dptr;
UNIT **units = NULL;
UNIT **activated = NULL;
SERHANDLE *serports = NULL;
int wait_count = 0;

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which, in general, won't be readily yielding the processor when 
   this thread needs to run */
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - starting\n");

units = (UNIT **)calloc(MAXIMUM_WAIT_OBJECTS, sizeof(*units));
activated = (UNIT **)calloc(MAXIMUM_WAIT_OBJECTS, sizeof(*activated));
serports = (SERHANDLE *)calloc(MAXIMUM_WAIT_OBJECTS, sizeof(*serports));
timeout_usec = 1000000;
pthread_mutex_lock (&sim_tmxr_poll_lock);
pthread_cond_signal (&sim_tmxr_serial_startup_cond);   /* Signal we're ready to go */
while (sim_asynch_enabled) {
    int i, j;
    DWORD status;
    int serport_count;
    TMXR *mp;
    DEVICE *d;

    if ((tmxr_open_device_count == 0) || (!sim_is_running)) {
        for (j=0; j<wait_count; ++j) {
            d = find_dev_from_unit(activated[j]);
            sim_debug (TMXR_DBG_ASY, d, "_tmxr_serial_poll() - Removing interest in %s. Other interest: %d\n", sim_uname(activated[j]), activated[j]->a_poll_waiter_count);
            --activated[j]->a_poll_waiter_count;
            --sim_tmxr_poll_count;
            }
        break;
        }
    /* If we started something we should wait for, let it finish before polling again */
    if (wait_count) {
        sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - waiting for %d units\n", wait_count);
        pthread_cond_wait (&sim_tmxr_poll_cond, &sim_tmxr_poll_lock);
        sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - continuing with timeout of %dms\n", timeout_usec/1000);
        }
    for (i=serport_count=0; i<tmxr_open_device_count; ++i) {
        mp = tmxr_open_devices[i];
        for (j=0; j<mp->lines; ++j) {
            if (mp->ldsc[j].serport) {
                units[serport_count] = mp->ldsc[j].uptr;
                if (units[serport_count] == NULL)
                    units[serport_count] = mp->uptr;
                serports[serport_count] = mp->ldsc[j].serport;
                ++serport_count;
                }
            }
        }
    if (serport_count == 0)                                 /* No open serial ports? */
        break;                                              /* We're done */
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
    if (timeout_usec > 1000000)
        timeout_usec = 1000000;
    status = WaitForMultipleObjects (serport_count, serports, FALSE, timeout_usec/1000);
    wait_count=0;
    pthread_mutex_lock (&sim_tmxr_poll_lock);
    switch (status) {
        case WAIT_FAILED:
            sim_printf ("WaitForMultipleObjects() Failed, LastError=%d\r\n", GetLastError());
            abort();
            break;
        case WAIT_TIMEOUT:
            sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - Poll Timeout - %dms\n", timeout_usec/1000);
            timeout_usec *= 2;     /* Double timeout time */  
            break;
        default:
            i = status - WAIT_OBJECT_0;
            wait_count = 0;
            j = wait_count;
            activated[j] = units[i];
            ++wait_count;
            if (!activated[j]->a_polling_now) {
                activated[j]->a_polling_now = TRUE;
                activated[j]->a_poll_waiter_count = 1;
                d = find_dev_from_unit(activated[j]);
                sim_debug (TMXR_DBG_ASY, d, "_tmxr_serial_poll() - Activating for data %s\n", sim_uname(activated[j]));
                pthread_mutex_unlock (&sim_tmxr_poll_lock);
                _sim_activate (activated[j], 0);
                pthread_mutex_lock (&sim_tmxr_poll_lock);
                }
            else {
                d = find_dev_from_unit(activated[j]);
                sim_debug (TMXR_DBG_ASY, d, "_tmxr_serial_poll() - Already Activated %s%d %d times\n", sim_uname(activated[j]), activated[j]->a_poll_waiter_count);
                ++activated[j]->a_poll_waiter_count;
                }
            if (wait_count)
                timeout_usec = 10000; /* Wait 10ms next time */
            break;
        }
    sim_tmxr_poll_count += wait_count;
    }
pthread_mutex_unlock (&sim_tmxr_poll_lock);
free(units);
free(activated);
free(serports);

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - exiting\n");

return NULL;
}
#endif /* _WIN32 */

#if defined(VMS)

#include <descrip.h>
#include <ttdef.h>
#include <tt2def.h>
#include <iodef.h>
#include <ssdef.h>
#include <starlet.h>
#include <unistd.h>

typedef struct {
    unsigned short status;
    unsigned short count;
    unsigned int dev_status; } IOSB;

#define MAXIMUM_WAIT_OBJECTS 64             /* Number of possible concurrently opened serial ports */

pthread_cond_t      sim_serial_line_startup_cond;


static void *
_tmxr_serial_line_poll(void *arg)
{
TMLN *lp = (TMLN *)arg;
DEVICE *dptr = tmxr_open_devices[0]->dptr;
UNIT *uptr = (lp->uptr ? lp->uptr : lp->mp->uptr);
DEVICE *d = find_dev_from_unit(uptr);
int wait_count = 0;

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which, in general, won't be readily yielding the processor when 
   this thread needs to run */
sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_line_poll() - starting\n");

pthread_mutex_lock (&sim_tmxr_poll_lock);
pthread_cond_signal (&sim_serial_line_startup_cond);   /* Signal we're ready to go */
while (sim_asynch_enabled) {
    int i, j;
    int serport_count;
    TMXR *mp = lp->mp;
    unsigned int status, term[2];
    unsigned char buf[4];
    IOSB iosb;

    if ((tmxr_open_device_count == 0) || (!sim_is_running)) {
        if (wait_count) {
            sim_debug (TMXR_DBG_ASY, d, "_tmxr_serial_line_poll() - Removing interest in %s. Other interest: %d\n", sim_uname(uptr), uptr->a_poll_waiter_count);
            --uptr->a_poll_waiter_count;
            --sim_tmxr_poll_count;
            }
        break;
        }
    /* If we started something we should wait for, let it finish before polling again */
    if (wait_count) {
        sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_line_poll() - waiting for %d units\n", wait_count);
        pthread_cond_wait (&sim_tmxr_poll_cond, &sim_tmxr_poll_lock);
        sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_line_poll() - continuing with timeout of 1 sec\n");
        }
    lp->a_active = TRUE;
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
    term[0] = term[1] = 0;
    status = sys$qiow (0, lp->serport, 
                       IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO,
                       &iosb, 0, 0, buf, 1, 1, term, 0, 0);
    if (status != SS$_NORMAL) {
        sim_printf ("_tmxr_serial_line_poll() - QIO Failed, Status=%d\r\n", status);
        abort();
        }
    wait_count = 0;
    sys$synch (0, &iosb);
    pthread_mutex_lock (&sim_tmxr_poll_lock);
    lp->a_active = FALSE;
    if (iosb.count == 1) {
        lp->a_buffered_character = buf[0] | SCPE_KFLAG;
        wait_count = 1;
        if (!uptr->a_polling_now) {
            uptr->a_polling_now = TRUE;
            uptr->a_poll_waiter_count = 1;
            sim_debug (TMXR_DBG_ASY, d, "_tmxr_serial_line_poll() - Activating for data %s\n", sim_uname(uptr));
            pthread_mutex_unlock (&sim_tmxr_poll_lock);
            _sim_activate (uptr, 0);
            pthread_mutex_lock (&sim_tmxr_poll_lock);
            }
        else {
            sim_debug (TMXR_DBG_ASY, d, "_tmxr_serial_line_poll() - Already Activated %s%d %d times\n", sim_uname(uptr), uptr->a_poll_waiter_count);
            ++uptr->a_poll_waiter_count;
            }
        }
    sim_tmxr_poll_count += wait_count;
    }
pthread_mutex_unlock (&sim_tmxr_poll_lock);

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_line_poll() - exiting\n");

return NULL;
}

static void *
_tmxr_serial_poll(void *arg)
{
int timeout_usec;
DEVICE *dptr = tmxr_open_devices[0]->dptr;
TMLN **lines = NULL;
pthread_t *threads = NULL;

/* Boost Priority for this I/O thread vs the CPU instruction execution 
   thread which, in general, won't be readily yielding the processor when 
   this thread needs to run */

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - starting\n");

lines = (TMLN **)calloc(MAXIMUM_WAIT_OBJECTS, sizeof(*lines));
threads = (pthread_t *)calloc(MAXIMUM_WAIT_OBJECTS, sizeof(*threads));
pthread_mutex_lock (&sim_tmxr_poll_lock);
pthread_cond_signal (&sim_tmxr_serial_startup_cond);   /* Signal we're ready to go */
pthread_cond_init (&sim_serial_line_startup_cond, NULL);
while (sim_asynch_enabled) {
    pthread_attr_t attr;
    int i, j;
    int serport_count;
    TMXR *mp;
    DEVICE *d;

    if ((tmxr_open_device_count == 0) || (!sim_is_running))
        break;
    pthread_attr_init (&attr);
    pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
    for (i=serport_count=0; i<tmxr_open_device_count; ++i) {
        mp = tmxr_open_devices[i];
        for (j=0; j<mp->lines; ++j) {
            if (mp->ldsc[j].serport) {
                lines[serport_count] = &mp->ldsc[j];
                pthread_create (&threads[serport_count], &attr, _tmxr_serial_line_poll, (void *)&mp->ldsc[j]);
                pthread_cond_wait (&sim_serial_line_startup_cond, &sim_tmxr_poll_lock); /* Wait for thread to stabilize */
                ++serport_count;
                }
            }
        }
    pthread_attr_destroy( &attr);
    if (serport_count == 0)                                 /* No open serial ports? */
        break;                                              /* We're done */
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
    for (i=0; i<serport_count; i++)
        pthread_join (threads[i], NULL);
    pthread_mutex_lock (&sim_tmxr_poll_lock);
    }
pthread_mutex_unlock (&sim_tmxr_poll_lock);
pthread_cond_destroy (&sim_serial_line_startup_cond);
free(lines);
free(threads);

sim_debug (TMXR_DBG_ASY, dptr, "_tmxr_serial_poll() - exiting\n");

return NULL;
}
#endif /* VMS */

#endif /* defined(SIM_ASYNCH_MUX) */

t_stat tmxr_start_poll (void)
{
#if defined(SIM_ASYNCH_MUX)
pthread_mutex_lock (&sim_tmxr_poll_lock);
if ((tmxr_open_device_count > 0) && 
    sim_asynch_enabled           && 
    sim_is_running               && 
    !sim_tmxr_poll_running) {
    pthread_attr_t attr;

    pthread_cond_init (&sim_tmxr_startup_cond, NULL);
    pthread_attr_init (&attr);
    pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
    pthread_create (&sim_tmxr_poll_thread, &attr, _tmxr_poll, NULL);
    pthread_attr_destroy( &attr);
    pthread_cond_wait (&sim_tmxr_startup_cond, &sim_tmxr_poll_lock); /* Wait for thread to stabilize */
    pthread_cond_destroy (&sim_tmxr_startup_cond);
    sim_tmxr_poll_running = TRUE;
    }
pthread_mutex_unlock (&sim_tmxr_poll_lock);
#endif
return SCPE_OK;
}

t_stat tmxr_stop_poll (void)
{
#if defined(SIM_ASYNCH_MUX)
pthread_mutex_lock (&sim_tmxr_poll_lock);
if (sim_tmxr_poll_running) {
    pthread_cond_signal (&sim_tmxr_poll_cond);
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
    pthread_join (sim_tmxr_poll_thread, NULL);
    sim_tmxr_poll_running = FALSE;
    /* Transitioning from asynch mode so kick all polling units onto the event queue */
    if (tmxr_open_device_count) {
        int i, j;

        for (i=0; i<tmxr_open_device_count; ++i) {
            TMXR *mp = tmxr_open_devices[i];

            if (mp->uptr)
                _sim_activate (mp->uptr, 0);
            for (j = 0; j < mp->lines; ++j)
                if (mp->ldsc[j].uptr)
                    _sim_activate (mp->ldsc[j].uptr, 0);
            }
        }
    }
else
    pthread_mutex_unlock (&sim_tmxr_poll_lock);
#endif
return SCPE_OK;
}

static void tmxr_add_to_open_list (TMXR* mux)
{
int i;
t_bool found = FALSE;

#if defined(SIM_ASYNCH_MUX)
pthread_mutex_lock (&sim_tmxr_poll_lock);
#endif
for (i=0; i<tmxr_open_device_count; ++i)
    if (tmxr_open_devices[i] == mux) {
        found = TRUE;
        break;
        }
if (!found) {
    tmxr_open_devices = (TMXR **)realloc(tmxr_open_devices, (tmxr_open_device_count+1)*sizeof(*tmxr_open_devices));
    tmxr_open_devices[tmxr_open_device_count++] = mux;
    for (i=0; i<mux->lines; i++)
        if (0 == mux->ldsc[i].send.delay)
            mux->ldsc[i].send.delay = SEND_DEFAULT_DELAY;
    }
#if defined(SIM_ASYNCH_MUX)
pthread_mutex_unlock (&sim_tmxr_poll_lock);
if ((tmxr_open_device_count == 1) && (sim_asynch_enabled))
    tmxr_start_poll ();
#endif
}

static void _tmxr_remove_from_open_list (TMXR* mux)
{
int i, j;

#if defined(SIM_ASYNCH_MUX)
tmxr_stop_poll ();
pthread_mutex_lock (&sim_tmxr_poll_lock);
#endif
for (i=0; i<tmxr_open_device_count; ++i)
    if (tmxr_open_devices[i] == mux) {
        for (j=i+1; j<tmxr_open_device_count; ++j)
            tmxr_open_devices[j-1] = tmxr_open_devices[j];
        --tmxr_open_device_count;
        break;
        }
#if defined(SIM_ASYNCH_MUX)
pthread_mutex_unlock (&sim_tmxr_poll_lock);
#endif
}

static t_stat _tmxr_locate_line_send_expect (const char *cptr, SEND **snd, EXPECT **exp)
{
char gbuf[CBUFSIZE];
DEVICE *dptr;
int i;
t_stat r;

if (snd)
    *snd = NULL;
if (exp)
    *exp = NULL;
cptr = get_glyph(cptr, gbuf, ':');
dptr = find_dev (gbuf);                 /* device match? */
if (!dptr)
    return SCPE_ARG;

for (i=0; i<tmxr_open_device_count; ++i)
    if (tmxr_open_devices[i]->dptr == dptr) {
        int line = (int)get_uint (cptr, 10, tmxr_open_devices[i]->lines, &r);
        if (r != SCPE_OK)
            return r;
        if (snd)
            *snd = &tmxr_open_devices[i]->ldsc[line].send;
        if (exp)
            *exp = &tmxr_open_devices[i]->ldsc[line].expect;
        return SCPE_OK;
        }
return SCPE_ARG;
}

t_stat tmxr_locate_line_send (const char *cptr, SEND **snd)
{
return _tmxr_locate_line_send_expect (cptr, snd, NULL);
}

t_stat tmxr_locate_line_expect (const char *cptr, EXPECT **exp)
{
return _tmxr_locate_line_send_expect (cptr, NULL, exp);
}

t_stat tmxr_change_async (void)
{
#if defined(SIM_ASYNCH_IO)
if (sim_asynch_enabled)
    tmxr_start_poll ();
else
    tmxr_stop_poll ();
#endif
return SCPE_OK;
}


/* Attach unit to master socket */

t_stat tmxr_attach_ex (TMXR *mp, UNIT *uptr, CONST char *cptr, t_bool async)
{
t_stat r;
int32 i;

r = tmxr_open_master (mp, cptr);                        /* open master socket */
if (r != SCPE_OK)                                       /* error? */
    return r;
mp->uptr = uptr;                                        /* save unit for polling */
uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);/* save */
uptr->flags = uptr->flags | UNIT_ATT;                   /* no more errors */
uptr->tmxr = (void *)mp;
if ((mp->lines > 1) ||
    ((mp->master == 0) &&
     (mp->ldsc[0].connecting == 0) &&
     (mp->ldsc[0].serport == 0)))
    uptr->dynflags = uptr->dynflags | UNIT_ATTMULT;     /* allow multiple attach commands */

#if defined(SIM_ASYNCH_MUX)
if (!async || (uptr->flags & TMUF_NOASYNCH))            /* if asynch disabled */
    uptr->dynflags |= TMUF_NOASYNCH;                    /* tag as no asynch */
#else
uptr->dynflags |= TMUF_NOASYNCH;                        /* tag as no asynch */
#endif

if (mp->dptr == NULL)                                   /* has device been set? */
    mp->dptr = find_dev_from_unit (uptr);               /* no, so set device now */

if (mp->dptr) {
    for (i=0; i<mp->lines; i++) {
        mp->ldsc[i].expect.dptr = mp->dptr;
        mp->ldsc[i].expect.dbit = TMXR_DBG_EXP;
        mp->ldsc[i].send.dptr = mp->dptr;
        mp->ldsc[i].send.dbit = TMXR_DBG_SEND;
        }
    }
tmxr_add_to_open_list (mp);
return SCPE_OK;
}


t_stat tmxr_startup (void)
{
return SCPE_OK;
}

t_stat tmxr_shutdown (void)
{
if (tmxr_open_device_count)
    return SCPE_IERR;
return SCPE_OK;
}

t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
{
int i, j;

if (0 == tmxr_open_device_count)
    fprintf(st, "No Attached Multiplexer Devices\n");
else {
    for (i=0; i<tmxr_open_device_count; ++i) {
        TMXR *mp = tmxr_open_devices[i];
        TMLN *lp;
        char *attach;

        fprintf(st, "Multiplexer device: %s", (mp->dptr ? sim_dname (mp->dptr) : ""));
        if (mp->lines > 1) {
            fprintf(st, ", ");
            tmxr_show_lines(st, NULL, 0, mp);
            }
        if (mp->packet)
            fprintf(st, ", Packet");
        if (mp->datagram)
            fprintf(st, ", UDP");
        if (mp->notelnet)
            fprintf(st, ", Telnet=disabled");
        if (mp->modem_control)
            fprintf(st, ", ModemControl=enabled");
        if (mp->buffered)
            fprintf(st, ", Buffered=%d", mp->buffered);
        attach = tmxr_mux_attach_string (NULL, mp);
        if (attach)
            fprintf(st, ",\n    attached to %s, ", attach);
        free (attach);
        tmxr_show_summ(st, NULL, 0, mp);
        fprintf(st, ", sessions=%d", mp->sessions);
        if (mp->lines == 1) {
            if (mp->ldsc->rxbps) {
                fprintf(st, ", Speed=%d", mp->ldsc->rxbps);
                if (mp->ldsc->rxbpsfactor != TMXR_RX_BPS_UNIT_SCALE)
                    fprintf(st, "*%.0f", mp->ldsc->rxbpsfactor/TMXR_RX_BPS_UNIT_SCALE);
                fprintf(st, " bps");
                }
            }
        fprintf(st, "\n");
        if (mp->ring_start_time) {
            fprintf (st, "    incoming Connection from: %s ringing for %d milliseconds\n", mp->ring_ipad, sim_os_msec () - mp->ring_start_time);
            }
        for (j = 0; j < mp->lines; j++) {
            lp = mp->ldsc + j;
            if (mp->lines > 1) {
                if (lp->dptr && (mp->dptr != lp->dptr))
                    fprintf (st, "Device: %s ", sim_dname(lp->dptr));
                fprintf (st, "Line: %d", j);
                if (mp->notelnet != lp->notelnet)
                    fprintf (st, " - %stelnet", lp->notelnet ? "no" : "");
                if (lp->uptr && (lp->uptr != lp->mp->uptr))
                    fprintf (st, " - Unit: %s", sim_uname (lp->uptr));
                if (mp->modem_control != lp->modem_control)
                    fprintf(st, ", ModemControl=%s", lp->modem_control ? "enabled" : "disabled");
                if (lp->loopback)
                    fprintf(st, ", Loopback");
                if (lp->rxbps) {
                    fprintf(st, ", Speed=%d", lp->rxbps);
                    if (lp->rxbpsfactor != TMXR_RX_BPS_UNIT_SCALE)
                        fprintf(st, "*%.0f", lp->rxbpsfactor/TMXR_RX_BPS_UNIT_SCALE);
                    fprintf(st, " bps");
                    }
                fprintf (st, "\n");
                }
            if ((!lp->sock) && (!lp->connecting) && (!lp->serport) && (!lp->master)) {
                if (lp->modem_control)
                    tmxr_fconns (st, lp, -1);
                continue;
                }
            tmxr_fconns (st, lp, -1);
            tmxr_fstats (st, lp, -1);
            }
        }
    }
return SCPE_OK;
}


/* Close a master listening socket.

   The listening socket associated with multiplexer descriptor "mp" is closed
   and deallocated.  In addition, all current Telnet sessions are disconnected.
   Serial and outgoing sessions are also disconnected.
*/

t_stat tmxr_close_master (TMXR *mp)
{
int32 i;
TMLN *lp;

for (i = 0; i < mp->lines; i++) {  /* loop thru conn */
    lp = mp->ldsc + i;

    if (!lp->destination && lp->sock) {                 /* not serial and is connected? */
        tmxr_report_disconnection (lp);                 /* report disconnection */
        tmxr_reset_ln (lp);                             /* disconnect line */
        }
    else {
        if (lp->sock) {
            tmxr_report_disconnection (lp);             /* report disconnection */
            tmxr_reset_ln (lp);
            }
        if (lp->serport) {
            sim_control_serial (lp->serport, 0, TMXR_MDM_DTR|TMXR_MDM_RTS, NULL);/* drop DTR and RTS */
            tmxr_close_ln (lp);
            }
        free (lp->destination);
        lp->destination = NULL;
        if (lp->connecting) {
            lp->sock = lp->connecting;
            lp->connecting = 0;
            tmxr_reset_ln (lp);
            }
        lp->conn = FALSE;
        }
    if (lp->master) {
        sim_close_sock (lp->master);                    /* close master socket */
        lp->master = 0;
        free (lp->port);
        lp->port = NULL;
        }
    lp->txbfd = 0;
    free (lp->txb);
    lp->txb = NULL;
    free (lp->rxb);
    lp->rxb = NULL;
    free (lp->rbr);
    lp->rbr = NULL;
    lp->modembits = 0;
    }

if (mp->master)
    sim_close_sock (mp->master);                        /* close master socket */
mp->master = 0;
free (mp->port);
mp->port = NULL;
if (mp->ring_sock != INVALID_SOCKET) {
    sim_close_sock (mp->ring_sock);
    mp->ring_sock = INVALID_SOCKET;
    free (mp->ring_ipad);
    mp->ring_ipad = NULL;
    mp->ring_start_time = 0;
    }
_tmxr_remove_from_open_list (mp);
return SCPE_OK;
}


/* Detach unit from master socket and close all active network connections 
   and/or serial ports.

   Note that we return SCPE_OK, regardless of whether a listening socket was
   attached.  
*/

t_stat tmxr_detach (TMXR *mp, UNIT *uptr)
{
int32 i;

if (!(uptr->flags & UNIT_ATT))                          /* attached? */
    return SCPE_OK;
tmxr_close_master (mp);                                 /* close master socket */
free (uptr->filename);                                  /* free setup string */
uptr->filename = NULL;
uptr->tmxr = NULL;
mp->last_poll_time = 0;
for (i=0; i < mp->lines; i++) {
    UNIT *uptr = mp->ldsc[i].uptr ? mp->ldsc[i].uptr : mp->uptr;
    UNIT *o_uptr = mp->ldsc[i].o_uptr ? mp->ldsc[i].o_uptr : mp->uptr;

    uptr->dynflags &= ~UNIT_TM_POLL;                    /* no polling */
    o_uptr->dynflags &= ~UNIT_TM_POLL;                  /* no polling */
    }
uptr->flags &= ~(UNIT_ATT);                             /* not attached */
uptr->dynflags &= ~(UNIT_TM_POLL|TMUF_NOASYNCH);        /* no polling, not asynch disabled  */
return SCPE_OK;
}


t_stat tmxr_activate (UNIT *uptr, int32 interval)
{
if (uptr->dynflags & UNIT_TMR_UNIT)
    return sim_timer_activate (uptr, interval);
#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) || 
    (!sim_asynch_enabled)) {
    return _sim_activate (uptr, interval);
    }
return SCPE_OK;
#else
return _sim_activate (uptr, interval);
#endif
}

t_stat tmxr_activate_after (UNIT *uptr, uint32 usecs_walltime)
{
#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) || 
    (!sim_asynch_enabled)) {
    return _sim_activate_after (uptr, (double)usecs_walltime);
    }
return SCPE_OK;
#else
return _sim_activate_after (uptr, (double)usecs_walltime);
#endif
}

t_stat tmxr_activate_after_abs (UNIT *uptr, uint32 usecs_walltime)
{
#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) || 
    (!sim_asynch_enabled)) {
    return _sim_activate_after_abs (uptr, (double)usecs_walltime);
    }
return SCPE_OK;
#else
return _sim_activate_after_abs (uptr, (double)usecs_walltime);
#endif
}


t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval)
{
int32 tmr = sim_rtcn_calibrated_tmr ();
int32 ticks = (interval + (sim_rtcn_tick_size (tmr)/2))/sim_rtcn_tick_size (tmr);/* Convert to ticks */

return tmxr_clock_coschedule_tmr (uptr, tmr, ticks);
}

t_stat tmxr_clock_coschedule_abs (UNIT *uptr, int32 interval)
{
sim_cancel (uptr);
return tmxr_clock_coschedule (uptr, interval);
}

#define MIN(a,b) (((a) < (b)) ? (a) : (b))

t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks)
{
TMXR *mp = (TMXR *)uptr->tmxr;
int32 interval = ticks * sim_rtcn_tick_size (tmr);

#if defined(SIM_ASYNCH_MUX)
if ((!(uptr->dynflags & UNIT_TM_POLL)) || 
    (!sim_asynch_enabled)) {
    return sim_clock_coschedule (uptr, tmr, ticks);
    }
return SCPE_OK;
#else
if (mp) {
    int32 i, soon = interval;
    double sim_gtime_now = sim_gtime ();

    for (i = 0; i < mp->lines; i++) {
        TMLN *lp = &mp->ldsc[i];

        if (tmxr_rqln_bare (lp, FALSE)) {
            int32 due;

            if (lp->rxbps)
                if (lp->rxnexttime > sim_gtime_now)
                    due = (int32)(lp->rxnexttime - sim_gtime_now);
                else
                    due = sim_processing_event ? 1 : 0;     /* avoid potential infinite loop if called from service routine */
            else
                due = (int32)((uptr->wait * sim_timer_inst_per_sec ())/TMXR_RX_BPS_UNIT_SCALE);
            soon = MIN(soon, due);
            }
        }
    if (soon != interval) {
        sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "scheduling %s after %d instructions\n", sim_uname (uptr), soon);
        return _sim_activate (uptr, soon);
        }
    }
sim_debug (TIMER_DBG_MUX, &sim_timer_dev, "coscheduling %s after interval %d ticks\n", sim_uname (uptr), ticks);
return sim_clock_coschedule_tmr (uptr, tmr, ticks);
#endif
}

t_stat tmxr_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 ticks)
{
sim_cancel (uptr);
return tmxr_clock_coschedule_tmr (uptr, tmr, ticks);
}

/* Generic Multiplexer attach help */

t_stat tmxr_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
TMXR *mux = (TMXR *)dptr->help_ctx;
t_bool single_line = FALSE;               /* default to Multi-Line help */

if (mux)
   single_line = (mux->lines == 1);

if (!flag)
    fprintf (st, "%s Multiplexer Attach Help\n\n", dptr->name);
if (single_line) {          /* Single Line Multiplexer */
    fprintf (st, "The %s multiplexer may be connected to terminal emulators supporting the\n", dptr->name);
    fprintf (st, "Telnet protocol via sockets, or to hardware terminals via host serial\n");
    fprintf (st, "ports.\n\n");
    if (mux->modem_control) {
        fprintf (st, "The %s device is a full modem control device and therefore is capable of\n", dptr->name);
        fprintf (st, "passing port configuration information and modem signals.\n");
        }
    fprintf (st, "A Telnet listening port can be configured with:\n\n");
    fprintf (st, "   sim> ATTACH %s {interface:}port\n\n", dptr->name);
    fprintf (st, "Line buffering can be enabled for the %s device with:\n\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s Buffer{=bufsize}\n\n", dptr->name);
    fprintf (st, "Line buffering can be disabled for the %s device with:\n\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s NoBuffer\n\n", dptr->name);
    fprintf (st, "The default buffer size is 32k bytes, the max buffer size is 1024k bytes\n\n");
    fprintf (st, "The outbound traffic the %s device can be logged to a file with:\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s Log=LogFileName\n\n", dptr->name);
    fprintf (st, "File logging can be disabled for the %s device with:\n\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s NoLog\n\n", dptr->name);
    fprintf (st, "The %s device may be connected to a serial port on the host system.\n", dptr->name);
    }
else {
    fprintf (st, "%s multiplexer lines may be connected to terminal emulators supporting the\n", dptr->name);
    fprintf (st, "Telnet protocol via sockets, or to hardware terminals via host serial\n");
    fprintf (st, "ports.  Concurrent Telnet and serial connections may be mixed on a given\n");
    fprintf (st, "multiplexer.\n\n");
    if (mux && mux->modem_control) {
        fprintf (st, "The %s device is a full modem control device and therefore is capable of\n", dptr->name);
        fprintf (st, "passing port configuration information and modem signals on all lines.\n");
        }
    fprintf (st, "Modem Control signalling behaviors can be enabled/disabled on a specific\n");
    fprintf (st, "multiplexer line with:\n\n");
    fprintf (st, "   sim> ATTACH %s Line=n,Modem\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s Line=n,NoModem\n\n", dptr->name);
    fprintf (st, "A Telnet listening port can be configured with:\n\n");
    fprintf (st, "   sim> ATTACH %s {interface:}port\n\n", dptr->name);
    if (mux)
        fprintf (st, "Line buffering for all %d lines on the %s device can be configured with:\n\n", mux->lines, dptr->name);
    else
        fprintf (st, "Line buffering for all lines on the %s device can be configured with:\n\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s Buffer{=bufsize}\n\n", dptr->name);
    if (mux)
        fprintf (st, "Line buffering for all %d lines on the %s device can be disabled with:\n\n", mux->lines, dptr->name);
    else
        fprintf (st, "Line buffering for all lines on the %s device can be disabled with:\n\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s NoBuffer\n\n", dptr->name);
    fprintf (st, "The default buffer size is 32k bytes, the max buffer size is 1024k bytes\n\n");
    fprintf (st, "The outbound traffic for the lines of the %s device can be logged to files\n", dptr->name);
    fprintf (st, "with:\n\n");
    fprintf (st, "   sim> ATTACH %s Log=LogFileName\n\n", dptr->name);
    fprintf (st, "The log file name for each line uses the above LogFileName as a template\n");
    fprintf (st, "for the actual file name which will be LogFileName_n where n is the line\n");
    fprintf (st, "number.\n\n");
    fprintf (st, "Multiplexer lines may be connected to serial ports on the host system.\n");
    }
fprintf (st, "Serial ports may be specified as an operating system specific device names\n");
fprintf (st, "or using simh generic serial names.  simh generic names are of the form\n");
fprintf (st, "serN, where N is from 0 thru one less than the maximum number of serial\n");
fprintf (st, "ports on the local system.  The mapping of simh generic port names to OS \n");
fprintf (st, "specific names can be displayed using the following command:\n\n");
fprintf (st, "   sim> SHOW SERIAL\n");
fprintf (st, "   Serial devices:\n");
fprintf (st, "    ser0   COM1 (\\Device\\Serial0)\n");
fprintf (st, "    ser1   COM3 (Winachcf0)\n\n");
if (single_line) {          /* Single Line Multiplexer */
    fprintf (st, "   sim> ATTACH %s Connect=ser0\n\n", dptr->name);
    fprintf (st, "or equivalently:\n\n");
    fprintf (st, "   sim> ATTACH %s Connect=COM1\n\n", dptr->name);
    }
else {
    fprintf (st, "   sim> ATTACH %s Line=n,Connect=ser0\n\n", dptr->name);
    fprintf (st, "or equivalently:\n\n");
    fprintf (st, "   sim> ATTACH %s Line=n,Connect=COM1\n\n", dptr->name);
    if (mux)
        fprintf (st, "Valid line numbers are from 0 thru %d\n\n", mux->lines-1);
    }
if (single_line) {          /* Single Line Multiplexer */
    fprintf (st, "The input data rate for the %s device can be controlled by\n", dptr->name);
    fprintf (st, "specifying SPEED=nnn{*fac} on the the ATTACH command.\n");
    }
else {
    fprintf (st, "The input data rate for all lines or a particular line of a the %s\n", dptr->name);
    fprintf (st, "device can be controlled by specifying SPEED=nnn{*fac} on the ATTACH command.\n");
    }
fprintf (st, "SPEED values can be any one of:\n\n");
fprintf (st, "    0 50 75 110 134 150 300 600 1200 1800 2000 2400\n");
fprintf (st, "    3600 4800 7200 9600 19200 38400 57600 76800 115200\n\n");
fprintf (st, "A SPEED value of 0 causes input data to be delivered to the simulated\n");
fprintf (st, "port as fast as it arrives.\n\n");
fprintf (st, "If a simulated multiplexor devices can programmatically set a serial\n");
fprintf (st, "port line speed, the programmatically specified speed will take precidence\n");
fprintf (st, "over any input speed specified on an attach command.\n");
fprintf (st, "Some simulated systems run very much faster than the original system\n");
fprintf (st, "which is being simulated.  To accommodate this, the speed specified may\n");
fprintf (st, "include a factor which will increase the input data delivery rate by\n");
fprintf (st, "the specified factor.  A factor is specified with a speed value of the\n");
fprintf (st, "form \"speed*factor\".  Factor values can range from 1 thru 32.\n");
fprintf (st, "Example:\n\n");
fprintf (st, "   sim> ATTACH %s 1234,SPEED=2400\n", dptr->name);
fprintf (st, "   sim> ATTACH %s 1234,SPEED=9600*8\n", dptr->name);
if (!single_line)
    fprintf (st, "   sim> ATTACH %s Line=2,SPEED=2400\n", dptr->name);
fprintf (st, "\n");
fprintf (st, "The SPEED parameter only influences the rate at which data is deliverd\n");
fprintf (st, "into the simulated multiplexor port.  Output data rates are unaffected\n");
fprintf (st, "If an attach command specifies a speed multiply factor, that value will\n");
fprintf (st, "persist independent of any programatic action by the simulated system to\n");
fprintf (st, "change the port speed.\n\n");
fprintf (st, "An optional serial port configuration string may be present after the port\n");
fprintf (st, "name.  If present, it must be separated from the port name with a semicolon\n");
fprintf (st, "and has this form:\n\n");
fprintf (st, "   <rate>-<charsize><parity><stopbits>\n\n");
fprintf (st, "where:\n");
fprintf (st, "   rate     = communication rate in bits per second\n");
fprintf (st, "   charsize = character size in bits (5-8, including optional parity)\n");
fprintf (st, "   parity   = parity designator (N/E/O/M/S for no/even/odd/mark/space parity)\n");
fprintf (st, "   stopbits = number of stop bits (1, 1.5, or 2)\n\n");
fprintf (st, "As an example:\n\n");
fprintf (st, "   9600-8n1\n\n");
fprintf (st, "The supported rates, sizes, and parity options are host-specific.  If\n");
fprintf (st, "a configuration string is not supplied, then the default of 9600-8N1\n");
fprintf (st, "is used.\n");
fprintf (st, "Note: The serial port configuration option is only available on multiplexer\n");
fprintf (st, "      lines which are not operating with full modem control behaviors enabled.\n");
fprintf (st, "      Lines with full modem control behaviors enabled have all of their\n");
fprintf (st, "      configuration managed by the Operating System running within the\n");
fprintf (st, "      simulator.\n\n");
fprintf (st, "An attachment to a serial port with the '-V' switch will cause a\n");
fprintf (st, "connection message to be output to the connected serial port.\n");
fprintf (st, "This will help to confirm the correct port has been connected and\n");
fprintf (st, "that the port settings are reasonable for the connected device.\n");
fprintf (st, "This would be done as:\n\n");
if (single_line)            /* Single Line Multiplexer */
    fprintf (st, "   sim> ATTACH -V %s Connect=SerN\n", dptr->name);
else {
    fprintf (st, "   sim> ATTACH -V %s Line=n,Connect=SerN\n\n", dptr->name);
    fprintf (st, "Line specific tcp listening ports are supported.  These are configured\n");
    fprintf (st, "using commands of the form:\n\n");
    fprintf (st, "   sim> ATTACH %s Line=n,{interface:}port{;notelnet}\n\n", dptr->name);
    }
fprintf (st, "Direct computer to computer connections (Virutal Null Modem cables) may\n");
fprintf (st, "be established using the telnet protocol or via raw tcp sockets.\n\n");
fprintf (st, "   sim> ATTACH %s Line=n,Connect=host:port{;notelnet}\n\n", dptr->name);
fprintf (st, "Computer to computer virtual connections can be one way (as illustrated\n");
fprintf (st, "above) or symmetric.  A symmetric connection is configured by combining\n"); 
if (single_line) {          /* Single Line Multiplexer */
    fprintf (st, "a one way connection with a tcp listening port on the same line:\n\n");
    fprintf (st, "   sim> ATTACH %s listenport,Connect=host:port\n\n", dptr->name);
    }
else {
    fprintf (st, "a one way connection with a tcp listening port on the same line:\n\n");
    fprintf (st, "   sim> ATTACH %s Line=n,listenport,Connect=host:port\n\n", dptr->name);
    }
fprintf (st, "When symmetric virtual connections are configured, incoming connections\n");
fprintf (st, "on the specified listening port are checked to assure that they actually\n");
fprintf (st, "come from the specified connection destination host system.\n\n");
if (single_line) {          /* Single Line Multiplexer */
    fprintf (st, "The %s device can be attached in LOOPBACK mode:\n\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s Loopback\n\n", dptr->name);
    }
else {
    fprintf (st, "A line on the %s device can be attached in LOOPBACK mode:\n\n", dptr->name);
    fprintf (st, "   sim> ATTACH %s Line=n,Loopback\n\n", dptr->name);
    }
fprintf (st, "When operating in LOOPBACK mode, all outgoing data arrives as input and\n");
fprintf (st, "outgoing modem signals (if enabled) (DTR and RTS) are reflected in the\n");
fprintf (st, "incoming modem signals (DTR->(DCD and DSR), RTS->CTS)\n\n");
if (single_line)            /* Single Line Multiplexer */
    fprintf (st, "The connection configured for the %s device is unconfigured by:\n\n", dptr->name);
else
    fprintf (st, "All connections configured for the %s device are unconfigured by:\n\n", dptr->name);
fprintf (st, "   sim> DETACH %s\n\n", dptr->name);
if (dptr->modifiers) {
    MTAB *mptr;

    for (mptr = dptr->modifiers; mptr->mask != 0; mptr++)
        if (mptr->valid == &tmxr_dscln) {
            fprintf (st, "A specific line on the %s device can be disconnected with:\n\n", dptr->name);
            fprintf (st, "   sim> SET %s %s=n\n\n", dptr->name, mptr->mstring);
            fprintf (st, "This will cause a telnet connection to be closed, but a serial port will\n");
            fprintf (st, "normally have DTR dropped for 500ms and raised again (thus hanging up a\n");
            fprintf (st, "modem on that serial port).\n\n");
            fprintf (st, "A line which is connected to a serial port can be manually closed by\n");
            fprintf (st, "adding the -C switch to a %s command.\n\n", mptr->mstring);
            fprintf (st, "   sim> SET -C %s %s=n\n\n", dptr->name, mptr->mstring);
            }
    }
return SCPE_OK;
}

/* Stub examine and deposit */

t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
return SCPE_NOFNC;
}

t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
return SCPE_NOFNC;
}


/* Write a message directly to a socket */

void tmxr_msg (SOCKET sock, const char *msg)
{
if ((sock) && (sock != INVALID_SOCKET))
    sim_write_sock (sock, msg, (int32)strlen (msg));
return;
}


/* Write a message to a line */

void tmxr_linemsg (TMLN *lp, const char *msg)
{
while (*msg) {
    while (SCPE_STALL == tmxr_putc_ln (lp, (int32)(*msg)))
        if (lp->txbsz == tmxr_send_buffered_data (lp))
            sim_os_ms_sleep (10);
    ++msg;
    }
return;
}


/* Write a formatted message to a line */

void tmxr_linemsgf (TMLN *lp, const char *fmt, ...)
{
va_list arglist;

va_start (arglist, fmt);
tmxr_linemsgvf (lp, fmt, arglist);
va_end (arglist);
}

void tmxr_linemsgvf (TMLN *lp, const char *fmt, va_list arglist)
{
char stackbuf[STACKBUFSIZE];
int32 bufsize = sizeof(stackbuf);
char *buf = stackbuf;
int32 i, len;

buf[bufsize-1] = '\0';
while (1) {                                         /* format passed string, args */
#if defined(NO_vsnprintf)
    len = vsprintf (buf, fmt, arglist);
#else                                               /* !defined(NO_vsnprintf) */
    len = vsnprintf (buf, bufsize-1, fmt, arglist);
#endif                                              /* NO_vsnprintf */

/* If the formatted result didn't fit into the buffer, then grow the buffer and try again */

    if ((len < 0) || (len >= bufsize-1)) {
        if (buf != stackbuf)
            free (buf);
        bufsize = bufsize * 2;
        if (bufsize < len + 2)
            bufsize = len + 2;
        buf = (char *) malloc (bufsize);
        if (buf == NULL)                            /* out of memory */
            return;
        buf[bufsize-1] = '\0';
        continue;
        }
    break;
    }

/* Output the formatted data expanding newlines where they exist */

for (i = 0; i < len; ++i) {
    if (('\n' == buf[i]) && ((i == 0) || ('\r' != buf[i-1]))) {
        while (SCPE_STALL == tmxr_putc_ln (lp, '\r'))
            if (lp->txbsz == tmxr_send_buffered_data (lp))
                sim_os_ms_sleep (10);
        }
    while (SCPE_STALL == tmxr_putc_ln (lp, buf[i]))
        if (lp->txbsz == tmxr_send_buffered_data (lp))
            sim_os_ms_sleep (10);
    }
if (buf != stackbuf)
    free (buf);
return;
}


/* Print connections - used only in named SHOW command */

void tmxr_fconns (FILE *st, const TMLN *lp, int32 ln)
{
int32 hr, mn, sc;
uint32 ctime;

if (ln >= 0)
    fprintf (st, "line %d: ", ln);

if ((lp->sock) || (lp->connecting)) {                   /* tcp connection? */
    if (lp->destination)                                /* remote connection? */
        if (lp->datagram)
            fprintf (st, "Datagram Connection from %s to remote port %s\n", lp->port, lp->destination);/* print port name */
        else
            fprintf (st, "Connection to remote port %s\n", lp->destination);/* print port name */
    else                                                /* incoming connection */
        fprintf (st, "Connection from IP address %s\n", lp->ipad);
    }
else
    if (lp->destination)                                /* remote connection? */
        fprintf (st, "Connecting to remote port %s\n", lp->destination);/* print port name */
if (lp->sock) {
    char *sockname, *peername;

    sim_getnames_sock (lp->sock, &sockname, &peername);
    fprintf (st, "Connection %s->%s\n", sockname, peername);
    free (sockname);
    free (peername);
    }

if ((lp->port) && (!lp->datagram))
    fprintf (st, "Listening on port %s\n", lp->port);   /* print port name */

if (lp->serport)                                        /* serial connection? */
    fprintf (st, "Connected to serial port %s\n", lp->destination);  /* print port name */

if (lp->cnms) {
    ctime = (sim_os_msec () - lp->cnms) / 1000;
    hr = ctime / 3600;
    mn = (ctime / 60) % 60;
    sc = ctime % 60;
    if (ctime)
        fprintf (st, " %s %02d:%02d:%02d\n", lp->connecting ? "Connecting for" : "Connected", hr, mn, sc);
    }
else
    fprintf (st, " Line disconnected\n");

if (lp->modem_control) {
    fprintf (st, " Modem Bits: %s%s%s%s%s%s\n", (lp->modembits & TMXR_MDM_DTR) ? "DTR " : "",
                                                (lp->modembits & TMXR_MDM_RTS) ? "RTS " : "",
                                                (lp->modembits & TMXR_MDM_DCD) ? "DCD " : "",
                                                (lp->modembits & TMXR_MDM_RNG) ? "RNG " : "",
                                                (lp->modembits & TMXR_MDM_CTS) ? "CTS " : "",
                                                (lp->modembits & TMXR_MDM_DSR) ? "DSR " : "");
    }

if ((lp->serport == 0) && (lp->sock) && (!lp->datagram))
    fprintf (st, " %s\n", (lp->notelnet) ? "Telnet disabled (RAW data)" : "Telnet protocol");
if (lp->send.buffer)
    sim_show_send_input (st, &lp->send);
if (lp->expect.buf)
    sim_exp_showall (st, &lp->expect);
if (lp->txlog)
    fprintf (st, " Logging to %s\n", lp->txlogname);
return;
}


/* Print statistics - used only in named SHOW command */

void tmxr_fstats (FILE *st, const TMLN *lp, int32 ln)
{
static const char *enab = "on";
static const char *dsab = "off";

if (ln >= 0)
    fprintf (st, "Line %d:", ln);
if ((!lp->sock) && (!lp->connecting) && (!lp->serport))
    fprintf (st, " not connected\n");
else {
    if (ln >= 0)
        fprintf (st, "\n");
    fprintf (st, "  input (%s)", (lp->rcve? enab: dsab));
    if (lp->rxcnt)
        fprintf (st, " queued/total = %d/%d", tmxr_rqln (lp), lp->rxcnt);
    if (lp->rxpcnt)
        fprintf (st, " packets = %d", lp->rxpcnt);
    fprintf (st, "\n  output (%s)", (lp->xmte? enab: dsab));
    if (lp->txcnt || lp->txbpi)
        fprintf (st, " queued/total = %d/%d", tmxr_tqln (lp), lp->txcnt);
    if (lp->txpcnt || tmxr_tpqln (lp))
        fprintf (st, " packet data queued/packets sent = %d/%d",
            tmxr_tpqln (lp), lp->txpcnt);
    fprintf (st, "\n");
    }
if (lp->txbfd)
    fprintf (st, "  output buffer size = %d\n", lp->txbsz);
if (lp->txcnt || lp->txbpi)
    fprintf (st, "  bytes in buffer = %d\n", 
               ((lp->txcnt > 0) && (lp->txcnt > lp->txbsz)) ? lp->txbsz : lp->txbpi);
if (lp->txdrp)
    fprintf (st, "  dropped = %d\n", lp->txdrp);
return;
}


/* Disconnect a line.

   Disconnect a line of the multiplexer associated with descriptor "desc" from a
   tcp session or a serial port.  Two calling sequences are supported:

    1. If "val" is zero, then "uptr" is implicitly associated with the line
       number corresponding to the position of the unit in the zero-based array
       of units belonging to the associated device, and "cptr" is ignored.  For
       example, if "uptr" points to unit 3 in a given device, then line 3 will
       be disconnected.

    2. If "val" is non-zero, then "cptr" points to a string that is parsed for
       an explicit line number, and "uptr" is ignored.  For example, if "cptr"
       points to the string "3", then line 3 will be disconnected.

   If the line was connected to a tcp session, the socket associated with the
   line will be closed.  If the line was connected to a serial port, the port
   will NOT be closed, but DTR will be dropped.  After a 500ms delay DTR will
   be raised again.  If the sim_switches -C flag is set, then a serial port 
   connection will be closed.

   Implementation notes:

    1. This function is usually called as an MTAB processing routine.
*/

t_stat tmxr_dscln (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
TMXR *mp = (TMXR *) desc;
TMLN *lp;
t_stat status;

if (val)                                                        /* explicit line? */
    uptr = NULL;                                                /* indicate to get routine */

tmxr_debug_trace (mp, "tmxr_dscln()");

lp = tmxr_get_ldsc (uptr, cptr, mp, &status);                   /* get referenced line */

if (lp == NULL)                                                 /* bad line number? */
    return status;                                              /* report it */

if ((lp->sock) || (lp->serport)) {                              /* connection active? */
    if (!lp->notelnet)
        tmxr_linemsg (lp, "\r\nOperator disconnected line\r\n\n");/* report closure */
    tmxr_reset_ln_ex (lp, (sim_switches & SWMASK ('C')));       /* drop the line */
    }

return SCPE_OK;
}


/* Enable logging for line */

t_stat tmxr_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
TMXR *mp = (TMXR *) desc;
TMLN *lp;

if (cptr == NULL)                                       /* no file name? */
    return SCPE_2FARG;
lp = tmxr_find_ldsc (uptr, val, mp);                    /* find line desc */
if (lp == NULL)
    return SCPE_IERR;
if (lp->txlog)                                          /* close existing log */
    tmxr_set_nolog (NULL, val, NULL, desc);
lp->txlogname = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc namebuf */
if (lp->txlogname == NULL)                              /* can't? */
    return SCPE_MEM;
strncpy (lp->txlogname, cptr, CBUFSIZE);                /* save file name */
sim_open_logfile (cptr, TRUE, &lp->txlog, &lp->txlogref);/* open log */
if (lp->txlog == NULL) {                                /* error? */
    free (lp->txlogname);                               /* free buffer */
    return SCPE_OPENERR;
    }
if (mp->uptr)                                           /* attached?, then update attach string */
    lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp);
return SCPE_OK;
}


/* Disable logging for line */

t_stat tmxr_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
TMXR *mp = (TMXR *) desc;
TMLN *lp;

if (cptr)                                               /* no arguments */
    return SCPE_2MARG;
lp = tmxr_find_ldsc (uptr, val, mp);                    /* find line desc */
if (lp == NULL)
    return SCPE_IERR;
if (lp->txlog) {                                        /* logging? */
    sim_close_logfile (&lp->txlogref);                  /* close log */
    free (lp->txlogname);                               /* free namebuf */
    lp->txlog = NULL;
    lp->txlogname = NULL;
    }
if (mp->uptr)
    lp->mp->uptr->filename = tmxr_mux_attach_string (lp->mp->uptr->filename, lp->mp);
return SCPE_OK;
}


/* Show logging status for line */

t_stat tmxr_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
const TMXR *mp = (const TMXR *) desc;
TMLN *lp;

lp = tmxr_find_ldsc (uptr, val, mp);                    /* find line desc */
if (lp == NULL)
    return SCPE_IERR;
if (lp->txlog)
    fprintf (st, "logging to %s", lp->txlogname);
else fprintf (st, "no logging");
return SCPE_OK;
}


/* Set the line connection order.

   Example command for eight-line multiplexer:

      SET <dev> LINEORDER=1;5;2-4;7

   Resulting connection order: 1,5,2,3,4,7,0,6.

   Parameters:
    - uptr = (not used)
    - val  = (not used)
    - cptr = pointer to first character of range specification
    - desc = pointer to multiplexer's TMXR structure

   On entry, cptr points to the value portion of the command string, which may
   be either a semicolon-separated list of line ranges or the keyword ALL.

   If a line connection order array is not defined in the multiplexer
   descriptor, the command is rejected.  If the specified range encompasses all
   of the lines, the first value of the connection order array is set to -1 to
   indicate sequential connection order.  Otherwise, the line values in the
   array are set to the order specified by the command string.  All values are
   populated, first with those explicitly specified in the command string, and
   then in ascending sequence with those not specified.

   If an error occurs, the original line order is not disturbed.
*/

t_stat tmxr_set_lnorder (UNIT *uptr, int32 val, CONST char *carg, void *desc)
{
TMXR *mp = (TMXR *) desc;
char *tbuf;
char *tptr;
CONST char *cptr;
t_addr low, high, max = (t_addr) mp->lines - 1;
int32 *list;
t_bool *set;
uint32 line, idx = 0;
t_stat result = SCPE_OK;

if (mp->lnorder == NULL)                                /* line connection order undefined? */
    return SCPE_NXPAR;                                  /* "Non-existent parameter" error */

else if ((carg == NULL) || (*carg == '\0'))             /* line range not supplied? */
    return SCPE_MISVAL;                                 /* "Missing value" error */

list = (int32 *) calloc (mp->lines, sizeof (int32));    /* allocate new line order array */

if (list == NULL)                                       /* allocation failed? */
    return SCPE_MEM;                                    /* report it */

set = (t_bool *) calloc (mp->lines, sizeof (t_bool));   /* allocate line set tracking array */

if (set == NULL) {                                      /* allocation failed? */
    free (list);                                        /* free successful list allocation */
    return SCPE_MEM;                                    /* report it */
    }

tbuf = (char *) calloc (strlen(carg)+2, sizeof(*carg));
strcpy (tbuf, carg);
tptr = tbuf + strlen (tbuf);                            /* append a semicolon */
*tptr++ = ';';                                          /*   to the command string */
*tptr = '\0';                                           /*   to make parsing easier for get_range */
cptr = tbuf;

while (*cptr) {                                         /* parse command string */
    cptr = get_range (NULL, cptr, &low, &high, 10, max, ';');/* get a line range */

    if (cptr == NULL) {                                 /* parsing error? */
        result = SCPE_ARG;                              /* "Invalid argument" error */
        break;
        }

    else if ((low > max) || (high > max)) {             /* line out of range? */
        result = SCPE_SUB;                              /* "Subscript out of range" error */
        break;
        }

    else if ((low == 0) && (high == max)) {             /* entire line range specified? */
        list [0] = -1;                                  /* set sequential order flag */
        idx = (uint32) max + 1;                         /* indicate no fill-in needed */
        break;
        }

    else
        for (line = (uint32) low; line <= (uint32) high; line++) /* see if previously specified */
            if (set [line] == FALSE) {                  /* not already specified? */
                set [line] = TRUE;                      /* now it is */
                list [idx] = line;                      /* add line to connection order */
                idx = idx + 1;                          /* bump "specified" count */
                }
    }

if (result == SCPE_OK) {                                /* assignment successful? */
    if (idx <= max)                                     /* any lines not specified? */
        for (line = 0; line <= max; line++)             /* fill them in sequentially */
            if (set [line] == FALSE) {                  /* specified? */
                list [idx] = line;                      /* no, so add it */
                idx = idx + 1;
                }

    memcpy (mp->lnorder, list, mp->lines * sizeof (int32)); /* copy working array to connection array */
    }

free (list);                                            /* free list allocation */
free (set);                                             /* free set allocation */
free (tbuf);                                            /* free arg copy with ; */

return result;
}


/* Show line connection order.

   Parameters:
    - st   = stream on which output is to be written
    - uptr = (not used)
    - val  = (not used)
    - desc = pointer to multiplexer's TMXR structure

   If a connection order array is not defined in the multiplexer descriptor, the
   command is rejected.  If the first value of the connection order array is set
   to -1, then the connection order is sequential.  Otherwise, the line values
   in the array are printed as a semicolon-separated list.  Ranges are printed
   where possible to shorten the output.
*/

t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 i, j, low, last;
const TMXR *mp = (const TMXR *) desc;
int32 *iptr = mp->lnorder;
t_bool first = TRUE;

if (iptr == NULL)                                       /* connection order undefined? */
    return SCPE_NXPAR;                                  /* "Non-existent parameter" error */

if (*iptr < 0)                                          /* sequential order indicated? */
    fprintf (st, "Order=0-%d\n", mp->lines - 1);        /* print full line range */

else {
    low = last = *iptr++;                               /* set first line value */

    for (j = 1; j <= mp->lines; j++) {                  /* print remaining lines in order list */
        if (j < mp->lines)                              /* more lines to process? */
            i = *iptr++;                                /* get next line in list */
        else                                            /* final iteration */
            i = -1;                                     /* get "tie-off" value */

        if (i != last + 1) {                            /* end of a range? */
            if (first) {                                /* first line to print? */
                fputs ("Order=", st);                   /* print header */
                first = FALSE;
                }

            else                                        /* not first line printed */
                fputc (';', st);                        /* print separator */

            if (low == last)                            /* range null? */
                fprintf (st, "%d", last);               /* print single line value */

            else                                        /* range established */
                fprintf (st, "%d-%d", low, last);       /* print start and end line */

            low = i;                                    /* start new range */
            }

        last = i;                                       /* note value for range check */
        }
    }

if (first == FALSE)                                     /* sanity check for lines == 0 */
    fputc ('\n', st);

return SCPE_OK;
}

/* Show summary processor */

t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
const TMXR *mp = (const TMXR *) desc;
int32 i, t;

if (mp == NULL)
    return SCPE_IERR;
for (i = t = 0; i < mp->lines; i++)
    if ((mp->ldsc[i].sock != 0) || (mp->ldsc[i].serport != 0))
        t = t + 1;
if (mp->lines > 1)
    fprintf (st, "%d current connection%s", t, (t != 1) ? "s" : "");
else
    fprintf (st, "%s", (t == 1) ? "connected" : "disconnected");
return SCPE_OK;
}

/* Show conn/stat processor */

t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
const TMXR *mp = (const TMXR *) desc;
int32 i, any;

if (mp == NULL)
    return SCPE_IERR;
for (i = any = 0; i < mp->lines; i++) {
    if ((mp->ldsc[i].sock != 0) || 
        (mp->ldsc[i].serport != 0) || mp->ldsc[i].modem_control) {
        if ((mp->ldsc[i].sock != 0) || (mp->ldsc[i].serport != 0))
            any++;
        if (val)
            tmxr_fconns (st, &mp->ldsc[i], i);
        else
            if ((mp->ldsc[i].sock != 0) || (mp->ldsc[i].serport != 0))
                tmxr_fstats (st, &mp->ldsc[i], i);
        }
    }
if (any == 0)
    fprintf (st, (mp->lines == 1? "disconnected\n": "all disconnected\n"));
return SCPE_OK;
}

/* Show number of lines */

t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
const TMXR *mp = (const TMXR *) desc;

if (mp == NULL)
    return SCPE_IERR;
fprintf (st, "lines=%d", mp->lines);
return SCPE_OK;
}


static struct {
    u_char value;
    const char *name;
    } tn_chars[] =
    {
        {TN_IAC,    "TN_IAC"},                /* protocol delim */
        {TN_DONT,   "TN_DONT"},               /* dont */
        {TN_DO,     "TN_DO"},                 /* do */
        {TN_WONT,   "TN_WONT"},               /* wont */
        {TN_WILL,   "TN_WILL"},               /* will */
        {TN_SB,     "TN_SB"},                 /* sub-option negotiation */
        {TN_GA,     "TN_SG"},                 /* go ahead */
        {TN_EL,     "TN_EL"},                 /* erase line */
        {TN_EC,     "TN_EC"},                 /* erase character */
        {TN_AYT,    "TN_AYT"},                /* are you there */
        {TN_AO,     "TN_AO"},                 /* abort output */
        {TN_IP,     "TN_IP"},                 /* interrupt process */
        {TN_BRK,    "TN_BRK"},                /* break */
        {TN_DATAMK, "TN_DATAMK"},             /* data mark */
        {TN_NOP,    "TN_NOP"},                /* no operation */
        {TN_SE,     "TN_SE"},                 /* end sub-option negot */
        /* Options */
        {TN_BIN,    "TN_BIN"},                /* bin */
        {TN_ECHO,   "TN_ECHO"},               /* echo */
        {TN_SGA,    "TN_SGA"},                /* sga */
        {TN_STATUS, "TN_STATUS"},             /* option status query */
        {TN_TIMING, "TN_TIMING"},             /* Timing Mark */
        {TN_NAOCRD, "TN_NAOCRD"},             /* Output Carriage-Return Disposition */
        {TN_NAOHTS, "TN_NAOHTS"},             /* Output Horizontal Tab Stops */
        {TN_NAOHTD, "TN_NAOHTD"},             /* Output Horizontal Tab Stop Disposition */
        {TN_NAOFFD, "TN_NAOFFD"},             /* Output Forfeed Disposition */
        {TN_NAOVTS, "TN_NAOVTS"},             /* Output Vertical Tab Stop */
        {TN_NAOVTD, "TN_NAOVTD"},             /* Output Vertical Tab Stop Disposition */
        {TN_NAOLFD, "TN_NAOLFD"},             /* Output Linefeed Disposition */
        {TN_EXTEND, "TN_EXTEND"},             /* Extended Ascii */
        {TN_LOGOUT, "TN_LOGOUT"},             /* Logout */
        {TN_BM,     "TN_BM"},                 /* Byte Macro */
        {TN_DET,    "TN_DET"},                /* Data Entry Terminal */
        {TN_SENDLO, "TN_SENDLO"},             /* Send Location */
        {TN_TERMTY, "TN_TERMTY"},             /* Terminal Type */
        {TN_ENDREC, "TN_ENDREC"},             /* Terminal Type */
        {TN_TUID,   "TN_TUID"},               /* TACACS User Identification */
        {TN_OUTMRK, "TN_OUTMRK"},             /* Output Marking */
        {TN_TTYLOC, "TN_TTYLOC"},             /* Terminal Location Number */
        {TN_3270,   "TN_3270"},               /* 3270 Regime */
        {TN_X3PAD,  "TN_X3PAD"},              /* X.3 PAD */
        {TN_NAWS,   "TN_NAWS"},               /* Negotiate About Window Size */
        {TN_TERMSP, "TN_TERMSP"},             /* Terminal Speed */
        {TN_TOGFLO, "TN_TOGFLO"},             /* Remote Flow Control */
        {TN_LINE,   "TN_LINE"},               /* line mode */
        {TN_XDISPL, "TN_XDISPL"},             /* X Display Location */
        {TN_ENVIRO, "TN_ENVIRO"},             /* Environment */
        {TN_AUTH,   "TN_AUTH"},               /* Authentication */
        {TN_ENCRYP, "TN_ENCRYP"},             /* Data Encryption */
        {TN_NEWENV, "TN_NEWENV"},             /* New Environment */
        {TN_TN3270, "TN_TN3270"},             /* TN3270 Enhancements */
        {TN_CHARST, "TN_CHARST"},             /* CHARSET */
        {TN_COMPRT, "TN_COMPRT"},             /* Com Port Control */
        {TN_KERMIT, "TN_KERMIT"},             /* KERMIT */
        {0, NULL}};

static char *tmxr_debug_buf = NULL;
static size_t tmxr_debug_buf_used = 0;
static size_t tmxr_debug_buf_size = 0;

static void tmxr_buf_debug_char (char value)
{
if (tmxr_debug_buf_used+2 > tmxr_debug_buf_size) {
    tmxr_debug_buf_size += 1024;
    tmxr_debug_buf = (char *)realloc (tmxr_debug_buf, tmxr_debug_buf_size);
    }
tmxr_debug_buf[tmxr_debug_buf_used++] = value;
tmxr_debug_buf[tmxr_debug_buf_used] = '\0';
}

static void tmxr_buf_debug_string (const char *string)
{
while (*string)
    tmxr_buf_debug_char (*string++);
}

static void tmxr_buf_debug_telnet_option (u_char chr)
{
int j;

for (j=0; 1; ++j) {
    if (NULL == tn_chars[j].name) {
        if (isprint(chr))
            tmxr_buf_debug_char (chr);
        else {
            tmxr_buf_debug_char ('_');
            if ((chr >= 1) && (chr <= 26)) {
                tmxr_buf_debug_char ('^');
                tmxr_buf_debug_char ('A' + chr - 1);
                }
            else {
                char octal[8];

                sprintf(octal, "\\%03o", (u_char)chr);
                tmxr_buf_debug_string (octal);
                }
            tmxr_buf_debug_char ('_');
            }
        break;
        }
    if ((u_char)chr == tn_chars[j].value) {
        tmxr_buf_debug_char ('_');
        tmxr_buf_debug_string (tn_chars[j].name);
        tmxr_buf_debug_char ('_');
        break;
        }
    }
}

static int tmxr_buf_debug_telnet_options (u_char *buf, int bufsize)
{
int optsize = 2;

tmxr_buf_debug_telnet_option ((u_char)buf[0]);
tmxr_buf_debug_telnet_option ((u_char)buf[1]);
switch ((u_char)buf[1]) {
    case TN_IAC:
    default:
        return optsize;
        break;
    case TN_WILL:
    case TN_WONT:
    case TN_DO:
    case TN_DONT:
        ++optsize;
        tmxr_buf_debug_telnet_option ((u_char)buf[2]);
        break;
    }
return optsize;
}

void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize)
{
DEVICE *dptr = (lp->dptr ? lp->dptr : (lp->mp ? lp->mp->dptr : NULL));

if ((dptr) && (dbits & dptr->dctrl)) {
    int i;

    tmxr_debug_buf_used = 0;
    if (tmxr_debug_buf)
        tmxr_debug_buf[tmxr_debug_buf_used] = '\0';

    if (lp->notelnet) {
        int same, group, sidx, oidx;
        char outbuf[80], strbuf[18];
        static char hex[] = "0123456789ABCDEF";

        for (i=same=0; i<bufsize; i += 16) {
            if ((i > 0) && (0 == memcmp(&buf[i], &buf[i-16], 16))) {
                ++same;
                continue;
                }
            if (same > 0) {
                if (lp->mp->lines > 1)
                    sim_debug (dbits, dptr, "Line:%d %04X thru %04X same as above\n", (int)(lp-lp->mp->ldsc), i-(16*same), i-1);
                else
                    sim_debug (dbits, dptr, "%04X thru %04X same as above\n", i-(16*same), i-1);
                same = 0;
                }
            group = (((bufsize - i) > 16) ? 16 : (bufsize - i));
            for (sidx=oidx=0; sidx<group; ++sidx) {
                outbuf[oidx++] = ' ';
                outbuf[oidx++] = hex[(buf[i+sidx]>>4)&0xf];
                outbuf[oidx++] = hex[buf[i+sidx]&0xf];
                if (isprint((u_char)buf[i+sidx]))
                    strbuf[sidx] = buf[i+sidx];
                else
                    strbuf[sidx] = '.';
                }
            outbuf[oidx] = '\0';
            strbuf[sidx] = '\0';
            if (lp->mp->lines > 1)
                sim_debug (dbits, dptr, "Line:%d %04X%-48s %s\n", (int)(lp-lp->mp->ldsc), i, outbuf, strbuf);
            else
                sim_debug (dbits, dptr, "%04X%-48s %s\n", i, outbuf, strbuf);
            }
        if (same > 0) {
            if (lp->mp->lines > 1)
                sim_debug (dbits, dptr, "Line:%d %04X thru %04X same as above\n", (int)(lp-lp->mp->ldsc), i-(16*same), bufsize-1);
            else
                sim_debug (dbits, dptr, "%04X thru %04X same as above\n", i-(16*same), bufsize-1);
            }
        }
    else {
        tmxr_debug_buf_used = 0;
        if (tmxr_debug_buf)
            tmxr_debug_buf[tmxr_debug_buf_used] = '\0';
        for (i=0; i<bufsize; ++i) {
            switch ((u_char)buf[i]) {
                case TN_CR:
                    tmxr_buf_debug_string ("_TN_CR_");
                    break;
                case TN_LF:
                    tmxr_buf_debug_string ("_TN_LF_");
                    break;
                case TN_IAC:
                    if (!lp->notelnet) {
                        i += (tmxr_buf_debug_telnet_options ((u_char *)(&buf[i]), bufsize-i) - 1);
                        break;
                        }
                default:
                    if (isprint((u_char)buf[i]))
                        tmxr_buf_debug_char (buf[i]);
                    else {
                        tmxr_buf_debug_char ('_');
                        if ((buf[i] >= 1) && (buf[i] <= 26)) {
                            tmxr_buf_debug_char ('^');
                            tmxr_buf_debug_char ('A' + buf[i] - 1);
                            }
                        else {
                            char octal[8];

                            sprintf(octal, "\\%03o", (u_char)buf[i]);
                            tmxr_buf_debug_string (octal);
                            }
                        tmxr_buf_debug_char ('_');
                        }
                    break;
                }
            }
        if (lp->mp->lines > 1)
            sim_debug (dbits, dptr, "Line:%d %s %d bytes '%s'\n", (int)(lp-lp->mp->ldsc), msg, bufsize, tmxr_debug_buf);
        else
            sim_debug (dbits, dptr, "%s %d bytes '%s'\n", msg, bufsize, tmxr_debug_buf);
        }
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_tmxr.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/* sim_tmxr.h: terminal multiplexer definitions

   Copyright (c) 2001-2008, Robert M Supnik

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of Robert M Supnik shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from Robert M Supnik.

   Based on the original DZ11 simulator by Thord Nilson, as updated by
   Arthur Krewat.

   10-Oct-12    MP      Added extended attach support for serial, per line 
                        listener and outgoing connections
   17-Jan-11    MP      Added buffered line capabilities
   20-Nov-08    RMS     Added three new standardized SHOW routines
   07-Oct-08    JDB     Added serial port support to TMXR, TMLN
   27-May-08    JDB     Added lnorder to TMXR structure,
                        added tmxr_set_lnorder and tmxr_set_lnorder
   14-May-08    JDB     Added dptr to TMXR structure
   04-Jan-04    RMS     Changed TMXR ldsc to be pointer to linedesc array
                        Added tmxr_linemsg, logging (from Mark Pizzolato)
   29-Dec-03    RMS     Added output stall support, increased buffer size
   22-Dec-02    RMS     Added break support (from Mark Pizzolato)
   20-Aug-02    RMS     Added tmxr_open_master, tmxr_close_master, tmxr.port
   30-Dec-01    RMS     Renamed tmxr_fstatus, added tmxr_fstats
   20-Oct-01    RMS     Removed tmxr_getchar, formalized buffer guard,
                        added tmxr_rqln, tmxr_tqln
*/

#ifndef SIM_TMXR_H_
#define SIM_TMXR_H_    0

#ifdef  __cplusplus
extern "C" {
#endif

#ifndef SIMH_SERHANDLE_DEFINED
#define SIMH_SERHANDLE_DEFINED 0
typedef struct SERPORT *SERHANDLE;
#endif

#include "sim_sock.h"

#define TMXR_V_VALID    15
#define TMXR_VALID      (1 << TMXR_V_VALID)
#define TMXR_MAXBUF     256                             /* buffer size */

#define TMXR_DTR_DROP_TIME 500                          /* milliseconds to drop DTR for 'pseudo' modem control */
#define TMXR_MODEM_RING_TIME 3                          /* seconds to wait for DTR for incoming connections */
#define TMXR_DEFAULT_CONNECT_POLL_INTERVAL 1            /* seconds between connection polls */

#define TMXR_DBG_XMT    0x0010000                        /* Debug Transmit Data */
#define TMXR_DBG_RCV    0x0020000                        /* Debug Received Data */
#define TMXR_DBG_RET    0x0040000                        /* Debug Returned Received Data */
#define TMXR_DBG_MDM    0x0080000                        /* Debug Modem Signals */
#define TMXR_DBG_CON    0x0100000                        /* Debug Connection Activities */
#define TMXR_DBG_ASY    0x0200000                        /* Debug Asynchronous Activities */
#define TMXR_DBG_TRC    0x0400000                        /* Debug trace routine calls */
#define TMXR_DBG_PXMT   0x0800000                        /* Debug Transmit Packet Data */
#define TMXR_DBG_PRCV   0x1000000                        /* Debug Received Packet Data */
#define TMXR_DBG_EXP    0x2000000                        /* Debug Expect Activities */
#define TMXR_DBG_SEND   0x4000000                        /* Debug Send Activities */

/* Modem Control Bits */

#define TMXR_MDM_DTR        0x01    /* Data Terminal Ready */
#define TMXR_MDM_RTS        0x02    /* Request To Send     */
#define TMXR_MDM_DCD        0x04    /* Data Carrier Detect */
#define TMXR_MDM_RNG        0x08    /* Ring Indicator      */
#define TMXR_MDM_CTS        0x10    /* Clear To Send       */
#define TMXR_MDM_DSR        0x20    /* Data Set Ready      */
#define TMXR_MDM_INCOMING   (TMXR_MDM_DCD|TMXR_MDM_RNG|TMXR_MDM_CTS|TMXR_MDM_DSR)  /* Settable Modem Bits */
#define TMXR_MDM_OUTGOING   (TMXR_MDM_DTR|TMXR_MDM_RTS)  /* Settable Modem Bits */

/* Unit flags */

#define TMUF_V_NOASYNCH   (UNIT_V_UF + 12)              /* Asynch Disabled unit */
#define TMUF_NOASYNCH     (1u << TMUF_V_NOASYNCH)       /* This flag can be defined */
                                                        /* statically in a unit's flag field */
                                                        /* This will disable the unit from */
                                                        /* supporting asynchronmous mux behaviors */
/* Receive line speed limits */

#define TMLN_SPD_50_BPS     200000 /* usec per character */
#define TMLN_SPD_75_BPS     133333 /* usec per character */
#define TMLN_SPD_110_BPS     90909 /* usec per character */
#define TMLN_SPD_134_BPS     74626 /* usec per character */
#define TMLN_SPD_150_BPS     66666 /* usec per character */
#define TMLN_SPD_300_BPS     33333 /* usec per character */
#define TMLN_SPD_600_BPS     16666 /* usec per character */
#define TMLN_SPD_1200_BPS     8333 /* usec per character */
#define TMLN_SPD_1800_BPS     5555 /* usec per character */
#define TMLN_SPD_2000_BPS     5000 /* usec per character */
#define TMLN_SPD_2400_BPS     4166 /* usec per character */
#define TMLN_SPD_3600_BPS     2777 /* usec per character */
#define TMLN_SPD_4800_BPS     2083 /* usec per character */
#define TMLN_SPD_7200_BPS     1388 /* usec per character */
#define TMLN_SPD_9600_BPS     1041 /* usec per character */
#define TMLN_SPD_19200_BPS     520 /* usec per character */
#define TMLN_SPD_38400_BPS     260 /* usec per character */
#define TMLN_SPD_57600_BPS     173 /* usec per character */
#define TMLN_SPD_76800_BPS     130 /* usec per character */
#define TMLN_SPD_115200_BPS     86 /* usec per character */



typedef struct tmln TMLN;
typedef struct tmxr TMXR;
struct loopbuf {
    int32               bpr;                          /* xmt buf remove */
    int32               bpi;                          /* xmt buf insert */
    int32               size;
    };

struct tmln {
    int                 conn;                           /* line connected flag */
    SOCKET              sock;                           /* connection socket */
    char                *ipad;                          /* IP address */
    SOCKET              master;                         /* line specific master socket */
    char                *port;                          /* line specific listening port */
    int32               sessions;                       /* count of tcp connections received */
    uint32              cnms;                           /* conn time */
    int32               tsta;                           /* Telnet state */
    int32               rcve;                           /* rcv enable */
    int32               xmte;                           /* xmt enable */
    int32               dstb;                           /* disable Telnet binary mode */
    t_bool              notelnet;                       /* raw binary data (no telnet interpretation) */
    uint8               *telnet_sent_opts;              /* Telnet Options which we have sent a DON'T/WON'T */
    int32               rxbpr;                          /* rcv buf remove */
    int32               rxbpi;                          /* rcv buf insert */
    int32               rxbsz;                          /* rcv buffer size */
    int32               rxcnt;                          /* rcv count */
    int32               rxpcnt;                         /* rcv packet count */
    int32               txbpr;                          /* xmt buf remove */
    int32               txbpi;                          /* xmt buf insert */
    int32               txcnt;                          /* xmt count */
    int32               txpcnt;                         /* xmt packet count */
    int32               txdrp;                          /* xmt drop count */
    int32               txbsz;                          /* xmt buffer size */
    int32               txbfd;                          /* xmt buffered flag */
    t_bool              modem_control;                  /* line supports modem control behaviors */
    int32               modembits;                      /* modem bits which are currently set */
    FILE                *txlog;                         /* xmt log file */
    FILEREF             *txlogref;                      /* xmt log file reference */
    char                *txlogname;                     /* xmt log file name */
    char                *rxb;                           /* rcv buffer */
    char                *rbr;                           /* rcv break */
    char                *txb;                           /* xmt buffer */
    uint8               *rxpb;                          /* rcv packet buffer */
    uint32              rxpbsize;                       /* rcv packet buffer size */
    uint32              rxpboffset;                     /* rcv packet buffer offset */
    uint32              rxbps;                          /* rcv bps speed (0 - unlimited) */
    double              rxbpsfactor;                    /* receive speed factor (scaled to usecs) */
#define TMXR_RX_BPS_UNIT_SCALE 1000000.0
    uint32              rxdelta;                        /* rcv inter character min time (usecs) */
    double              rxnexttime;                     /* min time for next receive character */
    uint32              txbps;                          /* xmt bps speed (0 - unlimited) */
    uint32              txdelta;                        /* xmt inter character min time (usecs) */
    double              txnexttime;                     /* min time for next transmit character */
    uint8               *txpb;                          /* xmt packet buffer */
    uint32              txpbsize;                       /* xmt packet buffer size */
    uint32              txppsize;                       /* xmt packet packet size */
    uint32              txppoffset;                     /* xmt packet buffer offset */
    TMXR                *mp;                            /* back pointer to mux */
    char                *serconfig;                     /* line config */
    SERHANDLE           serport;                        /* serial port handle */
    t_bool              ser_connect_pending;            /* serial connection notice pending */
    SOCKET              connecting;                     /* Outgoing socket while connecting */
    char                *destination;                   /* Outgoing destination address:port */
    t_bool              loopback;                       /* Line in loopback mode */
    t_bool              halfduplex;                     /* Line in half-duplex mode */
    t_bool              datagram;                       /* Line is datagram packet oriented */
    t_bool              packet;                         /* Line is packet oriented */
    int32               lpbpr;                          /* loopback buf remove */
    int32               lpbpi;                          /* loopback buf insert */
    int32               lpbcnt;                         /* loopback buf used count */
    int32               lpbsz;                          /* loopback buffer size */
    char                *lpb;                           /* loopback buffer */
    UNIT                *uptr;                          /* input polling unit (default to mp->uptr) */
    UNIT                *o_uptr;                        /* output polling unit (default to lp->uptr)*/
    DEVICE              *dptr;                          /* line specific device */
    EXPECT              expect;                         /* Expect rules */
    SEND                send;                           /* Send input state */
    };

struct tmxr {
    int32               lines;                          /* # lines */
    char                *port;                          /* listening port */
    SOCKET              master;                         /* master socket */
    TMLN                *ldsc;                          /* line descriptors */
    int32               *lnorder;                       /* line connection order */
    DEVICE              *dptr;                          /* multiplexer device */
    UNIT                *uptr;                          /* polling unit (connection) */
    char                logfiletmpl[FILENAME_MAX];      /* template logfile name */
    int32               txcount;                        /* count of transmit bytes */
    int32               buffered;                       /* Buffered Line Behavior and Buffer Size Flag */
    int32               sessions;                       /* count of tcp connections received */
    uint32              poll_interval;                  /* frequency of connection polls (seconds) */
    uint32              last_poll_time;                 /* time of last connection poll */
    uint32              ring_start_time;                /* time ring signal was raised */
    char                *ring_ipad;                     /* incoming connection address awaiting DTR */
    SOCKET              ring_sock;                      /* incoming connection socket awaiting DTR */
    t_bool              notelnet;                       /* default telnet capability for incoming connections */
    t_bool              modem_control;                  /* multiplexer supports modem control behaviors */
    t_bool              packet;                         /* Lines are packet oriented */
    t_bool              datagram;                       /* Lines use datagram packet transport */
    };

int32 tmxr_poll_conn (TMXR *mp);
t_stat tmxr_reset_ln (TMLN *lp);
t_stat tmxr_detach_ln (TMLN *lp);
int32 tmxr_input_pending_ln (TMLN *lp);
int32 tmxr_getc_ln (TMLN *lp);
t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize);
t_stat tmxr_get_packet_ln_ex (TMLN *lp, const uint8 **pbuf, size_t *psize, uint8 frame_byte);
void tmxr_poll_rx (TMXR *mp);
t_stat tmxr_putc_ln (TMLN *lp, int32 chr);
t_stat tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size);
t_stat tmxr_put_packet_ln_ex (TMLN *lp, const uint8 *buf, size_t size, uint8 frame_byte);
void tmxr_poll_tx (TMXR *mp);
int32 tmxr_send_buffered_data (TMLN *lp);
t_stat tmxr_open_master (TMXR *mp, CONST char *cptr);
t_stat tmxr_close_master (TMXR *mp);
t_stat tmxr_connection_poll_interval (TMXR *mp, uint32 seconds);
t_stat tmxr_attach_ex (TMXR *mp, UNIT *uptr, CONST char *cptr, t_bool async);
t_stat tmxr_detach (TMXR *mp, UNIT *uptr);
t_stat tmxr_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
char *tmxr_line_attach_string(TMLN *lp);
t_stat tmxr_set_modem_control_passthru (TMXR *mp);
t_stat tmxr_clear_modem_control_passthru (TMXR *mp);
t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits);
t_stat tmxr_set_line_loopback (TMLN *lp, t_bool enable_loopback);
t_bool tmxr_get_line_loopback (TMLN *lp);
t_stat tmxr_set_line_halfduplex (TMLN *lp, t_bool enable_loopback);
t_bool tmxr_get_line_halfduplex (TMLN *lp);
t_stat tmxr_set_line_speed (TMLN *lp, CONST char *speed);
t_stat tmxr_set_config_line (TMLN *lp, CONST char *config);
t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll);
t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll);
t_stat tmxr_set_console_units (UNIT *rxuptr, UNIT *txuptr);
t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
void tmxr_msg (SOCKET sock, const char *msg);
void tmxr_linemsg (TMLN *lp, const char *msg);
void tmxr_linemsgf (TMLN *lp, const char *fmt, ...);
void tmxr_linemsgvf (TMLN *lp, const char *fmt, va_list args);
void tmxr_fconns (FILE *st, const TMLN *lp, int32 ln);
void tmxr_fstats (FILE *st, const TMLN *lp, int32 ln);
t_stat tmxr_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tmxr_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tmxr_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_dscln (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
int32 tmxr_rqln (const TMLN *lp);
int32 tmxr_tqln (const TMLN *lp);
int32 tmxr_tpqln (const TMLN *lp);
t_bool tmxr_tpbusyln (const TMLN *lp);
t_stat tmxr_set_lnorder (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc);
t_stat tmxr_activate (UNIT *uptr, int32 interval);
t_stat tmxr_activate_after (UNIT *uptr, uint32 usecs_walltime);
t_stat tmxr_activate_after_abs (UNIT *uptr, uint32 usecs_walltime);
t_stat tmxr_clock_coschedule (UNIT *uptr, int32 interval);
t_stat tmxr_clock_coschedule_abs (UNIT *uptr, int32 interval);
t_stat tmxr_clock_coschedule_tmr (UNIT *uptr, int32 tmr, int32 ticks);
t_stat tmxr_clock_coschedule_tmr_abs (UNIT *uptr, int32 tmr, int32 ticks);
t_stat tmxr_change_async (void);
t_stat tmxr_locate_line_send (const char *dev_line, SEND **snd);
t_stat tmxr_locate_line_expect (const char *dev_line, EXPECT **exp);
t_stat tmxr_startup (void);
t_stat tmxr_shutdown (void);
t_stat tmxr_start_poll (void);
t_stat tmxr_stop_poll (void);
void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize);
#define tmxr_debug(dbits, lp, msg, buf, bufsize) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) _tmxr_debug (dbits, lp, msg, buf, bufsize); } while (0)
#define tmxr_debug_msg(dbits, lp, msg) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) sim_debug (dbits, (lp)->mp->dptr, "%s", msg); } while (0)
#define tmxr_debug_return(lp, val) do {if (sim_deb && (val) && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_RET & (lp)->mp->dptr->dctrl)) { if ((lp)->rxbps) sim_debug (TMXR_DBG_RET, (lp)->mp->dptr, "Ln%d: 0x%x - Next after: %.0f\n", (int)((lp)-(lp)->mp->ldsc), val, (lp)->rxnexttime); else sim_debug (TMXR_DBG_RET, (lp)->mp->dptr, "Ln%d: 0x%x\n", (int)((lp)-(lp)->mp->ldsc), val); } } while (0)
#define tmxr_debug_trace(mp, msg) do {if (sim_deb && (mp)->dptr && (TMXR_DBG_TRC & (mp)->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, mp->dptr, "%s\n", (msg)); } while (0)
#define tmxr_debug_trace_line(lp, msg) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_TRC & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, (lp)->mp->dptr, "Ln%d:%s\n", (int)((lp)-(lp)->mp->ldsc), (msg)); } while (0)
#define tmxr_debug_connect(mp, msg) do {if (sim_deb && (mp)->dptr && (TMXR_DBG_CON & (mp)->dptr->dctrl)) sim_debug (TMXR_DBG_CON, mp->dptr, "%s\n", (msg)); } while (0)
#define tmxr_debug_connect_line(lp, msg) do {if (sim_deb && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_CON & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_CON, (lp)->mp->dptr, "Ln%d:%s\n", (int)((lp)-(lp)->mp->ldsc), (msg)); } while (0)

#if defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_IO)
#undef SIM_ASYNCH_MUX
#endif /* defined(SIM_ASYNCH_MUX) && !defined(SIM_ASYNCH_IO) */

#if defined(SIM_ASYNCH_MUX)
#define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, TRUE)
#else
#define tmxr_attach(mp, uptr, cptr) tmxr_attach_ex(mp, uptr, cptr, FALSE)
#endif
#if (!defined(NOT_MUX_USING_CODE))
#define sim_activate tmxr_activate
#define sim_activate_after tmxr_activate_after
#define sim_activate_after_abs tmxr_activate_after_abs
#define sim_clock_coschedule tmxr_clock_coschedule 
#define sim_clock_coschedule_abs tmxr_clock_coschedule_abs
#define sim_clock_coschedule_tmr tmxr_clock_coschedule_tmr
#define sim_clock_coschedule_tmr_abs tmxr_clock_coschedule_tmr_abs
#endif


#ifdef  __cplusplus
}
#endif

#endif /* _SIM_TMXR_H_ */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































Deleted src/sim_video.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
/* sim_video.c: Bitmap video output

   Copyright (c) 2011-2013, Matt Burke

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the author shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from the author.

   08-Nov-2013  MB      Added globals for current mouse status
   11-Jun-2013  MB      First version
*/

#include "sim_video.h"
#include "scp.h"

t_bool vid_active = FALSE;
int32 vid_mouse_xrel;
int32 vid_mouse_yrel;
int32 vid_cursor_x;
int32 vid_cursor_y;
t_bool vid_mouse_b1 = FALSE;
t_bool vid_mouse_b2 = FALSE;
t_bool vid_mouse_b3 = FALSE;
static VID_QUIT_CALLBACK vid_quit_callback = NULL;

t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback)
{
vid_quit_callback = callback;
return SCPE_OK;
}

t_stat vid_show (FILE* st, DEVICE *dptr,  UNIT* uptr, int32 val, CONST char* desc)
{
return vid_show_video (st, uptr, val, desc);
}

#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)

char vid_release_key[64] = "Ctrl-Right-Shift";

#include <SDL.h>
#include <SDL_thread.h>

static const char *key_names[] = 
    {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", 
     "0",   "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9",    
     "A",   "B",  "C",  "D",  "E",  "F",  "G",  "H",  "I",  "J", 
     "K",   "L",  "M",  "N",  "O",  "P",  "Q",  "R",  "S",  "T", 
     "U",   "V",  "W",  "X",  "Y",  "Z", 
     "BACKQUOTE",   "MINUS",   "EQUALS", "LEFT_BRACKET", "RIGHT_BRACKET", 
     "SEMICOLON", "SINGLE_QUOTE", "BACKSLASH", "LEFT_BACKSLASH", "COMMA", 
     "PERIOD", "SLASH", "PRINT", "SCRL_LOCK", "PAUSE", "ESC", "BACKSPACE", 
     "TAB", "ENTER", "SPACE", "INSERT", "DELETE", "HOME", "END", "PAGE_UP", 
     "PAGE_DOWN", "UP", "DOWN", "LEFT", "RIGHT", "CAPS_LOCK", "NUM_LOCK", 
     "ALT_L", "ALT_R", "CTRL_L", "CTRL_R", "SHIFT_L", "SHIFT_R", 
     "WIN_L", "WIN_R", "MENU", "KP_ADD", "KP_SUBTRACT", "KP_END", "KP_DOWN", 
     "KP_PAGE_DOWN", "KP_LEFT", "KP_RIGHT", "KP_HOME", "KP_UP", "KP_PAGE_UP", 
     "KP_INSERT", "KP_DELETE", "KP_5", "KP_ENTER", "KP_MULTIPLY", "KP_DIVIDE"
     };

const char *vid_key_name (int32 key)
{
static char tmp_key_name[40];

    if (key < sizeof(key_names)/sizeof(key_names[0]))
        sprintf (tmp_key_name, "SIM_KEY_%s", key_names[key]);
    else
        sprintf (tmp_key_name, "UNKNOWN KEY: %d", key);
    return tmp_key_name;
}

#if defined(HAVE_LIBPNG)
/* From: https://github.com/driedfruit/SDL_SavePNG */

/*
 * Save an SDL_Surface as a PNG file.
 *
 * Returns 0 success or -1 on failure, the error message is then retrievable
 * via SDL_GetError().
 */
#define SDL_SavePNG(surface, file) \
	SDL_SavePNG_RW(surface, SDL_RWFromFile(file, "wb"), 1)

/*
 * SDL_SavePNG -- libpng-based SDL_Surface writer.
 *
 * This code is free software, available under zlib/libpng license.
 * http://www.libpng.org/pub/png/src/libpng-LICENSE.txt
 */
#include <SDL.h>
#include <png.h>

#define SUCCESS 0
#define ERROR -1

#define USE_ROW_POINTERS

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define rmask 0xFF000000
#define gmask 0x00FF0000
#define bmask 0x0000FF00
#define amask 0x000000FF
#else
#define rmask 0x000000FF
#define gmask 0x0000FF00
#define bmask 0x00FF0000
#define amask 0xFF000000
#endif

/* libpng callbacks */ 
static void png_error_SDL(png_structp ctx, png_const_charp str)
{
    SDL_SetError("libpng: %s\n", str);
}
static void png_write_SDL(png_structp png_ptr, png_bytep data, png_size_t length)
{
    SDL_RWops *rw = (SDL_RWops*)png_get_io_ptr(png_ptr);
    SDL_RWwrite(rw, data, sizeof(png_byte), length);
}

static SDL_Surface *SDL_PNGFormatAlpha(SDL_Surface *src) 
{
    SDL_Surface *surf;
    SDL_Rect rect = { 0 };

    /* NO-OP for images < 32bpp and 32bpp images that already have Alpha channel */ 
    if (src->format->BitsPerPixel <= 24 || src->format->Amask) {
        src->refcount++;
        return src;
    }

    /* Convert 32bpp alpha-less image to 24bpp alpha-less image */
    rect.w = src->w;
    rect.h = src->h;
    surf = SDL_CreateRGBSurface(src->flags, src->w, src->h, 24,
        src->format->Rmask, src->format->Gmask, src->format->Bmask, 0);
    SDL_LowerBlit(src, &rect, surf, &rect);

    return surf;
}

static int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst) 
{
    png_structp png_ptr;
    png_infop info_ptr;
    png_colorp pal_ptr;
    SDL_Palette *pal;
    int i, colortype;
#ifdef USE_ROW_POINTERS
    png_bytep *row_pointers;
#endif
    /* Initialize and do basic error checking */
    if (!dst)
    {
        SDL_SetError("Argument 2 to SDL_SavePNG_RW can't be NULL, expecting SDL_RWops*\n");
        return (ERROR);
    }
    if (!surface)
    {
        SDL_SetError("Argument 1 to SDL_SavePNG_RW can't be NULL, expecting SDL_Surface*\n");
        if (freedst) SDL_RWclose(dst);
        return (ERROR);
    }
    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_SDL, NULL); /* err_ptr, err_fn, warn_fn */
    if (!png_ptr) 
    {
        SDL_SetError("Unable to png_create_write_struct on %s\n", PNG_LIBPNG_VER_STRING);
        if (freedst) SDL_RWclose(dst);
        return (ERROR);
    }
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        SDL_SetError("Unable to png_create_info_struct\n");
        png_destroy_write_struct(&png_ptr, NULL);
        if (freedst) SDL_RWclose(dst);
        return (ERROR);
    }
    if (setjmp(png_jmpbuf(png_ptr)))    /* All other errors, see also "png_error_SDL" */
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        if (freedst) SDL_RWclose(dst);
        return (ERROR);
    }

    /* Setup our RWops writer */
    png_set_write_fn(png_ptr, dst, png_write_SDL, NULL); /* w_ptr, write_fn, flush_fn */

    /* Prepare chunks */
    colortype = PNG_COLOR_MASK_COLOR;
    if (surface->format->BytesPerPixel > 0
    &&  surface->format->BytesPerPixel <= 8
    && (pal = surface->format->palette))
    {
        colortype |= PNG_COLOR_MASK_PALETTE;
        pal_ptr = (png_colorp)malloc(pal->ncolors * sizeof(png_color));
        for (i = 0; i < pal->ncolors; i++) {
            pal_ptr[i].red   = pal->colors[i].r;
            pal_ptr[i].green = pal->colors[i].g;
            pal_ptr[i].blue  = pal->colors[i].b;
        }
        png_set_PLTE(png_ptr, info_ptr, pal_ptr, pal->ncolors);
        free(pal_ptr);
    }
    else if (surface->format->BytesPerPixel > 3 || surface->format->Amask)
        colortype |= PNG_COLOR_MASK_ALPHA;

    png_set_IHDR(png_ptr, info_ptr, surface->w, surface->h, 8, colortype,
        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

//    png_set_packing(png_ptr);

    /* Allow BGR surfaces */
    if (surface->format->Rmask == bmask
    && surface->format->Gmask == gmask
    && surface->format->Bmask == rmask)
        png_set_bgr(png_ptr);

    /* Write everything */
    png_write_info(png_ptr, info_ptr);
#ifdef USE_ROW_POINTERS
    row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surface->h);
    for (i = 0; i < surface->h; i++)
        row_pointers[i] = (png_bytep)(Uint8*)surface->pixels + i * surface->pitch;
    png_write_image(png_ptr, row_pointers);
    free(row_pointers);
#else
    for (i = 0; i < surface->h; i++)
        png_write_row(png_ptr, (png_bytep)(Uint8*)surface->pixels + i * surface->pitch);
#endif
    png_write_end(png_ptr, info_ptr);

    /* Done */
    png_destroy_write_struct(&png_ptr, &info_ptr);
    if (freedst) SDL_RWclose(dst);
    return (SUCCESS);
}
#endif /* defined(HAVE_LIBPNG) */

/* 
    Some platforms (OS X), require that ALL input event processing be 
    performed by the main thread of the process.

    To satisfy this requirement, we leverage the SDL_MAIN functionality 
    which does:
    
             #defines main SDL_main
     
     and we define the main() entry point here.  Locally, we run the 
     application's SDL_main in a separate thread, and while that thread
     is running, the main thread performs event handling and dispatch.
     
 */

#define EVENT_REDRAW     1                              /* redraw event for SDL */
#define EVENT_CLOSE      2                              /* close event for SDL */
#define EVENT_CURSOR     3                              /* new cursor for SDL */
#define EVENT_WARP       4                              /* warp mouse position for SDL */
#define EVENT_DRAW       5                              /* draw/blit region for SDL */
#define EVENT_SHOW       6                              /* show SDL capabilities */
#define EVENT_OPEN       7                              /* vid_open request */
#define EVENT_EXIT       8                              /* program exit */
#define EVENT_SCREENSHOT 9                              /* produce screenshot of video window */
#define EVENT_BEEP      10                              /* audio beep */
#define MAX_EVENTS      20                              /* max events in queue */

typedef struct {
    SIM_KEY_EVENT events[MAX_EVENTS];
    SDL_sem *sem;
    int32 head;
    int32 tail;
    int32 count;
    } KEY_EVENT_QUEUE;

typedef struct {
    SIM_MOUSE_EVENT events[MAX_EVENTS];
    SDL_sem *sem;
    int32 head;
    int32 tail;
    int32 count;
    } MOUSE_EVENT_QUEUE;

int vid_thread (void* arg);
int vid_video_events (void);
void vid_show_video_event (void);
void vid_screenshot_event (void);
void vid_beep_event (void);

/* 
   libSDL and libSDL2 have significantly different APIs.  
   The consequence is that this code has significant #ifdef sections.

   The current structure is to implement the API differences in each 
   routine that has a difference.  This allows the decision and flow 
   logic to exist once and thus to allow logic changes to be implemented 
   in one place.

 */


t_bool vid_mouse_captured;
int32 vid_flags;                                        /* Open Flags */
int32 vid_width;
int32 vid_height;
t_bool vid_ready;
char vid_title[128];
static void vid_beep_setup (int duration_ms, int tone_frequency);
static void vid_beep_cleanup (void);
#if SDL_MAJOR_VERSION == 1

/*
   Some platforms that use X11 display technology have libSDL 
   environments which need to call XInitThreads when libSDL is used
   in multi-threaded programs.  This routine attempts to locate
   the X11 shareable library and if it is found loads it and calls
   the XInitThreads routine to meet this requirement.
 */
#ifdef HAVE_DLOPEN
#include <dlfcn.h>
#endif

static void _XInitThreads (void)
{
#ifdef HAVE_DLOPEN
static void *hLib = NULL;                   /* handle to Library */
#define __STR_QUOTE(tok) #tok
#define __STR(tok) __STR_QUOTE(tok)
static const char* lib_name = "libX11." __STR(HAVE_DLOPEN);
typedef int (*_func)();
_func _func_ptr = NULL;

if (!hLib)
    hLib = dlopen(lib_name, RTLD_NOW);
if (hLib)
    _func_ptr = (_func)((size_t)dlsym(hLib, "XInitThreads"));
if (_func_ptr)
    _func_ptr();
#endif
}

t_bool vid_key_state[SDLK_LAST];
SDL_Surface *vid_image;                                 /* video buffer */
SDL_Surface *vid_window;                                /* window handle */
#else
t_bool vid_key_state[SDL_NUM_SCANCODES];
SDL_Texture *vid_texture;                               /* video buffer in GPU */
SDL_Renderer *vid_renderer;
SDL_Window *vid_window;                                 /* window handle */
uint32 vid_windowID;
#endif
SDL_Thread *vid_thread_handle = NULL;                   /* event thread handle */
SDL_Cursor *vid_cursor = NULL;                          /* current cursor */
t_bool vid_cursor_visible = FALSE;                      /* cursor visibility state */
uint32 vid_mono_palette[2];                             /* Monochrome Color Map */
SDL_Color vid_colors[256];
KEY_EVENT_QUEUE vid_key_events;                         /* keyboard events */
MOUSE_EVENT_QUEUE vid_mouse_events;                     /* mouse events */
DEVICE *vid_dev;

#if defined (SDL_MAIN_AVAILABLE)
#if defined (main)
#undef main
#endif

static int main_argc;
static char **main_argv;
static SDL_Thread *vid_main_thread_handle;

int main_thread (void *arg)
{
SDL_Event user_event;
int stat;

stat = SDL_main (main_argc, main_argv);
user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_EXIT;
user_event.user.data1 = NULL;
user_event.user.data2 = NULL;
while (SDL_PushEvent (&user_event) < 0)
    sim_os_ms_sleep (10);
return stat;
}

int main (int argc, char *argv[])
{
SDL_Event event;
int status;

main_argc = argc;
main_argv = argv;

#if SDL_MAJOR_VERSION == 1
_XInitThreads();
SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE);

vid_main_thread_handle = SDL_CreateThread (main_thread , NULL);
#else
SDL_SetHint (SDL_HINT_RENDER_DRIVER, "software");

SDL_Init (SDL_INIT_VIDEO);

vid_main_thread_handle = SDL_CreateThread (main_thread , "simh-main", NULL);
#endif

sim_os_set_thread_priority (PRIORITY_ABOVE_NORMAL);

vid_beep_setup (400, 660);

while (1) {
    int status = SDL_WaitEvent (&event);
    if (status == 1) {
        if (event.type == SDL_USEREVENT) {
            if (event.user.code == EVENT_EXIT)
                break;
            if (event.user.code == EVENT_OPEN)
                vid_video_events ();
            else {
                if (event.user.code == EVENT_SHOW)
                    vid_show_video_event ();
                else {
                    if (event.user.code == EVENT_SCREENSHOT)
                        vid_screenshot_event ();
                    else {
                        if (event.user.code == EVENT_BEEP)
                            vid_beep_event ();
                        else {
                            sim_printf ("main(): Unexpected User event: %d\n", event.user.code);
                            break;
                            }
                        }
                    }
                }
            }
        else {
//          sim_printf ("main(): Ignoring unexpected event: %d\n", event.type);
            }
        }
    else {
        if (status < 0)
            sim_printf ("main() - ` error: %s\n", SDL_GetError());
        }
    }
SDL_WaitThread (vid_main_thread_handle, &status);
vid_beep_cleanup ();
SDL_Quit ();
return status;
}

static t_stat vid_create_window ()
{
int wait_count = 0;
SDL_Event user_event;

vid_ready = FALSE;
user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_OPEN;
user_event.user.data1 = NULL;
user_event.user.data2 = NULL;
SDL_PushEvent (&user_event);

while ((!vid_ready) && (++wait_count < 20))
    sim_os_ms_sleep (100);
if (!vid_ready) {
    vid_close ();
    return SCPE_OPENERR;
    }
return SCPE_OK;
}
#else
static int vid_create_window ()
{
int wait_count = 0;

#if SDL_MAJOR_VERSION == 1
vid_thread_handle = SDL_CreateThread (vid_thread, NULL);
#else
vid_thread_handle = SDL_CreateThread (vid_thread, "vid-thread", NULL);
#endif
if (vid_thread_handle == NULL) {
    vid_close ();
    return SCPE_OPENERR;
    }
while ((!vid_ready) && (++wait_count < 20))
    sim_os_ms_sleep (100);
if (!vid_ready) {
    vid_close ();
    return SCPE_OPENERR;
    }
return SCPE_OK;
}
#endif

t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags)
{
if (!vid_active) {
    int wait_count = 0;
    t_stat stat;

    if ((strlen(sim_name) + 7 + (dptr ? strlen (dptr->name) : 0) + (title ? strlen (title) : 0)) < sizeof (vid_title))
        sprintf (vid_title, "%s%s%s%s%s", sim_name, dptr ? " - " : "", dptr ? dptr->name : "", title ? " - " : "", title ? title : "");
    else
        sprintf (vid_title, "%s", sim_name);
    vid_flags = flags;
    vid_active = TRUE;
    vid_width = width;
    vid_height = height;
    vid_mouse_captured = FALSE;
    vid_cursor_visible = (vid_flags & SIM_VID_INPUTCAPTURED);
    vid_mouse_xrel = 0;
    vid_mouse_yrel = 0;

    vid_key_events.head = 0;
    vid_key_events.tail = 0;
    vid_key_events.count = 0;
    vid_key_events.sem = SDL_CreateSemaphore (1);
    vid_mouse_events.head = 0;
    vid_mouse_events.tail = 0;
    vid_mouse_events.count = 0;
    vid_mouse_events.sem = SDL_CreateSemaphore (1);

    vid_dev = dptr;

    stat = vid_create_window ();
    if (stat != SCPE_OK)
        return stat;

    sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n");
    }
return SCPE_OK;
}

t_stat vid_close (void)
{
if (vid_active) {
    SDL_Event user_event;
    int status;

    vid_active = FALSE;
    if (vid_ready) {
        sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_close()\n");
        user_event.type = SDL_USEREVENT;
        user_event.user.code = EVENT_CLOSE;
        user_event.user.data1 = NULL;
        user_event.user.data2 = NULL;

        while (SDL_PushEvent (&user_event) < 0)
            sim_os_ms_sleep (10);
        if (vid_thread_handle) {
            SDL_WaitThread (vid_thread_handle, &status);
            vid_thread_handle = NULL;
            }
        vid_dev = NULL;
        }
    while (vid_ready)
        sim_os_ms_sleep (10);
    if (vid_mouse_events.sem) {
        SDL_DestroySemaphore(vid_mouse_events.sem);
        vid_mouse_events.sem = NULL;
        }
    if (vid_key_events.sem) {
        SDL_DestroySemaphore(vid_key_events.sem);
        vid_key_events.sem = NULL;
        }
    }
return SCPE_OK;
}

t_stat vid_poll_kb (SIM_KEY_EVENT *ev)
{
if (SDL_SemTryWait (vid_key_events.sem) == 0) {         /* get lock */
    if (vid_key_events.count > 0) {                     /* events in queue? */
        *ev = vid_key_events.events[vid_key_events.head++];
        vid_key_events.count--;
        if (vid_key_events.head == MAX_EVENTS)
            vid_key_events.head = 0;
        SDL_SemPost (vid_key_events.sem);
        return SCPE_OK;
        }
    SDL_SemPost (vid_key_events.sem);
    }
return SCPE_EOF;
}

t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev)
{
t_stat stat = SCPE_EOF;
SIM_MOUSE_EVENT *nev;

if (SDL_SemTryWait (vid_mouse_events.sem) == 0) {
    if (vid_mouse_events.count > 0) {
        stat = SCPE_OK;
        *ev = vid_mouse_events.events[vid_mouse_events.head++];
        vid_mouse_events.count--;
        if (vid_mouse_events.head == MAX_EVENTS)
            vid_mouse_events.head = 0;
        nev = &vid_mouse_events.events[vid_mouse_events.head];
        if ((vid_mouse_events.count > 0) &&
            (0 == (ev->x_rel + nev->x_rel)) &&
            (0 == (ev->y_rel + nev->y_rel)) &&
            (ev->b1_state == nev->b1_state) &&
            (ev->b2_state == nev->b2_state) &&
            (ev->b3_state == nev->b3_state)) {
            if ((++vid_mouse_events.head) == MAX_EVENTS)
                vid_mouse_events.head = 0;
            vid_mouse_events.count--;
            stat = SCPE_EOF;
            sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "vid_poll_mouse: ignoring bouncing events\n");
            }
        }
    if (SDL_SemPost (vid_mouse_events.sem))
        sim_printf ("%s: vid_poll_mouse(): SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError());
    }
return stat;
}

void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf)
{
#if SDL_MAJOR_VERSION == 1
int32 i;
uint32* pixels;

sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h);

pixels = (uint32 *)vid_image->pixels;

for (i = 0; i < h; i++)
    memcpy (pixels + ((i + y) * vid_width) + x, buf + w*i, w*sizeof(*pixels));
#else
SDL_Event user_event;
SDL_Rect *vid_dst;
uint32 *vid_data;

sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h);

vid_dst = (SDL_Rect *)malloc (sizeof(*vid_dst));
if (!vid_dst) {
    sim_printf ("%s: vid_draw() memory allocation error\n", vid_dev ? sim_dname(vid_dev) : "Video Device");
    return;
    }
vid_dst->x = x;
vid_dst->y = y;
vid_dst->w = w;
vid_dst->h = h;
vid_data = (uint32 *)malloc (w*h*sizeof(*buf));
if (!vid_data) {
    sim_printf ("%s: vid_draw() memory allocation error\n", vid_dev ? sim_dname(vid_dev) : "Video Device");
    free (vid_dst);
    return;
    }
memcpy (vid_data, buf, w*h*sizeof(*buf));
user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_DRAW;
user_event.user.data1 = (void *)vid_dst;
user_event.user.data2 = (void *)vid_data;
if (SDL_PushEvent (&user_event) < 0) {
    sim_printf ("%s: vid_draw() SDL_PushEvent error: %s\n", vid_dev ? sim_dname(vid_dev) : "Video Device", SDL_GetError());
    free (vid_dst);
    free (vid_data);
    }
#endif
}

t_stat vid_set_cursor (t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y)
{
SDL_Cursor *cursor = SDL_CreateCursor (data, mask, width, height, hot_x, hot_y);
SDL_Event user_event;

sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor(%s, %d, %d) Setting New Cursor\n", visible ? "visible" : "invisible", width, height);
if (sim_deb) {
    uint32 i, j;

    for (i=0; i<height; i++) {
        sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "Cursor:  ");
        for (j=0; j<width; j++) {
            int byte = (j + i*width) >> 3;
            int bit = 7 - ((j + i*width) & 0x7);
            static char mode[] = "TWIB";

            sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "%c", mode[(((data[byte]>>bit)&1)<<1)|(mask[byte]>>bit)&1]);
            }
        sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "\n");
        }
    }

user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_CURSOR;
user_event.user.data1 = cursor;
user_event.user.data2 = (void *)((size_t)visible);

if (SDL_PushEvent (&user_event) < 0) {
    sim_printf ("%s: vid_set_cursor() SDL_PushEvent error: %s\n", vid_dev ? sim_dname(vid_dev) : "Video Device", SDL_GetError());
    SDL_FreeCursor (cursor);
    }

return SCPE_OK;
}

void vid_set_cursor_position (int32 x, int32 y)
{
int32 x_delta = vid_cursor_x - x;
int32 y_delta = vid_cursor_y - y;

if ((x_delta) || (y_delta)) {
    sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position(%d, %d) - Cursor position changed\n", x, y);
    /* Any queued mouse motion events need to have their relative 
       positions adjusted since they were queued based on different info. */
    if (SDL_SemWait (vid_mouse_events.sem) == 0) {
        int32 i;
        SIM_MOUSE_EVENT *ev;

        for (i=0; i<vid_mouse_events.count; i++) {
            ev = &vid_mouse_events.events[(vid_mouse_events.head + i)%MAX_EVENTS];
            sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "Pending Mouse Motion Event Adjusted from: (%d, %d) to (%d, %d)\n", ev->x_rel, ev->y_rel, ev->x_rel + x_delta, ev->y_rel + y_delta);
            vid_mouse_xrel -= ev->x_rel;                            /* remove previously accumulated relative position */
            vid_mouse_yrel -= ev->y_rel;
            ev->x_rel += x_delta;
            ev->y_rel += y_delta;
            vid_mouse_xrel += ev->x_rel;                            /* update cumulative x & y rel */
            vid_mouse_yrel += ev->y_rel;
            }
        if (SDL_SemPost (vid_mouse_events.sem))
            sim_printf ("%s: vid_set_cursor_position(): SDL_SemPost error: %s\n", vid_dev ? sim_dname(vid_dev) : "Video Device", SDL_GetError());
        }
    else {
        sim_printf ("%s: vid_set_cursor_position(): SDL_SemWait error: %s\n", vid_dev ? sim_dname(vid_dev) : "Video Device", SDL_GetError());
        }
    vid_cursor_x = x;
    vid_cursor_y = y;
    if (vid_cursor_visible) {
        SDL_Event user_event;

        user_event.type = SDL_USEREVENT;
        user_event.user.code = EVENT_WARP;
        user_event.user.data1 = NULL;
        user_event.user.data2 = NULL;

        if (SDL_PushEvent (&user_event) < 0)
            sim_printf ("%s: vid_set_cursor_position() SDL_PushEvent error: %s\n", sim_dname(vid_dev), SDL_GetError());
        sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position() - Warp Queued\n");
        }
    else {
        sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position() - Warp Skipped\n");
        }
    }
}

void vid_refresh (void)
{
SDL_Event user_event;

sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_refresh() - Queueing Refresh Event\n");

user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_REDRAW;
user_event.user.data1 = NULL;
user_event.user.data2 = NULL;

if (SDL_PushEvent (&user_event) < 0)
    sim_printf ("%s: vid_refresh() SDL_PushEvent error: %s\n", sim_dname(vid_dev), SDL_GetError());
}

int vid_map_key (int key)
{
switch (key) {

    case SDLK_BACKSPACE:
        return SIM_KEY_BACKSPACE;

    case SDLK_TAB:
        return SIM_KEY_TAB;

    case SDLK_RETURN:
        return SIM_KEY_ENTER;

    case SDLK_ESCAPE:
        return SIM_KEY_ESC;

    case SDLK_SPACE:
        return SIM_KEY_SPACE;

    case SDLK_QUOTE:
        return SIM_KEY_SINGLE_QUOTE;

    case SDLK_COMMA:
        return SIM_KEY_COMMA;

    case SDLK_MINUS:
        return SIM_KEY_MINUS;

    case SDLK_PERIOD:
        return SIM_KEY_PERIOD;

    case SDLK_SLASH:
        return SIM_KEY_SLASH;

    case SDLK_0:
        return SIM_KEY_0;

    case SDLK_1:
        return SIM_KEY_1;

    case SDLK_2:
        return SIM_KEY_2;

    case SDLK_3:
        return SIM_KEY_3;

    case SDLK_4:
        return SIM_KEY_4;

    case SDLK_5:
        return SIM_KEY_5;

    case SDLK_6:
        return SIM_KEY_6;

    case SDLK_7:
        return SIM_KEY_7;

    case SDLK_8:
        return SIM_KEY_8;

    case SDLK_9:
        return SIM_KEY_9;

    case SDLK_SEMICOLON:
        return SIM_KEY_SEMICOLON;

    case SDLK_EQUALS:
        return SIM_KEY_EQUALS;

    case SDLK_LEFTBRACKET:
        return SIM_KEY_LEFT_BRACKET;

    case SDLK_BACKSLASH:
        return SIM_KEY_BACKSLASH;

    case SDLK_RIGHTBRACKET:
        return SIM_KEY_RIGHT_BRACKET;

    case SDLK_BACKQUOTE:
        return SIM_KEY_BACKQUOTE;

    case SDLK_a:
        return SIM_KEY_A;

    case SDLK_b:
        return SIM_KEY_B;

    case SDLK_c:
        return SIM_KEY_C;

    case SDLK_d:
        return SIM_KEY_D;

    case SDLK_e:
        return SIM_KEY_E;

    case SDLK_f:
        return SIM_KEY_F;

    case SDLK_g:
        return SIM_KEY_G;

    case SDLK_h:
        return SIM_KEY_H;

    case SDLK_i:
        return SIM_KEY_I;

    case SDLK_j:
        return SIM_KEY_J;

    case SDLK_k:
        return SIM_KEY_K;

    case SDLK_l:
        return SIM_KEY_L;

    case SDLK_m:
        return SIM_KEY_M;

    case SDLK_n:
        return SIM_KEY_N;

    case SDLK_o:
        return SIM_KEY_O;

    case SDLK_p:
        return SIM_KEY_P;

    case SDLK_q:
        return SIM_KEY_Q;

    case SDLK_r:
        return SIM_KEY_R;

    case SDLK_s:
        return SIM_KEY_S;

    case SDLK_t:
        return SIM_KEY_T;

    case SDLK_u:
        return SIM_KEY_U;

    case SDLK_v:
        return SIM_KEY_V;

    case SDLK_w:
        return SIM_KEY_W;

    case SDLK_x:
        return SIM_KEY_X;

    case SDLK_y:
        return SIM_KEY_Y;

    case SDLK_z:
        return SIM_KEY_Z;

    case SDLK_DELETE:
        return SIM_KEY_DELETE;
#if SDL_MAJOR_VERSION == 1
    case SDLK_KP0:
        return SIM_KEY_KP_INSERT;

    case SDLK_KP1:
        return SIM_KEY_KP_END;

    case SDLK_KP2:
        return SIM_KEY_KP_DOWN;

    case SDLK_KP3:
        return SIM_KEY_KP_PAGE_DOWN;

    case SDLK_KP4:
        return SIM_KEY_KP_LEFT;

    case SDLK_KP5:
        return SIM_KEY_KP_5;

    case SDLK_KP6:
        return SIM_KEY_KP_RIGHT;

    case SDLK_KP7:
        return SIM_KEY_KP_HOME;

    case SDLK_KP8:
        return SIM_KEY_KP_UP;

    case SDLK_KP9:
        return SIM_KEY_KP_PAGE_UP;
#else
    case SDLK_KP_0:
        return SIM_KEY_KP_INSERT;

    case SDLK_KP_1:
        return SIM_KEY_KP_END;

    case SDLK_KP_2:
        return SIM_KEY_KP_DOWN;

    case SDLK_KP_3:
        return SIM_KEY_KP_PAGE_DOWN;

    case SDLK_KP_4:
        return SIM_KEY_KP_LEFT;

    case SDLK_KP_5:
        return SIM_KEY_KP_5;

    case SDLK_KP_6:
        return SIM_KEY_KP_RIGHT;

    case SDLK_KP_7:
        return SIM_KEY_KP_HOME;

    case SDLK_KP_8:
        return SIM_KEY_KP_UP;

    case SDLK_KP_9:
        return SIM_KEY_KP_PAGE_UP;
#endif
    case SDLK_KP_PERIOD:
        return SIM_KEY_KP_DELETE;

    case SDLK_KP_DIVIDE:
        return SIM_KEY_KP_DIVIDE;

    case SDLK_KP_MULTIPLY:
        return SIM_KEY_KP_MULTIPLY;

    case SDLK_KP_MINUS:
        return SIM_KEY_KP_SUBTRACT;

    case SDLK_KP_PLUS:
        return SIM_KEY_KP_ADD;

    case SDLK_KP_ENTER:
        return SIM_KEY_KP_ENTER;

    case SDLK_UP:
        return SIM_KEY_UP;

    case SDLK_DOWN:
        return SIM_KEY_DOWN;

    case SDLK_RIGHT:
        return SIM_KEY_RIGHT;

    case SDLK_LEFT:
        return SIM_KEY_LEFT;

    case SDLK_INSERT:
        return SIM_KEY_INSERT;

    case SDLK_HOME:
        return SIM_KEY_HOME;

    case SDLK_END:
        return SIM_KEY_END;

    case SDLK_PAGEUP:
        return SIM_KEY_PAGE_UP;

    case SDLK_PAGEDOWN:
        return SIM_KEY_PAGE_DOWN;

    case SDLK_F1:
        return SIM_KEY_F1;

    case SDLK_F2:
        return SIM_KEY_F2;

    case SDLK_F3:
        return SIM_KEY_F3;

    case SDLK_F4:
        return SIM_KEY_F4;

    case SDLK_F5:
        return SIM_KEY_F5;

    case SDLK_F6:
        return SIM_KEY_F6;

    case SDLK_F7:
        return SIM_KEY_F7;

    case SDLK_F8:
        return SIM_KEY_F8;

    case SDLK_F9:
        return SIM_KEY_F9;

    case SDLK_F10:
        return SIM_KEY_F10;

    case SDLK_F11:
        return SIM_KEY_F11;

    case SDLK_F12:
        return SIM_KEY_F12;
#if SDL_MAJOR_VERSION != 1
    case SDLK_NUMLOCKCLEAR:
        return SIM_KEY_NUM_LOCK;
#endif
    case SDLK_CAPSLOCK:
        return SIM_KEY_CAPS_LOCK;
#if SDL_MAJOR_VERSION == 1
    case SDLK_SCROLLOCK:
        return SIM_KEY_SCRL_LOCK;
#else
    case SDLK_SCROLLLOCK:
        return SIM_KEY_SCRL_LOCK;
#endif
    case SDLK_RSHIFT:
        return SIM_KEY_SHIFT_R;

    case SDLK_LSHIFT:
        return SIM_KEY_SHIFT_L;

    case SDLK_RCTRL:
        return SIM_KEY_CTRL_R;

    case SDLK_LCTRL:
        return SIM_KEY_CTRL_L;

    case SDLK_RALT:
        return SIM_KEY_ALT_R;

    case SDLK_LALT:
        return SIM_KEY_ALT_L;
#if SDL_MAJOR_VERSION == 1
    case SDLK_RMETA:
        return SIM_KEY_ALT_R;

    case SDLK_LMETA:
        return SIM_KEY_WIN_L;
#else
    case SDLK_LGUI:
        return SIM_KEY_WIN_L;

    case SDLK_RGUI:
        return SIM_KEY_WIN_R;
#endif
#if SDL_MAJOR_VERSION == 1
    case SDLK_PRINT:
        return SIM_KEY_PRINT;
#else
    case SDLK_PRINTSCREEN:
        return SIM_KEY_PRINT;
#endif
    case SDLK_PAUSE:
        return SIM_KEY_PAUSE;

    case SDLK_MENU:
        return SIM_KEY_MENU;

    default:
        return SIM_KEY_UNKNOWN;
        }
}

void vid_key (SDL_KeyboardEvent *event)
{
SIM_KEY_EVENT ev;

if (vid_mouse_captured) {
    static const Uint8 *KeyStates = NULL;
    static int numkeys;

    if (!KeyStates)
#if SDL_MAJOR_VERSION == 1
        KeyStates = SDL_GetKeyState(&numkeys);
    if ((vid_flags & SIM_VID_INPUTCAPTURED) && 
        (event->state == SDL_PRESSED) && 
        KeyStates[SDLK_RSHIFT] && 
        (KeyStates[SDLK_LCTRL] || KeyStates[SDLK_RCTRL])) {
#else
        KeyStates = SDL_GetKeyboardState(&numkeys);
    if ((vid_flags & SIM_VID_INPUTCAPTURED) && 
        (event->state == SDL_PRESSED) && 
        KeyStates[SDL_SCANCODE_RSHIFT] && 
        (KeyStates[SDL_SCANCODE_LCTRL] || KeyStates[SDL_SCANCODE_RCTRL])) {
#endif
        sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_key() - Cursor Release\n");
#if SDL_MAJOR_VERSION == 1
        if (SDL_WM_GrabInput (SDL_GRAB_OFF) < 0)        /* relese cursor */
            sim_printf ("%s: vid_key(): SDL_WM_GrabInput error: %s\n", sim_dname(vid_dev), SDL_GetError());
        if (SDL_ShowCursor (SDL_ENABLE) < 0)            /* show cursor */
            sim_printf ("%s: vid_key(): SDL_ShowCursor error: %s\n", sim_dname(vid_dev), SDL_GetError());
#else
        if (SDL_SetRelativeMouseMode(SDL_FALSE) < 0)    /* release cursor, show cursor */
            sim_printf ("%s: vid_key(): SDL_SetRelativeMouseMode error: %s\n", sim_dname(vid_dev), SDL_GetError());
#endif
        vid_mouse_captured = FALSE;
        return;
        }
    }
if (!sim_is_running)
    return;
if (SDL_SemWait (vid_key_events.sem) == 0) {
    if (vid_key_events.count < MAX_EVENTS) {
        ev.key = vid_map_key (event->keysym.sym);
        sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event: State: %s, Keysym(scancode,sym): (%d,%d) - %s\n", (event->state == SDL_PRESSED) ? "PRESSED" : "RELEASED", event->keysym.scancode, event->keysym.sym, vid_key_name(ev.key));
        if (event->state == SDL_PRESSED) {
#if SDL_MAJOR_VERSION == 1
            if (!vid_key_state[event->keysym.sym]) {    /* Key was not down before */
                vid_key_state[event->keysym.sym] = TRUE;
#else
            if (!vid_key_state[event->keysym.scancode]) {/* Key was not down before */
                vid_key_state[event->keysym.scancode] = TRUE;
#endif
                ev.state = SIM_KEYPRESS_DOWN;
                }
            else
                ev.state = SIM_KEYPRESS_REPEAT;
            }
        else {
#if SDL_MAJOR_VERSION == 1
            vid_key_state[event->keysym.sym] = FALSE;
#else
            vid_key_state[event->keysym.scancode] = FALSE;
#endif
            ev.state = SIM_KEYPRESS_UP;
            }
        vid_key_events.events[vid_key_events.tail++] = ev;
        vid_key_events.count++;
        if (vid_key_events.tail == MAX_EVENTS)
            vid_key_events.tail = 0;
        }
    else {
        sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event DISCARDED: State: %s, Keysym: Scancode: %d, Keysym: %d\n", (event->state == SDL_PRESSED) ? "PRESSED" : "RELEASED", event->keysym.scancode, event->keysym.sym);
        }
    if (SDL_SemPost (vid_key_events.sem))
        sim_printf ("%s: vid_key(): SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError());
    }
}

void vid_mouse_move (SDL_MouseMotionEvent *event)
{
SDL_Event dummy_event;
SDL_MouseMotionEvent *dev = (SDL_MouseMotionEvent *)&dummy_event;
SIM_MOUSE_EVENT ev;

if ((!vid_mouse_captured) && (vid_flags & SIM_VID_INPUTCAPTURED))
    return;

if (!sim_is_running)
    return;
if (!vid_cursor_visible)
    return;
sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", 
           event->x, event->y, event->xrel, event->yrel, (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0);
#if SDL_MAJOR_VERSION == 1
while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {
#else
while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) {
#endif
    /* Coalesce motion activity to avoid thrashing */
    event->xrel += dev->xrel;
    event->yrel += dev->yrel;
    event->x = dev->x;
    event->y = dev->y;
    event->state = dev->state;
    sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: Additional Event Coalesced:pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", 
        dev->x, dev->y, dev->xrel, dev->yrel, (dev->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (dev->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (dev->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0);
    };
if (SDL_SemWait (vid_mouse_events.sem) == 0) {
    if (!vid_mouse_captured) {
        event->xrel = (event->x - vid_cursor_x);
        event->yrel = (event->y - vid_cursor_y);
        }
    vid_mouse_xrel += event->xrel;                          /* update cumulative x rel */
    vid_mouse_yrel += event->yrel;                          /* update cumulative y rel */
    vid_mouse_b1 = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE;
    vid_mouse_b2 = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE;
    vid_mouse_b3 = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE;
    sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d) - Count: %d vid_mouse_rel:(%d,%d), vid_cursor:(%d,%d)\n", 
                                            event->x, event->y, event->xrel, event->yrel, (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0, vid_mouse_events.count, vid_mouse_xrel, vid_mouse_yrel, vid_cursor_x, vid_cursor_y);
    if (vid_mouse_events.count < MAX_EVENTS) {
        SIM_MOUSE_EVENT *tail = &vid_mouse_events.events[(vid_mouse_events.tail+MAX_EVENTS-1)%MAX_EVENTS];

        ev.x_rel = event->xrel;
        ev.y_rel = event->yrel;
        ev.b1_state = vid_mouse_b1;
        ev.b2_state = vid_mouse_b2;
        ev.b3_state = vid_mouse_b3;
        ev.x_pos = event->x;
        ev.y_pos = event->y;
        if ((vid_mouse_events.count > 0) &&             /* Is there a tail event? */
            (ev.b1_state == tail->b1_state) &&          /* With the same button state? */
            (ev.b2_state == tail->b2_state) && 
            (ev.b3_state == tail->b3_state)) {          /* Merge the motion */
            tail->x_rel += ev.x_rel;
            tail->y_rel += ev.y_rel;
            tail->x_pos = ev.x_pos;
            tail->y_pos = ev.y_pos;
            sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: Coalesced into pending event: (%d,%d) vid_mouse_rel:(%d,%d)\n", 
                tail->x_rel, tail->y_rel, vid_mouse_xrel, vid_mouse_yrel);
            }
        else {                                          /* Add a new event */
            vid_mouse_events.events[vid_mouse_events.tail++] = ev;
            vid_mouse_events.count++;
            if (vid_mouse_events.tail == MAX_EVENTS)
                vid_mouse_events.tail = 0;
            }
        }
    else {
        sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event Discarded: Count: %d\n", vid_mouse_events.count);
        }
    if (SDL_SemPost (vid_mouse_events.sem))
        sim_printf ("%s: vid_mouse_move(): SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError());
    }
}

void vid_mouse_button (SDL_MouseButtonEvent *event)
{
SDL_Event dummy_event;
SIM_MOUSE_EVENT ev;
t_bool state;

if ((!vid_mouse_captured) && (vid_flags & SIM_VID_INPUTCAPTURED)) {
    if ((event->state == SDL_PRESSED) &&
        (event->button == SDL_BUTTON_LEFT)) {               /* left click and cursor not captured? */
        sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_mouse_button() - Cursor Captured\n");
#if SDL_MAJOR_VERSION == 1
        SDL_WM_GrabInput (SDL_GRAB_ON);                     /* lock cursor to window */
        SDL_ShowCursor (SDL_DISABLE);                       /* hide cursor */
        SDL_WarpMouse (vid_width/2, vid_height/2);          /* back to center */
        SDL_PumpEvents ();
        while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {};
#else
        if (SDL_SetRelativeMouseMode (SDL_TRUE) < 0)        /* lock cursor to window, hide cursor */
            sim_printf ("%s: vid_mouse_button(): SDL_SetRelativeMouseMode error: %s\n", sim_dname(vid_dev), SDL_GetError());
        SDL_WarpMouseInWindow (NULL, vid_width/2, vid_height/2);/* back to center */
        SDL_PumpEvents ();
        while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) {};
#endif
        vid_mouse_captured = TRUE;
        }
    return;
    }
if (!sim_is_running)
    return;
state = (event->state == SDL_PRESSED) ? TRUE : FALSE;
if (SDL_SemWait (vid_mouse_events.sem) == 0) {
    switch (event->button) {
        case SDL_BUTTON_LEFT:
            vid_mouse_b1 = state;
            break;
        case SDL_BUTTON_MIDDLE:
            vid_mouse_b2 = state;
            break;
        case SDL_BUTTON_RIGHT:
            vid_mouse_b3 = state;
            break;
            }
    sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event: State: %d, Button: %d, (%d,%d)\n", event->state, event->button, event->x, event->y);
    if (vid_mouse_events.count < MAX_EVENTS) {
        ev.x_rel = 0;
        ev.y_rel = 0;
        ev.x_pos = event->x;
        ev.y_pos = event->y;
        ev.b1_state = vid_mouse_b1;
        ev.b2_state = vid_mouse_b2;
        ev.b3_state = vid_mouse_b3;
        vid_mouse_events.events[vid_mouse_events.tail++] = ev;
        vid_mouse_events.count++;
        if (vid_mouse_events.tail == MAX_EVENTS)
            vid_mouse_events.tail = 0;
        }
    else {
        sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event Discarded: Count: %d\n", vid_mouse_events.count);
        }
    if (SDL_SemPost (vid_mouse_events.sem))
        sim_printf ("%s: Mouse Button Event: SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError());
    }
}

void vid_update (void)
{
SDL_Rect vid_dst;

vid_dst.x = 0;
vid_dst.y = 0;
vid_dst.w = vid_width;
vid_dst.h = vid_height;

sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Video Update Event: \n");
if (sim_deb)
    fflush (sim_deb);
#if SDL_MAJOR_VERSION == 1
if (SDL_BlitSurface (vid_image, NULL, vid_window, &vid_dst) < 0)
    sim_printf ("%s: vid_update(): SDL_BlitSurface error: %s\n", sim_dname(vid_dev), SDL_GetError());
SDL_UpdateRects (vid_window, 1, &vid_dst);
#else
if (SDL_RenderClear (vid_renderer))
    sim_printf ("%s: Video Update Event: SDL_RenderClear error: %s\n", sim_dname(vid_dev), SDL_GetError());
if (SDL_RenderCopy (vid_renderer, vid_texture, NULL, NULL))
    sim_printf ("%s: Video Update Event: SDL_RenderCopy error: %s\n", sim_dname(vid_dev), SDL_GetError());
SDL_RenderPresent (vid_renderer);
#endif
}

void vid_update_cursor (SDL_Cursor *cursor, t_bool visible)
{
if (!cursor)
    return;
sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Cursor Update Event: Previously %s, Now %s, New Cursor object at: %p, Old Cursor object at: %p\n", 
                            SDL_ShowCursor(-1) ? "visible" : "invisible", visible ? "visible" : "invisible", cursor, vid_cursor);
SDL_SetCursor (cursor);
#if SDL_MAJOR_VERSION == 1
if (visible)
    SDL_WarpMouse (vid_cursor_x, vid_cursor_y);/* sync position */
#else
if ((vid_window == SDL_GetMouseFocus ()) && visible)
    SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y);/* sync position */
#endif
if ((vid_cursor != cursor) && (vid_cursor))
    SDL_FreeCursor (vid_cursor);
vid_cursor = cursor;
SDL_ShowCursor (visible);
vid_cursor_visible = visible;
}

void vid_warp_position (void)
{
sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Mouse Warp Event: Warp to: (%d,%d)\n", vid_cursor_x, vid_cursor_y);

SDL_PumpEvents ();
#if SDL_MAJOR_VERSION == 1
SDL_WarpMouse (vid_cursor_x, vid_cursor_y);
#else
SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y);
#endif
SDL_PumpEvents ();
}

void vid_draw_region (SDL_UserEvent *event)
{
SDL_Rect *vid_dst = (SDL_Rect *)event->data1;
uint32 *buf = (uint32 *)event->data2;

sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Draw Region Event: (%d,%d,%d,%d)\n", vid_dst->x, vid_dst->x, vid_dst->w, vid_dst->h);

#if SDL_MAJOR_VERSION == 1
if (1) {
    int32 i;
    uint32* pixels;

    pixels = (uint32 *)vid_image->pixels;

    for (i = 0; i < vid_dst->h; i++)
        memcpy (pixels + ((i + vid_dst->y) * vid_width) + vid_dst->x, buf + vid_dst->w*i, vid_dst->w*sizeof(*pixels));
    }
#else
if (SDL_UpdateTexture(vid_texture, vid_dst, buf, vid_dst->w*sizeof(*buf)))
    sim_printf ("%s: vid_draw() - SDL_UpdateTexture error: %s\n", sim_dname(vid_dev), SDL_GetError());
#endif

free (vid_dst);
free (buf);
event->data1 = NULL;
}

int vid_video_events (void)
{
SDL_Event event;
#if SDL_MAJOR_VERSION == 1
static const char *eventtypes[] = {
    "NOEVENT",              /**< Unused (do not remove) */
    "ACTIVEEVENT",          /**< Application loses/gains visibility */
    "KEYDOWN",              /**< Keys pressed */
    "KEYUP",                /**< Keys released */
    "MOUSEMOTION",          /**< Mouse moved */
    "MOUSEBUTTONDOWN",      /**< Mouse button pressed */
    "MOUSEBUTTONUP",        /**< Mouse button released */
    "JOYAXISMOTION",        /**< Joystick axis motion */
    "JOYBALLMOTION",        /**< Joystick trackball motion */
    "JOYHATMOTION",         /**< Joystick hat position change */
    "JOYBUTTONDOWN",        /**< Joystick button pressed */
    "JOYBUTTONUP",          /**< Joystick button released */
    "QUIT",                 /**< User-requested quit */
    "SYSWMEVENT",           /**< System specific event */
    "EVENT_RESERVEDA",      /**< Reserved for future use.. */
    "EVENT_RESERVEDB",      /**< Reserved for future use.. */
    "VIDEORESIZE",          /**< User resized video mode */
    "VIDEOEXPOSE",          /**< Screen needs to be redrawn */
    "EVENT_RESERVED2",      /**< Reserved for future use.. */
    "EVENT_RESERVED3",      /**< Reserved for future use.. */
    "EVENT_RESERVED4",      /**< Reserved for future use.. */
    "EVENT_RESERVED5",      /**< Reserved for future use.. */
    "EVENT_RESERVED6",      /**< Reserved for future use.. */
    "EVENT_RESERVED7",      /**< Reserved for future use.. */
    "USEREVENT",            /** Events SDL_USEREVENT(24) through SDL_MAXEVENTS-1(31) are for your use */
    "",
    "",
    "",
    "",
    "",
    "",
    ""
    };
#else
static const char *eventtypes[SDL_LASTEVENT];
#endif
static const char *windoweventtypes[256];
static t_bool initialized = FALSE;

if (!initialized) {
    initialized = TRUE;
#if SDL_MAJOR_VERSION != 1
    eventtypes[SDL_QUIT] = "QUIT";          /**< User-requested quit */

    /* These application events have special meaning on iOS, see README-ios.txt for details */
    eventtypes[SDL_APP_TERMINATING] = "APP_TERMINATING";   /**< The application is being terminated by the OS
                                     Called on iOS in applicationWillTerminate()
                                     Called on Android in onDestroy()
                                */
    eventtypes[SDL_APP_LOWMEMORY] = "APP_LOWMEMORY";          /**< The application is low on memory, free memory if possible.
                                     Called on iOS in applicationDidReceiveMemoryWarning()
                                     Called on Android in onLowMemory()
                                */
    eventtypes[SDL_APP_WILLENTERBACKGROUND] = "APP_WILLENTERBACKGROUND"; /**< The application is about to enter the background
                                     Called on iOS in applicationWillResignActive()
                                     Called on Android in onPause()
                                */
    eventtypes[SDL_APP_DIDENTERBACKGROUND] = "APP_DIDENTERBACKGROUND"; /**< The application did enter the background and may not get CPU for some time
                                     Called on iOS in applicationDidEnterBackground()
                                     Called on Android in onPause()
                                */
    eventtypes[SDL_APP_WILLENTERFOREGROUND] = "APP_WILLENTERFOREGROUND"; /**< The application is about to enter the foreground
                                     Called on iOS in applicationWillEnterForeground()
                                     Called on Android in onResume()
                                */
    eventtypes[SDL_APP_DIDENTERFOREGROUND] = "APP_DIDENTERFOREGROUND"; /**< The application is now interactive
                                     Called on iOS in applicationDidBecomeActive()
                                     Called on Android in onResume()
                                */

    /* Window events */
    eventtypes[SDL_WINDOWEVENT] = "WINDOWEVENT"; /**< Window state change */
    eventtypes[SDL_SYSWMEVENT] = "SYSWMEVENT";             /**< System specific event */

    windoweventtypes[SDL_WINDOWEVENT_NONE] = "NONE";                /**< Never used */
    windoweventtypes[SDL_WINDOWEVENT_SHOWN] = "SHOWN";              /**< Window has been shown */
    windoweventtypes[SDL_WINDOWEVENT_HIDDEN] = "HIDDEN";            /**< Window has been hidden */
    windoweventtypes[SDL_WINDOWEVENT_EXPOSED] = "EXPOSED";          /**< Window has been exposed and should be
                                                                         redrawn */
    windoweventtypes[SDL_WINDOWEVENT_MOVED] = "MOVED";              /**< Window has been moved to data1, data2
                                     */
    windoweventtypes[SDL_WINDOWEVENT_RESIZED] = "RESIZED";          /**< Window has been resized to data1xdata2 */
    windoweventtypes[SDL_WINDOWEVENT_SIZE_CHANGED] = "SIZE_CHANGED";/**< The window size has changed, either as a result of an API call or through the system or user changing the window size. */
    windoweventtypes[SDL_WINDOWEVENT_MINIMIZED] = "MINIMIZED";      /**< Window has been minimized */
    windoweventtypes[SDL_WINDOWEVENT_MAXIMIZED] = "MAXIMIZED";      /**< Window has been maximized */
    windoweventtypes[SDL_WINDOWEVENT_RESTORED] = "RESTORED";        /**< Window has been restored to normal size
                                                                         and position */
    windoweventtypes[SDL_WINDOWEVENT_ENTER] = "ENTER";              /**< Window has gained mouse focus */
    windoweventtypes[SDL_WINDOWEVENT_LEAVE] = "LEAVE";              /**< Window has lost mouse focus */
    windoweventtypes[SDL_WINDOWEVENT_FOCUS_GAINED] = "FOCUS_GAINED";/**< Window has gained keyboard focus */
    windoweventtypes[SDL_WINDOWEVENT_FOCUS_LOST] = "FOCUS_LOST";    /**< Window has lost keyboard focus */
    windoweventtypes[SDL_WINDOWEVENT_CLOSE] = "CLOSE";              /**< The window manager requests that the
                                                                         window be closed */

    /* Keyboard events */
    eventtypes[SDL_KEYDOWN] = "KEYDOWN";                            /**< Key pressed */
    eventtypes[SDL_KEYUP] = "KEYUP";                                /**< Key released */
    eventtypes[SDL_TEXTEDITING] = "TEXTEDITING";                    /**< Keyboard text editing (composition) */
    eventtypes[SDL_TEXTINPUT] = "TEXTINPUT";                        /**< Keyboard text input */

    /* Mouse events */
    eventtypes[SDL_MOUSEMOTION] = "MOUSEMOTION";                    /**< Mouse moved */
    eventtypes[SDL_MOUSEBUTTONDOWN] = "MOUSEBUTTONDOWN";            /**< Mouse button pressed */
    eventtypes[SDL_MOUSEBUTTONUP] = "MOUSEBUTTONUP";                /**< Mouse button released */
    eventtypes[SDL_MOUSEWHEEL] = "MOUSEWHEEL";                      /**< Mouse wheel motion */

    /* Joystick events */
    eventtypes[SDL_JOYAXISMOTION] = "JOYAXISMOTION";                /**< Joystick axis motion */
    eventtypes[SDL_JOYBALLMOTION] = "JOYBALLMOTION";                /**< Joystick trackball motion */
    eventtypes[SDL_JOYHATMOTION] = "JOYHATMOTION";                  /**< Joystick hat position change */
    eventtypes[SDL_JOYBUTTONDOWN] = "JOYBUTTONDOWN";                /**< Joystick button pressed */
    eventtypes[SDL_JOYBUTTONUP] = "JOYBUTTONUP";                    /**< Joystick button released */
    eventtypes[SDL_JOYDEVICEADDED] = "JOYDEVICEADDED";              /**< A new joystick has been inserted into the system */
    eventtypes[SDL_JOYDEVICEREMOVED] = "JOYDEVICEREMOVED";          /**< An opened joystick has been removed */

    /* Game controller events */
    eventtypes[SDL_CONTROLLERAXISMOTION] = "CONTROLLERAXISMOTION";          /**< Game controller axis motion */
    eventtypes[SDL_CONTROLLERBUTTONDOWN] = "CONTROLLERBUTTONDOWN";          /**< Game controller button pressed */
    eventtypes[SDL_CONTROLLERBUTTONUP] = "CONTROLLERBUTTONUP";              /**< Game controller button released */
    eventtypes[SDL_CONTROLLERDEVICEADDED] = "CONTROLLERDEVICEADDED";        /**< A new Game controller has been inserted into the system */
    eventtypes[SDL_CONTROLLERDEVICEREMOVED] = "CONTROLLERDEVICEREMOVED";    /**< An opened Game controller has been removed */
    eventtypes[SDL_CONTROLLERDEVICEREMAPPED] = "CONTROLLERDEVICEREMAPPED";  /**< The controller mapping was updated */

    /* Touch events */
    eventtypes[SDL_FINGERDOWN] = "FINGERDOWN";
    eventtypes[SDL_FINGERUP] = "FINGERUP";
    eventtypes[SDL_FINGERMOTION] = "FINGERMOTION";

    /* Gesture events */
    eventtypes[SDL_DOLLARGESTURE] = "DOLLARGESTURE";
    eventtypes[SDL_DOLLARRECORD] = "DOLLARRECORD";
    eventtypes[SDL_MULTIGESTURE] = "MULTIGESTURE";

    /* Clipboard events */
    eventtypes[SDL_CLIPBOARDUPDATE] = "CLIPBOARDUPDATE"; /**< The clipboard changed */

    /* Drag and drop events */
    eventtypes[SDL_DROPFILE] = "DROPFILE"; /**< The system requests a file open */

#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL >= 3)
    /* Render events */
    eventtypes[SDL_RENDER_TARGETS_RESET] = "RENDER_TARGETS_RESET"; /**< The render targets have been reset */
#endif

#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL >= 4)
    /* Render events */
    eventtypes[SDL_RENDER_DEVICE_RESET] = "RENDER_DEVICE_RESET"; /**< The render device has been reset */
#endif

    /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use,
     *  and should be allocated with SDL_RegisterEvents()
     */
    eventtypes[SDL_USEREVENT] = "USEREVENT";
#endif  /* SDL_MAJOR_VERSION != 1 */
    }

sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Starting\n");

vid_mono_palette[0] = sim_end ? 0xFF000000 : 0x000000FF;        /* Black */
vid_mono_palette[1] = 0xFFFFFFFF;                               /* White */

memset (&vid_key_state, 0, sizeof(vid_key_state));

#if SDL_MAJOR_VERSION == 1
vid_window = SDL_SetVideoMode (vid_width, vid_height, 8, 0);

SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);

if (sim_end)
    vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
else
    vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);

#else
SDL_CreateWindowAndRenderer (vid_width, vid_height, SDL_WINDOW_SHOWN, &vid_window, &vid_renderer);

if ((vid_window == NULL) || (vid_renderer == NULL)) {
    sim_printf ("%s: Error Creating Video Window: %s\n", sim_dname(vid_dev), SDL_GetError());
    SDL_Quit ();
    return 0;
    }

SDL_SetRenderDrawColor (vid_renderer, 0, 0, 0, 255);
SDL_RenderClear (vid_renderer);
SDL_RenderPresent (vid_renderer);

vid_texture = SDL_CreateTexture (vid_renderer,
                                 SDL_PIXELFORMAT_ARGB8888,
                                 SDL_TEXTUREACCESS_STREAMING,
                                 vid_width, vid_height);
if (!vid_texture) {
    sim_printf ("%s: Error configuring Video environment: %s\n", sim_dname(vid_dev), SDL_GetError());
    SDL_DestroyRenderer(vid_renderer);
    vid_renderer = NULL;
    SDL_DestroyWindow(vid_window);
    vid_window = NULL;
    SDL_Quit ();
    return 0;
    }

SDL_StopTextInput ();

vid_windowID = SDL_GetWindowID (vid_window);

#endif

if (vid_flags & SIM_VID_INPUTCAPTURED) {
    char title[150];

    memset (title, 0, sizeof(title));
    strncpy (title, vid_title, sizeof(title)-1);
    strncat (title, "                                             ReleaseKey=", sizeof(title)-(1+strlen(title)));
    strncat (title, vid_release_key, sizeof(title)-(1+strlen(title)));
#if SDL_MAJOR_VERSION == 1
    SDL_WM_SetCaption (title, title);
#else
    SDL_SetWindowTitle (vid_window, title);
#endif
    }
else
#if SDL_MAJOR_VERSION == 1
    SDL_WM_SetCaption (vid_title, sim_name);
#else
    SDL_SetWindowTitle (vid_window, vid_title);
#endif

vid_ready = TRUE;

sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Started\n");

while (vid_active) {
    int status = SDL_WaitEvent (&event);
    if (status == 1) {
        switch (event.type) {

            case SDL_KEYDOWN:
            case SDL_KEYUP:
                vid_key ((SDL_KeyboardEvent*)&event);
                break;

            case SDL_MOUSEBUTTONDOWN:
            case SDL_MOUSEBUTTONUP:
                vid_mouse_button ((SDL_MouseButtonEvent*)&event);
                break;

            case SDL_MOUSEMOTION:
                vid_mouse_move ((SDL_MouseMotionEvent*)&event);
                break;
#if SDL_MAJOR_VERSION != 1
            case SDL_WINDOWEVENT:
                if (event.window.windowID == vid_windowID) {
                    sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Window Event: %d - %s\n", event.window.event, windoweventtypes[event.window.event]);
                    switch (event.window.event) {
                        case SDL_WINDOWEVENT_ENTER:
                             if (vid_flags & SIM_VID_INPUTCAPTURED)
                                 SDL_WarpMouseInWindow (NULL, vid_width/2, vid_height/2);   /* center position */
                            break;
                        }
                    }
                break;
#endif
            case SDL_USEREVENT:
                /* There are 6 user events generated */
                /* EVENT_REDRAW to update the display */
                /* EVENT_DRAW   to update a region in the display texture */
                /* EVENT_SHOW   to display the current SDL video capabilities */
                /* EVENT_CURSOR to change the current cursor */
                /* EVENT_WARP   to warp the cursor position */
                /* EVENT_CLOSE  to wake up this thread and let */
                /*              it notice vid_active has changed */
                while (vid_active && event.user.code) {
                    if (event.user.code == EVENT_REDRAW) {
                        vid_update ();
                        event.user.code = 0;    /* Mark as done */
#if SDL_MAJOR_VERSION == 1
if (0)                        while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_USEREVENT))) {
#else
if (0)                        while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SDL_USEREVENT, SDL_USEREVENT)) {
#endif
                            if (event.user.code == EVENT_REDRAW) {
                                /* Only do a single video update between waiting for events */
                                sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_thread() - Ignored extra REDRAW Event\n");
                                event.user.code = 0;    /* Mark as done */
                                continue;
                                }
                            break;
                            }
                        }
                    if (event.user.code == EVENT_CURSOR) {
                        vid_update_cursor ((SDL_Cursor *)(event.user.data1), (t_bool)((size_t)event.user.data2));
                        event.user.data1 = NULL;
                        event.user.code = 0;    /* Mark as done */
                        }
                    if (event.user.code == EVENT_WARP) {
                        vid_warp_position ();
                        event.user.code = 0;    /* Mark as done */
                        }
                    if (event.user.code == EVENT_CLOSE) {
                        event.user.code = 0;    /* Mark as done */
                        }
                    if (event.user.code == EVENT_DRAW) {
                        vid_draw_region ((SDL_UserEvent*)&event);
                        event.user.code = 0;    /* Mark as done */
                        }
                    if (event.user.code == EVENT_SHOW) {
                        vid_show_video_event ();
                        event.user.code = 0;    /* Mark as done */
                        }
                    if (event.user.code == EVENT_SCREENSHOT) {
                        vid_screenshot_event ();
                        event.user.code = 0;    /* Mark as done */
                        }
                    if (event.user.code == EVENT_BEEP) {
                        vid_beep_event ();
                        event.user.code = 0;    /* Mark as done */
                        }
                    if (event.user.code != 0) {
                        sim_printf ("vid_thread(): Unexpected user event code: %d\n", event.user.code);
                        }
                    }
                break;
            case SDL_QUIT:
                sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - QUIT Event - %s\n", vid_quit_callback ? "Signaled" : "Ignored");
                if (vid_quit_callback)
                    vid_quit_callback ();
                break;

            default:
                sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Ignored Event: Type: %s(%d)\n", eventtypes[event.type], event.type);
                break;
            }
        }
    else {
        if (status < 0)
            sim_printf ("%s: vid_thread() - SDL_WaitEvent error: %s\n", sim_dname(vid_dev), SDL_GetError());
        }
    }
vid_ready = FALSE;
if (vid_cursor) {
    SDL_FreeCursor (vid_cursor);
    vid_cursor = NULL;
    }
#if SDL_MAJOR_VERSION != 1
SDL_DestroyTexture(vid_texture);
vid_texture = NULL;
SDL_DestroyRenderer(vid_renderer);
vid_renderer = NULL;
SDL_DestroyWindow(vid_window);
#endif /* SDL_MAJOR_VERSION != 1 */
vid_window = NULL;
sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Exiting\n");
return 0;
}

int vid_thread (void *arg)
{
#if SDL_MAJOR_VERSION == 1
_XInitThreads();
SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE);
#else
SDL_SetHint (SDL_HINT_RENDER_DRIVER, "software");

SDL_Init (SDL_INIT_VIDEO);
#endif
vid_beep_setup (400, 660);
vid_video_events ();
vid_beep_cleanup ();
SDL_Quit ();
return 0;
}

const char *vid_version(void)
{
static char SDLVersion[80];
SDL_version compiled, running;

#if SDL_MAJOR_VERSION == 1
const SDL_version *ver = SDL_Linked_Version();
running.major = ver->major;
running.minor = ver->minor;
running.patch = ver->patch;
#else
SDL_GetVersion(&running);
#endif
SDL_VERSION(&compiled);

if ((compiled.major == running.major) &&
    (compiled.minor == running.minor) &&
    (compiled.patch == running.patch))
    sprintf(SDLVersion, "SDL Version %d.%d.%d", 
                        compiled.major, compiled.minor, compiled.patch);
else
    sprintf(SDLVersion, "SDL Version (Compiled: %d.%d.%d, Runtime: %d.%d.%d)", 
                        compiled.major, compiled.minor, compiled.patch,
                        running.major, running.minor, running.patch);
return (const char *)SDLVersion;
}

t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
return SCPE_NOFNC;
}

t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
if (vid_flags & SIM_VID_INPUTCAPTURED)
    fprintf (st, "ReleaseKey=%s", vid_release_key);
return SCPE_OK;
}

static t_stat _vid_show_video (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
int i;

fprintf (st, "Video support using SDL: %s\n", vid_version());
#if defined (SDL_MAIN_AVAILABLE)
fprintf (st, "  SDL Events being processed on the main process thread\n");
#endif
if (!vid_active) {
#if !defined (SDL_MAIN_AVAILABLE)
    SDL_Init(SDL_INIT_VIDEO);
#endif
    }
else {
    fprintf (st, "  Currently Active Video Window: (%d by %d pixels)\n", vid_width, vid_height);
    fprintf (st, "  ");
    vid_show_release_key (st, uptr, val, desc);
    fprintf (st, "\n");
#if SDL_MAJOR_VERSION != 1
    fprintf (st, "  SDL Video Driver: %s\n", SDL_GetCurrentVideoDriver());
#endif
    }
#if SDL_MAJOR_VERSION == 1
if (1) {
    char driver_name[64];
    const SDL_VideoInfo *info = SDL_GetVideoInfo();

    fprintf (st, "  Video Driver:                                     %s\n", SDL_VideoDriverName(driver_name, sizeof(driver_name)));
    fprintf (st, "  hardware surfaces available:                      %s\n", info->hw_available ? "Yes" : "No");
    fprintf (st, "  window manager available:                         %s\n", info->wm_available ? "Yes" : "No");
    fprintf (st, "  hardware to hardware blits accelerated:           %s\n", info->blit_hw ? "Yes" : "No");
    fprintf (st, "  hardware to hardware colorkey blits accelerated:  %s\n", info->blit_hw_CC ? "Yes" : "No");
    fprintf (st, "  hardware to hardware alpha blits accelerated:     %s\n", info->blit_hw_A ? "Yes" : "No");
    fprintf (st, "  software to hardware blits accelerated:           %s\n", info->blit_sw ? "Yes" : "No");
    fprintf (st, "  software to hardware colorkey blits accelerated:  %s\n", info->blit_sw_CC ? "Yes" : "No");
    fprintf (st, "  software to hardware alpha blits accelerated:     %s\n", info->blit_sw_A ? "Yes" : "No");
    fprintf (st, "  color fills accelerated:                          %s\n", info->blit_fill ? "Yes" : "No");
    fprintf (st, "  Video Memory:                                     %dKb\n", info->video_mem);
    }
#else
for (i = 0; i < SDL_GetNumVideoDisplays(); ++i) {
    SDL_DisplayMode display;

    if (SDL_GetCurrentDisplayMode(i, &display)) {
        fprintf (st, "Could not get display mode for video display #%d: %s", i, SDL_GetError());
        }
    else {
        fprintf (st, "  Display %s(#%d): current display mode is %dx%dpx @ %dhz. \n", SDL_GetDisplayName(i), i, display.w, display.h, display.refresh_rate);
        }
    }
fprintf (st, "  Available SDL Renderers:\n");
for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) {
    SDL_RendererInfo info;

    if (SDL_GetRenderDriverInfo (i, &info)) {
        fprintf (st, "Could not get render driver info for driver #%d: %s", i, SDL_GetError());
        }
    else {
        uint32 j, k;
        static struct {uint32 format; const char *name;} PixelFormats[] = {
            {SDL_PIXELFORMAT_INDEX1LSB,     "Index1LSB"},
            {SDL_PIXELFORMAT_INDEX1MSB,     "Index1MSB"},
            {SDL_PIXELFORMAT_INDEX4LSB,     "Index4LSB"},
            {SDL_PIXELFORMAT_INDEX4MSB,     "Index4MSB"},
            {SDL_PIXELFORMAT_INDEX8,        "Index8"},
            {SDL_PIXELFORMAT_RGB332,        "RGB332"},
            {SDL_PIXELFORMAT_RGB444,        "RGB444"},
            {SDL_PIXELFORMAT_RGB555,        "RGB555"},
            {SDL_PIXELFORMAT_BGR555,        "BGR555"},
            {SDL_PIXELFORMAT_ARGB4444,      "ARGB4444"},
            {SDL_PIXELFORMAT_RGBA4444,      "RGBA4444"},
            {SDL_PIXELFORMAT_ABGR4444,      "ABGR4444"},
            {SDL_PIXELFORMAT_BGRA4444,      "BGRA4444"},
            {SDL_PIXELFORMAT_ARGB1555,      "ARGB1555"},
            {SDL_PIXELFORMAT_RGBA5551,      "RGBA5551"},
            {SDL_PIXELFORMAT_ABGR1555,      "ABGR1555"},
            {SDL_PIXELFORMAT_BGRA5551,      "BGRA5551"},
            {SDL_PIXELFORMAT_RGB565,        "RGB565"},
            {SDL_PIXELFORMAT_BGR565,        "BGR565"},
            {SDL_PIXELFORMAT_RGB24,         "RGB24"},
            {SDL_PIXELFORMAT_BGR24,         "BGR24"},
            {SDL_PIXELFORMAT_RGB888,        "RGB888"},
            {SDL_PIXELFORMAT_RGBX8888,      "RGBX8888"},
            {SDL_PIXELFORMAT_BGR888,        "BGR888"},
            {SDL_PIXELFORMAT_BGRX8888,      "BGRX8888"},
            {SDL_PIXELFORMAT_ARGB8888,      "ARGB8888"},
            {SDL_PIXELFORMAT_RGBA8888,      "RGBA8888"},
            {SDL_PIXELFORMAT_ABGR8888,      "ABGR8888"},
            {SDL_PIXELFORMAT_BGRA8888,      "BGRA8888"},
            {SDL_PIXELFORMAT_ARGB2101010,   "ARGB2101010"},
            {SDL_PIXELFORMAT_YV12,          "YV12"},
            {SDL_PIXELFORMAT_IYUV,          "IYUV"},
            {SDL_PIXELFORMAT_YUY2,          "YUY2"},
            {SDL_PIXELFORMAT_UYVY,          "UYVY"},
            {SDL_PIXELFORMAT_YVYU,          "YVYU"},
            {SDL_PIXELFORMAT_UNKNOWN,       "Unknown"}};

        fprintf (st, "     Render #%d - %s\n", i, info.name);
        fprintf (st, "        Flags: 0x%X - ", info.flags);
        if (info.flags & SDL_RENDERER_SOFTWARE)
            fprintf (st, "Software|");
        if (info.flags & SDL_RENDERER_ACCELERATED)
            fprintf (st, "Accelerated|");
        if (info.flags & SDL_RENDERER_PRESENTVSYNC)
            fprintf (st, "PresentVSync|");
        if (info.flags & SDL_RENDERER_TARGETTEXTURE)
            fprintf (st, "TargetTexture|");
        fprintf (st, "\n");
        if ((info.max_texture_height != 0) || (info.max_texture_width != 0))
            fprintf (st, "        Max Texture: %d by %d\n", info.max_texture_height, info.max_texture_width);
        fprintf (st, "        Pixel Formats:\n");
        for (j=0; j<info.num_texture_formats; j++) {
            for (k=0; 1; k++) {
                if (PixelFormats[k].format == info.texture_formats[j]) {
                    fprintf (st, "            %s\n", PixelFormats[k].name);
                    break;
                    }
                if (PixelFormats[k].format == SDL_PIXELFORMAT_UNKNOWN) {
                    fprintf (st, "            %s - 0x%X\n", PixelFormats[k].name, info.texture_formats[j]);
                    break;
                    }
                }
            }
        }
    }
if (vid_active) {
    SDL_RendererInfo info;

    SDL_GetRendererInfo (vid_renderer, &info);
    fprintf (st, "  Currently Active Renderer: %s\n", info.name);
    }
if (1) {
    static const char *hints[] = {
#if defined (SDL_HINT_FRAMEBUFFER_ACCELERATION)
                SDL_HINT_FRAMEBUFFER_ACCELERATION   ,
#endif
#if defined (SDL_HINT_RENDER_DRIVER)
                SDL_HINT_RENDER_DRIVER              ,
#endif
#if defined (SDL_HINT_RENDER_OPENGL_SHADERS)
                SDL_HINT_RENDER_OPENGL_SHADERS      ,
#endif
#if defined (SDL_HINT_RENDER_DIRECT3D_THREADSAFE)
                SDL_HINT_RENDER_DIRECT3D_THREADSAFE ,
#endif
#if defined (SDL_HINT_RENDER_DIRECT3D11_DEBUG)
                SDL_HINT_RENDER_DIRECT3D11_DEBUG    ,
#endif
#if defined (SDL_HINT_RENDER_SCALE_QUALITY)
                SDL_HINT_RENDER_SCALE_QUALITY       ,
#endif
#if defined (SDL_HINT_RENDER_VSYNC)
                SDL_HINT_RENDER_VSYNC               ,
#endif
#if defined (SDL_HINT_VIDEO_ALLOW_SCREENSAVER)
                SDL_HINT_VIDEO_ALLOW_SCREENSAVER    ,
#endif
#if defined (SDL_HINT_VIDEO_X11_XVIDMODE)
                SDL_HINT_VIDEO_X11_XVIDMODE         ,
#endif
#if defined (SDL_HINT_VIDEO_X11_XINERAMA)
                SDL_HINT_VIDEO_X11_XINERAMA         ,
#endif
#if defined (SDL_HINT_VIDEO_X11_XRANDR)
                SDL_HINT_VIDEO_X11_XRANDR           ,
#endif
#if defined (SDL_HINT_GRAB_KEYBOARD)
                SDL_HINT_GRAB_KEYBOARD              ,
#endif
#if defined (SDL_HINT_MOUSE_RELATIVE_MODE_WARP)
                SDL_HINT_MOUSE_RELATIVE_MODE_WARP    ,
#endif
#if defined (SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS)
                SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS   ,
#endif
#if defined (SDL_HINT_IDLE_TIMER_DISABLED)
                SDL_HINT_IDLE_TIMER_DISABLED ,
#endif
#if defined (SDL_HINT_ORIENTATIONS)
                SDL_HINT_ORIENTATIONS ,
#endif
#if defined (SDL_HINT_ACCELEROMETER_AS_JOYSTICK)
                SDL_HINT_ACCELEROMETER_AS_JOYSTICK ,
#endif
#if defined (SDL_HINT_XINPUT_ENABLED)
                SDL_HINT_XINPUT_ENABLED ,
#endif
#if defined (SDL_HINT_GAMECONTROLLERCONFIG)
                SDL_HINT_GAMECONTROLLERCONFIG ,
#endif
#if defined (SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS)
                SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS ,
#endif
#if defined (SDL_HINT_ALLOW_TOPMOST)
                SDL_HINT_ALLOW_TOPMOST ,
#endif
#if defined (SDL_HINT_TIMER_RESOLUTION)
                SDL_HINT_TIMER_RESOLUTION ,
#endif
#if defined (SDL_HINT_VIDEO_HIGHDPI_DISABLED)
                SDL_HINT_VIDEO_HIGHDPI_DISABLED ,
#endif
#if defined (SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK)
                SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK ,
#endif
#if defined (SDL_HINT_VIDEO_WIN_D3DCOMPILER)
                SDL_HINT_VIDEO_WIN_D3DCOMPILER              ,
#endif
#if defined (SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT)
                SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT    ,
#endif
#if defined (SDL_HINT_WINRT_PRIVACY_POLICY_URL)
                SDL_HINT_WINRT_PRIVACY_POLICY_URL ,
#endif
#if defined (SDL_HINT_WINRT_PRIVACY_POLICY_LABEL)
                SDL_HINT_WINRT_PRIVACY_POLICY_LABEL ,
#endif
#if defined (SDL_HINT_WINRT_HANDLE_BACK_BUTTON)
                SDL_HINT_WINRT_HANDLE_BACK_BUTTON ,
#endif
#if defined (SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES)
                SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES,
#endif
                NULL};
    fprintf (st, "  Currently Active SDL Hints:\n");
    for (i=0; hints[i]; i++) {
        if (SDL_GetHint (hints[i]))
            fprintf (st, "      %s = %s\n", hints[i], SDL_GetHint (hints[i]));
        }
    }
#endif /* SDL_MAJOR_VERSION != 1 */
#if !defined (SDL_MAIN_AVAILABLE)
if (!vid_active)
    SDL_Quit();
#endif
return SCPE_OK;
}

static t_stat _show_stat;
static FILE *_show_st;
static UNIT *_show_uptr;
static int32 _show_val;
static CONST void *_show_desc;

void vid_show_video_event (void)
{
_show_stat = _vid_show_video (_show_st, _show_uptr, _show_val, _show_desc);
}

t_stat vid_show_video (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
SDL_Event user_event;

_show_stat = -1;
_show_st = st;
_show_uptr = uptr;
_show_val = val;
_show_desc = desc;

user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_SHOW;
user_event.user.data1 = NULL;
user_event.user.data2 = NULL;
#if defined (SDL_MAIN_AVAILABLE)
while (SDL_PushEvent (&user_event) < 0)
    sim_os_ms_sleep (10);
#else
vid_show_video_event ();
#endif
while (_show_stat == -1)
    SDL_Delay (20);
return _show_stat;
}

static t_stat _vid_screenshot (const char *filename)
{
int stat;
char *fullname = NULL;

if (!vid_active) {
    sim_printf ("No video display is active\n");
    return SCPE_UDIS | SCPE_NOMESSAGE;
    }
fullname = (char *)malloc (strlen(filename) + 5);
if (!filename)
    return SCPE_MEM;
#if SDL_MAJOR_VERSION == 1
#if defined(HAVE_LIBPNG)
if (!match_ext (filename, "bmp")) {
    sprintf (fullname, "%s%s", filename, match_ext (filename, "png") ? "" : ".png");
    stat = SDL_SavePNG(vid_image, fullname);
    }
else {
    sprintf (fullname, "%s", filename);
    stat = SDL_SaveBMP(vid_image, fullname);
    }
#else
sprintf (fullname, "%s%s", filename, match_ext (filename, "bmp") ? "" : ".bmp");
stat = SDL_SaveBMP(vid_image, fullname);
#endif /* defined(HAVE_LIBPNG) */
#else /* SDL_MAJOR_VERSION != 1 */
if (1) {
    SDL_Surface *sshot = sim_end ? SDL_CreateRGBSurface(0, vid_width, vid_height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000) :
                                   SDL_CreateRGBSurface(0, vid_width, vid_height, 32, 0x0000ff00, 0x000ff000, 0xff000000, 0x000000ff) ;
    SDL_RenderReadPixels(vid_renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch);
#if defined(HAVE_LIBPNG)
    if (!match_ext (filename, "bmp")) {
        sprintf (fullname, "%s%s", filename, match_ext (filename, "png") ? "" : ".png");
        stat = SDL_SavePNG(sshot, fullname);
        }
    else {
        sprintf (fullname, "%s", filename);
        stat = SDL_SaveBMP(sshot, fullname);
        }
#else
    sprintf (fullname, "%s%s", filename, match_ext (filename, "bmp") ? "" : ".bmp");
    stat = SDL_SaveBMP(sshot, fullname);
#endif /* defined(HAVE_LIBPNG) */
    SDL_FreeSurface(sshot);
    }
#endif
if (stat) {
    sim_printf ("Error saving screenshot to %s: %s\n", fullname, SDL_GetError());
    free (fullname);
    return SCPE_IOERR | SCPE_NOMESSAGE;
    }
else {
    if (!sim_quiet)
        sim_printf ("Screenshot saved to %s\n", fullname);
    free (fullname);
    return SCPE_OK;
    }
}

static t_stat _screenshot_stat;
static const char *_screenshot_filename;

void vid_screenshot_event (void)
{
_screenshot_stat = _vid_screenshot (_screenshot_filename);
}

t_stat vid_screenshot (const char *filename)
{
SDL_Event user_event;

_screenshot_stat = -1;
_screenshot_filename = filename;

user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_SCREENSHOT;
user_event.user.data1 = NULL;
user_event.user.data2 = NULL;
#if defined (SDL_MAIN_AVAILABLE)
while (SDL_PushEvent (&user_event) < 0)
    sim_os_ms_sleep (10);
#else
vid_screenshot_event ();
#endif
while (_screenshot_stat == -1)
    SDL_Delay (20);
return _screenshot_stat;
}

#include <SDL_audio.h>
#include <math.h>

const int AMPLITUDE = 20000;
const int SAMPLE_FREQUENCY = 11025;
static int16 *vid_beep_data;
static int vid_beep_offset;
static int vid_beep_duration;
static int vid_beep_samples;

static void vid_audio_callback(void *ctx, Uint8 *stream, int length)
{
int16 *data = (int16 *)stream;
int i, sum, remnant = ((vid_beep_samples - vid_beep_offset) * sizeof (*vid_beep_data));

if (length > remnant) {
    memset (stream + remnant, 0, length - remnant);
    length = remnant;
    if (remnant == 0) {
        SDL_PauseAudio(1);
        return;
        }
    }
memcpy (stream, &vid_beep_data[vid_beep_offset], length);
for (i=sum=0; i<length; i++)
    sum += stream[i];
vid_beep_offset += length / sizeof(*vid_beep_data);
}

static void vid_beep_setup (int duration_ms, int tone_frequency)
{
if (!vid_beep_data) {
    int i;
    SDL_AudioSpec desiredSpec;

    memset (&desiredSpec, 0, sizeof(desiredSpec));
    desiredSpec.freq = SAMPLE_FREQUENCY;
    desiredSpec.format = AUDIO_S16SYS;
    desiredSpec.channels = 1;
    desiredSpec.samples = 2048;
    desiredSpec.callback = vid_audio_callback;

    SDL_OpenAudio(&desiredSpec, NULL);

    vid_beep_samples = (int)((SAMPLE_FREQUENCY * duration_ms) / 1000.0);
    vid_beep_duration = duration_ms;
    vid_beep_data = (int16 *)malloc (sizeof(*vid_beep_data) * vid_beep_samples);
    for (i=0; i<vid_beep_samples; i++)
        vid_beep_data[i] = (int16)(AMPLITUDE * sin(((double)(i * M_PI * tone_frequency)) / SAMPLE_FREQUENCY));
    }
}

static void vid_beep_cleanup (void)
{
SDL_CloseAudio();
free (vid_beep_data);
vid_beep_data = NULL;
}

void vid_beep_event (void)
{
vid_beep_offset = 0;                /* reset to beginning of sample set */
SDL_PauseAudio (0);                 /* Play sound */
}

void vid_beep (void)
{
SDL_Event user_event;

user_event.type = SDL_USEREVENT;
user_event.user.code = EVENT_BEEP;
user_event.user.data1 = NULL;
user_event.user.data2 = NULL;
#if defined (SDL_MAIN_AVAILABLE)
while (SDL_PushEvent (&user_event) < 0)
    sim_os_ms_sleep (10);
#else
vid_beep_event ();
#endif
SDL_Delay (vid_beep_duration + 100);/* Wait for sound to finnish */
}

#else /* !(defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)) */
/* Non-implemented versions */

uint32 vid_mono_palette[2];                             /* Monochrome Color Map */

t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags)
{
return SCPE_NOFNC;
}

t_stat vid_close (void)
{
return SCPE_OK;
}

t_stat vid_poll_kb (SIM_KEY_EVENT *ev)
{
return SCPE_EOF;
}

t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev)
{
return SCPE_EOF;
}

void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf)
{
return;
}

t_stat vid_set_cursor (t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y)
{
return SCPE_NOFNC;
}

void vid_set_cursor_position (int32 x, int32 y)
{
return;
}

void vid_refresh (void)
{
return;
}

void vid_beep (void)
{
return;
}

const char *vid_version (void)
{
return "No Video Support";
}

t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
return SCPE_NOFNC;
}

t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
fprintf (st, "no release key");
return SCPE_OK;
}

t_stat vid_show_video (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
fprintf (st, "video support unavailable");
return SCPE_OK;
}

t_stat vid_screenshot (const char *filename)
{
sim_printf ("video support unavailable\n");
return SCPE_NOFNC|SCPE_NOMESSAGE;
}
#endif /* defined(USE_SIM_VIDEO) */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/sim_video.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/* sim_video.c: Bitmap video output

   Copyright (c) 2011-2013, Matt Burke

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the name of the author shall not be
   used in advertising or otherwise to promote the sale, use or other dealings
   in this Software without prior written authorization from the author.

   08-Nov-2013  MB      Added globals for current mouse status
   11-Jun-2013  MB      First version
*/

#ifndef SIM_VIDEO_H_
#define SIM_VIDEO_H_     0

#include "sim_defs.h"

#ifdef  __cplusplus
extern "C" {
#endif

#define SIM_KEYPRESS_DOWN      0                        /* key states */
#define SIM_KEYPRESS_UP        1
#define SIM_KEYPRESS_REPEAT    2


#define SIM_KEY_F1             0                        /* key syms */
#define SIM_KEY_F2             1
#define SIM_KEY_F3             2
#define SIM_KEY_F4             3
#define SIM_KEY_F5             4
#define SIM_KEY_F6             5
#define SIM_KEY_F7             6
#define SIM_KEY_F8             7
#define SIM_KEY_F9             8
#define SIM_KEY_F10            9
#define SIM_KEY_F11            10
#define SIM_KEY_F12            11

#define SIM_KEY_0              12
#define SIM_KEY_1              13
#define SIM_KEY_2              14
#define SIM_KEY_3              15
#define SIM_KEY_4              16
#define SIM_KEY_5              17
#define SIM_KEY_6              18
#define SIM_KEY_7              19
#define SIM_KEY_8              20
#define SIM_KEY_9              21

#define SIM_KEY_A              22
#define SIM_KEY_B              23
#define SIM_KEY_C              24
#define SIM_KEY_D              25
#define SIM_KEY_E              26
#define SIM_KEY_F              27
#define SIM_KEY_G              28
#define SIM_KEY_H              29
#define SIM_KEY_I              30
#define SIM_KEY_J              31
#define SIM_KEY_K              32
#define SIM_KEY_L              33
#define SIM_KEY_M              34
#define SIM_KEY_N              35
#define SIM_KEY_O              36
#define SIM_KEY_P              37
#define SIM_KEY_Q              38
#define SIM_KEY_R              39
#define SIM_KEY_S              40
#define SIM_KEY_T              41
#define SIM_KEY_U              42
#define SIM_KEY_V              43
#define SIM_KEY_W              44
#define SIM_KEY_X              45
#define SIM_KEY_Y              46
#define SIM_KEY_Z              47

#define SIM_KEY_BACKQUOTE      48
#define SIM_KEY_MINUS          49
#define SIM_KEY_EQUALS         50
#define SIM_KEY_LEFT_BRACKET   51
#define SIM_KEY_RIGHT_BRACKET  52
#define SIM_KEY_SEMICOLON      53
#define SIM_KEY_SINGLE_QUOTE   54
#define SIM_KEY_BACKSLASH      55
#define SIM_KEY_LEFT_BACKSLASH 56
#define SIM_KEY_COMMA          57
#define SIM_KEY_PERIOD         58
#define SIM_KEY_SLASH          59

#define SIM_KEY_PRINT          60
#define SIM_KEY_SCRL_LOCK      61
#define SIM_KEY_PAUSE          62

#define SIM_KEY_ESC            63
#define SIM_KEY_BACKSPACE      64
#define SIM_KEY_TAB            65
#define SIM_KEY_ENTER          66
#define SIM_KEY_SPACE          67
#define SIM_KEY_INSERT         68
#define SIM_KEY_DELETE         69
#define SIM_KEY_HOME           70
#define SIM_KEY_END            71
#define SIM_KEY_PAGE_UP        72
#define SIM_KEY_PAGE_DOWN      73
#define SIM_KEY_UP             74
#define SIM_KEY_DOWN           75
#define SIM_KEY_LEFT           76
#define SIM_KEY_RIGHT          77

#define SIM_KEY_CAPS_LOCK      78
#define SIM_KEY_NUM_LOCK       79

#define SIM_KEY_ALT_L          80
#define SIM_KEY_ALT_R          81
#define SIM_KEY_CTRL_L         82
#define SIM_KEY_CTRL_R         83
#define SIM_KEY_SHIFT_L        84
#define SIM_KEY_SHIFT_R        85
#define SIM_KEY_WIN_L          86
#define SIM_KEY_WIN_R          87
#define SIM_KEY_MENU           88

#define SIM_KEY_KP_ADD         89
#define SIM_KEY_KP_SUBTRACT    90
#define SIM_KEY_KP_END         91
#define SIM_KEY_KP_DOWN        92
#define SIM_KEY_KP_PAGE_DOWN   93
#define SIM_KEY_KP_LEFT        94
#define SIM_KEY_KP_RIGHT       95
#define SIM_KEY_KP_HOME        96
#define SIM_KEY_KP_UP          97
#define SIM_KEY_KP_PAGE_UP     98
#define SIM_KEY_KP_INSERT      99
#define SIM_KEY_KP_DELETE      100
#define SIM_KEY_KP_5           101
#define SIM_KEY_KP_ENTER       102
#define SIM_KEY_KP_MULTIPLY    103
#define SIM_KEY_KP_DIVIDE      104

#define SIM_KEY_UNKNOWN        200

struct mouse_event {
    int32 x_rel;                                          /* X axis relative motion */
    int32 y_rel;                                          /* Y axis relative motion */
    int32 x_pos;                                          /* X axis position */
    int32 y_pos;                                          /* Y axis position */
    t_bool b1_state;                                      /* state of button 1 */
    t_bool b2_state;                                      /* state of button 2 */
    t_bool b3_state;                                      /* state of button 3 */
    };

struct key_event {
    uint32 key;                                           /* key sym */
    uint32 state;                                         /* key state change */
    };

typedef struct mouse_event SIM_MOUSE_EVENT;
typedef struct key_event SIM_KEY_EVENT;

t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags);
#define SIM_VID_INPUTCAPTURED       1                       /* Mouse and Keyboard input captured (calling */
                                                            /* code responsible for cursor display in video) */
typedef void (*VID_QUIT_CALLBACK)(void);
t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback);
t_stat vid_close (void);
t_stat vid_poll_kb (SIM_KEY_EVENT *ev);
t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev);
void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf);
void vid_beep (void);
void vid_refresh (void);
const char *vid_version (void);
const char *vid_key_name (int32 key);
t_stat vid_set_cursor (t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask, uint32 hot_x, uint32 hot_y);
t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
t_stat vid_show_video (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
t_stat vid_show (FILE* st, DEVICE *dptr,  UNIT* uptr, int32 val, CONST char* desc);
t_stat vid_screenshot (const char *filename);

extern t_bool vid_active;
extern uint32 vid_mono_palette[2];
extern int32 vid_mouse_xrel;                            /* mouse cumulative x rel */
extern int32 vid_mouse_yrel;                            /* mouse cumulative y rel */
extern t_bool vid_mouse_b1;                             /* mouse button 1 state */
extern t_bool vid_mouse_b2;                             /* mouse button 2 state */
extern t_bool vid_mouse_b3;                             /* mouse button 3 state */
void vid_set_cursor_position (int32 x, int32 y);        /* cursor position (set by calling code) */

#define SIM_VID_DBG_MOUSE   0x01000000
#define SIM_VID_DBG_CURSOR  0x02000000
#define SIM_VID_DBG_KEY     0x04000000
#define SIM_VID_DBG_VIDEO   0x08000000

#ifdef  __cplusplus
}
#endif

#if defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)
#include <SDL.h>
#endif /* HAVE_LIBSDL */

#endif
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































































































































































































Deleted src/test.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/* test.c - Front panel LED and switch testing program, built as pidp8i-test

   Copyright © 2016-2017 Paul R. Bernard and Warren Young

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.

   Except as contained in this notice, the names of the authors above shall
   not be used in advertising or otherwise to promote the sale, use or other
   dealings in this Software without prior written authorization from those
   authors.
*/

#include "gpio-common.h"

#include <assert.h>
#include <ctype.h>
#include <curses.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

typedef unsigned int uint32;
typedef unsigned char uint8;

static uint16_t lastswitchstatus[3];    // to watch for switch changes

uint8 path[] = {
    0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x11, 0x12, 0x13, 0x14, 0x15,
    0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x2c, 0x2b, 0x2a, 0x29,
    0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x31, 0x32, 0x33,
    0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x4c, 0x4b,
    0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x87,
    0x76, 0x77, 0x78, 0x79, 0x7a, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
    0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x68, 0x67, 0x66, 0x65, 0x64,
    0x63, 0x62, 0x61, 0x69, 0x6a, 0x6b, 0x6c, 0x71, 0x72, 0x75, 0x74,
    0x73
};

static int auto_advance = 1;

#define KEY_CHECK \
        switch (getch()) { \
            case KEY_DOWN: \
            case KEY_LEFT:  auto_advance = 0; return step - 1; \
            case KEY_UP: \
            case KEY_RIGHT: auto_advance = 0; return step + 1; \
            case 'r': \
            case 'R':       auto_advance = 1; return step + 1; \
            case 'x': \
            case 'X': \
            case 3:         exit (1); \
        }
#define DISPLAY_HOLD_ITERATIONS 20
#define DISPLAY_HOLD \
        sleep_us (250 * 1000); \
        if (auto_advance) { putchar('.'); } else { dhi = 0; } \
        KEY_CHECK


typedef int (*action_handler)(int, int);
struct action {
    action_handler ph;
    int step;
    int arg;
};


static void banner (const char* b, ...)
{
    va_list ap;
    va_start (ap, b);

    if (!auto_advance) {
        clear();
        refresh();
        printf ("Manual mode: Press x or Ctrl-C to exit, "
                "arrows to step, r to resume.");
    }

    printf ("\r\n");
    vprintf (b, ap);
    va_end (ap);
}


int all_leds_on (int step, int ignored)
{
    puts ("\r");
    banner ("Turn on ALL LEDs");

    for (int row = 0; row < NLEDROWS; ++row) ledstatus[row] = 07777;

    for (int dhi = 0; dhi < DISPLAY_HOLD_ITERATIONS; ++dhi) {
        DISPLAY_HOLD;
    }

    return step + 1;
}


int all_leds_off (int step, int ignored)
{
    puts ("\r");
    banner ("Turn off ALL LEDs");

    memset (ledstatus, 0, sizeof(ledstatus));
    for (int dhi = 0; dhi < DISPLAY_HOLD_ITERATIONS; ++dhi) {
        DISPLAY_HOLD;
    }

    return step + 1;
}


int led_row_on (int step, int row)
{
    if (row == 0) puts ("\r");
    memset (ledstatus, 0, sizeof(ledstatus));

    banner ("Turning on LED row %d", row + 1);

    for (int dhi = 0; dhi < DISPLAY_HOLD_ITERATIONS / 4; ++dhi) {
        ledstatus[row] = 07777;
        DISPLAY_HOLD;
    }
    ledstatus[row] = 0;
    
    return step + 1;
}


int led_col_on (int step, int col)
{
    if (col == 0) puts ("\r");
    memset (ledstatus, 0, sizeof(ledstatus));

    banner ("Turning on LED col %d", col + 1);

    for (int dhi = 0; dhi < DISPLAY_HOLD_ITERATIONS / 4; ++dhi) {
        for (int row = 0; row < NLEDROWS; ++row)
            ledstatus[row] |= 1 << col;
        DISPLAY_HOLD;
    }
    ledstatus[col] = 0;
    
    return step + 1;
}


int switch_scan (int step, int ignored)
{
    int path_idx = 0, led_row = 0, delay = 0;

    puts ("\r");
    banner ("Reading the switches.  Toggle any pattern desired.  "
            "Ctrl-C to quit.\r\n");

    memset (ledstatus, 0, sizeof(ledstatus));
    for (int i = 0; i < NROWS; ++i)
        lastswitchstatus[i] = switchstatus[i];

    for (;;) {
        if (delay++ >= 30) {
            delay = 0;

            ledstatus[led_row] = 0;
            ledstatus[led_row = (path[path_idx] >> 4) - 1] = 04000 >> ((path[path_idx] & 0x0F) - 1);
            sleep_us (1);
            KEY_CHECK;

            if (++path_idx >= sizeof (path) / sizeof (path[0]))
                path_idx = 0;
        }

        if (lastswitchstatus[0] != switchstatus[0] ||
            lastswitchstatus[1] != switchstatus[1] || lastswitchstatus[2] != switchstatus[2]) {
            for (int i = 0; i < NROWS; ++i) {
                printf ("%04o ", ~switchstatus[i] & 07777);
                lastswitchstatus[i] = switchstatus[i];
            }
            printf ("\r\n");
        }
        usleep (1000);
    }

    return step + 1;
}


void start_gpio (void)
{
    assert (sizeof (lastswitchstatus == switchstatus));

    // Tell the GPIO thread we're updating the display via direct
    // ledstatus[] manipulation instead of set_pidp8i_leds calls.
    pidp8i_simple_gpio_mode = 1;

    // Create GPIO thread
    if (start_pidp8i_gpio_thread ("test program") != 0) {
        exit (EXIT_FAILURE);
    }
}


// Tell ncurses we want character-at-a-time input without echo,
// non-blocking reads, and no input interpretation.
void init_ncurses (void)
{
    initscr ();
    nodelay (stdscr, TRUE);
    keypad  (stdscr, TRUE);
    noecho ();
    cbreak ();
    clear ();
    refresh ();
}


void run_actions (void)
{
    // Define action sequence
    struct action actions[] = {
        { all_leds_on,  0,  0 },
        { all_leds_off, 1,  0 },

        { led_row_on,   2,  0 },
        { led_row_on,   3,  1 },
        { led_row_on,   4,  2 },
        { led_row_on,   5,  3 },
        { led_row_on,   6,  4 },
        { led_row_on,   7,  5 },
        { led_row_on,   8,  6 },
        { led_row_on,   9,  7 },

        { led_col_on,  10,  0 },
        { led_col_on,  11,  1 },
        { led_col_on,  12,  2 },
        { led_col_on,  13,  3 },
        { led_col_on,  14,  4 },
        { led_col_on,  15,  5 },
        { led_col_on,  16,  6 },
        { led_col_on,  17,  7 },
        { led_col_on,  18,  8 },
        { led_col_on,  19,  9 },
        { led_col_on,  20, 10 },
        { led_col_on,  21, 11 },

        { switch_scan, 22, 0 },
    };
    const size_t num_actions = sizeof(actions) / sizeof(actions[0]);

    // Run actions
    int i = 0;
    while (i < num_actions) {
        i = (actions[i].ph)(i, actions[i].arg);
        if (i == num_actions) i = 0;
        if (i == -1)          i = num_actions - 1;
    }
}


static void emergency_shut_down (int signum)
{
    // Shut ncurses down before we call printf, so it's down at the
    // bottom.  This duplicates part of the graceful shutdown path,
    // which is why it checks whether it's necessary.
    endwin ();

    printf ("\r\nExiting pidp8i-test, signal %d: %s\n\n", signum,
            strsignal (signum));

    exit (2);       // continues in graceful_shut_down
}


static void graceful_shut_down ()
{
    if (!isendwin()) endwin ();
    turn_off_pidp8i_leds ();
}


static void register_shut_down_handlers ()
{
    struct sigaction sa;
    memset (&sa, 0, sizeof (sa));
    sa.sa_handler = emergency_shut_down;
    sigaction (SIGINT, &sa, 0);
    atexit (graceful_shut_down);
}


int main (int argc, char *argv[])
{
    start_gpio ();

    if ((argc < 2) || (strcmp (argv[1], "-v") != 0)) {
        register_shut_down_handlers ();
        init_ncurses ();
        run_actions ();
    }

    return 0;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































Deleted tools/bosi.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#!/bin/bash
# bosi - The Binary OS Image creation/update script
#
# Copyright © 2016-2017 by Warren Young
# 
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
# THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
# Except as contained in this notice, the names of the authors above shall
# not be used in advertising or otherwise to promote the sale, use or
# other dealings in this Software without prior written authorization from
# those authors.


# Display the usage message
function usage() {
    cat <<USAGE
usage: $0 <verb> [tag]

    The available verbs are init, build, prepare, shrink, image, and finish.

    You may include a tag parameter with the 'image' and 'finish' verbs
    to override the default tag ('ils') used in image and zip file
    outputs.

    See RELEASE-PROCESS.md for more info.

USAGE
    exit 1
}

verb="$1"
tag="$2"
test -n "$verb" || usage
test -z "$tag" && tag=ils

nu=pidp8i
nh=/home/$nu
repo=pidp8i
dldir="$HOME/tangentsoft.com/dl"
os=jessie-lite
img=$dldir/pidp8i-$(date +%Y.%m.%d)-$tag-$os.img
greadlink=$(type -p greadlink || type -p readlink)
this=$($greadlink -f $0)
topdir="$($greadlink -f "$(dirname "$this")"/..)"


# Initial steps
function do_init() {
    if [ "$USER" != "root" ]
    then
        echo "The init step has to be run as root.  The explanation is"
        echo "given in the section for 'init' in RELEASE-PROCESS.md."
        echo
        exit 1
    fi

    set -x

    apt-get update && apt-get -y upgrade || true

    test -f /usr/include/curses.h || apt-get -y install libncurses-dev
	test -h /media/usb || apt-get -y install usbmount

    if [ -z "$(type -p fossil)" ]
    then
        bn=fossil-release
        tb=$bn.tar.gz
        wget -O $tb https://fossil-scm.org/index.html/tarball/$bn?uuid=release
        apt-get -y install libssl-dev
        ( tar xf $tb && cd $bn && ./configure && make -j3 && make install )
        chown -R pi.pi $bn
        rm $tb
    fi

    if [ ! -e "$nh" ]
    then
        # First pass on a clean SD card: rename 'pi' user and group to
        # 'pidp8i' and rename its home directory to match.
        usermod  -l $nu -d $nh -m pi 
        groupmod -n $nu pi
    fi

    sed -i.orig \
            -e 's/^FS_MOUNTO.*/FS_MOUNTOPTIONS="-fstype=vfat,dmask=0000,fmask=0000"/' \
            /etc/usbmount/usbmount.conf

    reboot
}


# Clone repo and build the software under [new] pidp8i account
function do_build() {
    if [ "$USER" != "$nu" ]
    then
        echo "The build step has to be run as $nu."
        echo
        exit 1
    fi

    set -x

    if [ ! -d museum ]
    then
        mkdir -p museum $repo
        fossil clone https://tangentsoft.com/$repo museum/$repo.fossil
    fi

    cd $repo

    if [ -r ChangeLog.md ]
    then
        fossil revert           # just in case
        fossil update release
    else
        fossil open ~/museum/$repo.fossil release
        ./configure
    fi

    tools/mmake
    sudo make install || true       # don't care about return code
    sudo reboot
}


# This script prepares the OS's configuration to a clean first boot state.
function do_prepare() {
    if [ "$USER" != "$nu" ]
    then
        echo "The prepare step has to be run as $nu."
        echo
        exit 1
    fi

    set -x

    history -c ; rm -f ~/.bash_history

    sudo systemctl stop pidp8i || true          # avoid sim hogging CPU
    sudo systemctl enable sshd || true          # disabled by default
    sudo shred -u /etc/ssh/*key* || true        # allow multiple passes
    sudo dphys-swapfile uninstall || true
    sudo dd if=/dev/zero of=/junk bs=1M || true # it *will* error-out!
    sudo rm -f /junk

    encpass=$(openssl passwd -1 edsonDeCastro1968)
    sudo usermod -p $encpass pidp8i
    sudo passwd -e pidp8i

    sudo poweroff
}


# Shrink the filesystem on the OS SD card we're about to image to just a
# bit bigger than required to hold its present contents.
#
# The extra 100 megs in the arithmetic below accounts for the /boot
# partition, since the `resizepart` command takes a partition end value,
# not a size value.
#
# We don't calculate the actual end of the /boot partition and use that
# value because we want a bit of slack space to buy time for an end user
# who neglects to expand the card image into the free space available on
# their SD card after first boot.
function do_shrink() {
    test "$USER" = "root" || exec sudo $this shrink

    set -x

    umount /dev/sda2 || true    # might auto-mount, might not
    e2fsck -f /dev/sda2         # resize2fs demands it

    # Pack it down tight
    blocks=$(
        resize2fs -M /dev/sda2 2>&1 |
        grep 'blocks long' | 
        grep -wo '[0-9]\+'
    )
    if [ "$blocks" -gt 0 ]
    then
        # And now give it a bit of breathing room
        parted /dev/sda resizepart 2 $(($blocks * 4096 + 10**8))b
        resize2fs /dev/sda2
        poweroff
    else
        echo "Failed to extract new filesystem size from resize2fs!"
        echo
        exit 1
    fi
}


# This script images the OS SD card in a USB reader on a Mac OS X box.
function do_image() {
    while read line
    do
        case $line in
            /dev/*)
                dev=$(echo $line | cut -f1 -d' ')
                ;;

            0:*)
                case $line in
                    *FDisk_partition_scheme*) ;;
                    *) dev= ;;      # can't be the OS SD card
                esac
                ;;

            1:*)
                case $line in
                    *Windows_FAT_32\ boot*) ;;
                    *) dev= ;;      # can't be the OS SD card
                esac
                ;;

            2:*)
                case $line in
                    *Linux\ Untitled*) break ;; # found it!
                    *) dev= ;;      # can't be the OS SD card
                esac
                ;;
        esac
    done < <(diskutil list)

    if [ -z "$dev" ]
    then
        echo "Failed to find OS SD card!"
        echo
        exit 1
    fi

    echo
    echo "-------------------------------------------------------"
    diskutil info "$dev"
    echo "-------------------------------------------------------"
    echo
    read -p "Is that the OS SD card? [y/N]: " answer
    case $answer in
        [Yy]*) ;;
        *) exit 1
    esac

    rdev=${dev/disk/rdisk}              # speeds zeroing and re-imaging

    mf=/tmp/MANIFEST.txt
    readme=/tmp/README.md
    cp "$topdir/doc/OS-images.md" $readme

    set -x

    diskutil unmountDisk $dev           # it auto-mounted
    sudo time dd if=$rdev bs=1m of=$img
    sum=($(shasum -a 256 "$img"))
    bytes=($(wc -c $img))

    cat > $mf <<MF
SHA-256 hash and size of ${sum[1]}:

Hash:  ${sum[0]}
Size:  ${bytes[0]}
MF

    imgdir="$(dirname "$img")"
    sed -i '' -e "s_$imgdir/__" "$mf"   # nix local paths in manifest
    unix2dos $mf                        # might be opened on Windows
    time zip -9j $img.zip $img $mf $readme
    rm -f $mf $readme

    # Now re-image the card, starting with a zeroed card to ensure a
    # clean test.  Ignore the end-of-device error from the zero step.
    sudo time dd if=/dev/zero of=$rdev bs=1m || true
    sudo time dd if=$img of=$rdev bs=1m
    diskutil unmountDisk $dev || true   # Paragon ExtFS might be installed
}


# Clean up after the above
function do_finish() {
    set -x

    rmtrash $img
    cd $dldir/..
    make synch
}


# Main routine
set -e
case "$verb" in
    in*) do_init ;;
    bu*) do_build ;;
    pr*) do_prepare ;;
    sh*) do_shrink ;;
    im*) do_image ;;
    fi*) do_finish ;;
    *)   usage ;;
esac
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































































































































































































































































































































































































Deleted tools/corecount.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash
########################################################################
# corecount - Prints the number of CPU cores found on this system
#
# Copyright © 2017 by Warren Young
# 
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# 
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
# THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
# Except as contained in this notice, the names of the authors above shall
# not be used in advertising or otherwise to promote the sale, use or
# other dealings in this Software without prior written authorization from
# those authors.
########################################################################

sys="$(uname -s)"
if [ -r /proc/cpuinfo ]
then
	# It's a Linux box
	grep -Ec '^processor\s+:' /proc/cpuinfo
elif [ "$sys" = "Darwin" -o "$sys" = "FreeBSD" -o "$sys" = "OpenBSD" -o "$sys" = "NetBSD" ]
then
	# It's a macOS or BSD box
	/usr/sbin/sysctl -n hw.ncpu
else
	# No known way to find out, so report only 1 core
	echo 1
fi
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































Deleted tools/mkbootscript.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env perl
########################################################################
# mkbootscript - Generate boot/*.script from obj/*.lst.  See the usage
#     message below for more details.
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

use strict;
use warnings;

use File::Basename;

# Parse command line
my $outPath = '../boot';
if (@ARGV == 0 || ! -r $ARGV[0]) {
	print <<USAGE;
usage: $0 <somefile.lst>

Given a palbart listing file, transform its contents into a SIMH boot
script named after the listing file.  Comments in the listing file are
variously translated to either comments or echo statements in the boot
script.

Output is stored in $outPath/somefile.script relative to the listing
file, as makes sense when translating obj/*.lst files produced from
examples/*.pal files.

USAGE
	exit 1;
}

# Globals
my $keepComments = 1;	# keep header comments; ignore the rest
my (@comments, @directives);
my $firstAddr;
my %core;
my $inFile = $ARGV[0];
my $bni = basename($inFile);
my $outFile = join('/', ( dirname($inFile), $outPath, $bni ));
$outFile =~ s{\.lst$}{.script};
my $oneLiner = $bni;	# use input file name as one-liner fall-back


# Parse the input file
my $comment;
open my $lst, '<', $inFile or die "Cannot read $inFile: $!\n";
while (<$lst>) {
	chomp;
	my ($line, $addr, $val, $tail) = m{
		^\s+		# ignore leading whitespace
		(\d+\s+)	# first number on the line must be a line number
		(\d+)?		# if followed by another number, it's an address
		\s*			# ignore space between addr and val
		(\d+)?		# ...and the value to store at that address
		(.*)		# everything else on the line
		$
	}x;
	my ($lineIsEmpty) = m{^\s+\d+\s*$};
	next unless $lineIsEmpty || $tail;
	($comment) = $tail =~ m{/\s*(.*)$} if $tail;

	if (defined $line and int($line) == 1 and defined $comment) {
		# Save the comment on the first line as a one-line description
		# of what the program does, emitted to the console by SIMH when
		# running our output script unless we find a "SIMH: echo..."
		# directive later on in that file, which overrides it.
		$oneLiner = $comment;
		$oneLiner =~ s{ - }{: };
		$oneLiner =~ s{([\w-]+).pal}{"$1" example};
	}
	elsif ($keepComments and defined $lineIsEmpty) {
		# The first blank line in the input file will appear in the
		# listing as a file containing only a line number.  Stop saving
		# comments, since everything after this would be comments on
		# individual source lines, which don't get copied into output.
		$keepComments = 0;
	}
	elsif (defined $addr and defined $val) {
		# Save address and value to our core image
		$firstAddr = oct($addr) if not defined $firstAddr;
		$core{oct($addr)} = oct($val);
	}
	elsif ($keepComments and defined $comment and defined $line) {
		# It's a header comment line
		if ($comment =~ m{^SIMH: }) {
			# It's a directive to SIMH, so save it separately
			push @directives, substr($comment, 6);
		}
		else {
			# Nothing special, so just save the text portion
			push @comments, $comment;
		}
	}
}
close $lst;

# Remove leading and trailing blank comment lines 
while (@comments and length($comments[0]) == 0) {
	shift @comments;
}
while (@comments and length($comments[$#comments]) == 0) {
	pop @comments;
}

# Write parsed data into output file
open my $scr, '>', $outFile or die "Cannot write $outFile: $!\n";
for my $c (@comments) {
	print $scr "; $c\n";
}
print $scr ";\n";
my $foundEcho;
for my $d (@directives) {
	print $scr $d, "\n";
	$foundEcho = 1 if $d =~ m{^echo };
}
print $scr "echo Running $oneLiner...\n" unless $foundEcho;
for my $a (sort { $a <=> $b } keys %core) {
	printf $scr "dep %05o %04o\n", $a, $core{$a};
}
printf $scr "go  %05o\n", $firstAddr;
close $scr;
print "Converted $inFile to $outFile\n";
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































































































































Deleted tools/mkrel.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash
########################################################################
# mkrel - Automatically merge trunk changes into the release branch
#   for a new public release of the software.  Also tags the trunk with
#   the date of release, so old releases can be easily checked out.
#
# Copyright © 2016-2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

set -e

tag=v$(date +%Y%m%d)
fossil update &&
	fossil ci --tag $tag -m "Tagged release $tag" &&
	cd ../release &&
	fossil update &&
	fossil merge $tag &&
	! fossil status | grep -q '^CONFLICT' &&
	tools/mmake &&
	fossil diff --command 'colordiff -wu' | less &&
	fossil ci -m "Merged trunk changes for $tag into release branch"
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































Deleted tools/mmake.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/bash
########################################################################
# mmake - Runs make -jN where N is 1.5x the number of CPU cores
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

make -j$(($("$(dirname "$0")"/corecount) * 15 / 10)) "$@"
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































Deleted tools/restyle.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/bin/bash
# 
# restyle - A wrapper around indent(1) to produce the code style
#           documented in the HACKERS.md file.
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

if indent --version 2>&1 | grep -q 'GNU indent'
then
	# It's GNU indent here, so start with K&R, then:
	# 
	# -   nce:  don't cuddle else
	# -   cli4: indent case statement labels 4 spaces
	# -   nlp:  don't align continued statements at the opening parenthesis
	# -   pcs:  put a space before the opening parenthesis of a function call
	# -   di1:  don't line up variable types and names in separate columns
	# -   i4:   use 4-space indents
	# -   l100: allow lines up to 100 columns before forcibly breaking them
	# -   ncs:  don't put a space between a cast and its operand
	# -   ss:   add a space before semicolon with empty loop body
	# -   nbbo: don't break long lines before || and && operators
    indent -kr \
            -nce -cli4 -nlp -pcs -di1 -i4 -l100 \
            -nut -ncs -ss -nbbo "$@"
else
    # BSD `indent` does't understand the `-kr` option, so we need to use
    # the following alternative on BSD and macOS systems:
    indent \
            -nce -cli4 -nlp -pcs -di1 -i4 -l100 \
            -bap -ncdb -nfc1 -npsl -nsc "$@"
fi
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































Deleted tools/simh-update.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#!/bin/bash
########################################################################
# simh-update - Attempt to automatically merge in the latest upstream
#	SIMH 4 changes from the GitHub repository.
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

SRCDIR="@srcdir@"
SRCSUBDIR="$SRCDIR/src"
PRGNAME="$(basename "$0")"
WORKDIR="@builddir@/$PRGNAME-temp"
OUR_SIMH_DIR="$WORKDIR/simh/ours"
CURR_SIMH_DIR="$WORKDIR/simh/curr"
LOGFILE="$WORKDIR/output.log"
PATCHFILE="$WORKDIR/pidp8i.patch"
OLD_SGCID=$(grep ^SGCID "@srcdir@"/Makefile.in | cut -f2 -d=)
SOFFICE=/Applications/LibreOffice.app/Contents/MacOS/soffice

# If LibreOffice isn't here, we can't convert DOC to PDF below.
if [ ! -x "$SOFFICE" ]
then
    cat <<USAGE
Sorry, this must be run on a system where LibreOffice is installed
as $SOFFICE.

TODO: Find this same program in other places.

USAGE
    exit 1
fi

# If we don't have the Git worktree sub-command, we're probably running
# this on Jessie, which ships Git 2.1.4.
if ! git help worktree &> /dev/null
then
    cat <<ERROR
Sorry, this must be run on a system with the "git worktree" feature,
which first shipped in Git 2.5.

ERROR
    exit 1
fi

# Set up working directory
rm -rf "$WORKDIR"
mkdir -p "$WORKDIR"

# From here on, send all output to the log file.
# Code based on http://stackoverflow.com/a/20564208/142454
exec 1<&-
exec 2<&-
exec 1<>"$LOGFILE"
exec 2>&1
function say() {
	echo "$@" >> /dev/tty
}

# Bail on errors so we don't have to test everything.  Ideally, nothing
# from here on will fail.  If it does, the log file will explain it.
# Code based on http://stackoverflow.com/a/185900/142454
function error() {
	lineno="$1"
	message="$2"
	code="${3:-1}"
	if [ -n "$message" ] ; then message=": $message" ; fi
	read -r -d '%' errmsg <<ERROR
Error on or near line $lineno, code ${code}$message!  (See log file for
more info: $LOGFILE)
%
ERROR
	say
	say "$errmsg"
	say
	exit $code
}
trap 'error ${LINENO}' ERR

# Deal with uncommitted changes in $SRCSUBDIR
cd "$SRCSUBDIR/.."		# we need the src/ prefix to do this test properly!
if [ $(fossil status | grep '^EDITED.*src/' | wc -l) -gt 0 ]
then
	if [ "$1" = "-f" ]
	then
		say "Tossing uncommitted changes in $SRCSUBDIR..."
		fossil revert $(fossil status | grep '^EDITED.*src/' | cut -f 2- -d' ')
		shift
	else
		read -r -d '%' errmsg <<ERROR
Cowardly refusing to update SIMH to the current upstream version while
there are uncommitted changes in $SRCSUBDIR.  Say

    make simh-update-f

or pass -f to force those changes to be tossed.
%
ERROR
		say
		say "$errmsg"
		say
		exit 3
	fi
fi
cd "@builddir@"

# Retreive the tip-of-master and $OLD_SGCID versions of SIMH
say Retreiving upstream SIMH versions...
mkdir -p "$OUR_SIMH_DIR"
mkdir -p "$CURR_SIMH_DIR"
git clone https://github.com/simh/simh "$CURR_SIMH_DIR"
pushd "$CURR_SIMH_DIR"
NEW_SGCID=$(git rev-parse HEAD)
say "Pulled ${NEW_SGCID:0:8} as curr; prev is ${OLD_SGCID:0:8}."
git worktree add "$OUR_SIMH_DIR" $OLD_SGCID
popd

# Copy over updated versions of the docs and replace them in the Fossil
# unversioned area.  We simplify the upstream naming scheme in the
# transfer, dropping unnecessary prefixes and suffixes.
pushd "$SRCDIR"
for fs in pdp8_doc simh_faq simh_doc
do
	ft=$(echo $fs | sed -e 's/simh_//' -e 's/_doc//')
	test "$ft" = "doc" && ft=main
	pdfout=doc/simh/$ft.pdf
    pdftmp="$fs.pdf"
    say -n "Converting upstream $fs.doc to $pdfout..."
    if [ ! -e "$pdfout" ] ; then touch $pdfout ; fi  # complaint squisher
    if "$SOFFICE" --convert-to pdf "$CURR_SIMH_DIR/doc/$fs.doc" &&
            [ -s "$pdfout" != -s "$pdftmp" ]
    then
        # The upstream doc has apparently changed, since the PDF output
        # file is a different size.  Replace our public version.
        #
        # We can't use cmp or similar here because a bunch of metadata
        # change each time we re-render the PDF, even if the source doc
        # is unchanged.  There are proper PDF comparison tools, but none
        # preinstalled everywhere, and we don't want to make one of
        # those tools a dependency of this script.  Size comparison
        # suffices for our purposes, since most any substantial text
        # change will change the output file size.
        say "changes detected."
        mv "$pdftmp" "$pdfout"
        fossil uv add "$pdfout"
    else
        say "unchanged."
    fi
done
say "Syncing new PDFs..."
fossil uv sync
popd

# Rename upstream Git paths to match our *.in files so that our produced
# patches are made against those higher-level versions.  If we didn't do
# this, we'd have to manually resubstitute variables for absolute paths.
#
# Filter out Makefile.in because we don't want to try and patch the
# upstream plain Makefile to work with autosetup.  It complicates the
# resulting patch file to no purpose.
say Renaming upstream files to match our \*.in variants...
find "$SRCSUBDIR" -name \*.in -print | grep -v Makefile.in | while read f
do
	inf="${f#$SRCSUBDIR/}"	# make path fully relative
	genf="${inf%.in}"		# remove .in from the end
    if [ -f "$OUR_SIMH_DIR/$genf" ]
    then
        mv  "$OUR_SIMH_DIR/$genf"  "$OUR_SIMH_DIR/$inf"
        mv "$CURR_SIMH_DIR/$genf" "$CURR_SIMH_DIR/$inf"
    fi
    # else, it's a *.in file specific to our code base, not a
    # parameterized version of an upstream file
done

# Produce a patch file for modifying the upstream $OLD_SGCID version to
# merge in our local changes.
#
# For some reason, diff(1) returns an error when we do this, at least on
# OS X.  Perhaps it is not happy about the fact that the file set in
# each tree is different?  Regardless of reason, we must check for a
# non-empty patch file to determine whether an actual error occurred.
say Producing clean patch file from upstream ${OLD_SGCID:0:8} version
say to our local PiDP-8/I version...
if ! diff -ru "$OUR_SIMH_DIR" "$SRCSUBDIR" | grep -v '^Only in' > "$PATCHFILE" &&
		 [ ! -s "$PATCHFILE" ]
then
	error $LINENO "patch generation failed" 2
fi

# For each file in src that is also present in the current upstream
# version of SIMH, overwrite our version.
find "$SRCSUBDIR" -type f -print | while read f
do
	base="${f#$SRCSUBDIR}"
	upstream="$CURR_SIMH_DIR/$base"
	test -e "$upstream" && cp "$upstream" "$f"
done

# Now try to apply the patch we made above to the upstream files.
patch -p0 < "$PATCHFILE"

# No error, so save the new tip-of-master Git commit ID and rebuild
say "Patch appears to have applied cleanly.  Attempting a rebuild..."
sed -e "s/^SGCID=.*/SGCID=$NEW_SGCID/" -i tmp @srcdir@/Makefile.in
tools/mmake

# Restore stdout and let the human test it
say "Build completed without error.  Running default bootscript to test it..."
say
say "(Nuke $WORKDIR when finished.)"
say
exec 1<&-
exec 1<>/dev/tty
exec make run
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































































































































































































































































Deleted tools/version.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env perl
########################################################################
# tools/version - Print a string summarizing the software version
#
# Copyright © 2017 Warren Young
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the names of the authors above
# shall not be used in advertising or otherwise to promote the sale,
# use or other dealings in this Software without prior written
# authorization from those authors.
########################################################################

use strict;
use warnings;

use Cwd 'abs_path';
use File::Basename;

my $topdir = dirname($0) . '/..';
if (not -e "$topdir/.fslckout") {
	# We're not within a Fossil checkout, so try to get the version
	# number from the top directory name.
	$topdir = basename(abs_path($topdir));
	my ($v) = $topdir =~ m{v\d+};
	print 'pkg:', ($v ? $v : 'vUNKNOWN'), "\n";
	exit 0;
}

# Get version info from Fossil
my ($branch, $checkout, $version, $comment);
open my $s, '-|', 'fossil status 2> /dev/null'
        or die "Failed to run fossil status!\n";
while (<$s>) {
	chomp;
	my ($attr, $value) = split /:\s+/;

	if ($attr eq 'checkout') {
		my @elems = split ' ', $value;
		$checkout = substr($elems[0], 0, 10);
	}
	elsif ($attr eq 'tags') {
		my @tags = split /, /, $value;
		for my $t (@tags) {
			if ($t =~ m{^v\d+}) {
				$version = $t;
			}
			else {
				$branch = $t;
			}
		}
	}
	elsif ($attr eq 'comment') {
		$comment = $value;
	}
}
die "The fossil status command in $0 failed!\n" unless close $s;

($version) = $comment =~ m{(v\d+)} if $branch eq 'release';
print $branch, ':', ($version || "id[$checkout]");
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<