Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From 2a4f4cec29a53c13 To 20a61bf4e6ef46c8
2017-12-16
| ||
06:38 | Better description of the CC8 example programs in the CC8 docs. check-in: 442d9cff50 user: tangent tags: trunk | |
06:26 | cc8-tu56-update no longer copies basic.c to the tape image: the OS/8 compiler isn't currently able to compile it. check-in: 20a61bf4e6 user: tangent tags: trunk | |
06:25 | The CC8 cross-compiler now writes out *.sb instead of *.s to match the OS/8 file naming convention for SABR output, and to avoid the confusing use of *.s for some POSIX assembly languages. It was using *.s simply because it could replace *.c on the input file name with a single character replacement. If the input file name is exactly at the file name buffer's limit (20 bytes, including the trailing null), we still write out *.s rather that mess with resizing buffers or reserving one byte, complicating all the other uses of that buffer size. check-in: 857b3fafc0 user: tangent tags: trunk | |
2017-09-15
| ||
07:09 | "make clean" now removes bin/*rk05* check-in: b0d9bf39ba user: tangent tags: clean-os8-packs | |
07:07 | Moved media/subsys underneath media/os8, since everything in here currently requires OS/8 in one way or another. Doing so simplifies the path name building code in tools/mkos8 considerably. It also swaps out an explanation in media/subsys/README.md for why it is outside the os8 tree for an explanation of why it's in a subdirectory of that tree, a distinct improvement. check-in: 2a4f4cec29 user: tangent tags: clean-os8-packs | |
2017-09-14
| ||
13:41 | Comment typo fix check-in: a5ecc26447 user: tangent tags: clean-os8-packs | |
> > | 1 2 | inst test |
|
| > | | | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | examples/*.fc src/*.[ch] src/*.in src/cc8/*/*.[ch] src/cc8/include/* src/cc8/os8/*.sb src/cc8/os8/bldcc8.bi src/PDP8/pdp8_*.[ch] src/PDP8/pidp8i.c.in |
1 | doc/simh/*.pdf | > | 1 2 | doc/simh/*.pdf test/* |
> | 1 | .agignore |
|
| | | | | | | | | | | < | | | | | | > | | | | | | | | > > > > > > > > > > > > > > > | < > | < | < < > > > > > | | < < < > > < < < > > > > > < > | > > > > | 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 | # Creators of and Major Contributors to the PiDP-8/I Project * **[Oscar Vermeulen](mailto: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** is the 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** wrote the installation scripts for the 2015.12.15 release, which were folded into the `make install` handler within the current `Makefile.in`. He also wrote the version of the SysV init script shipped here as `etc/pidp8i-init.in`. * **[Ian Schofield](mailto: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](mailto: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](mailto: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](mailto:k1mu.nospam@gmail.com)** is the current maintainer of [OS/8 Adventure][advent] which we've included in our OS/8 disk image. He's also provided several other files which have landed in the distribution such as the [VTEDIT][vtedit] feature. He also optimized the `pep001.pal` example so that it fits into a single page of PDP-8 core. * **[Tony Hill](mailto: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. This is the basis for the current automatic upstream feature merge capability, which is why many releases since December 2016 include an update to the latest version of upstream SIMH. His contributions are made to the project [as `tony`][thcomm]. * **[Jonathan Trites](mailto:tritesnikov@gmail.com)** wrote the initial version of the script now called `libexec/mkos8`, which builds the OS/8 disk images from source tapes. * **[Bill Cattey](mailto:bill.cattey@gmail.com)** is the project lead and primary developer of the system that builds the OS/8 RK05 disk images from source tapes. He greatly extended the `mkos8` script, curated the tape collection we ship as `media/.../*.tu56`, created some of those tapes, and more. He has also contributed to other areas of the software project. His contributions are made to the project [as `poetnerd`][pncomm]. * **[Warren Young](mailto:tangentsoft@gmail.com)** Did everything listed in [the change log][cl] that is not attributed to anyone else. His contributions are made to the project [as `tangent`][wycomm], though keep in mind that some of those are commits of external contributions made by people who do not have commit rights on our software repository. The changelog provides proper attribution for these where the checkin comments do not. [advent]: http://www.rickmurphy.net/advent/ [cl]: https://tangentsoft.com/pidp8i/doc/trunk/ChangeLog.md [pncomm]: https://tangentsoft.com/pidp8i/timeline?u=poetnerd [thcomm]: https://tangentsoft.com/pidp8i/timeline?u=tony [vtedit]: https://tangentsoft.com/pidp8i/wiki?name=Using+VTEDIT [wycomm]: https://tangentsoft.com/pidp8i/timeline?u=tangent |
1 2 3 4 5 6 7 | # 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. | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | 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 | # 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. ## <a id="simh"></a>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 ## <a id="hw"></a>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 ## <a id="autosetup"></a>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 ## <a id="palbart"></a>palbart License The `palbart` program and its manual page are released under the terms of the license given in [`src/palbart/LICENSE.md`][pl]. [pl]: https://tangentsoft.com/pidp8i/doc/trunk/src/palbart/LICENSE.md ## <a id="d8tape"></a>d8tape License The `d8tape` program is distributed under the license given in [`src/d8tape/LICENSE.md`][d8tl]. [d8tl]: https://tangentsoft.com/pidp8i/doc/trunk/src/d8tape/LICENSE.md ## <a id="cc8"></a>CC8 Compiler License The license for the `src/cc8` subtree is messy as it comes to us from multiple authors over many years. There are two compilers here. First we have the OS/8 "native" compiler in `src/cc8/os8`, which is entirely Ian Schofield's work, released under the terms of the [GNU General Public License version 3][gpl3]. Then we have the CC8 cross-compiler which is based on Ron Cain's [Small-C][smc], originally published in [Dr. Dobbs' Journal][ddj]. Wikipedia describes Small-C as "copyrighted but sharable," which I take to mean that we cannot claim it as our exclusive property, but we can modify it and distribute those modifications to others, which is what we're doing here. Ian Schofield then took the Small-C source base and added a SABR back-end, `code8.c`, which is also distributed under the [GPLv3][gpl3]. There is [another PDP-8 C compiler project][smsc] based on Small-C by Vincent Slyngstad, which uses an entirely different approach for code generation. Ian Schofield took some of the library routines from this implementation. [ddj]: https://en.wikipedia.org/wiki/Dr._Dobb%27s_Journal [gpl3]: https://tangentsoft.com/pidp8i/doc/trunk/src/cc8/LICENSE.txt [smc]: https://en.wikipedia.org/wiki/Small-C [smsc]: http://so-much-stuff.com/pdp8/C/C.php ## <a id="os8"></a>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 ## <a id="dec"></a>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 [pdp8pd]: http://mailman.trailing-edge.com/pipermail/simh/2017-January/016164.html ## <a id="etos"></a>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 |
1 2 3 4 5 6 7 8 | # 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. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # PiDP-8/I Changes ## Version 2017.12.eh? — The "Languages and Custom OS/8 Disk Packs" release * All prior versions were shipping `os8.rk05`, a "Field Service Diagnostic" OS/8 disk pack image with uncertain provenance, configuration, and modification history. We have replaced that with a script run at build time that programmatically assembles a set of clean OS/8 RK05 disk images from curated, pristine, tested sources based on the user's chosen configuration options. This provides the following features and benefits as compared to the old `os8.rk05`: - The PiDP-8/I software build process now builds up to three RK05 disk images: - `os8v3d-bin.rk05` is a bootable OS/8 V3D disk configured according to your chosen configuration options, which are described below and in [`README.md`][tlrm]. It is made from the pristine DECtape images shipped by DEC for OS/8 V3D plus several third-party tapes curated for and built by the project's maintainers. See [the OS/8 media `README.md` file][os8rm] for more details. - `os8v3d-patched.rk05` is a copy of the `bin` disk with [most][os8p] of the patches DEC published over the years for OS/8 V3D applied. That set of patches was chosen and tested for applicability to our modern PiDP-8/I world and for mutual compatibility. This is the boot disk used for the IF=0 and IF=7 cases unless you give `--disable-os8-patches` to the `configure` script, in which case these boot options use the `bin` disk. - `os8v3d-src.rk05` is a non-bootable disk containing the contents of the OS/8 V3D source code tapes plus the source code for the extensions to OS/8 V3D. The *ten* TU56 tape images used as input to this process are also included among the PiDP-8/I software — see `media/os8/al-*-sa-*.tu56` — but we find it much more convenient to explore the sources on a single RK05 disk than to repeatedly attach and detach the TU56 tapes. You can suppress building this with `--disable-os8-src`. Default versions of these disk images are also now published on the project's home page for the benefit of those not running our PiDP-8/I software. There are quite a few OS/8 RK05 disk images floating around on the Internet these days, and many of them have bugs and breakage in them that we've fixed. It would completely fail to break our hearts if these images were used by many people outside the PiDP-8/I project. - U/W FOCAL V4E is installed on SYS: by default. Start with our [U/W FOCAL Manual Supplement for the PiDP-8/I][uwfs], then follow links from there to further information. The primary linked source is the [U/W FOCAL Manual][uwfm] by Jim van Zee (creator of U/W FOCAL) converted from scanned and OCR'd PDF form to Markdown format, which Fossil renders nicely for us on the web. This is a fascinating programming language, well worth studying! - Ian Schofield's CC8 OS/8 C compiler is installed on `SYS:` by default, and its examples and other files are on `DSK:`. We have also merged in his `cc8` host-side cross-compiler. See [the CC8 `README`][cc8rm] for details. This is a considerably improved compiler relative to what was distributed on the mailing list in August 2017. Ian has been working within the PiDP-8/I project since that initial public release, which we are now distributing publicly for the first time. We thank him for trusting us to host and distribute his project. - The MACREL v2 macro assembler and its associated FUTIL V8B tool are installed by default. Not only is this new functionality relative to prior releases of the PiDP-8/I software, it is a considerable upgrade over to the original MACREL and FUTIL V7 that are more commonly found on the net. - DCP disassembler is installed by default. - John Comeau's CHECKMO-II chess program is installed by default. - By default, SIMH no longer folds lowercase input and output to uppercase. Instead, we apply patches to OS/8's command processor and its BASIC implementation to up-case input, since neither OS/8 nor BASIC can cope with lowercase input. All other programs are left to fend for themselves, which often works out fine. U/W FOCAL, Adventure, and TECO all handle lowercase input to some extent, for example, and all three can emit lowercase text if given it. With the prior SIMH setting, you could not use lowercase in these programs at all. This default can be overridden. See the documentation for the new `--lowercase` configuration option in `README.md`. - The `INIT.TX` message displayed by default on OS/8 boot is now more informative than the old `FIELD SERVICE PDP-8 DIAGNOSTIC SYSTEM` message. It also now uses lowercase unless you built the simulator to force uppercase with `--lowercase=upper`. Those that do not want any boot message can disable it at configuration time with the `--disable-os8-init` flag. The message can be modified by editing `media/os8/init.tx.in` and saying `make`, which will rebuild the OS/8 media. - All of the above features can be disabled if not wanted, as can several features present on the old `os8.rk05` disk: Adventure, FORTRAN IV, FORTRAN II, Kermit-12, and the BASIC game and demo programs. You can disable each feature above with a `--disable-os8-*` option to the `configure` script, or you can disable all of them collectively with the `--os8-minimal` option, which gets you a nearly bare-bones OS/8 installation with lots of spare disk space with which you can do what *you* want. - Replaced the mismatched FORTRAN compiler and runtime with matched versions from the distribution DECtapes, and ensured that Adventure runs under this version of the FORTRAN Run Time System (FRTS). At various points in the past, either FORTRAN or Adventure has been broken. - Repaired several broken BASIC programs on `RKB0:` by going back to primary sources. Either the `os8.rk05` disk image was corrupted at some point or it is an image of a real RK05 disk pack that was corrupted, causing several of these BASIC programs to not run properly. - The `*.MU` and music player files are left off of `RKB0:` by default, since they apparently do not cause sufficient RFI on the PiDP-8/I hardware to be picked up by normal AM radios. This saves space for things that *do* work. - No longer installing the `VTEDIT` macros for TECO by default. Although some may enjoy this alternative way of running TECO, it was decided that we should offer stock TECO by default for its historical value. If you want VTEDIT back, it can be re-enabled with a `configure` script option. - In the old `os8.rk05` disk image, both `SYS:` and `DSK:` were set to `RKA0:`, which meant that to address anything on `RKB0:`, you had to specify the device path explicitly or manually change the default in OS/8 with an `ASSIGN RKB0 DSK` command or similar. In the new disk pack, programs run with the OS/8 `R` command are installed on `RKA0:` which is the `SYS:` disk, and user data files, FOCAL and BASIC programs, etc. are on `RKB0:` which is assigned as `DSK:`. This means OS/8 and its programs are now far more likely to find files without an explicit device name, because files are installed where OS/8 looks for them by default. Example: .R FRTS ⇠ loads FRTS from SYS: (RKA0:) *ADVENT ⇠ loads ADVENT.LD from DSK: (RKB0:) *[Esc] Welcome to Adventure!! Notice that no device names had to be specified. OS/8 did the right thing by default here, even though the files involved are on two separate OS/8 devices. To a very rough approximation, `SYS:` on these new RK05 disk packs acts like the Unix `PATH` and `DSK:` acts like your user's home directory. The idea for this came from Ian Schofield's `cc8.rk05` disk image, which we are also shipping in this release. - OS/8 has a limit on the number of devices it can support, and we made different choices than the creator of `os8.rk05`. Briefly, we replaced the second floppy (`RXA1:`) with a third RK05 disk, that being deemed a more useful configuration for this hard disk based OS/8 configuration. A dual-floppy configuration implies that you are booting from floppy and need the second one for user files and such. In our RK05 based configuration, users should need floppy disk support rarely, and then primarily to get data on and off of the attached hard disk(s). We chose to stick with the dual TU56 tape drive setup of the prior version as we found the ability to mount two tapes very helpful, particularly during the `mkos8` build process. The difference in the `RESORC` output between the versions is: Old: RKA0,RKB0,RKA1,RKB1, RXA0,RXA1,DTA0,DTA1,TTY,LPT,PTP,PTR New: RKA0,RKB0,RKA1,RKB1,RKA2,RKB2,RXA0, DTA0,DTA1,TTY,LPT,PTP,PTR This automatic OS/8 media build feature was suggested by Jonathan Trites who wrote the initial version of the script that is now called `libexec/mkos8`. That script was then extended and factored into its current form by Bill Cattey and Warren Young. Warren thinks Bill did most of the hard work in the items above. The source media used by the `mkos8` script comes from many sources and was curated for the PiDP-8/I project by Bill Cattey. See the [OS/8 media README][os8rm] for more details. See the [the top-level `README`][tlrm] for information on modifying the default OS/8 configuration. Pretty much everything above can be disabled if it's enabled by default, and vice versa. * Added several new wiki articles covering the above: * More Project Euler Problem #1 solutions in: * [C][pe1c] * [FORTRAN IV][pe1f4] * [FORTRAN II][pe1f2] * [U/W FOCAL][pe1u] * [Demos in BASIC][dibas], deescribing `DSK:*.BA` * [OS/8 Console TTY Setup][os8ct], describing how we have modified the stock behavior of OS/8 to behave appropriately with a glass terminal or SSH on its console, as opposed to its default behavior, which assumes a teletype. * [OS/8 LCSYS.BI Disassembled][os8lc], a symbolic disassembly of the `LCSYS.BI` patch we distribute with the system, which is widely available online elsewhere. That script is a raw binary patch, which makes its operation a mystery unless you happen to be able to read PDP-8 machine code. * Added Bill Cattey's `txt2ptp` program which converts plain ASCII text files files to the paper tape format used by SIMH, which eases transfer of text data into the simulator. That program is also linked to `ptp2txt`, which makes it perform the inverse function: given a SIMH paper tape image file, produce an ASCII text file on the host machine with its contents. This program was written to ease the movement of FOCAL program text between SIMH and its host OS, but they should prove useful for other similar tasks. * Integrated Robert Krten's `d8tape` PDP-8 host-side disassembler. This is distinct from the OS/8 DCP disassembler, which runs inside the simulator. It is intended as a companion to `palbart`, which we integrated last year. * Added a new "blinkenlights" demo program called `bin/teco-pi-demo` which drives SIMH from the outside, running a TECO macro under OS/8 to calculate *pi* to 248 digits at a very slow rate, producing a display that manages to land somewhere between the random default display of [Deeper Thought][dt2vk] and the clear, boring patterns of our preexisting IF=5 demo script. Why 248 digits? Because at 249, TECO8 runs out of memory, aborting the demo early. At the default execution rate, it would take over 17 years to complete this demo, making it a good choice to run on PiDP-8/I units primarily being used as *objets d'art*. The demo has a finite run time, but your Raspberry Pi is likely to die before it completes. `;)` This script is also included as a demonstration of how the end user can reuse the technology that we developed to automatically build the custom OS/8 disk images described above to achieve different ends. Perhaps you have some other program you'd like to run within SIMH in an automated fashion? This shows one way how, and demonstrates a pre-built and tested set of tools for achieving it. We have also written [a tutorial][csd] explaining how `bin/teco-pi-demo` works and how to reuse the components it is built atop for your own ends. This demo also has a benchmark mode (command line option `-b`) which has two purposes: 1. It lets you see how much faster your host system runs PDP-8 code than a Raspberry Pi Model B+ running the PiDP-8/I simulator. 2. Given that information, the benchmark overrides a hardcoded timing value in the source code as distributed which prevents programs like `teco-pi-demo` from spamming the OS/8 terminal input handler. The default is for the slowest host we support this software on, that same Model B+ referred to above, but if we know you're running on a faster host, we can shorten this delay and remain reliable. If you run the demo in benchmark mode twice, you'll notice that the TECO script is input nearly instantaneously the second time, whereas you can see the demo "type" the script in very quickly the first time. (Remove `lib/pidp8i/ips.py`, say `make reconfig` and run the demo again to see the difference.) * The `DF` + `SING_STEP` feature for automatically attaching binary media images to the simulator from files on USB sticks now looks at all directories under `/media`, not just `usb0` through `usb7` so that it works with several other common Linux USB automounting schemes, such as the one Raspbian Desktop uses. * Fixed the order of initialization in the GPIO setup code for the James L-W serial mod case. Fix by Dylan McNamee. * The helper program that selects which boot script to run when the PiDP-8/I boots based on the IF switch settings broke at some point in the past, apparently because it was using its own idiosyncratic GPIO handling code, and thus did not track our evolving GPIO handling methods. Now it shares the same code used by `pidp8i-sim` and `pidp8i-test`, so it works properly again. * The SysV init script that starts `pidp8i-sim` under GNU Screen on the PiDP-8/I now sets the working directory to `$prefix/share/media` on start, so relative paths given to SIMH commands (e.g. `ATTACH`) are more likely to do what you want. In prior releases, you generally had to give absolute paths to attach media and such because CWD would be set somewhere unhelpful. * The Fetch LED is no longer lit when in STOP or single-step mode. In real hardware, it can be either on or off in this mode, depending on various conditions, but it is most often off, so while it is not perfectly correct now, it is less wrong. Most of the investigation into this issue is by Bill Cattey, with the current partial fix by me. A more precise fix may come later. (See ticket [347ae45403] if you care to know the details.) * The Pause LED state was over-counted in the LED sub-sampling scheme so that it would tend to be brighter than it should have been. Problem noticed by Ian Schofield. * The MB row's state was not showing the right thing. The problem was noticed in comparison to real PDP-8/I hardware by Vincent Slyngstad and verified by William Cattey. Ian Schofield suggested the current fix. * Updated SIMH to upstream checkin ID 27f9fc3c3, December 11, 2017. There have been no substantial changes to the PDP-8 simulator since the last update, 8 months ago, but there have been a lot of bug fixes to the SCP core program. * Updated for Raspbian Stretch, released in September 2017. It should still run on Raspbian Jessie, however. * Assorted portability, build system, and documentation improvements. * **TODO** - Create udev script replacement for usbmount so that `DF` + `SING_STEP` works on Stretch. [apt]: https://linux.die.net/man/8/apt [cc8rm]: https://tangentsoft.com/pidp8i/doc/trunk/src/cc8/README.md [csd]: https://tangentsoft.com/pidp8i/doc/trunk/doc/class-simh.md [dibas]: https://tangentsoft.com/pidp8i/wiki?name=Demos+in+BASIC [dt2vk]: https://github.com/VentureKing/Deeper-Thought-2 [os8ct]: https://tangentsoft.com/pidp8i/wiki?name=OS/8+Console+TTY+Setup [os8lc]: https://tangentsoft.com/pidp8i/wiki?name=OS/8+LCSYS.BI+Disassembled [os8p]: https://tangentsoft.com/pidp8i/doc/trunk/doc/os8-patching.md [os8rm]: https://tangentsoft.com/pidp8i/doc/trunk/media/os8/README.md [pe1c]: https://tangentsoft.com/pidp8i/wiki?name=PEP001.C [pe1f2]: https://tangentsoft.com/pidp8i/wiki?name=PEP001.FT#fortran-ii [pe1f4]: https://tangentsoft.com/pidp8i/wiki?name=PEP001.FT#fortran-iv [pe1u]: https://tangentsoft.com/pidp8i/wiki?name=PEP001.FC [uwfm]: https://tangentsoft.com/pidp8i/doc/trunk/doc/uwfocal-manual.md [uwfs]: https://tangentsoft.com/pidp8i/doc/trunk/doc/uwfocal-manual-supp.md ## 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. |
︙ | ︙ | |||
19 20 21 22 23 24 25 | 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. | | | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | 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. |
︙ | ︙ | |||
529 530 531 532 533 534 535 | * 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.) | | | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | * 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: |
︙ | ︙ | |||
735 736 737 738 739 740 741 | [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. | | | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 | [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`][tlrm] 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.) |
︙ | ︙ | |||
806 807 808 809 810 811 812 | 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! | | | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 | 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! [tlrm]: 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 |
︙ | ︙ |
︙ | ︙ | |||
23 24 25 26 27 28 29 | 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 | | | | | > < | < < | < < < | | | | | | < | | | | | | 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 | 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 could build Fossil from source, or you could just go grab a prebuilt binary we keep on the project site: $ wget https://tangentsoft.com/pidp8i/uv/fossil-raspbian-9.1-stretch $ sudo install -m 755 fossil-* /usr/local/bin/fossil 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]: https://fossil-scm.org/index.html/uv/download.html [dvcs]: https://en.wikipedia.org/wiki/Distributed_revision_control [fbook]: https://www.fossil-scm.org/schimpf-book/home [fml]: https://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/fossil-users [fossil]: https://fossil-scm.org/ [fqsg]: https://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 $ 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 the PiDP-8/I software project 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 |
︙ | ︙ | |||
109 110 111 112 113 114 115 | 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] | | | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 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 employs some trickery that causes some unwanted side effects that don't affect Fossil by design: 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 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | Fossil Developer Access ---- If you have a developer account on tangentsoft.com's Fossil instance, just add your username to the URL like so: | | > > > > > > | | | | | | > | | | | 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 | 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 https://username@tangentsoft.com/pidp8i pidp8i.fossil If you've already cloned anonymously, you don't have to clone again to inform Fossil about your developer account. Just do a manual sync, changing the URL to include the user name: $ fossil sync https://username@tangentsoft.com/pidp8i Either way, 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, and you'll get credit under your developer account name for the checkin. If you're working offline, Fossil will still do the checkin locally, and it will sync up with the central repoisitory after 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 |
︙ | ︙ | |||
258 259 260 261 262 263 264 | Manipulating the Build System Source Files ---- The [autosetup build system][asbs] is composed of these files and directories: auto.def | | | > | | > | | | | | | | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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 the files in `autosetup/` to get some needed effect, you should try to get that change into the upstream [Autosetup][asbs] 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` 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 <a id="dirs"></a> Directory Structure ---- The directory structure of the PiDP-8/I project is as follows: * <b>`.`</b> - Top level, occupied only by the few files the end user of the source code needs immediately at hand on first unpacking the project: the top level build system files, the top-level `README*.md` files, and licensing information. If a given file *can* be buried deeper, it *should* be buried to reduce clutter at this most precious level of the hierarchy. * <b>`.fossil-settings`</b> - Versioned settings for the Fossil build system. Say `fossil help set` at the command line for more on this. Such settings are intended to be correct for all users of the system; rather than expressing defaults, they express *policy*. Any setting whose value may vary between users of the Fossil repository should be done locally with a `fossil set` command. * <b>`autosetup`</b> - The bulk of the [Autosetup build system][asbs]. These are generic files, not modified by the project itself. We occasionally run `tools/autosetup-update` to merge in upstream changes. * <b>`bin`</b> - Programs run both in development and after installation. Some files here are created directly by the project's developers, while others are outputs of the build system. The content of this directory is copied to `$prefix/bin` at installation time, which is added to the user's `PATH` by the installer. * <b>`boot`</b> - SIMH initialization scripts. The `*.script.in` files are written by the project developers but have build-time values substituted in by the `configure` script to produce a `*.script` version. Some of the remaining `*.script` files are hand-written and as such are checked into Fossil directly. The remainder are outputs of `tools/mkbootscript`, which produces them from `palbart` assembly listings. All of these `*.script` files are installed to `$prefix/share/boot` regardless of their origin. * <b>`doc`</b> - Documentation files not immediately important enough to a new user of the software that they do not have to be at the top level of the project tree. Fossil allows us to treat the contents of `doc` much like the wiki, so how do we decide whether to put a given document into `doc` or the wiki? The rule is simple: is the document's history tied to the history of the PiDP-8/I project itself? If so, it goes in `doc`, else it goes in the wiki. When checking out older versions of the PiDP-8/I software, you expect to roll back to contemporaneous versions of the project documentation; such files go into `doc`. Documents which are independent of the PiDP-8/I project history go into the wiki. (The wiki does also have history, but rolling back to a prior version of the PiDP-8/I repository and then saying `fossil ui` will show you the current version of the wiki documents, not the versions as they existed at the time of the historical checkin you rolled back to.) The `doc/graphics` subdirectory holds JPEGs and SVGs displayed inline within wiki articles. * <b>`etc`</b> - Files which get copied to `/etc` or one of its subdirectories at installation time. * <b>`examples`</b> - Example programs for the end user's edification. Many of these are referenced by documentation files. * <b>`hardware`</b> - Schematics and such for the PiDP-8/I board or associated hardware. * <b>`labels`</b> - Graphics intended to be printed out and used as labels for removable media. * <b>`lib`</b> - Library routines used by other programs. * <b>`libexec`</b> - A logical extension of `lib`, these are standalone programs that nevertheless are intended to be run primarily by other programs. Whereas a file in `lib` might have its interface described by a programmer's reference manual, the interface of a program in `libexec` is described by its usage message. Examples: * <b>`mkos8`</b> - Run by the build system. <p>It is sometimes run by hand in development, but primarily only to further its development. Once it runs correctly after adding some feature, we let <code>make</code> run it for us.</p> * <b>`scanswitch`</b> - Run by `etc/pidp8i`. <p>As with <code>mkos8</code>, it is generally run by hand only by developers modifying its behavior.</p> Programs in `libexec` are installed to `$prefix/libexec`, which is *not* put into the user's `PATH`, on purpose. If a program should end up in the user's `PATH`, it belongs in `bin`. Alternately, a wrapper may be put in `bin` which calls a `libexec` program as a helper. * <b>`media`</b> - Binary media images used either by SIMH directly or by tools like `mkos8` to produce media used by SIMH. The contents of this tree are installed to `$prefix/share/media`. * <b>`obj`</b> - Intermediate output directory used by the build system. It is safe to remove this directory at any time, as its contents may be recreated by `make`. No file checked into Fossil should be placed here. (Contrast `bin` which does have some files checked into Fossil; all of the *other* files that end up in `bin` can be recreated by `make`, but not these few hand-written programs.) * <b>`src`</b> - Source code for the project's programs, especially those that cannot be used until they are built. The build system's output directories are `bin`, `boot`, `libexec`, and `obj`. Programs that can be used without being "built", example programs, and single-file scripts are placed elsewhere: `bin`, `examples`, `libexec`, `tools`, etc. Basically, we place such files where the build system *would* place them if they were built from something under `src`. The top level of `src` is for the SIMH core, with the PDP-8 simulator specific bits in the `PDP8` subdirectory. The subdirectories of `src` are for other programs' source code. * <b>`test`</b> - Output directory used by `tools/test-*`. * <b>`tools`</b> - Programs run only during development and not installed. If a program is initially created here but we later decide that it should be installed for use by end users of the PiDP-8/I system, we move it to either `bin` or `libexec`, depending on whether it is run directly at the command line or run from some other program that is also installed, respectively. <a id="patches"></a> 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 |
︙ | ︙ | |||
362 363 364 365 366 367 368 | 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 | | | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | 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]: https://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 ---- |
︙ | ︙ |
︙ | ︙ | |||
32 33 34 35 36 37 38 | # 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. | | > > > | | > | | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | | | | 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 | # 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=27f9fc3c3e7ff105c6102dfffc6da7fb838d1e8f # C build flags for src/*.c and PDP8/*.c, containing the SIMH core # modules and the SIMH PDP-8 simulator, respectively. TOP_CFLAGS := @CFLAGS@ @BUILDMODE@ \ -Wno-unused-result -Wno-parentheses \ -DUSE_READER_THREAD -DHAVE_DLOPEN=$(subst .,,@SH_SOEXT@) -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 PDP8_CFLAGS = $(TOP_CFLAGS) # Greatly stripped-down build options for the cc8 cross-compiler # primarily because it's K&R C. Building under TOP_CFLAGS spews # pages of warnings. The only thing we share is whether to build # a debug or optimized version, from BUILDMODE, set by auto.def. CC8_CROSS_CFLAGS = -w @BUILDMODE@ # Krten's d8tape doesn't need much in the way of options. It builds # without warnings under the supported version of Raspbian. On some # other OS types, it complains about one of the printf() format # specifiers, which we cannot fix portably, so we suppress that one. D8TAPE_CFLAGS = -Wno-format @BUILDMODE@ # Ditto palbart. PALBART_CFLAGS = @BUILDMODE@ SIM = bin/pidp8i-sim BINS = $(SIM) @CC8_CROSS@ \ bin/d8tape \ bin/palbart \ bin/pidp8i-test \ bin/ptp2txt \ libexec/scanswitch BIN_SCRIPTS = \ bin/pidp8i \ @srcdir@/bin/teco-pi-demo # Some *.py files are generated by Autosetup, so they need different # handling than the other libraries for the out-of-tree build case. PIDP8I_DIRS := lib/pidp8i/dirs.py PIDP8I_DIN := @srcdir@/$(PIDP8I_DIRS).in GENNED_PY := \ lib/pidp8i/__init__.py \ lib/pidp8i/ips.py \ $(PIDP8I_DIRS) SIMH_PY := lib/simh.py SIMH_PY_SRC := @srcdir@/$(SIMH_PY) MKOS8 := @srcdir@/libexec/mkos8 MKOS8_LIB := @srcdir@/lib/mkos8 MKOS8_PY := \ $(MKOS8_LIB)/__init__.py \ $(MKOS8_LIB)/argparser.py \ lib/mkos8/opts.py MKOS8_PY_ALL := $(GENNED_PY) $(MKOS8_PY) $(SIMH_PY_SRC) MKOS8_SRCS := $(MKOS8) $(MKOS8_PY_ALL) $(PIDP8I_DIN) BUILDDIRS := bin libexec obj/cc8/cross obj/d8tape obj/palbart obj/PDP8 INSTDIRS := bin etc lib/mkos8 lib/pidp8i libexec share/boot share/media share/include share/man/man1 SIM_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 \ |
︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 | 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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | > > > | | | > > > > > > > > > > > > > > > | > > > > > < < | | < < < < | | > > | > > | | < | > | > | | < > > > | | | < < < > > > | > > > > | > > > > > > | > > > > | | | 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 | obj/sim_serial.o \ obj/sim_sock.o \ obj/sim_tape.o \ obj/sim_timer.o \ obj/sim_tmxr.o \ obj/sim_video.o CC8_OBJS := \ obj/cc8/cross/code8.o \ obj/cc8/cross/data.o \ obj/cc8/cross/error.o \ obj/cc8/cross/expr.o \ obj/cc8/cross/function.o \ obj/cc8/cross/gen.o \ obj/cc8/cross/io.o \ obj/cc8/cross/lex.o \ obj/cc8/cross/main.o \ obj/cc8/cross/preproc.o \ obj/cc8/cross/primary.o \ obj/cc8/cross/stmt.o \ obj/cc8/cross/sym.o \ obj/cc8/cross/while.o D8TAPE_OBJS := \ obj/d8tape/dasm.o \ obj/d8tape/flow.o \ obj/d8tape/main.o \ obj/d8tape/version.o MISC_OBJS := \ obj/ptp2txt.o \ obj/scanswitch.o \ obj/test.o PALBART_OBJS := obj/palbart/palbart.o ifeq (@BUILD_DEEPER_THOUGHT@, 1) BINS += bin/deeper endif LIBS = -lm -ldl -lpthread ASM_PTS := $(wildcard @srcdir@/src/asm/*.pal) ASM_PTS := $(subst @srcdir@/src/asm,bin,$(ASM_PTS)) ASM_PTS := $(ASM_PTS:.pal=-pal.pt) FC_EX_PTS := $(wildcard @srcdir@/examples/*.fc) FC_EX_PTS := $(subst @srcdir@/examples,bin,$(FC_EX_PTS)) FC_EX_PTS := $(FC_EX_PTS:.fc=-focal.pt) PAL_EX_PTS := $(wildcard @srcdir@/examples/*.pal) PAL_EX_PTS := $(subst @srcdir@/examples,bin,$(PAL_EX_PTS)) PAL_EX_PTS := $(PAL_EX_PTS:.pal=-pal.pt) LISTINGS := $(ASM_PTS:-pal.pt=.lst) $(PAL_EX_PTS:-pal.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. # # The MKOS8_INFILES set of files are those which, if changed, require # rebuilding the OS/8 media. Touching the combined set merely causes # a reconfig and build. # # The PRECIOUS set are those whose outfiles we want make(1) to treat as # "precious", meaning it won't delete files generated by a target if the # rule being processed to create that target fails. # # The rest have no special treatment. MKOS8_INFILES = \ @srcdir@/lib/pidp8i/__init__.py.in \ @srcdir@/lib/pidp8i/ips.py.in \ @srcdir@/media/os8/init.tx.in \ @srcdir@/src/PDP8/pidp8i.c.in \ $(PIDP8I_DIN) PRECIOUS_INFILES = \ @srcdir@/Makefile.in \ @srcdir@/examples/Makefile.in \ @srcdir@/src/Makefile.in \ @srcdir@/src/cc8/Makefile.in \ @srcdir@/src/PDP8/Makefile.in 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@/boot/run.script.in \ @srcdir@/etc/pidp8i-init.in \ @srcdir@/etc/sudoers.in \ @srcdir@/src/gpio-common.c.in \ @srcdir@/tools/simh-update.in \ $(MKOS8_INFILES) MKOS8_OUTFILES := $(subst @srcdir@/,,$(MKOS8_INFILES)) MKOS8_OUTFILES := $(subst .in,,$(MKOS8_OUTFILES)) PRECIOUS_OUTFILES := $(subst @srcdir@/,,$(PRECIOUS_INFILES)) PRECIOUS_OUTFILES := $(subst .in,,$(PRECIOUS_OUTFILES)) OUTFILES := $(subst @srcdir@/,,$(INFILES)) OUTFILES := $(subst .in,,$(OUTFILES)) OS8_BIN_RK05 = bin/os8v3d-bin.rk05 OS8_SRC_RK05 = @OS8_SRC_RK05@ OS8_RK05S = $(OS8_BIN_RK05) $(OS8_SRC_RK05) CLTXT = /boot/cmdline.txt ADF := adrules.mk .PHONY: all tags .PRECIOUS: $(PRECIOUS_OUTFILES) all: $(OUTFILES) $(PRECIOUS_OUTFILES) $(BUILDDIRS) $(BINS) $(BOOTSCRIPTS) $(LISTINGS) $(ASM_PTS) $(FC_EX_PTS) $(PAL_EX_PTS) $(OS8_RK05S) clean: @rm -f $(BINS) $(BOOTSCRIPTS) $(ASM_PTS) $(PAL_EX_PTS) $(LISTINGS) \ $(OUTFILES) $(ADF) \ config.log cscope.out tags \ bin/*.pt bin/*.rk05 bin/*.save bin/txt2ptp \ lib/*.pyc lib/*/*.pyc lib/mkos8/opts.py \ obj/*.log obj/*.pt obj/mkos8.opts \ src/config.h \ @srcdir@/examples/*.err @find obj \( -name \*.o -o -name \*.d \) -delete @-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@/src @srcdir@/lib @srcdir@/libexec/mkos8 ifeq (@HAVE_PROG_CSCOPE@, 1) @cscope -bR -s@srcdir@ endif install: all instdirs @echo Installing to @prefix@... @# Install files into those dirs and set their perms @for f in $(BINS) ; do \ dest=@prefix@/bin/$$(basename $$f) ; \ echo "Installing binary $$dest..." ; \ @INSTALL@ -m 755 -D -s $$f $$dest ; \ done @for f in $(BIN_SCRIPTS) ; do \ dest=@prefix@/bin/$$(basename $$f) ; \ echo "Installing script $$dest..." ; \ @INSTALL@ -m 755 -D $$f $$dest ; \ done @( cd @prefix@/bin ; \ echo "Installing txt2ptp symlink..." ; \ ln -f ptp2txt txt2ptp ; \ ) @(test -x /sbin/setcap && \ for f in @prefix@/bin/pidp8i-* ; do \ echo "Setting real-time priority capabilities on $$(basename $$f)..." ; \ /sbin/setcap 'cap_sys_nice=eip' $$f ; \ done \ ) || true @test -e @MEDIADIR@/os8/os8.rk05 || echo "Installing media..." && $(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 |
︙ | ︙ | |||
212 213 214 215 216 217 218 | 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" ; \ | > | > > > > > > | | > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > | | > > > | > > > > > > > > > > > > > > > | < > > > | | > > > | < | | < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | > > > > > < < < < | > > > > > > > > > > > > > > > > > > > > > > > > | < < | < < < < < < < < < < | < | > > | | > > > > > | 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 | 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 CC8 stuff if built @test -n "@CC8_CROSS@" && \ echo "Installing cc8 cross-compiler..." ; \ @INSTALL@ -m 755 bin/cc8 @prefix@/bin && \ @INSTALL@ -m 644 @srcdir@/src/cc8/include/* @prefix@/share/include @# Install palbart stuff @@INSTALL@ -m 755 bin/palbart @prefix@/bin @@INSTALL@ -m 644 @srcdir@/src/palbart/palbart.1 @prefix@/share/man/man1 @# Install mkos8 and its dependencies @echo "Installing mkos8..." @@INSTALL@ -m 775 -g @INSTGRP@ $(MKOS8) @prefix@/libexec @( for src in $(MKOS8_PY_ALL) ; do \ test -e $$src || src=@srcdir@/$$src ; \ dest=@prefix@/$$(echo $$src | sed -e 's_^@srcdir@/__') ; \ echo "Installing $$src to $$dest..." ; \ @INSTALL@ -m 644 -g @INSTGRP@ -D $${src} $${dest} ; \ @INSTALL@ -m 644 -g @INSTGRP@ -D $${src}c $${dest}c ; \ done \ ) @sed -e 's#^build =.*#build = "@ABSPREFIX@"#' \ -e 's#^media =.*#media = os.path.join (build, "share/media/")#' \ -e 's#^os8mo =.*#os8mo = os8mi#' \ < $(PIDP8I_DIRS) > @prefix@/$(PIDP8I_DIRS) @chgrp @INSTGRP@ @prefix@/$(PIDP8I_DIRS) instdirs: @echo "Creating installation directory tree..." @for d in $(INSTDIRS) ; do @INSTALL@ -m 755 -d @prefix@/$$d ; done mediainstall: instdirs @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 -o @INSTUSR@ -g @INSTGRP@ {} @ABSPREFIX@/share/{} \; @@INSTALL@ -m 644 -o @INSTUSR@ -g @INSTGRP@ bin/os8v3d-*.rk05 @ABSPREFIX@/share/media/os8 @@INSTALL@ -m 664 -o @INSTUSR@ -g @INSTGRP@ boot/*.script @BOOTDIR@ # No-dependencies versions of the bin/os8v3d-*.rk05 targets used by # tools/test-mkos8, because there's no point rebuilding the simulator # on each iteration. os8-bin: $(MKOS8)@MKOS8_OPTS@ bin os8-patched: $(MKOS8)@MKOS8_OPTS@ bin patch reconfig: @AUTOREMAKE@ release: all @srcdir@/tools/mkrel run: $(SIM) $(SIM) boot/run.script simh-update simh-update-f: @@srcdir@/tools/simh-update $(subst simh-update,,$@) test-mkos8: tools/test-mkos8 # Build the OS/8 binary media needed by 0.script. # # We use order-only prerequisites for the simulator here because we only # care that it *exists*, not whether it is newer than the previously # built RK05 media or not. # # Also notice that the init.tx file is not a prerequisite: we purposely # do not rebiuld the RK05 media just because the configure script was # re-run, which *always* regenerates the init.tx file because the # timestamp always changes from one run to the next. (Until computers # get fast enough to do a complete re-configure in under a second, # anyway!) The thing is, we only want the RK05 bin media rebuilt when # the configure --*-os8-* options change. *That* is when we care about # the updated init.tx file, not before. We needn't even make it an # order-only prereq because configure and the INFILES rules above ensure # that it always exists. OS8_BIN_SRCS := $(MKOS8_SRCS) \ @srcdir@/media/os8/al-*-ba-*.tu56 \ @srcdir@/media/os8/subsys/*.tu56 ifneq (@MKOS8_BIN_PATCHES@,) OS8_BIN_SRCS += @srcdir@/media/os8/patches/patch_list.txt endif $(OS8_BIN_RK05): $(OS8_BIN_SRCS) | $(SIM) $(MKOS8_OUTFILES) $(MKOS8)@MKOS8_OPTS@ bin @MKOS8_BIN_PATCHES@ # Also build an OS/8 source disk, as a convenience to avoid the # need to mount up the 7 source tapes in succession. # # Using an order-only dependency for the simulator and the bin disk: we # only need *a* version of each, they don't have to be recent! OS8_SRC_SRCS = $(MKOS8_SRCS) \ @srcdir@/media/os8/al-*-sa-*.tu56 $(OS8_SRC_RK05): $(OS8_SRC_SRCS) | $(SIM) $(OS8_BIN_RK05) $(MKOS8)@MKOS8_OPTS@ src # Rule for building PAL assembly language programs in src/asm/*.pal. obj/%.lst bin/%-pal.pt: @srcdir@/src/asm/%.pal bin/palbart bin/palbart -lr $< || cat obj/$*.err mv @srcdir@/src/asm/$*.lst obj mv @srcdir@/src/asm/$*.rim bin/$*-pal.pt # Ditto for those in examples/*.pal. obj/%.lst bin/%-pal.pt: @srcdir@/examples/%.pal bin/palbart bin/palbart -lr $< || cat obj/$*.err mv @srcdir@/examples/$*.lst obj mv @srcdir@/examples/$*.rim bin/$*-pal.pt # Rule for converting ASCII FOCAL examples in examples/*.fc to # bin/*-focal.pt. bin/%-focal.pt: @srcdir@/examples/%.fc bin/txt2ptp bin/txt2ptp < $< > bin/$*-focal.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 $< $@ $(BUILDDIRS): mkdir -p $@ $(SIM): $(SIM_OBJS) obj/gpio-@LED_DRIVER_MODULE@ls.o $(CC) -o $@ $^ $(LIBS) bin/cc8: $(CC8_OBJS) $(CC) -o $@ $^ $(LIBS) bin/d8tape: $(D8TAPE_OBJS) $(CC) -o $@ $^ bin/palbart: $(PALBART_OBJS) $(CC) -o $@ $^ bin/pidp8i-test: obj/test.o obj/gpio-nls.o obj/gpio-common.o $(CC) -o $@ $^ $(LIBS) -lncurses bin/ptp2txt: obj/ptp2txt.o $(CC) -o $@ $^ ln -f bin/ptp2txt bin/txt2ptp bin/txt2ptp: bin/ptp2txt ln -f bin/ptp2txt bin/txt2ptp 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) # Reconfigure whenever one of the *.in or autosetup files changes unless # this is "make clean". # # We purposely list only one of the OUTFILES on the left hand side # because to list them all is to invite Make to run N copies of the # configure script in parallel up to the limit of -j or the number of # files in INFILES, whichever is lower. Order-only prerequisites can't # help here (|) as that only affects the right hand side. ifeq ($(findstring clean,$(MAKECMDGOALS)),) media/os8/init.tx: $(INFILES) $(PRECIOUS_INFILES) @AUTODEPS@ @AUTOREMAKE@ && $(MAKE) # Also do it if the autodep tool is newer than its output, suggesting # that if re-run, it would generate different output. $(ADF): @srcdir@/tools/mkadrules @AUTOREMAKE@ && $(MAKE) endif # Rebuild simulator if the version string tool changes, since its output # may have changed. src/gpio-common.c: @srcdir@/tools/version # Pull in *.d files generated by the autodependency mechanism. See the # header comment of tools/mkadrules. -include \ $(SIM_OBJS:.o=.d) \ $(CC8_OBJS:.o=.d) \ $(D8TAPE_OBJS:.o=.d) \ $(MISC_OBJS:.o=.d) \ $(PALBART_OBJS:.o=.d) -include $(ADF) |
1 2 3 4 5 6 7 8 | # 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. | | | > > > > > > | > | > | > | > > > | > | > | > > > | > | > | > > > | > > > | > | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > > > > | > | > > | > > > > > > > > > > > > > > | | | | > > > | > | | > | < > > > | | 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 | # 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 [a compatible OS][os]. * This software distribution, unpacked somewhere convenient within the filesystem on the Raspberry Pi. We recommend that you unpack it somewhere your user has read/write access like `$HOME/src/pidp8i`. Since it installs as a system service, you might prefer `/usr/local/src` or `/opt/src`, though you'll have to adjust permissions for that. The [old stable 2015.12.15 release][osd] required that you unpack the software into `/opt/pidp8`, but we now neither require nor recommend that. * We require several tools and libraries that aren't always installed: * A working C compiler and other standard Linux build tools, such as `make(1)`. * Python's `pexpect` library * The `usbmount` tool This is provides two things: * USB stick auto-mounting on stripped-down OSes like Raspbian Lite so you can use the PiDP-8/I `SING_STEP` + `DF` feature without having to manually mount the USB stick first. * A known directory structure that allows the PiDP-8/I software to find the media image files on those sticks. (`*.pt`, `*.dt`, `*.rk`, etc.) Full-blown GUI OSes tend to have USB auto-mounting set up already, though they won't meet the second criteria unless they use the same directory layout as `usbmount`: `/media/usbN`, where `N` is a number from 0 to 7, depending on the order you attached the USB stick. Many Linuxes use `/media/LABEL` instead, for example, where `LABEL` is the partition's label; the PiDP-8/I software won't find the files on those USB sticks in that case. * The `ncurses` development libraries To install all of this on a Raspbian type OS, say: $ sudo apt update $ sudo apt install build-essential $ sudo apt install libncurses-dev python-pip usbmount $ sudo pip install pexpect [os]: https://tangentsoft.com/pidp8i/wiki?name=OS+Compatibility <a id="unpacking"></a> ## Getting the Software onto Your Pi If you're reading this file within an unpacked distribution of the PiDP-8/I software, you should skip this section, because you have already achieved its aim. If you are reading this [online][this] and have not yet downloaded and unpacked the software source code onto your Pi, this section will get you going. [this]: https://tangentsoft.com/pidp8i/doc/trunk/README.md <a id="transferring"></a> ### Transferring the File to the Pi The first step is to get the tarball (`*.tar.gz` file) or Zip file onto the Pi. There are many options: 1. **Copy the file to the SD card** you're using to boot the Pi. When inserted into a Mac or Windows PC, typically only the `/boot` partition mounts as a drive your OS can see. (There's a much larger partition on the SD card, but most PCs cannot see it.) There should be enough free space left in this small partition to copy the file over. When you boot the Pi up with that SD card, you will find the tarball or Zip file in `/boot`. 2. **Pull the file down to the Pi** over the web, directly to the Pi: $ wget -O pidp8i.tar.gz https://goo.gl/JowPoC That will get you a file called `pidp8i.tar.gz` in the current working directory. 3. **SCP the file over** to a running Pi from another machine. If your Pi has OpenSSH installed and running, you can use [WinSCP][wscp], [Cyberduck][cd], [FileZilla][fz] or another SCP or SFTP-compatible file transfer program to copy the file to the Pi over the network. [cd]: https://cyberduck.io/ [fz]: https://filezilla-project.org/ [wscp]: https://winscp.net/eng/ 4. **Clone the Fossil repository** using the instructions in the [`HACKERS.md` file][hack]. (Best for experts or those who wish to become experts.) [hack]: https://tangentsoft.com/pidp8i/doc/trunk/HACKERS.md 5. **Switch to the binary OS installation images** available from the [top-level project page][cprj]. These are default installations of Raspbian Lite with the PiDP-8/I software already downloaded, built, and installed. These images were produced in part using option #4 above, so you can use Fossil to update your software to the current version at any time, as long as the Pi is connected to the Internet. <a id="unpacking"></a> ### Unpacking the Software on Your Pi Having transferred the distribution file onto your Pi, you can unpack it with one of the two following commands. If you grabbed the tarball: $ tar xvf /path/to/pidp8i-VERSION.tar.gz If you grabbed the Zip file instead: $ unzip /path/to/pidp8i-VERSION.zip The file name will vary somewhat, depending on when and how you transferred the file. After unpacking it, you will have a new directory beginning with `pidp8i`. `cd` into that directory, then proceed with the [configuration](#configuring) steps below. <a id="help"></a> ### If You Need More Help If the above material is not sufficient to get you started, you might want to look at [the documentation][rpfd] provided by the Raspberry Pi Foundation. In particular, we recommend their [Linux][rpfl] and [Raspbian][rpfr] guides. The book "[Make: Linux for Makers][lfm]" by Aaron Newcomb is also supposed to be good. [rpfd]: https://www.raspberrypi.org/documentation/ [rpfl]: https://www.raspberrypi.org/documentation/linux/ [rpfr]: https://www.raspberrypi.org/documentation/raspbian [lfm]: https://www.makershed.com/products/make-linux-for-makers <a id="configuring"></a> ## 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 The `configure` step is generally needed only the first time you build the software in a new directory. You may want to add options after it, as described [below](#options). After that initial configuration, the software normally auto-reconfigures itself on updates using the same options you gave before, but occasionally we make some change that prevents this from happening. If you get a build error after updating to a new version of the software, try saying: $ make reconfig ...and then continuing with the `make && sudo make install` steps before reporting a build error. If `make reconfig` also fails, you can try running the `configure` script again manually. <a id="running"></a> ### Running the Software For the most part, this is covered in the documentation linked from the [Learning More](/#learning) section of the project home page. The only tricky bit is that if this is the first time you have configured, built and installed the software as above on a given system, you will have to log out and back in before commands like `pidp8i` will be in your user's `PATH`. <a id="options"></a> ### Configure Script Options You can change many things about the way the software is built and installed by giving options to the `configure` script: <a id="prefix"></a> #### --prefix Perhaps the most widely useful `configure` script option is `--prefix`, which lets you override the default installation directory, `/opt/pidp8i`. There are many good reasons to change where the software gets installed, but the default is also a good one, so unless you know for a fact that you want to change this default, leave it alone. For example, you might prefer that the installer put the built software under your home directory. This will do that: $ ./configure --prefix=$HOME/pidp8i && sudo make install You might think that installing to a directory your user has complete control over would remove the need for installing via `sudo`, but that is not the case, since the installation script needs root privileges to mark a few of the executables as having permission to run at high priority levels, which improves the quality of the display, particularly with the [incandescent lamp simulator][ils] feature enabled. <a id="lowercase"></a> #### --lowercase The American Standards Association (predecessor to ANSI) delivered the second major version of the ASCII character encoding standard the same year the first PDP-8 came out, 1965. The big new addition? Lowercase. That bit of history means that when the PDP-8 was new, lowercase was a |
︙ | ︙ | |||
125 126 127 128 129 130 131 | getting the software to work as you expect when built in this mode, try enabling CAPS LOCK. [sa]: http://homepage.cs.uiowa.edu/~jones/pdp8/faqs/#charsets [tty]: https://tangentsoft.com/pidp8i/wiki?name=OS/8+Console+TTY+Setup | | | | > > > > > > > > > > > | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > | | | | | | | > > > > > > | > > > | > > > > > > > | > > > > > > > > > > | > > > | > > > > | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | | > | | | | | | | | | > | | | | | | 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 | getting the software to work as you expect when built in this mode, try enabling CAPS LOCK. [sa]: http://homepage.cs.uiowa.edu/~jones/pdp8/faqs/#charsets [tty]: https://tangentsoft.com/pidp8i/wiki?name=OS/8+Console+TTY+Setup <a id="nls"></a> #### --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]. <a id="serial-mod"></a> #### --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. <a id="alt-serial-mod"></a> #### --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. #### --disable-cc8-cross Give this option if you do not want to build Ian Schofield's `cc8` C cross-compiler on the host. Note that this is different from `--disable-os8-cc8`, which disables the *native OS/8* C compiler. They are two different C compilers: one runs outside the SIMH PDP-8 simulator and the other runs inside the simulator under OS/8. <a id="disable-os8"></a> #### --disable-os8-\* Several default components of the [OS/8 RK05 disk image](#os8di) used by boot options IF=0 and IF=7 can be left out to save space and build time: * **--disable-os8-advent** — Leave out the [Adventure][advent] game. * **--disable-os8-ba** - Leave out the BASIC games and demos which come from DEC's book "101 BASIC Computer Games." These are normally installed to `RKB0:` as `*.BA`, thus the option's name. (We considered naming it `--disable-os8-basic-games-and-demos`, but that's too long, and it can't be `--disable-os8-basic` because that implies that it is the OS/8 BASIC subsystem that is being left out, which is not even currently an option.) * **--disable-os8-chess** — Leave out John Comeau's [CHECKMO-II chess implementation][chess]. * **--disable-os8-cc8** - Leave out Ian Schofield's native OS/8 CC8 compiler normally installed to `SYS:`. This option is implicitly given if you give `--disable-os8-fortran-ii` because the output of the OS/8 CC8 compiler is a SABR file, and SABR is part of the FORTRAN II subsystem. * **--disable-os8-crt** — Suppress the [console rubout behavior][tty] enabled while building the OS/8 binary RK05 disk image. You probably only want to do this if you have attached a real teletype to your PiDP-8/I, and thus do not want video terminal style rubout processing. * **--disable-os8-focal** - Do not install any version of FOCAL on the OS/8 system disk. This option sets `--disable-os8-uwfocal` and overrides `--enable-os8-focal69`, both discussed below. * **--disable-os8-fortran-ii** - Leaves out the FORTRAN II compiler, SABR, the linking loader (`LOADER`), the `LIBSET` tool, and the `*.RL` library files. * **--disable-os8-fortran-iv** - Leave the FORTRAN IV compiler out. * **--disable-os8-init** - Generate `RKB0:INIT.TX` but do not display it on OS/8 boot. Rather than disable the default on-boot init message, you may want to edit `media/os8/init.tx.in` to taste and rebuild. (We still build the file when you give this option in case you later decide you want to enable the boot message, or you need to call up configuration information stored in `INIT.TX`.) * **--disable-os8-k12** - Leave out the Kermit-12 implementation normally installed to `RKA0:` * **--disable-os8-macrel** - Leave the MACREL v2 assembler and its associated FUTIL V8B tool out. * **--disable-os8-patches** - Do not apply any of the OS/8 V3D patches published by DEC. See the [documentation][os8p] for this option for more information. * **--disable-os8-src** - Do not build the `os8v3d-src.rk05` disk image from the OS/8 source tapes. This is not controlled by `--os8-minimal` because that only affects `os8v3d-bin.rk05`. * **--disable-os8-uwfocal** - Leave out the U/W FOCAL V4E programming environment normally installed to `RKA0:`. Note that the default installation only installs `UWF16K.SV`, not the rest of the files on `media/os8/subsys/uwfocal*.tu56`. There is much more to explore here, but we cannot include it in the default installation set because that would overrun OS/8's limitation on the number of files on a volume. [advent]: http://www.rickmurphy.net/advent [chess]: https://chessprogramming.wikispaces.com/CHEKMO-II [os8p]: https://tangentsoft.com/pidp8i/doc/trunk/doc/os8-patching.md <a id="enable-os8"></a> #### --enable-os8-\* There are a few file sets not normally installed to the [OS/8 RK05 disk image](#os8di) used by boot options IF=0 and IF=7. You can install them with the following options: * **--enable-os8-music** — The `*.MU` music scores and Rich Wilson's associated compiler (`MUSIC.PA`) and player overlay (`PLAYOV.PA`) are not normally installed to the built OS/8 binary RK05 disk image because the Raspberry Pi reportedly does not emit eufficient RFI at AM radio frequencies when running these programs to cause audible music on a typical AM radio, the very point of these demos. Until a way is found around this problem — what, low RFI is a *problem* now? — this option will default to "off". * **--enable-os8-vtedit** — This option installs a default-run macro pack called VTEDIT which causes the OS/8 version of TECO to run in full-screen mode and to react to [several special keyboard commands][uvte] not normally recognized by TECO. This feature is disabled by default because the VTEDIT macro pack changes the way TECO operates, and many people want TECO to behave like *TECO*. VTEDIT was first created during the PDP-8's commercial lifetime, so enabling this option is not an anachronism, but TECO is much older and had a much more wide-reaching impact in history, so we choose to provide unvarnished TECO by default. That having been said, people don't go to a ren fair and expect to experience the historical ubiquity of typhoid fever, so do not feel guilty if you choose to try this option. [uvte]: https://tangentsoft.com/pidp8i/wiki?name=Using+VTEDIT * **--enable-os8-focal69** — Because the default installation includes U/W FOCAL, we have chosen to leave FOCAL 69 out by default to save space on the O/S 8 system disk. You can give this option to install this implementation alongside U/W FOCAL, or you can couple this option with `--disable-os8-uwfocal` to reverse our choice of which FOCAL implementation to install by default. You should know that the reason we made this choice is that the version of FOCAL 69 we are currently shipping is fairly minimal: we believe we are shipping the original DEC version of FOCAL 69 plus a few carefully-selected overlays. There are many more overlays and patches available on the Internet for FOCAL 69, but we have not had time to sort through these and make choices of which ones to ship or how to manage which ones get installed. Thus our choice: we want to provide the most functional version of FOCAL by default, and within the limitations of the time we have chosen to spend on this, that is U/W FOCAL today. (See our [U/W FOCAL manual supplement][suppd] for a list of differences between these versions of FOCAL, which implicitly explains why we chose it.) It is possible that we will eventually add enough patches and overlays to FOCAL 69 that it will become more powerful than U/W FOCAL, so we might then choose to switch the defaults, but that is just speculation at the time of this writing. [suppd]: https://tangentsoft.com/pidp8i/doc/trunk/doc/uwfocal-manual-supp.md#diffs #### --os8-minimal If you set this flag, it sets all `--enable-os8-*` flags to false and all `--disable-os8-*` flags to true. If you explicitly give any of these flags to the `configure` script, this flag overrides them. This flag only affects the optional installs made after the `BUILD` step: it does not remove optional features of OS/8 itself, such as its BASIC interpreter. Giving this option therefore gets you an empty OS/8 `DSK:` device and nothing in `SYS:` beyond what was left after the OS/8 `BUILD` step. There are a few exceptions: 1. This option does not affect the `--lowercase` option because that affects only OS/8's command interpreter and OS/8's BASIC implementation, so we deem it to be orthogonal to the purpose of the `--os8-minimal` flag, which only affects the optional post-`BUILD` features. If you want a *truly* pristime OS/8 disk, you should therefore also give `--lowercase=none`. 2. This option does not affect `--disable-os8-src`, because it only suppresses optional features in the "bin" media. If you want a minimal OS/8 bin disk and no src disk, give that option as well. #### --help Run `./configure --help` for more information on your options here. ## <a id="os8di"></a>OS/8 Disk Images For the first several years of the PiDP-8/I project, the OS/8 RK05 disk image included with the PiDP-8/I software (called `os8.rk05`) was based on an image of a real RK05 disk pack that someone allegedly found in a salvaged PDP-8 system. Parts of the image were corrupt, and not all of the pieces of software on the disk worked properly with the other parts. It was also a reflection of the time it was created and used out in the world, which was not always what we would wish to use today. In late 2017 [several of us][aut] created the `mkos8` tool, which takes the `--*-os8-*` options documented above and generates the `os8v3d-*.rk05` RK05 disk image files with your chosen configuration options. This set of disk images entirely replaces the old `os8.rk05` disk image, in that all features of the old disk image are still available, though not necessarily in the default configuration. In some cases, we have disabled some features that were included in the stock `os8.rk05` disk image, and in other cases we have changed the behavior of features. Mostly, though, the new disk images are simply more functional than the old ones. If you wish to know the full details of how these disk images are created, the best documentation so far is [the source code for the `mkos8` script][mkos8] and the [documentation for `class simh`][cs]. The remainder of this section describes some aspects of these disk images which are not clear from the descriptions of the `--*-os8-*` configuration options above. [aut]: https://tangentsoft.com/pidp8i/doc/trunk/AUTHORS.md ### Baseline The baseline for the bootable OS/8 disk images comes from a set of DECtapes distributed by Digital Equipment Corporation which are now included with the PiDP-8/I software; see the [`media/os8/*.tu56` files][os8mf]. From these files and your configuration options, the `mkos8` script creates the baseline `os8v3d-bin.rk05` disk image. The default build creates a complete OS/8 system including `BUILD` support, FORTRAN IV, MACREL v2, and more. ### Subtractions It turns out that it's pretty easy to run out of directory space on an OS/8 RK05 disk due to a limitation in the number of files on an OS/8 filesystem. For this reason, the archive of device drivers and TD8E system are left off the system packs. They can be found in [OS/8 Binary Distribution DECtape #2][bdt2]. If you do fancy work with `BUILD`, you may need to attach that DECtape image and copy files in from it. ### Default Additions The OS/8 RK05 disk image build process normally installs many software and data file sets to the disk image. See the [option descriptions above](#disable-os8): the "disable" option set effectively lists those packages that `mkos8` installs by default, and the following set of ["enable" options](#enable-os8) lists those left out by default. ### Console Enhancements The default build [enhances the console](/wiki?name=Console+TTY+Setup), adding support for lower case terminals where: 1. The SIMH PDP-8 simulator and a few select parts of OS/8 are adjusted to cope with lowercase input to [varying degrees](#lowercase). 2. Rubout/backspace handling is set to assume a video terminal rather than a teletype by default. ### Patches After the baseline disk image is created, `mkos8` makes a copy of it as `os8v3d-patched.rk05` and applies a [carefully selected set of official DEC patches][os8p] to it unless you give the `--disable-os8-patches` configuration option. The IF=0 and IF=7 boot options boot from the patched disk unless you give that option. [bdt2]: https://tangentsoft.com/pidp8i/file/media/os8/al-4712c-ba-os8-v3d-2.1978.tu56 [cl]: https://tangentsoft.com/pidp8i/doc/trunk/ChangeLog.md [cs]: https://tangentsoft.com/pidp8i/doc/trunk/doc/class-simh.md [mkos8]: https://tangentsoft.com/pidp8i/doc/trunk/libexec/mkos8 [os8mf]: https://tangentsoft.com/pidp8i/file/media/os8 [tlrm]: https://tangentsoft.com/pidp8i/doc/trunk/README.md <a id="overwrite-setup"></a> ## 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. There is an important exception here: when upgrading from v20170404 to v201712xx or newer, the old `os8.rk05` disk image will be left untouched per the above, but because `os8v3d-*.rk05` does not exist yet, those will be copied alongside `os8.rk05`. However, the next item still holds, so that the simulator will continue to use `os8.rk05` because it will be booted by the preexisting scripts. 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 the prior 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 change is to the binary PDP-8 media image files — including the [generated OS/8 disk images](#os8di) — and you're unwilling to overwrite your existing ones 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](#os8di) 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! <a id="testing"></a> ## Testing Your PiDP-8/I Hardware 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. <a id="using"></a> ## Using the Software For the most part, this software distribution works like the [old stable 2015.12.15 distribution][osd]. Its [documentation][oprj] 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: |
︙ | ︙ | |||
364 365 366 367 368 369 370 | 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 | | | < | | | 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 | 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 old stable 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]. [cprj]: https://tangentsoft.com/pidp8i/ [sm1]: http://obsolescence.wixsite.com/obsolescence/2016-pidp-8-building-instructions [sm2]: https://groups.google.com/d/msg/pidp-8/-leCRMKqI1Q/Dy5RiELIFAAJ [osd]: 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 [oprj]: 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 |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 | # authorization from those authors. ######################################################################## define defaultprefix /opt/pidp8i use cc use cc-lib options { alt-serial-mod => "use GPIO drive scheme suitable for James L-W's serial mod method" debug-mode => "create a debug build (default is release)" lowercase: => "select how lowercase input is to be handled" no-lamp-simulator => "use simple LED driver instead of incandescent lamp simulator" | > > > > > > > > > | | | | > > > | > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | | | | | < < < | < < > | < | < < | < | < < | > > | < < < < < < < < < < < < | 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 | # authorization from those authors. ######################################################################## define defaultprefix /opt/pidp8i use cc use cc-lib use cc-shared # Canonicalize some paths which may be relative and generate others from them set abspfx [file-normalize [get-define prefix]] define ABSPREFIX $abspfx define BOOTDIR "$abspfx/share/boot" define MEDIADIR "$abspfx/share/media" # Define command line options options { alt-serial-mod => "use GPIO drive scheme suitable for James L-W's serial mod method" cc8-cross=1 => "do not build the cc8 cross-compiler on the host" debug-mode => "create a debug build (default is release)" lowercase: => "select how lowercase input is to be handled" no-lamp-simulator => "use simple LED driver instead of incandescent lamp simulator" os8-advent=1 => "leave Adventure off the built OS/8 RK05 image" os8-ba=1 => "leave *.BA BASIC games and demos off the built OS/8 RK05 image" os8-cc8=1 => "leave the native OS/8 CC8 compiler off the built OS/8 RK05 image" os8-crt=1 => "suppress CRT-style rubout processing in the built OS/8 RK05 image" os8-chess=1 => "leave the CHECKMO-II game of chess off the built OS/8 RK05 image" os8-dcp=1 => "leave the DCP disassembler off the built OS/8 RK05 image" os8-focal=1 => "leave FOCAL 69 and U/W FOCAL off the built OS/8 RK05 image" os8-focal69 => "add FOCAL 69 to the built OS/8 RK05 image" os8-fortran-ii=1 => "leave FORTRAN II off the built OS/8 RK05 image" os8-fortran-iv=1 => "leave FORTRAN IV off the built OS/8 RK05 image" os8-init=1 => "do not show the OS/8 INIT message in the built OS/8 RK05 image" os8-k12=1 => "leave 12-bit Kermit off the built OS/8 RK05 image" os8-macrel=1 => "leave MACREL assembler off the built OS/8 RK05 image" os8-minimal => "set all --disable-os8-* options, giving minimal OS/8 bin disk" os8-music => "add *.MU files to the built OS/8 RK05 image" os8-patches=1 => "do not apply DEC patches to the built OS/8 RK05 bin image" os8-src=1 => "do not build os8v3d-src.rk05 from OS/8 source tapes" os8-uwfocal=1 => "leave U/W FOCAL (only) off the built OS/8 RK05 image" os8-vtedit => "add the TECO VTEDIT setup to built OS/8 RK05 image" serial-mod => "use GPIO drive scheme suitable for Oscar Vermeulen's serial mod method" throttle: => "override the throttle values in the boot scripts" } # Handle meta-options first. if {![opt-bool os8-focal]} { if {[opt-bool os8-focal69]} { dict set $::autosetup(optset) "os8-focal69" 0 } if {[opt-bool os8-uwfocal]} { dict set $::autosetup(optset) "os8-uwfocal" 0 } } set os8min [opt-bool os8-minimal] set os8src [opt-bool os8-src] # Translate the --*-os8-* options to mkos8 command line option format # and build the Python option map it uses to interpret them. This # avoids the need to define the options by hand in both places. set mkos8_opts "" set os "# GENERATED BY auto.def; DO NOT MODIFY.\n\nopts = {\n" foreach opt [lsort [dict keys $::autosetup(optdefault)]] { # Skip meta-options handled above and non --*-os8-* options. if {$opt in {os8-focal os8-minimal os8-src}} { continue } if {[string first "os8-" $opt] != 0} { continue } # Add next line to Python output set od [dict get $::autosetup(optdefault) $opt] set oh [dict get $::autosetup(opthelpline) $opt] set obn [string replace $opt 0 3] append os "\t\"" $obn "\": \[ $od, \"" $oh "\" \],\n" # Fix grammar for upcoming msg-result calls if {[string first "do not " $oh] == 0} { set oh [string replace $oh 0 6] } elseif {[string first "do " $oh] == 0} { set oh [string replace $oh 0 2] } # Choose option to pass to mkos8 corresponding to this configure # script option. Also tell user what we're going to do; grammar # is inverted because the option help text says what happens when # you give the opposite of the option's default argument. set ov [opt-bool $opt] if {$ov == $od} { # Don't append a mkos8 option; the default is correct. msg-result "Will not $oh." } elseif {!$os8min && $ov} { append mkos8_opts " --enable-" $obn } else { append mkos8_opts " --disable-" $obn } } append os "}\n" if {![file exists "lib/mkos8"]} { file mkdir "lib/mkos8" } write-if-changed "lib/mkos8/opts.py" $os # Handle the OS/8 options not passed to mkos8 generically by above. if {$os8src} { msg-result "Building os8v3d-src.rk05 from OS/8 source tapes." define OS8_SRC_RK05 bin/os8v3d-src.rk05 } else { msg-result "Will not build os8v3d-src.rk05 from OS/8 source tapes." define OS8_SRC_RK05 {} } if {$os8min || ![opt-bool os8-patches]} { msg-result "Will not patch OS/8 on the RK05 bin disk." define OS8_BOOT_DISK "os8v3d-bin.rk05" define MKOS8_BIN_PATCHES {} } else { msg-result "Will apply OS/8 V3D patches to the RK05 bin disk." define OS8_BOOT_DISK "os8v3d-patched.rk05" define MKOS8_BIN_PATCHES patch } # React to remaining chosen command line options 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 cc8-cross]} { define CC8_CROSS bin/cc8 } else { define CC8_CROSS {} msg-result "Will not build the cc8 cross-compiler." } 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} } set lv [opt-val lowercase] if {$lv == ""} { set lv "auto" } if {$lv == "auto"} { define SIMH_PASS_LOWERCASE } elseif {$lv == "pass"} { define SIMH_PASS_LOWERCASE append mkos8_opts " --disable-lcmod" } elseif {$lv == "upper"} { append mkos8_opts " --disable-lcmod" } else { user-error "Legal values for --lowercase are {auto,pass,upper}." } msg-result "Lowercase handling set to '$lv' mode." if {[opt-bool os8-cc8] && ![opt-bool os8-fortran-ii]} { msg-result "Must clear --disable-os8-fortran-ii when CC8 is enabled." regsub -- {--disable-os8-fortran-ii } $mkos8_opts {} } # We've purposely held off exporting the mkos8 option set until now # because some of the configuration options can affect the option set. define MKOS8_OPTS $mkos8_opts # Force a rebuild of the OS/8 media if the option set changed. if {![file exists "obj"]} { file mkdir "obj" } write-if-changed "obj/mkos8.opts" $mkos8_opts { file delete -force bin/os8v3d-bin.rk05 msg-result "mkos8 options changed; will rebuild OS/8 disk images." } # 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 |
︙ | ︙ | |||
222 223 224 225 226 227 228 | user-error "No install(1) type program found; install GNU Coreutils." } msg-result "Found GNU install(1) program as [get-define INSTALL]." # If we have cscope here, we'll use it in the "tags" target define HAVE_PROG_CSCOPE [cc-check-progs cscope] | < < < < < | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | user-error "No install(1) type program found; install GNU Coreutils." } msg-result "Found GNU install(1) program as [get-define INSTALL]." # If we have cscope here, we'll use it in the "tags" target define HAVE_PROG_CSCOPE [cc-check-progs cscope] # 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." |
︙ | ︙ | |||
270 271 272 273 274 275 276 | # 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. | | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | 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 | # 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 ".timeout 5000 ; 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 # Get host, user, and date info for use by media/os8/init.tx. catch {exec hostname} host set user $::env(USER) define BUILDUSER "$user@$host" define BUILDTS [clock format [clock seconds] -format "%Y.%m.%d at %T %Z"] # The mkos8 script requires Python and some non-core modules. set status [catch {exec python -c exit} result] if {$status != 0} { user-error "Python does not appear to be installed here. It is required." } msg-result "Python is installed here." set status [catch {exec python -c "import pexpect" 2> /dev/null} result] if {$status != 0} { set msg "The Python pexpect module is not installed here. Fix with\n" append msg "\n sudo pip install pexpect\n" append msg "\nOR:\n" append msg "\n sudo easy_install pexpect\n" append msg "\nOR:\n" append msg "\n sudo apt install python-pexpect\n" user-error $msg } msg-result "Python module pexpect is installed here." set status [catch {exec python -c "import pkg_resources" 2> /dev/null} result] if {$status != 0} { set msg "The Python pkg_resources module is not installed here. Fix with\n" append msg "\n sudo pip install pkg_resources\n" append msg "\nOR:\n" append msg "\n sudo easy_install pkg_resources\n" append msg "\nOR:\n" append msg "\n sudo apt install python-pkg-resources\n" user-error $msg } msg-result "Python module pkg_resources is installed here." # 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 } # Generate autodependency Makefile rule sets. # # It is important to list "src" last, because GNU make takes the first # one that matches, and the wildcards in the generated rules for "src" # match all "src/*" subdirs. set status [catch { exec $srcdir/tools/mkadrules $srcdir src/cc8/cross src/d8tape src/palbart src/PDP8 src } result] if {$status == 0} { msg-result $result } else { user-error "Failed to generate autodependency rules: $result!" } # 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 boot/run.script.in make-template etc/pidp8i-init.in make-template etc/sudoers.in make-template examples/Makefile.in make-template lib/pidp8i/__init__.py.in make-template lib/pidp8i/dirs.py.in make-template lib/pidp8i/ips.py.in make-template media/os8/init.tx.in make-template src/Makefile.in make-template src/cc8/Makefile.in make-template src/cc8/os8/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" |
︙ | ︙ | |||
70 71 72 73 74 75 76 | 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) {} | | > > > < > > > > > > > > > > > > | | | | | | | | | | | | | 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 | 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 set autosetup(optdefault) {} # options-defaults is a dictionary of overrides for default values for options set autosetup(options-defaults) {} set autosetup(optionhelp) {} set autosetup(opthelpline) {} 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" licence license => "display the autosetup license" 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" } if {$autosetup(installed)} { # hidden options so we can produce a nice error options-add { sysinstall:path } } else { options-add { sysinstall:path => "install standalone autosetup to the given directory (e.g.: /usr/local)" } } options-add { 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-str conf o]} { set autosetup(autodef) $o } # 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 autosetup_load_auto_modules if {[opt-str help o]} { incr autosetup(showhelp) use help autosetup_help $o } if {[opt-bool licence license]} { use help autosetup_show_license exit 0 } if {[opt-str {manual ref reference} o]} { use help autosetup_reference $o } # Allow combining --install and --init set earlyexit 0 if {[opt-str install o]} { use install autosetup_install $o incr earlyexit } if {[opt-str init o]} { use init autosetup_init $o incr earlyexit } if {$earlyexit} { exit 0 } if {[opt-str sysinstall o]} { use install autosetup_install $o 1 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)" |
︙ | ︙ | |||
251 252 253 254 255 256 257 | } # @opt-val optionlist ?default=""? # # Returns a list containing all the values given for the non-boolean options in '$optionlist'. # There will be one entry in the list for each option given by the user, including if the # same option was used multiple times. | < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } # @opt-val optionlist ?default=""? # # Returns a list containing all the values given for the non-boolean options in '$optionlist'. # 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 no options were set, '$default' is returned (exactly, not as a list). # # Note: For most use cases, 'opt-str' should be preferred. # 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 } # @opt-str optionlist varname ?default? # # Sets '$varname' in the callers scope to the value for one of the given options. # # For the list of options given in '$optionlist', if any value is set for any option, # the option value is taken to be the *last* value of the last option (in the order given). # # If no option was given, and a default was specified with 'options-defaults', # that value is used. # # If no 'options-defaults' value was given and '$default' was given, it is used. # # If none of the above provided a value, no value is set. # # The return value depends on whether '$default' was specified. # If it was, the option value is returned. # If it was not, 1 is returns if a value was set, or 0 if not. # # Typical usage is as follows: # ## if {[opt-str {myopt altname} o]} { ## do something with $o ## } # # Or: ## define myname [opt-str {myopt altname} o "/usr/local"] # proc opt-str {names varname args} { global autosetup option-check-names {*}$names upvar $varname value if {[llength $args]} { # A default was given, so always return the string value of the option set default [lindex $args 0] set retopt 1 } else { # No default, so return 0 or 1 to indicate if a value was found set retopt 0 } foreach opt $names { if {[dict exists $::autosetup(optset) $opt]} { set result [lindex [dict get $::autosetup(optset) $opt] end] } } if {![info exists result]} { # No user-specified value. Has options-defaults been set? foreach opt $names { if {[dict exists $::autosetup(options-defaults) $opt]} { set result [dict get $autosetup(options-defaults) $opt] } } } if {[info exists result]} { set value $result if {$retopt} { return $value } return 1 } if {$retopt} { set value $default return $value } return 0 } proc option-check-names {args} { foreach o $args { if {$o ni $::autosetup(options)} { autosetup-error "Request for undeclared option --$o" } } |
︙ | ︙ | |||
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 | 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 } | > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > < | > > > > | 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 | set opt [lindex $opts $i] if {[string match =* $opt]} { # This is a special heading lappend autosetup(optionhelp) $opt "" set header {} continue } unset -nocomplain defaultvalue equal value #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 # Check for override if {[dict exists $autosetup(options-defaults) $name]} { # A default was specified with options-defaults, so use it set value [dict get $autosetup(options-defaults) $name] } if {$value eq "1"} { set opthelp "--disable-$name" } else { set opthelp "--$name" } # Set the default if {$value eq ""} { set value 0 } set defaultvalue $value dict set autosetup(optdefault) $name $defaultvalue 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 {$colon eq ":"} { # Was ":name=default" given? # If so, set $value to the display name and $defaultvalue to the default # (This is the preferred way to set a default value for a string option) if {[regexp {^([^=]+)=(.*)$} $value -> value defaultvalue]} { dict set autosetup(optdefault) $name $defaultvalue } } # Maybe override the default value if {[dict exists $autosetup(options-defaults) $name]} { # A default was specified with options-defaults, so use it set defaultvalue [dict get $autosetup(options-defaults) $name] dict set autosetup(optdefault) $name $defaultvalue } elseif {![info exists defaultvalue]} { # For backward compatiblity, if ":name" was given, use name as both # the display text and the default value, but only if the user # specified the option without the value set defaultvalue $value } if {$equal eq "="} { # String option with optional value set opthelp "--$name?=$value?" } else { # String option with required value set opthelp "--$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 $defaultvalue } 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] if {[info exists defaultvalue]} { set desc [string map [list @default@ $defaultvalue] $desc] } #string match \n* $desc if {$header ne ""} { lappend autosetup(optionhelp) $header "" set header "" } # A multi-line description lappend autosetup(optionhelp) $opthelp $desc dict set autosetup(opthelpline) $name $desc incr i 2 } } } # @module-options optionlist # |
︙ | ︙ | |||
475 476 477 478 479 480 481 | } } } # @options optionspec # # Specifies configuration-time options which may be selected by the user | | > > > | 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 | } } } # @options optionspec # # Specifies configuration-time options which may be selected by the user # and checked with 'opt-str' and 'opt-bool'. '$optionspec' contains a series # of options specifications separated by newlines, as 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. # # The description may contain '@default@', in which case it will be replaced with the default # value for the option (taking into account defaults specified with 'options-defaults'. # # 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" |
︙ | ︙ | |||
519 520 521 522 523 524 525 526 527 528 529 530 531 532 | foreach o [dict keys $::autosetup(getopt)] { if {$o ni $::autosetup(options)} { user-error "Unknown option --$o" } } } } proc config_guess {} { if {[file-isexec $::autosetup(dir)/autosetup-config.guess]} { if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.guess} alias]} { user-error $alias } return $alias | > > > > > > > > > > > | 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 | foreach o [dict keys $::autosetup(getopt)] { if {$o ni $::autosetup(options)} { user-error "Unknown option --$o" } } } } # @options-defaults dictionary # # Specifies a dictionary of options and a new default value for each of those options. # Use before any 'use' statements in 'auto.def' to change the defaults for # subsequently included modules. proc options-defaults {dict} { foreach {n v} $dict { dict set ::autosetup(options-defaults) $n $v } } proc config_guess {} { if {[file-isexec $::autosetup(dir)/autosetup-config.guess]} { if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.guess} alias]} { user-error $alias } return $alias |
︙ | ︙ | |||
571 572 573 574 575 576 577 | # 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 ""} { | | > | > > > > > | 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 | # 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 ""} { # Avoid duplicates foreach arg $args { set found 0 foreach str [split $::define($name) " "] { if {$str eq $arg} { incr found } } if {!$found} { append ::define($name) " " $arg } } } else { set ::define($name) [join $args] } #dputs "$name += [join $args] => $::define($name)" |
︙ | ︙ | |||
1550 1551 1552 1553 1554 1555 1556 | # Module which can install autosetup # autosetup(installed)=1 means that autosetup is not running from source # autosetup(sysinstall)=1 means that autosetup is running from a sysinstall verion # shared=1 means that we are trying to do a sysinstall. This is only possible from the development source. proc autosetup_install {dir {shared 0}} { | > | > | | > > | > | | 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 | # Module which can install autosetup # autosetup(installed)=1 means that autosetup is not running from source # autosetup(sysinstall)=1 means that autosetup is running from a sysinstall verion # shared=1 means that we are trying to do a sysinstall. This is only possible from the development source. proc autosetup_install {dir {shared 0}} { global autosetup if {$shared} { if {$autosetup(installed) || $autosetup(sysinstall)} { user-error "Can only --sysinstall from development sources" } } elseif {$autosetup(installed) && !$autosetup(sysinstall)} { user-error "Can't --install from project install" } if {$autosetup(sysinstall)} { # This is the sysinstall version, so install just uses references cd $dir puts "[autosetup_version] creating configure to use system-installed autosetup" autosetup_create_configure 1 puts "Creating autosetup/README.autosetup" file mkdir autosetup |
︙ | ︙ | |||
1588 1589 1590 1591 1592 1593 1594 | file mkdir $targetdir set f [open $target w] set publicmodules {} # First the main script, but only up until "CUT HERE" | | | | | | | 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 | file mkdir $targetdir set f [open $target w] set publicmodules {} # 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: # All modules are inserted if $shared is set puts $f "set autosetup(installed) 1" puts $f "set autosetup(sysinstall) $shared" foreach file [lsort [glob $autosetup(libdir)/*.{tcl,auto}]] { set modname [file tail $file] set ext [file ext $modname] set buf [readfile $file] if {!$shared} { if {$ext eq ".auto" || [string match "*\n# @synopsis:*" $buf]} { lappend publicmodules $file continue } } dputs "install: importing lib/[file tail $file]" puts $f "# ----- @module $modname -----" puts $f "\nset modsource($modname) \{" puts $f $buf puts $f "\}\n" } if {$shared} { foreach {srcname destname} [list $autosetup(libdir)/README.autosetup-lib README.autosetup \ $autosetup(srcdir)/LICENSE LICENSE] { dputs "install: importing $srcname as $destname" puts $f "\nset modsource($destname) \\\n[list [readfile $srcname]\n]\n" } } } close $in close $f catch {exec chmod 755 $target} set installfiles {autosetup-config.guess autosetup-config.sub autosetup-test-tclsh} set removefiles {} if {!$shared} { autosetup_install_readme $targetdir/README.autosetup 0 |
︙ | ︙ | |||
1653 1654 1655 1656 1657 1658 1659 | foreach fileinfo $installfiles { if {[llength $fileinfo] == 2} { lassign $fileinfo source dest } else { lassign $fileinfo source set dest $source } | | < | 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 | foreach fileinfo $installfiles { if {[llength $fileinfo] == 2} { lassign $fileinfo source dest } else { lassign $fileinfo source set dest $source } autosetup_install_file $autosetup(dir)/$source $targetdir/$dest } # Remove obsolete files foreach file $removefiles { if {[file exists $targetdir/$file]} { file delete $targetdir/$file } |
︙ | ︙ | |||
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 | proc autosetup_install_file {source target} { dputs "install: $source => $target" if {![file exists $source]} { error "Missing installation file '$source'" } writefile $target [readfile $source]\n } proc autosetup_install_readme {target sysinstall} { set readme "README.autosetup created by [autosetup_version]\n\n" if {$sysinstall} { append readme \ {This is the autosetup directory for a system install of autosetup. | > > > > | 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 | proc autosetup_install_file {source target} { dputs "install: $source => $target" if {![file exists $source]} { error "Missing installation file '$source'" } writefile $target [readfile $source]\n # If possible, copy the file mode file stat $source stat set mode [format %o [expr {$stat(mode) & 0x1ff}]] catch {exec chmod $mode $target} } proc autosetup_install_readme {target sysinstall} { set readme "README.autosetup created by [autosetup_version]\n\n" if {$sysinstall} { append readme \ {This is the autosetup directory for a system install of autosetup. |
︙ | ︙ |
︙ | ︙ | |||
26 27 28 29 30 31 32 | ## CC_FOR_BUILD ## LD use system module-options {} | < < < < < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | ## CC_FOR_BUILD ## LD use system module-options {} # 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 |
︙ | ︙ | |||
151 152 153 154 155 156 157 | cc-check-some-feature $args { cctest_type $each } } # @cc-check-defines define ... # | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | cc-check-some-feature $args { cctest_type $each } } # @cc-check-defines define ... # # Checks that the given preprocessor symbols are defined. proc cc-check-defines {args} { cc-check-some-feature $args { cctest_define $each } } # @cc-check-decls name ... |
︙ | ︙ | |||
238 239 240 241 242 243 244 | incr found break } } } } } | > | < < | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | incr found break } } } } } define-feature $function $found if {!$found} { msg-result "no" } return $found } # @cc-check-tools tool ... # |
︙ | ︙ |
︙ | ︙ | |||
45 46 47 48 49 50 51 | } } else { msg-result $version define PKG_CONFIG_VERSION $version set found 1 | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | } } else { msg-result $version define PKG_CONFIG_VERSION $version set found 1 if {[opt-str sysroot o]} { define SYSROOT [file-normalize $o] 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 { |
︙ | ︙ |
︙ | ︙ | |||
18 19 20 21 22 23 24 | ## infodir ## mandir ## includedir # # If '--prefix' is not supplied, it defaults to '/usr/local' unless 'defaultprefix' is defined *before* # including the 'system' module. | > > | > | > | 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 | ## infodir ## mandir ## includedir # # If '--prefix' is not supplied, it defaults to '/usr/local' unless 'defaultprefix' is defined *before* # including the 'system' module. if {[is-defined defaultprefix]} { user-notice "Note: defaultprefix is deprecated. Use options-defaults to set default options" options-defaults [list prefix [get-define defaultprefix]] } 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=/usr/local => {the target directory for the build (default: '@default@')} # 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 silent-rules=0 }] # @check-feature name { script } # # defines feature '$name' to the return value of '$script', # which should be 1 if found or 0 if not found. # |
︙ | ︙ | |||
126 127 128 129 130 131 132 | writefile $file $buf\n uplevel 1 $script } } # @make-template template ?outfile? # | | > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | writefile $file $buf\n uplevel 1 $script } } # @make-template template ?outfile? # # Reads the input file '<srcdir>/$template' and writes the output file '$outfile' # (unless unchanged). # 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 |
︙ | ︙ | |||
218 219 220 221 222 223 224 | set cond [expr {!$cond}] } } continue } lappend result $line } | | < | > | | | 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 | set cond [expr {!$cond}] } } continue } lappend result $line } write-if-changed $out [string map $mapping [join $result \n]] { msg-result "Created [relative-path $out] from [relative-path $template]" } } # build/host tuples and cross-compilation prefix opt-str build build "" define build_alias $build if {$build eq ""} { define build [config_guess] } else { define build [config_sub $build] } opt-str host host "" define host_alias $host if {$host eq ""} { define host [get-define build] set cross "" } else { define host [config_sub $host] set cross $host- |
︙ | ︙ | |||
254 255 256 257 258 259 260 | user-error "Invalid canonical $type: $v" } define ${type}_cpu $cpu define ${type}_vendor $vendor define ${type}_os $os } | | < | | < < | > > > > | > > > > > > > > > | 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 | user-error "Invalid canonical $type: $v" } define ${type}_cpu $cpu define ${type}_vendor $vendor define ${type}_os $os } opt-str prefix prefix /usr/local # These are for compatibility with autoconf define target [get-define host] define prefix $prefix define builddir $autosetup(builddir) define srcdir $autosetup(srcdir) define top_srcdir $autosetup(srcdir) define abs_top_srcdir [file-normalize $autosetup(srcdir)] define abs_top_builddir [file-normalize $autosetup(builddir)] # autoconf supports all of these define exec_prefix [opt-str exec-prefix exec_prefix $prefix] foreach {name defpath} { bindir /bin sbindir /sbin libexecdir /libexec libdir /lib } { define $name [opt-str $name o $exec_prefix$defpath] } foreach {name defpath} { datadir /share sharedstatedir /com infodir /share/info mandir /share/man includedir /include } { define $name [opt-str $name o $prefix$defpath] } if {$prefix ne {/usr}} { opt-str sysconfdir sysconfdir $prefix/etc } else { opt-str sysconfdir sysconfdir /etc } define sysconfdir $sysconfdir define localstatedir [opt-str localstatedir o /var] define SHELL [get-env SHELL [find-an-executable sh bash ksh]] # These could be used to generate Makefiles following some automake conventions define AM_SILENT_RULES [opt-bool silent-rules] define AM_MAINTAINER_MODE [opt-bool maintainer-mode] define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking] # Windows vs. non-Windows switch -glob -- [get-define host] { *-*-ming* - *-*-cygwin - *-*-msys { define-feature windows define EXEEXT .exe } |
︙ | ︙ |
︙ | ︙ | |||
19 20 21 22 23 24 25 | } cc-check-tools ar ranlib set objdir [get-env BUILDDIR objdir] make-config-header $objdir/include/autoconf.h | | > > < < < < < < < < | < < < < < < < | > > > > | | < < | 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 | } 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]*} *dir lib_* } autosetup_check_create project.spec \ {# Initial project.spec created by 'autosetup --init=tmake' tmake-require-version 0.7.3 # vim:set syntax=tcl: define? DESTDIR _install # XXX If configure creates additional/different files than include/autoconf.h # that should be reflected here Autosetup include/autoconf.h # e.g. for autoconf.h IncludePaths include ifconfig !CONFIGURED { # Not configured, so don't process subdirs AutoSubDirs off # And don't process this file any further ifconfig false } } if {![file exists build.spec]} { puts "Note: I don't see build.spec. Try running: tmake --genie" } } |
> > | 1 2 | *.pt *.rk05 |
> | 1 | .agignore |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/env perl ######################################################################## # cc8-to-os8 - Filter C code meant for the CC8 cross-compiler so that it # will work with the OS/8 version of CC8. # # This is not meant to fix up 100% of the differences in the C # compilers, just the ones which prevent src/cc8/examples/*.c # from building under OS/8 CC8 as-is. # # You can run it like a filter: # # $ cc8-to-os8 < foo.c | txt2ptp > foo.pt # # Or you can just give it one or more file name(s), with output going # to stdout, which gives this way to hack around the lack of #include: # # $ cc8-to-os8 myheader.h foo.c > OS8FOO.C # # 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; my $nblines = 0; # number of non-blank lines written out while (<>) { if (m{^[a-zA-Z_][a-zA-Z0-9_]*\s*\(}) { # Looks like a function definition without a type; assume int. print "int $_"; ++$nblines; } elsif (!m{^\#include } and length and $nblines) { # Pass it through unchanged. print; } else { # Unlike the CC8 cross-compiler, the OS/8 version of CC8 doesn't # process #includes, or in fact any C preprocessor directives, # not even #asm. Strip just the #includes in the hope that it's # init.h or libc.h, the contents of which are hard-coded into # the OS/8 CC8 compiler. } } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/python # -*- coding: utf-8 -*- ######################################################################## # teco-pi-demo - Starts the simulator with the OS/8, sends one of the # famous TECO "calculate pi" program to it, and starts it running at # a very slow rate of speed to act as a blinkenlights demo. # # 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. ######################################################################## # Bring in just the basics so we can bring in our local modules import os import sys sys.path.insert (0, os.path.dirname (__file__) + '/../lib') sys.path.insert (0, os.getcwd () + '/lib') # Other core modules we need from datetime import datetime import time # Our local modules from pidp8i import * from simh import * #### main ############################################################## def main (): # Check for command line flags benchmark = len (sys.argv) > 1 and sys.argv[1] == '-b' # Create the SIMH child instance and tell it where to send log output try: s = simh (dirs.build) except (RuntimeError) as e: print "Could not start simulator: " + e.message + '!' exit (1) s.set_logfile (os.fdopen (sys.stdout.fileno (), 'w', 0)) # Find and boot the built OS/8 bin disk rk = os.path.join (dirs.os8mo, 'os8v3d-bin.rk05') if not os.path.isfile (rk): print "Could not find " + rk + "; OS/8 media not yet built?" exit (1) print "Booting " + rk + "..." s.send_cmd ("att rk0 " + rk) s.send_cmd ("boot rk0") # Start TECO8 in the simulator under OS/8 s.os8_send_cmd ('\\.', "R TECO") # The macro comes from http://www.iwriteiam.nl/HaPi_TECO_macro.html # # The 248 preceding "UN" in the first line of the macro is the number # of digits of pi to calculate. That value was reached by experiment # as the largest value that runs without crashing TECO with a # # ?MEM STORAGE CAPACITY EXCEEDED # # error. You can see that by increasing the value below, commenting # out the throttle setting below, and running the demo. On a Pi 3, it # should take a bit over an hour to complete, if it doesn't error out. # # With the simulator throttled, generating 248 digits takes 17 years! # # That is based on generating 1 digit every ~16 seconds on a Pi 3 when # running unthrottled, roughly 8 MIPS. When throttled to 59 IPS — or # 17ms per instruction, as below — you multiply the seconds by the # factor 8 MIPS / 59 IPS = ~136000, giving about 2.2 million seconds # per digit. Multiplying that by 248 gives ~17 years. macro = [ 'GZ0J\UNQN"E 248UN \' BUH BUV HK', 'QN< J BUQ QN*10/3UI', 'QI< \+2*10+(QQ*QI)UA B L K QI*2-1UJ QA/QJUQ', 'QA-(QQ*QJ)-2\ 10@I// -1%I >', 'QQ/10UT QH+QT+48UW QW-58"E 48UW %V \' QV"N QV^T \' QWUV QQ-(QT*10)UH >', 'QV^T @^A/', '/HKEX', ] # First and last lines are handled specially, so slice them off. first = macro.pop (0) last = macro.pop () # Send the first line of the macro; implicitly awaits 1st TECO prompt s.os8_send_cmd ('\*', first) # Blindly send core lines of the macro; TECO gives no prompts for 'em. for line in macro: s.os8_send_line (line) # Send last line of macro sans CR, followed by two Esc characters to # start it running. s.os8_send_str (last) # not os8_send_line! s.os8_send_ctrl ('[') s.os8_send_ctrl ('[') if benchmark: # Run demo long enough to get a good sense of the simulator's # execution rate while unthrottled on this host hardware. If # you don't run it long enough, the IPS value is untrustworthy. try: s.spin (10) except pexpect.TIMEOUT: # Find out how many IPS was executing s.os8_send_ctrl ('e') s.send_cmd ('show clocks') line = s.read_tail ('Execution Rate:') curr_ips = int (line.strip().replace(',', '').split(' ')[0]) pf = open ('lib/pidp8i/ips.py', 'a') pf.write ('current = ' + str (curr_ips) + ' # ' + \ str (datetime.today ()) + '\n') pf.close () s.send_cmd ('quit') pdp_ratio = float (curr_ips) / ips.pdp8i rpi_ratio = float (curr_ips) / ips.raspberry_pi_b_plus print "\nYour system is " + format (rpi_ratio, '.1f') + \ " times faster than a Raspberry Pi Model B+" print "or " + format (pdp_ratio, '.1f') + \ " times faster than a PDP-8/I.\n" else: # Normal mode. Pop out to SIMH and throttle it down to a rate # suitable for a blinkenlights demo. 1/17 means SIMH runs one # instruction then waits for 17ms, yielding ~59 IPS. time.sleep (0.02) # FIXME: simulator chokes on 'cont' without this s.os8_send_ctrl ('e') s.send_cmd ('set throttle 1/17') # You can't hit Ctrl-E while running this script in the foreground # since pexpect takes over stdio. Therefore, if you want to be able # to send commands to the simulator while the demo is running, # uncomment the line below, which will let you send commands to the # simulator via telnet. From another terminal or SSH session: # # $ telnet localhost 3141 # # or from a remote machine: # # $ telnet 192.168.1.2 3141 # # It's disabled by default because SIMH can't be made to listen only # on localhost, so doing this may be a security risk. SIMH disables # obviously-unsafe commands like ! on the remote console, but it is # possible some mischief may be possible via this path anyway. It # could be used to exfiltrate a sensitive file via ATTACH, for one # thing. For another, it's a potential DoS vector. #s.send_cmd ('set remote telnet=3141') # Let it run. Never exits. s.send_cmd ('cont') s.spin () if __name__ == "__main__": main() |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/python # -*- coding: utf-8 -*- ######################################################################## # Create a tu56 or rk05 image and fill it with ASCII files, i.e. source code. # # It is intended to be be called manually when we have a POSIX # directory full of ASCII files we want to bulk-copy into SIMH. # # The argument is taken both as the name of the image to create # and the list of files to copy in. # # For now, it takes all input and produces all output in the # current working directory. # # IMPORTANT: Currently all input files are mindlessly passed through # txt2ptp which transforms POSIX ASCII files to OS/8 ASCII files. # It WILL mutilate non-ASCII files. # # This program is based on cc8-tu56-update. # # Copyright © 2017 by Warren Young and Bill Cattey # # 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. ######################################################################## # Bring in just the basics so we can bring in our local modules import os import sys import argparse sys.path.insert (0, os.path.dirname (__file__) + '/../lib') sys.path.insert (0, os.getcwd () + '/lib') # Our local modules from pidp8i import * from simh import * # Other global Python modules import glob import subprocess #### GLOBALS AND CONSTANTS ############################################# progmsg = True #### main ############################################################## def main (): global progmsg # Set up the arg parser and use it to parse the command line. parser = argparse.ArgumentParser() parser.add_argument("name", help="Create an OS/8 image from a list of ASCII files.") group = parser.add_mutually_exclusive_group(required=True) group.add_argument("--tu56", "-t", action="store_true") group.add_argument("--rk05a", "-ra", action="store_true") group.add_argument("--rk05b", "-rb", action="store_true") args = parser.parse_args() print "Filename: " + args.name if args.tu56: sdev = "dt0" os8dev = "DTA0:" imagename = args.name + ".tu56" stat_str = "DECtape" if args.rk05a: sdev = "rk1" os8dev = "RKA1:" imagename = args.name + ".rk05" stat_str = "partition A of" if args.rk05b: sdev = "rk1" os8dev = "RKB1:" imagename = args.name + ".rk05" stat_str = "partition B of" listname = args.name + ".list" # Create the SIMH child instance and tell it where to send log output try: s = simh (dirs.build, True) except (RuntimeError) as e: print "Could not start simulator: " + e.message + '!' exit (1) s.set_logfile (os.fdopen (sys.stdout.fileno (), 'w', 0)) # Attach a clean version of the image to the simulator if os.path.exists (imagename): print "Overwriting old " + stat_str + " image " + imagename s.send_cmd ("att " + sdev + " " + imagename) # Find and boot the bootable OS/8 disk. Use the "patched" version # because that is what "make run" uses; we use that command to # inspect this script's work. rk = os.path.join (dirs.os8mo, 'os8v3d-patched.rk05') if not os.path.isfile (rk): print "Could not find " + rk + "; OS/8 media not yet built?" exit (1) print "Booting " + rk + "..." s.send_cmd ("att rk0 " + rk) s.send_cmd ("boot rk0") s.os8_send_cmd ('\\.', "ZERO " + os8dev) manifest = open (listname, "r") for line in manifest: src = line.strip() if src == "": continue if src[0] == '#': continue # Allow commenting out files dest = src.upper () s.os8_send_file (src, os8dev + dest) # Exit simulator nicely so that image detaches cleanly s.back_to_cmd ('\\.') s.send_cmd ("det " + sdev) s.send_cmd ('quit') if __name__ == "__main__": main() |
︙ | ︙ | |||
37 38 39 40 41 42 43 | @else ; The software was configured with --lowercase=upper, meaning the user ; wants lowercase text to be forced to uppercase. This is bidirectional, ; affecting both input to the simulated PDP-8 and output from it. set tti ksr @endif | | | 37 38 39 40 41 42 43 44 45 | @else ; The software was configured with --lowercase=upper, meaning the user ; wants lowercase text to be forced to uppercase. This is bidirectional, ; affecting both input to the simulated PDP-8 and output from it. set tti ksr @endif att rk0 @MEDIADIR@/os8/@OS8_BOOT_DISK@ boot rk0 |
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ; A stripped down version of 5.script with the throttle value set to a ; ratio between two values. Used primarily to test our handling of this ; throttle type. For example, we need to disable ILS at simulator ; start/continue time when this throttle type is used because it ; throws our timing logic way off. set throttle 30/1 set df disabled set cpu noidle echo Running reeeealy slow version of the AC/MQ blinker... dep 00000 2020 dep 00001 5000 dep 00002 7200 dep 00003 1021 dep 00004 7421 dep 00005 1021 dep 00006 7040 dep 00007 2021 dep 00010 7000 dep 00011 5000 dep 00020 0000 dep 00021 0000 go 00000 |
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ; Same as 0.script, only with RK0 attached to the *.rk05 file in the ; build directory, not the one in the installation directory. Used ; by "make run" so you don't have to "make mediainstall" first. ; reset echo Loading OS/8 from the RK05 cartridge disk in the build directory... set cpu 32k set cpu noidle set df disabled @SET_THROTTLE@ @if SIMH_PASS_LOWERCASE set tti 7b @else set tti ksr @endif att rk0 bin/@OS8_BOOT_DISK@ boot rk0 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # PiDP-8/I Software Release Process This documents the process for producing release versions of the software. ## *Can* You Release Yet? Before release, you must: * Fix all Immediate, High, and Medium priority [Bugs](/bugs) * Implement all Immediate and High priority [Features](/features) Or reclassify them, of course. Most of the bug levels simply aid scheduling: Immediate priority bugs should be fixed before High, etc. Low priority bugs are "someone should fix this someday" type of problems, so they can move from release to release. The Features levels may be read as: * **Immediate**: ASAP, or sooner. :) * **High**: Features for this release. * **Medium**: Features we'll look at lifting individually to High for the next release. * **Low**: "Wouldn't it be nice if..." ## Update SIMH If `tools/simh-update` hasn't been run recently, you might want to do that and re-test before publishing a new version. ## Publish OS/8 RK05s Re-configure the software with default settings, remove `bin/*.rk05`, rebuild, and run `tools/publish-os8` to send the "final" OS/8 disk images for this version of the software up to tangentsoft.com as unversioned assets. Update the date stamp in the "OS/8 RK05 Media" section of the project home page. ## 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 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # How to Control SIMH and OS/8 from Python ## Introduction While we were building the `libexec/mkos8` tool, we built up a set of functionality for driving SIMH and OS/8 running under SIMH from the outside using [Python][py], a very powerful programming language well suited to scripting tasks. It certainly beats writing PDP-8 code to achieve the same ends! When someone on the mailing list asked for a way to automatically drive a demo script he'd found online, it was natural to generalize the core functionality of `mkos8` as a reusable Python class, then write a script to make use of it. I called resulting demo script `teco-pi-demo` and the reusable bits `class simh`, which is now shared with `mkos8`. This document describes how `teco-pi-demo` works, and through it, how `class simh` works, with an eye toward teaching you how to reuse this functionality for your own ends. [py]: https://www.python.org/ ## Invocation Because we do not install these components in the system's Python library path, you must modify that path to allow your script to find these components. Simply copy this invocation block into the top of your script: import os import sys sys.path.insert (0, os.path.dirname (__file__) + '/../lib') sys.path.insert (0, os.getcwd () + '/lib') from pidp8i import * from simh import * That adjusts the path, then imports all of the generic functionality from the PiDP-8/I `lib` directory into the current namespace. We do not pull the `mkos8` components into `teco-pi-demo` because they are intended only to be used by `libexec/mkos8`. If you find something in the `lib/mkos8` directory that you think is widely useful, make a case for it on the mailing list, and we'll see about moving it to either the `simh` or `pidp8i` namespace. The `sys.path.insert` business assumes that your script is installed into the PiDP-8/I's `bin` directory alongside `teco-pi-demo`. If you've installed it somewhere else, you'll need to adjust these paths. ## Starting SIMH The first thing we'lld do is start SIMH as a child process of our Python script under control of an instance of `class simh`: s = simh (dirs.build) We call that instance `s` for short, because we will be calling its methods a lot in this script. We pass `dirs.build` to its constructor, which tells it how to find the `pidp8i-sim` program, which is a version of the PDP-8 simulator from the SIMH project, configured and modified for the needs of the PiDP-8/I project. We call this the child program, which is what `class simh` controls from the outside. (Currently, we don't have a way to make it use other versions of the SIMH `pdp8` simulator. Please send a patch if you do that.) The next step is to tell the `s` object where to send its logging output: s.set_logfile (os.fdopen (sys.stdout.fileno (), 'w', 0)) Contrast the corresponding line in `mkos8` which chooses whether to send logging output to the console or to a log file: s.set_logfile (open (dirs.log + 'mkos8-' + first_act + '.log', 'w') \ if progmsg else os.fdopen (sys.stdout.fileno (), 'w', 0)) ## Finding and Booting the OS/8 Media If your program will use our OS/8 boot disk, you can find it programmatically by using the `dirs.os8mo` constant, which means "OS/8 media output directory", where "output" refers to the worldview of `mkos8`. Contrast `dirs.os8mi`, which points to the directory holding the input media for `mkos8`. This snippet shows how to use it: rk = os.path.join (dirs.os8mo, 'os8v3d-bin.rk05') if not os.path.isfile (rk): print "Could not find " + rk + "; OS/8 media not yet built?" exit (1) Now we attach the RK05 disk image to the PiDP-8/I simulator found by the `simh` object and boot from it: print "Booting " + rk + "..." s.send_cmd ("att rk0 " + rk) s.send_cmd ("boot rk0") This shows one of the most-used methods in `class simh`, `send_cmd`, which sends a line of text along with a carriage return to the spawned child program, which again is `pidp8i-sim`. ## Driving SIMH and OS/8 After the simulator starts up, we want to wait for an OS/8 `.` prompt and then send the first OS/8 command to start our demo. We use the `simh.os8_send_cmd` method for that: s.os8_send_cmd ('\.', "R TECO") This method differs from `send_cmd` in a couple of key ways. First, it waits for a configurable prompt character — sent as the first parameter — before sending the command. This is critical when driving OS/8 because OS/8 lacks a keyboard input buffer, so if you send text to it too early, all or part of your input is likely to be lost, so your command won't work. Second, because OS/8 can only accept so many characters of input per second, `os8_send_cmd` inserts a small delay between each input character to prevent character losses. (See the commentary for `simh._kbd_delay` if you want to know how that delay value was calculated.) The bulk of `teco-pi-demo` consists of more calls to `simh.os8_send_cmd` and `simh.send_cmd`. Read the script if you want more examples. Notice that we escape the OS/8 `.` command prompt in the first parameter because `class simh` treats it as a [regular expression][re], and a `.` in REs means "any character," which we definitely do *not* want to match on! If we did not escape this special RE character with a backslash, `class simh` would send the command when the first character from the running OS/8 instance came through, likely causing some or all of the command to be lost by the time OS/8 is ready to accept input. [re]: https://en.wikipedia.org/wiki/Regular_expression ## Escaping OS/8 to SIMH Sometimes you need to escape from OS/8 back to SIMH with a <kbd>Ctrl-E</kbd> keystroke so that you can send more SIMH commands after OS/8 starts up. This accomplishes that: s.os8_send_ctrl ('e') While out in the SIMH context, you *could* continue to call the `simh.os8_*` methods, but since SIMH can accept input as fast as your program can give it, it is best to use methods like `simh.send_cmd` which don't insert artificial delays. For many programs, this difference won't matter, but it results in a major speed improvement in a program like `mkos8` which sends many SIMH and OS/8 commands back-to-back! ## Getting Back to OS/8 from SIMH There are several ways to get back to the simulated OS/8 environment from SIMH context, each with different tradeoffs. ### Rebooting You saw the first one above: send a `boot rk0` command to SIMH. This restarts OS/8 entirely. This is good if you need a clean environment. If you need to save state between one run of OS/8 and the next, save it to the RK05 disk pack or other SIMH media, then re-load it when OS/8 reboots. ### Continuing The way `teco-pi-demo` does it is to send a `cont` command to SIMH. The problem with this method is that it sometimes hangs the simulator. The solution is to insert a small delay *before* escaping to the SIMH context. I'm not sure why this is sometimes necessary. My best guess is required to give OS/8 time to settle into an interruptible state before escaping to SIMH, so that on "continue," we re-enter OS/8 in a sane state. You can usually avoid the need for that delay by waiting for an OS/8 command prompt before escaping to SIMH, since that is a reliable indicator that OS/8 is in such an interruptible state. You don't see these anomalies when using OS/8 interactively because humans aren't fast enough to type commands at OS/8 fast enough to cause the problem. That is doubtless why there this bug still exists in OS/8 in 2017. ### Re-Entering If your use of OS/8 is such that all required state is saved to disk before re-entering OS/8, you can call the `simh.os8_restart` method to avoid the need for a delay *or* a reboot. It re-calls OS/8's entry point from SIMH context, which we've found through much testing is entirely reliable, as compared to sending a SIMH `cont` command without having delayed before escaping to SIMH context. `mkos8` uses this option extensively. ## Sending Escape Characters Several OS/8 programs expect an <kbd>Escape</kbd> (a.k.a. `ALTMODE`) keystroke to do things. Examples are `TECO` and `FRTS`. There isn't a specific method to do this because we can do that in terms of one we've just described: s.os8_send_ctrl ('[') Yes, <kbd>Escape</kbd> is <kbd>Ctrl-\[</kbd>. Now you can be the life of the party with that bit of trivia up your sleeve. Or maybe you go to better parties than I do. ## But There's More! The above introduced you to most of the functionality of `class simh` used by `teco-pi-demo`, but there's more to the class than that, primarily because the `mkos8` script's needs are broader. Rather than just recapitulate the class documentation here, please read through [the class's source code][ssc], paying particular attention to the method comments. It's a pretty simple class, making it a quick read. Another useful module is [`pidp8i.dirs`][dsc] which contains paths to many directories in the PiDP-8/I system, which you can reuse to avoid having to hard-code their locations. This not only makes your script independent of the installation location, which is configurable at build time via `./configure --prefix=/some/path`, but also allows it to run correctly from the PiDP-8/I software's build directory, which has a somewhat different directory structure from the installation tree. [ssc]: https://tangentsoft.com/pidp8i/file/lib/simh.py [dsc]: https://tangentsoft.com/pidp8i/file/lib/pidp8i/dirs.py ## <a id="license" name="credits"></a>Credits and License Written by and copyright © 2017 by Warren Young. Licensed under the terms of [the SIMH license][sl]. [sl]: https://tangentsoft.com/pidp8i/doc/trunk/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 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 | # DCP Disassembler for PDP-8 This document is based on the file DCP.WU found with DCP binaries. | Author | A.E. Brouwer, Math. Center, Amsterdam | | Date | 73-10-03 | | Version Number | DCP AB-V21 | | Last Update | 74-11-12 | | Environment | OS/8 operating system | | Memory Requirements | 16K, Optional 24K mode | ## DCP (Preliminary Description) DCP (sometimes called `deass`) is a program to deassemble (or disassemble) a PAL program given in binary or in core image format as 1st input file. Information about the program and meaningful tags can be given in a second input file. A well readable listing with meaningful tags but without comment can be obtained in a few passes (typically four). The first time no information is supplied; while reading the output one recognizes certain parts as messages ("NO ROOM FOR OUTPUT") or numeric tables (6030,7634,7766,7777) or simple subroutines (TTYOUT, PUSH, PRINT). Putting these things in an information file and then running dcp again gives you a much nicer output the second time. Now you may embark on the program itself and obtain after a small number of passes (depending on the complexity of the program and your laziness.) A source that might have been the original one except for its lack of comment. At this moment you could profitably use the CTRL/E feature of MCEDIT to provide the whole source of comment. (For example, we obtained a source of a fortran compiler in three days after five passes.) Below we will describe the OS/8 version of the program ## Assembly Instructions (Alas, we do not yet have source.) .R PAL8 *102,DCP_SBIN,DCPZ/L$ .SAVE SYS DCP ## Operating Instructions .R DCP *OUTPUT<INPUT,INFO(OPTIONS) ## Command Line Interpretation 1. If no input and no output specified then delete <kbd>DSK:DCPLS.TM<kbd> If command closed with altmode then exit to OS/8 monitor else call command decoder again. 2. If no output given but an output file is required because chaining to CREF.SV is requested then DSK:DCPLS.TM is used. 3. If no input given then use output filename with extensions .SV and .SM (if present.) E.G. *DEASS< is equivalent to *DEASS<DEASS.V if DEASS.SM does not exist, and to *DEASS<DEASS.SV,DEASS.SM otherwise. In this case a previous version of the output file is deleted first (if necessary). 4. If the output file has no explicit extension then add .DC if a source is produced, and .LS otherwise (One would expect .PA instead of .DC but that proved dangerous.) ## Options Affecting Interpretation of Command Line | /B | Expect .BN rather than .SV format in first inputfile | | | This changes the default extension into .BN if no | | | input is specified. | | /L | Produce .LS rather than .DC output | | /X | Chain to CREF.SV | | | (1st output becomes input and 2nd output becomes output) | | | This option implies the options /L and /T | e.g. .R DCP *DEASS,TTY:</X/B is equivalent to .R PIP *DEASS.LS</D$ .R DCP *DEASS.LS<DEASS.BN,DEASS.SM/L/T/B .R CREF *TTY:<DEASS.LS also DCP * *DEAS.SV,SPECS1,SPECS2,SPECS3/S means .R PIP *DEASS.TM</D$ .R DCP *DCPLS.TM<DEASS.SV,SPECS1,SPECS2,SPECS3/L/T .R CREF *DCPLS.TM ## Options | /A | Do not generate a 'START' label. | | (By default a label 'START' is generated when decoding | | core image file. This is possible since the core control | | contains the starting address.) | /B | Expect .BN instead of .SV input. | /C | The info file after the output | /D | 'JMP .-3', 'JMP I .+1' instructions | | for each reference a tag is generated) | /H | Do not generate literals. | /K | allow modification of literals. | | (Normally an instruction like 1377 will be translated as | | 'TAD (1234' but 2377 as 'ISZ A177' since no decent programmer | | ever writes 'ISZ (1234'. It was found however that several | | DEC programs contain such constructs.) | /L | Produce output in .LS format. | /N | Do not generate table of undefined symbols. | /S | Generate table of all symbols. | /T | Convert tabs into spaces. | /W | Do not interpret 6141 as the PDP12 'LINC' instruction. | /X | Chain to CREF.SV. | /(F) | (Where F designates a digit between 0 and 7.) | | Translate field F of the program (default: /0) | =NNNNMMMM | The = OPTION can be used to specify a part of the program to be decoded. NNN gives begin and MMMM end+1 of the range. (Note that if begin>3777 the command has to be closed with altmode instead of return.) ## Translation Is Done One Field at A Time Therefore, binaries that load into extended memory must be disassembled with /(F) for all memory fields used. This causes some flaws in the output: CIF 10 JMS I (200 is translated as: CIF 10 JMS I (START If LOC 200 in the current field is labeled START. Note that assembling the produced source gives the correct binary.) ## Input Format Each input section starts with $X (where X is a letter indicating the type of the section) and ends with $ . $\<CR\> indicates the end of all input (when not within a secion). Between the sections comment not containing $ may be inserted. ### Section Types | $A | Translate as 6bit ASCII (TEXT "STRING") | $D | Dont translate | $I | Translate as instruction (overriding other specs) | $L | Translate as identifier rather than as instruction | $N | Translate octal | $S | Subroutine with args | $T | Symbol definitions | $Z | Special coding | $ | End of input ### Content of Section 1. Sections $X where X is A,D,I,L or N. Contents: Lines of the form: MMMM-NNNN or NNNN Where NNNN and MMMM are octal addresses. e.g. the section: $N 1717-1730 1750 $ specifies that the locations 1717-1730 and 1750 are to be translated as octal numbers. 2. Sections $S. Contents: Lines of the form: SSSS:XXXXX Where SSSS is a subroutine address and XXXXX specifies the kind of arguments the subroutine has. e.g. the section: $S 1000:NL $ indicates that each call to the subroutine at LOC 1000 has two arguments of type octal and label respectively. 3. Sections $T. Contents: Lines of the form: TAG=NNNN or TAG Meaning: If no octal value of a tag is specified then its value is taken as one more than the value of the previous tag. 4. Section $Z. This is an ad hoc construct to enable the translation of symbol tables like those of PAL8 and CREF. e.g. $Z=52;0=240;1=301;40=260 NNNN-MMMM:(UUUL) $ indicates that the range NNNN-MMMM is a table of four-word entries three words in a special format and one label. The special format is as follows: The value is divided by 52 giving a quotient and a remainder. Both are converted into a character as follows: 0 gives a space, 1-37 give letters A-_, and 40-51 give digits 0-9. The coding here is not foolproof yet: A strange command might give strange output instead of an error message. In later versions this command will be generalized, so we don't describe it in full here. ## Error Messages These are very poor (because of lack of space): HLTNNNN, where NNNN indicates the address of the routine in DCP that detected the error. Errors are almost always violations of the input format. A complete list will appear in the final report. | Name | DCP (ERROR TABLE) | Author | A.E. Brouwer | Date | 75-02-13 As noted: The error messages of DCP look like 'HLT....' where .... stands for the octal address of the routine that detected the error. (Of course giving intelligible messages is highly desirable but lack of space prevented this. Some future version of DCP will chain to a file `DECPERR.SV` containing the messages.) Below the error numbers are given for DCP AB-V21. [Note: These numbers may change slightly each time that DCP is assembled anew.] ### DCP16 Error Table | Number | ERROR | ------ | -------------------------------------------------------------| | 0000 | PREMATURE END OF .BN INPUT | | 0230 | CLOSE ERROR | | 0301 | LOOKUP FOR SYS:CREV.SV FAILED | | 1414 | OUTPUT ERROR OR NO ROOM FOR OUTPUT | | 1451 | INPUT ERROR (INFO FILE) | | 1522 | NO CARRIAGE RETURN WHERE EXPECTED IN THE INFO FILE | | 1755 | UPPER BOUND IN BOUND PAIR LESS THAN LOWER BOUND | | 2031 | ASCII STRING CONTAINED A SIXBIT ZERO, BUT NOT AT THE END | | | (I.E. A WORD 00XX). (THIS MIGHT HAVE BEEN AN @, | | | BUT IS USUALLY AN ERROR.) | | 2046 | ASCII STRING WITHOUT TRAILING ZERO | | 2061 | DCP COULD NOT FIND A SUITABLE DELIMITER FOR THE ASCII STRING | | | IN THE RANGE "" TO "? | | 2125 | IMPOSSIBLE | | 2214 | TEXT BUFFER OVERFLOW (TOO MANY OR TOO LONG IDENTIFIERS). | | 2234 | NO IDENTIFIER WHERE EXPECTED (IN A $T SECTION). | | 2666 | ZERO SUBROUTINE ADDRESS SPECIFIED IN A $S SECTION | | 2705 | S-BUFFER OVERFLOW (TOO MANY SUBROUTINES WITH ARGS.) | | 2761 | UNKNOWN TYPE LETTER IN SPECIFICATION OF SUBROUTINE ARGS | | 3006 | $Z NO FOLLOWED BY = | | 3011 | $Z= NOT FOLLOWED BY A NONZERO NUMBER | | 3022 | NO CARRIAGE RETURN OR SEMICOLON WHERE EXPECTED IN $Z HEADER | | 3030 | NO = WHERE EXPECTED IN $Z HEADER LINE | | 3041 | ZERO LOWER BOUND IN BOUND PAIR IN $Z SECTION | | 3064 | Z-BUFFER OVERFLOW | | 3117 | PREMATURELY EXHAUSTED Z-FORMAT | | 3135 | UNKNOWN Z-FORMAT SYMBOL | | 3470 | T-BUFFER OVERFLOW | | 3723 | NO VALUE ASSIGNED TO FIRST TAG IN $T SECTION | | 4213 | NO INPUT AND NO OUTPUT AND NO DSK:DCPLS.TM TO DELETE | | 4245 | HANDLER FETCH ERROR | | 4341 | LOOKUP FOR INPUTFILE FAILED | | 4442 | OUTPUT OPEN ERROR | | 4456 | NO 16K MEMORY AVAILABLE | | 4470 | CHECKSUM OR FORMAT ERROR IN BINARY INPUT FILE | | 4613 | FORMAT ERROR IN CORE CONTROL BLOCK OF .SV INPUT FILE | | 4647 | ERROR READING CORE CONTROL BLOCK OF .SV INPUT | | 4723 | ERROR READING .SV INPUT FILE | ## DCP24 DCP Version 24 is a 24K version of DCP. | Name | DCP-AB-WW-V24 | Author | W.F. Wakker, Math. Center, Amsterdam | Date | 76-03-25 ### The Following Extensions Are Made - DCP24 Translates EAE instructions in both A and B mode (For mode switching, see below.) Example: 1200 DAD;1234 is translated as if the info-file contains the following info: $I 1200 $ $L 1201 $ $N 1234+ $ - In the info-file one can give : NNNN+ which has the same effect as NNNN-MMMM where MMMM=NNNN+1. - Several buffers have been enlarged. - The output is paginated and has a heading on each page. (The page number is in octal ....) - Error messages are unfortunately as poor as before (See DCP24 error table). - New sections, now possible in the info-file are: | $B | TRANSLATE AS 8-BIT ASCII | | $C | GIVE COMMENT | | $E | FORCE EAE MODE A | | $F | FORCE EAE MODE B | | $M | TRANSLATE NEGATIVE | - Section $B $B NNNN-MMMM $ Causes the location NNNN-MMMM to be translated as 8-bit ASCII, E.G. 0301 is translated as "A. Values less then 241 are translated as octal numbers. - Sections $E and $F When DCP encounters EAE instructions, some slight heuristics are done to determine the mode. The mode is initially A; SWAB, DAD, and DST cause the mode to change to mode B etc. When these heuristics are too poor, you can use the $E section to force mode A and the $F section to force mode B. - Section $M This section has the same effect as section $N, only all octals are given negative, E.G. 7770 becomes -10. It is also possible to give $B and $M to the same LOC. Example: 7477 is now translated as -"A. - Section $C Now you can give comment!! | Format | NNNN:THIS IS COMMENT | Effect | NNNN ........ /THIS IS COMMENT | Attention | The $C section must be the last one in the info-file: When $C is seen in the info-file, a setup is made to give the comment and no more input will be read ( E.G. The program acts like $$ on the end is seen). The comments are added to the listing in the last pass of the program. __YOU MUST SORT THE ADDRESSES.__ 300:COMM1 200:COMM2 Has as effect that from adress 300 on, no more comment will be given, since address 200 is not found any more. __DO NOT GIVE COMMENT ON ADDRESSES WHICH DO NOT BELONG TO THE PROGRAM__ - Extension of $S section As arguments in the $S section you can give N, L, A, I, B, M, (with the obvious meaning, see above ) and also U. U should only be used for the addresses 200 and 7700. It marks the entrypoint of the user service routine and gives a nice translation of each USR call. - Extension of $Z section New possible arguments: M, B. ### DCP-V24 (ERROR TABLE) | Number | ERROR | ------ | -------------------------------------------------------------| | 0000 | PREMATURE END OF .BN INPUT | | 0237 | CLOSE ERROR | | 0305 | LOOKUP FOR SYS:CREF.SV FAILED | | 1414 | OUTPUT ERROR OR NO ROOM FOR OUTPUT | | 1511 | NO CARRIAGE RETURN WHERE EXPECTED IN THE INFO FILE | | 1707 | NO : AS SEPARATOR IN $C SECTION | | 2145 | UPPER BOUND IN BOUND PAIR LESS THAN LOWER BOUND | | 2235 | NO : AS SEPARATOR IN FIRST LINE OF $C SECTION | | 2331 | INPUT ERROR (INFO FILE) | | 2431 | ASCII STRING CONTAINED A SIXBIT ZERO, BUT NO AT THE END | | | (I.E. A WORD 00XX). (THIS MIGHT HAVE BEEN AN @, | | | BUT IS USUALLY AN ERROR.) | | 2446 | ASCII STRING WITHOUT TRAILING ZERO | | 2461 | DCP COULD NOT FIND A SUITABLE DELIMITER FOR THE ASCII STRING | | | IN THE RANGE "" TO "? | | 2525 | IMPOSSIBLE | | 2614 | TEXT BUFFER OVERFLOW (TOO MANY OR TOO LONG IDENTIFIERS) | | 2634 | NO IDENTIFIER WHERE EXPECTED (IN A $T SECTION) | | 3266 | ZERO SUBROUTINE ADDRESS SPECIFIED IN A $S SECTION | | 3305 | S-BUFFER OVERFLOW (TOO MANY SUBROUTINES WITH ARGS) | | 3367 | UNKNOWN TYPE LETTER IN SPECIFICATION OF SUBROUTINE ARGS | | 3406 | $Z NOT FOLLOWED BY = | | 3411 | $Z= NOT FOLLOWED BY A NONZERO NUMBER | | 3422 | NO CARRIAGE RETURN OR SEMICOLON WHERE EXPECTED IN $Z HEADER | | 3430 | NO = WHERE EXPECTED IN $Z HEADER LINE | | 3441 | ZERO LOWER BOUND IN BOUND PAIR IN $Z SECTION | | 3463 | Z-BUFFER OVERFLOW | | 3517 | PREMATURELY EXHAUSTED Z-FORMAT | | 3541 | UNKNOWN Z-FORMAT SYMBOL | | 4070 | T-BUFFER OVERFLOW | | 4324 | NO VALUE ASSIGNED TO FIRST TAG IN $T SECTION | |
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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() |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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> |
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # OS/8 FORTRAN IV OS/8 `FORTRAN IV` is extensively documented: * Chapter 8 of the [1974 OS/8 Handbook][os8h1974] (large file!). * Section 2 of the [OS/8 Language Reference Manual AA-H609A-TA][os8lang]. * The [OS/8 Fortran IV Software Support Manual DEC-S8-LFSSA-A-D][os8f4suppt] This file serves more as a quick guide to what has been gathered to this repository as far as distribution DECtapes, and patches are concerned. The [1979 OS/8 Software Components Catalog][os8cat] provides an inventory of and part numbers for the OS/8 V3D binary and source distribution DECtapes. Images of these DECtapes are all found in media/os8/subsys as follows: | DEC Part | Filename | Description | | ----------- | ------------------------------- | ----------------- | | AL-4549D-BA | al-4549d-ba-fr4-v3d-1.1978.tu56 | Binary DECtape #1 | | AL-5596D-BA | al-5596d-ba-fr4-v3d-2.1978.tu56 | Binary DECtape #2 | | AL-4545D-SA | al-4545d-sa-fr4-v3d-1.tu56 | Source DECtape #1 | | AL-4546D-SA | al-4546d-sa-fr4-v3d-2.tu56 | Source DECtape #2 | | AL-4547D-SA | al-4547d-sa-fr4-v3d-3.tu56 | Source DECtape #3 | When with-os8-fortran-iv is enabled (which is the default), the contents of Binary DECtape #1 are installed on the OS/8 RK05 images built by `mkos8`. Binary DECtape #2 contains the `.RA` sources for the components of the FORTRAN IV library. Those files are already assembled and archived in `FORLIB.RL` and installed from Binary DECtape #1. The three source DECtapes contain the buildable source code for the rest of OS/8 FORTRAN IV system. Build instructions are found in Appendix B of the _OS/8 Fortran IV Software Support Manual_. If with-os8-patches is configured, the `os8v3d-patched.rk05` image will contain the following patches: * `F4 21.1.2 M` Fix for the `EQUIVALENCE` statement that brings `F4.SV` and `PASS3.SV` up to version 4B. * `F4 51.3.1 M` Enable recognition of `"` as an incorrect character in a subroutine call argument that brings `F4.SV` up to version 4C. * `F4 51.3.2 M` Enable recognition of syntax errors in type declarations. * `FORLIB 51.10.1 M` Updates `FORLIB.RL` to contain an corrected `DLOG` function that will correctly handle numbers smaller than `1.1-018`. There is one more patch available, `FRTS 51.3.3 O`, an optional patch that enables the FORTRAN IV runtime system to accommodate 2 page system handlers in addition to the TD8E handler. This patch has not yet been verified. FORTRAN IV on the system packs should work. The sources are available in the tree in the files named above. Enjoy! [os8h1974]: http://bitsavers.trailing-edge.com/pdf/dec/pdp8/os8/OS8_Handbook_Apr1974.pdf [os8lang]: http://bitsavers.trailing-edge.com/pdf/dec/pdp8/os8/AA-H609A-TA_OS8_Language_Reference_Manual_Mar79.pdf [os8f4suppt]: http://bitsavers.trailing-edge.com/pdf/dec/pdp8/os8/DEC-S8-LFSSA-A-D_F4swSupp.pdf [os8cat]: https://ia601002.us.archive.org/8/items/bitsavers_decpdp8sofoftwareComponentsCatalogJul79_7798622/AV-0872E-TA_PDP-8_Software_Components_Catalog_Jul79.pdf ### <a id="license"></a>License Copyright © 2017 by Bill Cattey. Licensed under the terms of [the SIMH license][sl]. [sl]: https://tangentsoft.com/pidp8i/doc/trunk/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 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 | # OS/8 `MACREL` `MACREL`, the MAcro RELocating assembler, was a late development. It was an attempt to replace `PAL8` with a Macro assembler capable of producing relocatable modules. When `MACREL` first came on the scene, several companies decided to port their next major upgrade to `MACREL` from `PAL8`. `MACREL` was so buggy that everybody basically had to revert to `PAL8` and back-port all the new code originally intended for the new major upgrade. This situation befell ETOS Version 5. We have a binary distribution DECtape image of `MACREL` version 1, DEC part number `AL-5642A-BA`. Unfortunately the version numbers of the patches did not match what was shown in the binaries. With the `MACREL` V1 patches, I wanted to do more research before recommending application of the patches. In the course of that research, I discovered that all the archived manuals to be found online were for `MACREL` v2. See: [Willem van der Mark's PDP-8 Manuals archive][vandermarkman] for: * [OS/8 MACREL/LINK -- Software Support -- Version 2C -- September 1980 AA-J7073-TA][maclinkss] * [OS/8 MACREL/LINK -- User Manual -- Version 2D -- January 1979 AA-5664B-TA][maclinkuser] Or see the [PDP8 doc tree on ftp.dbit com][dbitdocs] for: * [maclkssm.doc -- OS/8 MACREL/LINK V2 Software Support Manual][dbitmacssm] * [maclnkum.doc -- OS/8 MACREL/LINK V2 User's Manual.][dbitmacuser] * [macrelrn.doc -- OS/8 MACREL/LINK V2 Release Notes][dbitmacrel] Version 2 was the clearly better baseline. I didn't hold out much hope to find binary and source distributions of `MACREL` v2. (DEC Part numbers `AL-5642B-BA` for the binary DECtape and the 4 source DECtapes, `AL-5643B-SA`, `AL-5644B-SA`, `AL-H602B-SA`, and `AL-H602B-SA`.) Very recently we found a complete set of `MACREL` version 2 binaries as part of a buildable RTS-8 Archive at [ibiblio.org ... pdp-8/rts8/v3/release][rts8rel] We found a source distribution of `MACREL` v2 in Dave Gesswein's [misc_floppy][dgfloppy] archive. Part one is flagged as having errors, but another obscure site had a mis-labeled archive of this same stuff so we may be ok. The `MACREL` v2 source would not build under `MACREL` v1, but now we have `MACREL` v2 and initial tests look promising. Baseline `MACREL` v2 will be integrated into the system packs. Because we didn't have `MACREL` v2, no work was done to create patch files, or to validate them. With both source and binary for `MACREL` v2 now in hand, this work can proceed. The plan is to fetch the patches, validate them, and install all mandatory patches that can be verified. The current integration of `MACREL` v2 includes a hand-applied patch to `FUTIL`. We want the latest version of `FUTIL` because it contains new code handles extended memory and certain `MACREL` data structures. However version 8A of `FUTIL` shipped on the `MACREL` v2 tape had a bug that causes it to *hang* when run under `BATCH`. Patch `35.13.1M` fixes this problem and upgrades `FUTIL` to version 8B. This patch was applied by hand tested, and grouped with what we integrate onto the system packs when we add `MACREL`. To reduce uncertainty around the operation of `OVRDRV.MA`, Source patch `41.5.1M` has been applied by hand to `OVRDRV.MA`. See also: [our documentaiton on the OS/8 Patching][os8patches] [vandermarkman]: http://vandermark.ch/pdp8/index.php?n=PDP8.Manuals [maclinkss]: http://vandermark.ch/pdp8/uploads/PDP8/PDP8.Manuals/AA-J073A-TA.txt [maclinkuser]: http://vandermark.ch/pdp8/uploads/PDP8/PDP8.Manuals/AA-5664B-TA.txt [dbitdocs]: ftp://ftp.dbit.com/pub/pdp8/doc/ [dbitmacssm]: ftp://ftp.dbit.com/pub/pdp8/doc/maclkssm.doc [dbitmacuser]: ftp://ftp.dbit.com/pub/pdp8/doc/maclnkum.doc [dbitmacrel]: ftp://ftp.dbit.com/pub/pdp8/doc/macrelrn.doc [rts8rel]: http://www.ibiblio.org/pub/academic/computer-science/history/pdp-8/rts8/v3/release [dgfloppy]: http://www.pdp8online.com/images/images/misc_floppy.shtml [os8patches]: https://tangentsoft.com/pidp8i/doc/trunk/doc/os8-patching.md ### <a id="license"></a>License Copyright © 2017 by Bill Cattey. Licensed under the terms of [the SIMH license][sl]. [sl]: https://tangentsoft.com/pidp8i/doc/trunk/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 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 | # OS/8 System Patches Between major updates to distribution media, DEC would send out important information and patches to customers through its publication _PDP-8 Digital Software News_ (_DSN_ for short). Many issues of _DSN_ can be found on bitsavers.org under [pdf/dec/pdp8/softwarenews][dsn]. To help customers keep track of which patches to apply, _DSN_ added a Cumulative Index. Using the _PDP-8 DIGITAL Software News Cumulative Index_ found in the latest available issue of _DSN_, [October/November 1980][dsn8010], I created a spreadsheet of all patches relevant to the OS/8 V3D packs under construction. That spreadsheet enabled me to go to the particular issues containing the patches, and keep track of what action I took with them. I reviewed all the patches and came up with a list of the mandatory patches. Using OCR'd text from each relevant _DSN_ issue, I created a file per patch, which I then compared to the scanned PDF and corrected the OCR errors. Then I enhanced our `mkos8` script to apply the patches in an automated way. Most of the patches were for programs available in source form, so I built the programs from source, and then bench checked the patch against the source. In a few cases the code was too obscure, and I marked the patch as "plausable" rather than "verified" in my spreadsheet. The file [patch_list.txt][pl] lists all of the patch files in `media/os8/patches`. Comments in that file begin with `#` and are used to disable patches we have rejected for one reason or another. Each rejected patch also has a comment that explains why that particular patch was rejected from the default set. Typical reasons are: * The patch requires hardware our simulator doesn't have. * The patch conflicts with another patch we deem more important. * The patch changes some behavior, and we prefer that the unpatched behavior be the default. You may want to examine this file to see if there are any decisions you would reverse. After modifying that file, say "`make`" to rebuild the OS/8 binary RK05 disk image file with your choice of patches. You can disable all of these OS/8 patches by giving the `--disable-os8-patches` option to the `configure` script. [dsn]: http://bitsavers.org/pdf/dec/pdp8/softwarenews/ [dsn8010]: http://bitsavers.org/pdf/dec/pdp8/softwarenews/198010_PDP8swNews_AA-K629A-BA.pdf [pl]: https://tangentsoft.com/pidp8i/doc/trunk/media/os8/patches/patch_list.txt ## Review of Recommendations `BRTS 31.11.2O` is an optional patch which disables 8th bit parity. It is recommended because sometimes we may want to allow output that does not force the 8th bit. `BRTS 31.11.3O` is an optional patch that enables 132 column output. It is recommended because it is expected that wide column output is desirable. `TECO 31.20.1O` is an optional patch that permanently forces no case flagging. It is not recommended because we want to allow the option of case flagging. `TECO 31.20.2O` is an optional patch that turns off verbose errors. It was for slow terminals and experienced users who didn't want to wait to see the long error messages they already knew. It is not recommended because we expect a majority of users to be on high speed terminals needing the verbose errors. `TECO 31.20.3O` turns off a warning that you are using the `YANK` command to completely overwrite a buffer full of text. Issuing the command a second time succeeds. It was again to avoid experienced users. It is not recommended because we expect fewer advanced users who would be annoyed by the protection. `TECO 31.20.4O` implements rubout support specifically and uniquely for the `VT05` terminal in a way that breaks it for all other video terminals. It is not recommended because there are VERY few `VT05` deployments that would use it. It is at this point that I began to notice that in later years, patches became less carefully produced, and more prone to errors. Some are not correctable, even today. `BASIC.UF-31.5.1M` shows: 4044/4514 4556 changing location `4044` from `4514` to `4556`. Such a change would be consistent with the stated purpose of the patch, to correct references to page zero literals that moved with the `V3D` version of `BRTS`. The source around location '4044' looks like this: 04043 4775 JMS I (BUFCDF /SET UP USER BUF 04044 1273 TAD NSAM 04045 7041 CIA 04046 3276 DCA NCTR /-#OF BOARDS TO CLAR In my judgment the `TAD NSAM` to get the subscript into the `AC` should be retained, and the `4556` call to `UNSFIX` to truncate the value of the Floating Point Accumulator should NOT be inserted. I modified the patch to leave out that change. It remains to be seen if calls to User Functions in OS/8 `BASIC` will ever be run to test this code. Here at least is an analysis to later explorers. `EDIT 21.17.4 M` is supposedly a mandatory patch. It fixes a problem with line printer output through a specific parall interface card. Unfortunately, the patch overwrites mandatory patch in 21.17.2 and is NOT recommended. `ABSLDR 21.29.1 M` is supposedly a mandatory patch that enables `ABSLDR` to work with `SAVE` image files. Normally `ABSLDR` only loads `BIN` format files. The patch sequence number, `21.29` identifies the patch as being for the OS/8 V3D version of `ABSLDR`. But the patch changes locations that are not used by `ABSLDR.SV`. Furthermore, the patch says it upgrades `ABSLDR` from version 6B to version 6C. Version 6 of `ABSLDR` was part of the OS/8 V3D Device Extensions kit. See [our documention on the OS/8 V3D Device Extensions][os8ext]. Verification of this now seems within reach, with the expectation that it is mis-labeled, and is properly applied to the version with the Extensions kit. Until it is verified, applying this patch is *not* recommended. `PAL8-21.22.4M` is broken and doubly mis-labeled. Mis-label #1: It is an optional, not mandatory patch. Mis-label #2: It is for product sequence `35.14`, the `V13` codeline of `PAL-8` that, like `ABSLDR V6`, is in the Device Extensions kit. The breakage: Source listing quits working. *Do not apply this patch!* Patch `FRTS-51.3.3-O.patch8` is to enable 2-page system drivers like `RL01`. Except that the `RL01` driver is only available in the Extensions kit. The patch overwrites existing code that makes `FRTS` able to function with the `TD8E` 2-page system handler. I've read the code but don't fully understand it. Perhaps it generalizes the `TD8E` support. But if you happen to be using this setup under `TD8E` and `FRTS` doesn't work, then back out this patch. ## Patch Application Order The `patch` routine in `mkos8` applies the patches in the order they appear in `patch_list.txt`. That list is currently in alphabetical order. However, there may in future emerge patches that impose an order. For example, if the `ABSLDR` patch actually did work, it needs the `FUTIL 31.21.2 M` in order to patch into the `ABSLDR` overlay bits. I was skeptical of `FUTIL 31.21.2M` because, when I load `ABSLDR.SV` into core with GET, the contents of memory showed by `ODT` are *DIFFERENT* from those shown by `FUTIL`. With deeper understanding of the OS/8 Device Extensions kit, I see that the patch was incorporated into the version 8 `FUTIL` source, and also that `ODT` is expected to be updated in version 3S of the Keyboard Monitor. ## Then There's `MACREL` I've gone into detail on the explorations and understandings with regard to `MACREL` in a [sister document to this one][macreldoc]. Originally I reviewed the patches for `MACREL` v1, because that's all we had. But the version numbers of the patches did not match the version numbers of the executables. A little diversion into the guess work surrounding patch verification: Version number mismatches sometimes do occur with patches. For example, `TECO 31.20.11 M` says that it upgrades `TECO` to version `5.06`, but got the bits wrong. Instead of changing contents from `0771` to `0772`, it looked to change from `0772` to `0773`. `772` octal is `506` decimal, and the `TECO` version number is represented with a 12 bit number. It's called "5.06" but it's represented as `0772` octal, or `506` decimal. With that TECO patch, I simply changed the version amendment line in that `TECO` patch, because the rest was correct. Whoever published the patch got the version number wrong, and nobody complained. With no `MACREL` v1 source verification was not really possible, so applying those patches was postponed. But then we found both binary and source of `MACREL` v2! In the interests of shipping out system packs in finite time, we will integrate `MACREL` v2 into the system packs, and verify/apply `MACREL` v2 patches as follow-on work. After further testing of 'MACREL' I have concluded that integrating the source-level patch `41.5.1M` will reduce uncertainty. So I have hand-integrated that patch into the `MACREL` tu56 image as well. [macreldoc]:https://tangentsoft.com/pidp8i/doc/trunk/doc/os8-macrel.md ## `FUTIL`: I was dubious of some of the `FUTIL` patches, but with finding source to version 8A, I gained confidence in the version 7 patches, and understood how seriously important the first patch was to version 8. The `MACREL` v2 tape shipped with version 8A of `FUTIL`. That was necessary because V2 of `MACREL` supported the latest memory expansion, and so the OS/8 Core Control Block needed to change. Unfortunately, the `FUTIL.SV` distributed as version 8A had the wrong starting address and Job Status Word settings. It *hangs* when run under `BATCH`. Our automated pack builder and patcher `mkos8` run `FUTIL` under `BATCH`. The `MACREL` v2 DECtape image we use with `mkos8` contains a hand-applied patch `35.13.1M` that fixes this problem. Currently if you opt in to having `MACREL` on the system packs, you get `FUTIL` version 8B. If not, you get `FUTIL` version 7 and `mkos8` applies the relevant patches. If `FUTIL` version 8 is installed, the automated patch applier recognizes the version 7 patches don't fit and fails to install them. ## One-off Patches Most of the patches are parsed and applied in an automated manner by mkos8. However some are one-offs. See the `FUTIL` section above with regards to patch `35.13.1M`. `FORLIB 51.10.1 M` is a one line source change to `DLOG.RA`. The patch file provides that line. It also provides instructions on how to use `RALF` to assemble the source and on how to to use `LIBRA` to replace the old version of `DLOG` with the new one in `FORLIB.RL`. I followed the instructions to hand-tool a patched `FORLIB.RL` which I then put in the `local.tu56` DECtape image along with the other local hacks. The `patch` routine `mkos8` has in-line code to replace `FORLIB.RL` on `SYS:` if installation of FORTRAN IV is enabled. ## Unfinished Business There remain the following patches that are still under development, because they are not simple binary overlays on executables that could be applied with simple scripts driving `ODT` or `FUTIL`. Instead they are either batch scripts, or are applied to source code that is rebuilt either with an assembler or high level language compiler. `LQP 21.49.1 M` patches a device driver `.BN` file, then using `BUILD` to insert it into the system. At the present time the OS/8 V3D packs we build do not use the `LPQ` driver. (We ran out of device ID space and so we don't have anywhere to put an active `LPQ` driver.) ## The Tracking Spreadsheet Below is the latest snapshot of the tracking spreadsheet. Status column key: | **A** | Patch Applies Successfully | | **V** | Patch Source Verified | | **K** | Patch Source Probably OK. Weaker confidence than "Verified". | | **P** | Patch Source Plausible. Weaker confidence than "OK". | | **N** | Not recommended | | **O** | OCR Cleaned up. No other verification or application done. | | **D** | Does not apply. | | **B** | Bad patch. DO NOT APPLY. | ### OS/8 V3D Patches | Component | Issue | Sequence | Mon/Yr | Notes | Status | | ------ | ------ | ------ | ------ | ------ | ------ | | `HANDLER` | `CTRL/Z` and `NULL` | `01 O *` | Oct-77 | Optional. Not going to apply. | | | `CREF` | Bug with `FIXTAB` | `21.15.1M` | Apr/May-78 | `CREF-21.15.1-v2B.patch8` Corrects bad patch | AV | | | Input and output file specifications | `21.15.2M` | Feb/Mar-80 | `CREF-21.15.2-v2C.patch8` | AK | | `EDIT` | `EDIT` Problem with no `FORMFEED` at end of the input file | `21.17.1M` | Mar-78 | `EDIT-21.17.1M-v12B.patch8` | AV | | | `EDIT` `Q` command after `L` command | `21.17.2M` | Jun/Jul-79 | `EDIT-21.17.2M-v12C.patch8` | AV | | | `EDIT` `Q` command patch | `21.17.3M` | Jun/Jul-79 | `EDIT-21.17.3M-v12D.patch8` | AV | | | `EDIT.SV` `V` option will not work with `LPT DKC8-AA` | `21.17.4M` | Feb/Mar-80 | `EDIT-21.17.4M-v12C.patch8` Overwrites patch `21.12.2M` | AVB | | `FOTP` | Incorrect directory validation | `21.19.1M` | Jun/Jul-79 | `FOTP-21.19.1M-v9B.patch8` (Corrected from Aug/Sep 1978, Detailed in Apr/May 79) | AV | | `MCPIP` | `DATE-78` Patch for `MCPIP` | `21.21.1M` | Mar-78 | `MCPIP-21.21.1M-v6B.patch8` | AV | | `PAL8` | Incorrect core size routine | `21.22.1M` | Aug/Sep-78 | `PAL8-21.22.1M-v10B.patch8` | AV | | | Erroneous `LINK` generation noted on `PAGE` directive | `21.22.2M` | Aug/Sep-78 | `PAL8-21.22.2M-v10C.patch8` | AV | | | `EXPUNGE` patch to `PAL8` | `21.22.3M` | Feb/Mar-80 | `PAL8-21.22.3M-v10D.patch8` | AK | | | `TAB`s are translated incorrectly | `21.22.4M` | Oct/Nov-80 | `PAL8-21.22.4M` (Supercedes June/July 1980 (which had wrong contents of memory.)) Bad! Wrong version of `PAL8`! Breaks list output. | AB | | `PIP` | `PIP` `/Y` option does not work properly when transferring a system | `21.23-1M` | Aug/Sep-78 | `PIP-21.23.1M-V12B.patch8` | AK | | `PIP10` | `DATE-78` Patch to `PIP 10` | `21.24.1M` | Jun/Jul-79 | `PIP10-21.24.1M-V3B.patch8` (Corrected from Dec 78/Jan 79) | AV | | `SET` | Using `SET` with two-page system handlers | `21.26.1M` | Apr/May-78 | `SET-21.26.1M-v1C.patch8` | AV | | | `SCOPE` `RUBOUT`s fail in `SET` | `21.26.2M` | Apr/May-78 | `SET-21.26.2M-v1D.patch8` | AV | | | Parsing of `=` in `TTY WIDTH` option | `21.26.3M` | Aug/Sep-78 | `SET-21.26.3M-v1E.patch8` | AV | | `LPQ` | `LDP01` Handler fails to recognize `TAB`s | `21.49.1M` | Dec/Jan-80 | `LQP-21.49.1M-vB.patch8` (supercedes Mar 1978) | O | | `TM8E` | Write protect patch to `TM8E.PA` | `21.61.1H` | Feb/Mar-80 | New `TM8E` Source. Too hard to correct. | | ### OS/8 Extension Kit V3D Patches | Component | Issue | Sequence | Mon/Yr | Notes | Status | | ------ | ------ | ------ | ------ | ------ | ------ | | `SABR` | Line buffer problem in `SABR` | `21.91.1M` | Oct/Nov-79 | `SABR-21.91.1M-v18B.patch8` | AV | | `BASIC.UF` | `BASIC.UF` Incompatible from OS/8 V3C | `31.5.1M` | Aug/Sep-78 | `BASIC.UF-31.5.1M-V5B.patch8` Source also in _DSN_. | AV | | `BLOAD` | `BLOAD` Will not build `CCB` properly | `31.10.1M` | Feb/Mar-80 | `BLOAD-31.10.1M-v5B.patch8` | AV | | `BRTS` | `IOTABLE` Overflow | `31.11.1M` | Mar-78 | `BRTS-31.11.1-M-v5b.patch8` | AV | | | `BASIC` `PNT` Function | `31.11.2O` | Jun/Jul-78 | `BRTS-31.11.2-O.patch8` (superceds/corrects Mar 1978) | AV | | | Line size on output of `BASIC` | `31.11.3O` | Jun/Jul-78 | `BRTS-31.11.3-O.patch8` | AV | | | Change line printer width | `31.11.4F` | Oct/Nov-79 | Optional change of width to 132 columns | | | | Patch to `BRTS` for addressing `LAB 8/E` functions | `31.11.5M` | Oct/Nov-79 | `BRTS-31.11.5-x.patch8` (`BASIC.UF` patch is a prerequisite.) | AV | | `TECO` | Changing the default `EU` value for no `case` flagging | `31.20.1O` | Mar-78 | `TECO-31.20.01O.patch8` | AVN | | | Changing the default `EH` value for one line error printouts | `31.20.2O` | Mar-78 | `TECO-31.20.02O.patch8` | AVN | | | Removing `YANK` protection | `31.20.3O` | Mar-78 | `TECO-31.20.03O.patch8` | AVN | | | `SCOPE` Support for `VT05` users | `31.20.4O` | Mar-78 | `TECO-31.20.04O.patch8` | AP N | | | Problem with `AY` command | `31.20.5M` | Mar-78 | `TECO-31.20.05M-v5A.patch8` | AV | | | Conditionals inside iterations | `31.20.6M` | Mar-78 | `TECO-31.20.06M-v5B.patch8` | AV | | | Echoing of warning bells | `31.20.7M` | Mar-78 | `TECO-31.20.07M-v5B.patch8` | AV | | | `CTRL/U` Sometimes fails after `*` | `31.20.8M` | Apr/May-78 | `TECO-31.20.08M-v5.04.patch8` | AK | | | Multiplying by `0` in `TECO` | `31.20.10M` | Apr/May-78 | `TECO-31.20.10M-v5.05.patch8` | AV | | | `Q` registers don't work in 8K | `31.20.11M` | Apr/May-78 | `TECO-31.20.11M-v5.06.patch8` | AV | | | Can't skip over `W` | `31.20.12M` | Apr/May-78 | `TECO-31.20.12M-v5.07.patch8` | AV | | | Unspecified iterations after inserts | `31.20.13M` | Oct/Nov-78 | `TECO-31.20.13M-v5.08.patch8` (Corrected from Jun/Jul 78) | AV | | | New features in `TECO V5` | `31.20.14` N | Aug/Sep-78 | Documentation Only | | | `FUTIL` | `FUTIL` Patch | `31.21.1M` | Apr/May-78 | `FUTIL-31.21.1M-v7B.patch8` | AV | | | Fix `SHOW CCB` and mapping of `CD` modules | `31.21.2M` | Oct/Nov-78 | `FUTIL-31.21.2M-v7D.patch8` (Corrected from Aug/Sep 78) | AV | | | Optional: change `XS` format from `excess-240` to `excess-237`. Useful for viewing `COS` data files. | `31.21.3O` | Aug/Sep-78 | `FUTIL-31.21.3O.patch8` | AVN | | | `FUTIL` Patch to `MACREL`/`LINK` overlays | `31.21.4 N` | Jun/Jul-79 | Documentation Only | | | `MSBAT` | `DIM` Statement not working in `MSBAT` | `31.22.1M` | Dec 78/Jan-79 | `MSBAT-31.22.1M-v3B.patch8` | AV | | `BATCH` | `MANUAL INTERVENTION REQUIRED` Erroneously | `31.23.1M` | Aug/Sep-78 | `BATCH-31.23.1M-v7B.patch8` | AV | ### OS/8 FORTRAN IV V3D Patches | Component | Issue | Sequence | Mon/Yr | Notes | Status | | ------ | ------ | ------ | ------ | ------ | ------ | | `F4` | `EQUIVALENCE` Statement | `02M` / `21.1.2M` | Dec/Jan-80 | `F4-21.1.2M-v4B.patch8` (Revised, Oct 77: `F4` and `PASS3` not `FRTS` patched.) | AP | | | `FORTRAN` Compiler fails to recognize `"` as an error | `51.3.1M` | Jun/Jul-78 | `F4-51.3.1M-v4C.patch8` (Corrects March 1978) | AP | | | `FORTRAN` Compiler not recognizing syntax error | `51.3.2M` | Jun/Jul-78 | `F4-51.3.2M-v4x.patch8` | AP | | | `FORTRAN` runtime system 2-page handler | `51.3.3O` | Oct/Nov-78 | `FRTS-51.3.3-O.patch8` Needed for RL02. (Corrected from Aug/Sep 78) | A | | | Restriction with subscripted variables | `51.3.4R` | Aug/Sep-80 | Documentation: `FIV` `FORTRAN IV` will not allow subscripting to be used on both sides of an arithmetic expression. | | | `FORLIB` | `FORTRAN IV` `DLOG` Patch | `51.10.1M` | Feb/Mar-80 | `FORLIB-51.10.1M.patch8` (apply to `DLOG.RA`) | AV | ### OS/8 MACREL/LINKER V1A Patches These patches are listed for completeness. The version numbers don't match. We lack source so we cannot verify them. we've moved on to `MACREL` v2 as canon. | Component | Issue | Sequence | Mon/Yr | Notes | Status | | ------ | ------ | ------ | ------ | ------ | ------ | | `LINK` | Patch `V1D` to `LINK` | `40.2.1M` | Apr/May-78 | `LINK-40.2.1M-v1D.patch8` | O | | | Patch `VIE` to `LINK` | `40.2.2M` | Apr/May-78 | `LINK-40.2.2M-v1E.patch8` | O | | | `LINK` Corrections | `40.2.3M` | Apr/May-78 | `LINK-40.2.3M-v1F.patch8` | O | | `MACREL` | Patch `V1D` to `MACREL` | `40.5.1M` | Apr/May-78 | `MACREL-40.5.1M-v1D.patch8` | OD | | | Patch `V1E` to `MACREL` | `40.5.2M` | Apr/May-78 | `MACREL-40.5.2M-v1E.patch8` | OD | | `OVRDRV` | Patch `V1B` to `OVRDRV.MA` | `40.6.1M` | Apr/May-78 | `OVRDRV-40.6.1M-v1B-8srccom` | O | ### OS/8 V3D Device Extensions December 1978 Patches **WARNING**: Do not use this kit without first consulting _DSN_ Apr/May 1979. See also: [Our OS/8 Device Extensions documentation][os8ext] | Component | Issue | Sequence | Mon/Yr | Notes | Status | | ------ | ------ | ------ | ------ | ------ | ------ | | `FRTS` | `FRTS` Patch | `35.1.3M` | Apr/May-79 | | | | `MONITOR` | `MONITOR` `V3S` Patch | `35.2.1M` | Apr/May-79 | | | | `FUTIL` | `FUTIL` hangs under `BATCH` | `35.13.1M` CRITICAL! | Apr/May-79 | | AV | | `PAL8` | `EXPUNGE` Patch to `PAL8` | `35.14.1M` | Feb/Mar-80 | `PAL8-35.14.1M-v13B.patch8` | AN | | `ABSLDR` | Loader problem with `SAVE` image files | `21.29.1M` | Oct/Nov-80 | `ABSLDR-21.29.1M-v6C.patch8` (Supercedes June/July 1980) Bad: v6B was with OS/8 Device Extensions. | OB | | `ABSLDR` | `ABSLDR` Patch | `35.18.1M` | Apr/May-79 | | | | `BLOAD` | `BLOAD` Will not build `CCB` properly | `35.51.1M` | Feb/Mar-80 | `BLOAD-35.51.1M-v5C.patch8` | ON | ### OS/8 MACREL/LINKER V2A Patches These patches have not been turned into files. Armed with newly discovered sources verification is possible. Work on these will begin soon. | Component | Issue | Sequence | Mon/Yr | Notes | Status | | ------ | ------ | ------ | ------ | ------ | ------ | | User's |`EXPUNGE` Documentation error | `41.1.1N` | Jun/Jul-79 | | | | Guide | `MACREL` Version numbers: `MACREL` is `V2C` not `V2D`; `LINK` is `V2A` not `V2B`. | `41.1.2N` | Jun/Jul-79 | | | | | Macro restriction in `MACREL` | `41.1.3N` | Aug/Sep-79 | | | | | Error in `.MCALL` macro example | `41.1.4N` | Feb/Mar-80 | | | | `KREF` | Correct printing of numeric local symbols | `41.3.1M` | Apr/May-80 | | | | `MACREL` | `EXPUNGE` Patch to `MACREL` | `41.4.1F` | Jun/Jul-79 | | | | | Inconsistencies in `MACREL` error reporting | `41.4.2N` | Aug/Sep-79 | | | | | Forward reference patch to `MACREL` | `41.4.3M` | Aug/Sep-79 | | | | | Correct macro substring problem | `41.4.4M` | Apr/May-80 | | | | | Correct printing of numeric local symbols | `41.4.5M` | Apr/May-80 | | | | `OVRDRV` | Correct `CDF` problem | `41.5.1M` | Dec/Jan-80 | Source change applied by hand. | AV | | `FUTIL` | `FUTIL` hangs under `BATCH` | `35.13.1M` | Apr/May-79 | Critical to proper operation of our automated builder. Applied by hand to the `MACREL` v2 integration. | AV | ### <a id="license"></a>License Copyright © 2017 by Bill Cattey. Licensed under the terms of [the SIMH license][sl]. [sl]: https://tangentsoft.com/pidp8i/doc/trunk/SIMH-LICENSE.md [os8ext]: https://tangentsoft.com/pidp8i/doc/trunk/doc/os8-v3d-device-extenaions.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 | # OS/8 V3D Device Extensions The _OS/8 V3D Device Extensions_ kit (product code `QF026`) was released in December 1978. It was created to support the newest PDP-8 hardware: * The `KT8A` Memory Management option which enables addressing by a factor of four beyond the previous maximum of 32K to a whopping 128K of memory. The highest memory field for a PDP-8a goes up from 7 to 37 (octal). * The `RL01` disk supporting 4 times the previous usual disk capacity, now up to nearly 5 Meg. * The `RX02` double-density floppy disks. * Device drivers `VXSY` and `VXNS` enables use of `KT8A` extended memory as a file oriented system or non-system device. This distribution contains software updates: * A version of `BUILD`, the system builder that could run under `BATCH`. The previous version would just hang. * An update to the OS/8 system including `Keybord Monitor` version 3S, and a version of `ODT` that works with memory fields greater than 7. * `ABSLDR` version 6A supports loading into memory fields greater than 7. * `PAL8` version 13A allows code to specify memory fields greater than 7. * `CCL` version 7A updates the 'MEMORY' command to recognize up to 128K words of memory. * `PIP` version 14A knows the sizes of the new devices, and has updated how it copies in the monitor system head. * `RESORC` version 5A includes new devices. * `BOOT` version 5A boots new devices. * `RXCOPY` version 4B formats and copies single and double density floppies. * `FUTIL` version 8A recognizes new core control block format that can represent extended above field 7. The _OS/8 V3D Device Extensions User's Guide_ can be found in [Willem van der Mark's PDP-8 doc archive][vdmdoc], under [OS/8 - Device Extensions - User's Guide - December 1978 AA-D319A-TA.pdf][vdmextensions]. or on the [ftp.dbit.com pdp8 doc archive][dbitdoc] at [devextug.doc -- OS/8 Device Extensions User's Guide][dbitug] The release notes can be found on ftp.dbit.com at [devextrn.doc OS/8 Device Extensions Release Notes ][dbitrn]. Details on how the `KT8A` Memory Extension hardware works, physically and programatically, can also be found at Willem van der Mark's site: [vandermark.ch ... Emulator.128KMemory/EK-KT08A-UG_jul78-ocr.pdf][kt8adoc]. When reference is made to `PAL8` version 13, that version originally came from this kit. The distribution DECtape for this kit, part number `AL-H525A-BA` has not yet been found. The PDP-8 Software Components Catalog July 1979 gives no part number for a Source DECtape distribution of this kit. There is an RK05 source distribution, part number `AN-H529A-SA`. However, plausable source and binary have recently been found! The binaries were on someone's local hard disk and not published to the net anywhere I could find. Sadly those binaries did not include the DECtape's system area, and so the updated version of the OS/8 Keyboard Monitor, Command Decoder and `ODT` seemed lost until a tape could be found. It appears that the original source of these .en files is Johnny Billingquist's site, [ftp.update.uu.se ... dectape1][uuseext1]. Then, however, a self-extracting archive called, `os8v3f.exe` was found on a mirror site of ibiblio.org, [rtk.mirrors.pdp-11.ru ... fromhichols][rtknicnols]. Mainline ibiblio.org didn't have it, perhaps it was purged because of its `.exe` extension. The archive is also available directly from [ftp.update.uu.se ... fromnichols][uusenichols], but at slow speed. When that archive was extracted, the manifest of source files corresponds exactly to the manifest of binaries in the Extensions Kit file archive are present. This looks quite promising for a future project to upgrade to OS/8 V3D with the Device Extensions software, and to create system packs useful even on PDP-8a hardware with 128K words of memory! After comparing sources found for OS/78, and OS/278, as well as Willem van der Mark's locally modified sources labeled OS/8 version 4, I have moderate confidence that these sources will enable validation and integration of most, if not all the OS/8 V3D Device Extensions functionality. [rtknichols]: http://rtk.mirrors.pdp-11.ru/ftp.update.uu.se/pdp8/pdp-8/fromnichols/ [uuseext1]: ftp://ftp.update.uu.se/pub/pdp8/pdp-8/os8/os8.v3d/binaries/devext/dectapes/dectape1/ [uusenichols]: ftp://ftp.update.uu.se/pub/pdp8/pdp-8/fromnichols/ ## FUTIL This validation has been done with regards to `FUTIL`. The `MACREL` v2 tape shipped with version 8A of `FUTIL`. That was necessary because V2 of `MACREL` supported the latest memory expansion, and so the OS/8 Core Control Block format needed to change. `FUTIL` version 8A integrated patches for `FUTIL` version 7 into the source. Finding those patches in the version 8A source strongly increased my confidence in those patches. Unfortunately the `FUTIL.SV` verson 8A executable was saved incorrectly and then shipped. The Core Control Block setting and starting address were mis-specified. So `FUTIL` version 8A *hangs* when run under `BATCH`. The [April-May 1979][dsn1979apr] issue of _PDP-8 Digital Software News_ contained patch `35.13.1M` which fixed this problem and upgraded `FUTIL` to version 8B. I've confirmed both the problem and the fix. Currently if you opt in to having `MACREL` on the system packs, you get `MACREL` v2 and `FUTIL` version 8B. If leave `MACREL` out, you get `FUTIL` version 7. The automated pack builder recognizes that the version 7 patches won't apply to version 8, and fails to apply them. The research I did on the OS/8 Device Extensions kit and on `MACREL` increased my confidence about the `FUTIL` version 7 patches. See also [our documentation on the `MACREL` integration][macreldoc] and [our documentation on applying OS/8 patches][patchdoc]. ### <a id="license"></a>License Copyright © 2017 by Bill Cattey. Licensed under the terms of [the SIMH license][sl]. [vdmdoc]: http://vandermark.ch/pdp8/index.php?n=PDP8.Manuals [vdmextensions]: http://vandermark.ch/pdp8/uploads/PDP8/PDP8.Manuals/AA-D319A-TA.pdf [dbitdoc]: ftp://ftp.dbit.com/pub/pdp8/doc/ [dbitug]: ftp://ftp.dbit.com/pub/pdp8/doc/devextug.doc [dbitrn]: ftp://ftp.dbit.com/pub/pdp8/doc/devextrn.doc [kt8adoc]: http://www.vandermark.ch/pdp8/uploads/Emulator/Emulator.128KMemory/EK-KT08A-UG_jul78-ocr.pdf [dsn1979apr]: http://bitsavers.org/pdf/dec/pdp8/softwarenews/198010_PDP8swNews_AA-K629A-BA.pdf [macreldoc]:https://tangentsoft.com/pidp8i/doc/trunk/doc/os8-macrel.md [macreldoc]:https://tangentsoft.com/pidp8i/doc/trunk/doc/os8-patching.md [sl]: https://tangentsoft.com/pidp8i/doc/trunk/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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # PiDP-8/I 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're running one of the [binary OS images][devhome], 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].) If you built the PiDP-8/I software from source atop some other Raspberry Pi operating system installation, you will have to log out and back in after installing the software so the installer's adjustments to your `PATH` take effect. Then you can use the commands above. ## Test Procedure The test normally proceeds automatically forward, but you can take control of the test sequence with these keys: | Key | Effect | --------------------------------- | ------ | <kbd>↑</kbd> or <kbd>→</kbd> | Skip to next test | <kbd>↓</kbd> or <kbd>←</kbd> | Go back to previous test | <kbd>R</kbd> | Resume auto-advance behavior | <kbd>X</kbd> or <kbd>Ctrl-C</kbd> | Exit program Any of the arrow keypresses stop the auto-advancing behavior. The test proceeds as follows: * All On test: It turns on all LEDs for 5 seconds. |
︙ | ︙ | |||
90 91 92 93 94 95 96 97 98 99 | ## 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 | > | 102 103 104 105 106 107 108 109 110 111 112 | ## License This document is licensed under the same terms as the associated [`src/test.c` program][program]. [devhome]: https://tangentsoft.com/pidp8i/ [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 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # U/W FOCAL Manual Supplement for the PiDP-8/I ## Introduction This document is a supplement to the [U/W FOCAL Manual][uwfm]. ("The Manual") Although it is not a complete FOCAL tutorial — much less a reference guide! — we suggest that you start learning about our distribution of FOCAL by skimming through this document *first*, then proceeding to [the Manual][uwfm], since this document will alert you to the areas of the Manual that are simply incorrect for the PiDP-8/I distribution of U/W FOCAL. Having gotten through the Manual, come back here and re-read this supplement more carefully; you will get more out of this supplement on that second pass with the context from the Manual. Other helpful sources are the [U/W FOCAL reference cards][uwfr], the [U/W FOCAL DECUS submission][uwfd], the [DECUS and OMSI manuals for PS/8 FOCAL, 1971][f71], and the [DEC FOCAL-8 Manual][df8]. To a first approximation, those are ordered in decreasing degree of application to our distribution of U/W FOCAL. The final document in that series is still quite useful for understanding U/W FOCAL, however. See [below](#rationale) for the reasons why we felt it was necessary to write this document. ## <a id="starting" name="stopping"></a>Starting and Stopping U/W FOCAL The section "Starting the Program" in [the Manual][uwfm] is entirely concerned with loading U/W FOCAL from paper tape using the front panel and the BIN loader. The PiDP-8/I software project does not currently ship U/W FOCAL in SIMH paper tape image form. Instead, it's installed by default on the OS/8 system disk, which greatly simplifies starting it: .R UWF16K Yes, that's all. You're welcome. `:)` To get back to OS/8, just hit <kbd>Ctrl-C</kbd>. ## <a id="loading" name="saving"></a>Loading and Saving Programs There are many ways to get program text into U/W FOCAL other than simply typing it in. This section gives several methods, because each may be of use to you in different circumstances. Some of them may not be of direct use to you, but may open your eyes to techniques that may be useful to you in other contexts, so we encourage you to read this entire section. ### <a id="ls-pasting"></a>Pasting Text in from a Terminal Emulator #### The Naïve Way If you are SSHing into your PiDP-8/I, you might think to write your FOCAL programs in your favorite text editor on your client PC then copy and paste that text into U/W FOCAL over SSH. Currently, that won't work. (2017.10.05) We believe it is because of the way U/W FOCAL handles terminal I/O and interrupts. If you try, the input ends up trashed in FOCAL. #### <a id="ls-pip"></a>The Way That Works "But I really really want to write my FOCAL programs in [my favorite text editor][mfte] and paste them into my PiDP-8/I," I hear you say. Dispair not. There is a path. Follow. The problem affecting U/W FOCAL which prevents it from handling input at modern paste-through-SSH speeds doesn't affect OS/8 itself, so we'll use it as an intermediary: .R PIP *HELLO.DA<TTY: ⇠ use default extension for O I 01.10 TYPE "Hello, world!"! ⇠ paste your program text here ^Z ⇠ hit Ctrl-Z to tell PIP it's reached end-of-file (EOF) *$ ⇠ hit Escape to return to OS/8 from PIP ($ = Esc) .R UWF16K ⇠ run U/W FOCAL *O I HELLO ⇠ open text file for input; "types" pgm in for us _G ⇠ underscore = EOF seen, G starts program Hello, world! ⇠ and it runs! That is, we use OS/8's `PIP` command to accept text input from the terminal (a.k.a. TTY = teletype) and write it to a text file. Then we load that text in as program input using commands we'll explain in detail [below](#ls-write). [mfte]: https://duckduckgo.com/?q=%22my+favorite+text+editor%22 ### <a id="ls-punch"></a>The `PUNCH` Command When [the Manual][uwfm] talks about loading and saving programs, it is in terms of the `PUNCH` command, which punches the current program out on paper tape, because the Manual was written for the paper tape based version of U/W FOCAL. The PiDP-8/I software project ships the OS/8 version of U/W FOCAL instead, which doesn't even have a `PUNCH` command. (We get the [`PLOT` command](#miss-hw) instead.) Even if it did work, mounting and unmounting simulated paper tapes under SIMH is a bit of a hassle. We can do better. ### <a id="ls-library"></a>The `LIBRARY` Command The effective replacement for `PUNCH` in the OS/8 version of U/W FOCAL is the `LIBRARY` command. If you've read [the Manual][uwfm], you may be wondering if it's overloaded with `LINK` and `LOOK`, but no: those commands are apparently missing from the OS/8 version. (Open question: how do you use multiple fields of core for program code with the OS/8 version, then?) Briefly, then, I'll show how to use some of these commands: .R UWF16K ⇠ start fresh *1.10 TYPE "Hello, world!"! ⇠ input a simple one-line program *L S HELLO ⇠ write program to disk with LIBRARY SAVE *L O HELLO ⇠ verify that it's really there HELLO .FD 1 ⇠ yup, there it is! *E ⇠ ERASE all our hard work so far *W ⇠ is it gone? C U/W-FOCAL: 16K-V4 NO/DA/TE ⇠ goneski *L C HELLO ⇠ load it back in with LIBRARY CALL *W ⇠ did it come back? C U/W-FOCAL: HELLO NO/DA/TE 01.10 TYPE "Hello, world!"! ⇠ yay, there it is! *L D HELLO ⇠ nuke it on disk; it's the only way to *L O HELLO ⇠ ...be sure * ⇠ Houston, we have no program See the [DECUS submission][uwfd] and `CARD2.DA` in the [refcards][uwfr] for more examples. ### <a id="ls-write"></a>The `WRITE` Command U/W FOCAL's `LIBRARY` command saves programs as core images, which are a) non-relocatable; and b) non-portable to other versions of FOCAL. We can fix both of these problems by saving the program to an ASCII text file instead. With a program already typed in or loaded from disk: *O O HELLO; W; O C All of that has to be on a single line, with the semicolons. If you give these three commands separately, you end up with the `WRITE` command as the first line in the output file and the `OUTPUT CLOSE` command as the last; you must then either edit those commands out of the output file or tolerate having FOCAL run those two commands again every time you load the program from disk. What this does is opens a data output file (extension `.DA`) and makes it the output destination, so that the following `WRITE` command sends its text there, and then it is immediately closed with `O C`, returning control back to the terminal. You can then load that program back into U/W FOCAL with the same command we used above with the `PIP` solution: *O I HELLO If you `TYPE` that file from OS/8, you might be wondering why the banner line doesn't cause a problem on loading the file back in: C U/W-FOCAL: HELLO NO/DA/TE That leading `C` causes U/W FOCAL to treat it as a comment. Since we're in "direct mode" at that point, the comment is simply eaten. ### <a id="ls-ptr"></a>The Paper Tape Reader Above, I warned you off trying to save programs to simulated paper tape via the `PUNCH` command, but what about *reading* programs back in? You can do that, but it's trickier than you might guess. First, if you've read [the Manual][uwfm], you may think to attach a paper tape to SIMH then use U/W FOCAL's `OPEN READER` command, but as with `PUNCH`, that command has been replaced in this version of U/W FOCAL. With the removal of paper tape support in U/W FOCAL proper, they felt free to reassign `O R` to `OPEN RESTART/RESUME`. Thus, we again have to pop back out to OS/8 and use PIP to pull this off. First we must create that paper tape. If you place your FOCAL source code in `examples/*.fc`, you can simply type `make` at the top level of the PiDP-8/I source tree to have it translated to `bin/*-focal.pt` with the same base name. (This is done by Bill Cattey's `txt2ptp` program; there is also the inverse filter, `ptp2txt`. We include the `-focal` tag to distinguish these files from `*-pal.pt` files produced from `*.pal` source files by a similar process.) We'll work with the provided `examples/tratbl.fc` example program, which got translated to `bin/tratbl-focal.pt` when the PiDP-8/I software was built. To attach that paper tape to SIMH's paper tape reader device, hit <kbd>Ctrl-E</kbd> to get to the SIMH command prompt, then: sim> att ptr bin/tratbl-focal.pt sim> c On re-entering the simulator with the `c` ("continue") command, we can read that tape into OS/8: .R PIP *TRATBL.DA<PTR: ⇠ hit Esc *then* Enter .TYPE TRATBL.DA If the final command doesn't show you the program text you expect, something went wrong in the process above. There are several likely possibilities: 1. You hit <kbd>Enter</kbd> at the end of the PIP command, either instead of <kbd>Esc</kbd> or *before* hitting <kbd>Esc</kbd>. If you do it right, it should appear on screen as: *TRATBL.DA<PTR:$^ with the `$^` appearing when you hit <kbd>Esc</kbd>, signifying that it has read the paper tape and hit the end. Hitting <kbd>Enter</kbd> should then drop you back to the OS/8 prompt, not leave you in `PIP`. If you get another `*` prompt from `PIP` on hitting <kbd>Enter</kbd>, you fat-fingered something. Try again. 2. Every time you cause the PDP-8 to read the paper tape, you must re-attach it to SIMH to read it again. Neither SIMH nor OS/8 warns you if you try to read from the paper tape reader with nothing attached; you just get no input. This mimics what happens with real paper tapes: once the reader has read the tape, it falls out of the machine and needs to be fed back in to be read again. The difference between the real paper tape reader and SIMH is that that repeated sequence is much more of a hassle than just sticking the tape back in the reader: .<Ctrl-E> sim> ATT PTR ... sim> C That `TTY:` based `PIP` method above will start to look awfully attractive after a while... 3. You saved the FOCAL text out on the host side with Unix line endings, so on `TYPE`ing it at the OS/8 command prompt to check it, you got stair-stepped output. OS/8 expects CR+LF line endings, also called DOS line endings, though OS/8 long precedes MS-DOS, and the teletype based design of ASCII that made CR+LF a sensible way of ending lines in a text file long precedes *OS/8*. Fix the line endings, then say "make" to rebuild the `*-focal.pt` file, then reattach the tape, and try again. Once you make it through that gauntlet, loading the ASCII program text into U/W FOCAL is just as above: `O I TRATBL`. ## <a id="lowercase"></a>Lowercase Input The version of U/W FOCAL we include by default on the PiDP-8/I's OS/8 system disk copes with lowercase input only within a fairly narrow scope. The fact that it copes with lowercase input at all is likely due to the fact that the version we ship was released late in the commercial life of OS/8, by which time lowercase terminals were much more common than at the beginning of OS/8's lifetime. The examples in [the Manual][uwfm] are given in all-uppercase, which means there is no reason you would immediately understand how U/W FOCAL deals with lowercase input, having no examples to build a mental model from. If you just guess, chances are that you will be wrong sooner or later, because U/W FOCAL's behavior in this area can be surprising! The two main rules to keep in mind are: 1. U/W FOCAL is case-sensitive for variable and built-in function names, but it is case-insensitive for command names. 2. U/W FOCAL doesn't support lowercase variable and function names. It may sometimes appear to work, but internally, U/W FOCAL isn't doing what you want it to. The following gives incorrect output because of a violation of rule 1: *type fsin(pi/2)! 0.000000000E+00* The correct answer is 1. It fails because there is no built-in function called `fsin` nor a built-in constant `pi`. FOCAL gives an answer here instead of detecting our failure to call things by their right names because it is falling back to its rule to use a value of 0 where no value or function is available to do what you asked. Zero divided by 2 is 0; then it tries to subscript a nonexistent `fsin` variable with index 0, so it punts and gives the answer you see above, zero. A better language would have detected your errors and given a diagnostic, but U/W FOCAL is implemented in less than a page of PDP-8 core memory, roughly the same number of bytes as [Clang](http://clang.llvm.org/) gives when compiling an empty C program on the machine I'm typing this on. The fact that U/W FOCAL detects errors *at all* is somewhat impressive. To get the expected result, call the `FSIN` function and use the `PI` constant, which are very much not the same thing as `fsin` and `pi` to FOCAL: *type FSIN(PI/2)! 1.000000000E+00 U/W FOCAL doesn't care that you gave the `type` command in lowercase, but it *does* care about the case of the function and variable names. U/W FOCAL's tolerance of lowercase in command names doesn't extend to arguments. In particular, the `OPEN` command's argument must be uppercase: `o o` doesn't work, nor does `O o`, but `o O` does. Violating rule 2 can be even more surprising: .R UWF16K ⇠ We need a fresh environment for this demo. *s a=1 ⇠ What, no error? I thought you said... *s b=2 *s c=3 *type $ ! * No, that transcript isn't cut off at the end: the `TYPE` command simply doesn't give any output! Why? The reason is that U/W FOCAL can't \[currently\] cope with lowercase variable names. But wait, it gets weird: *s A=1 *s foo=42 *type $ ! A (+00) 1.000000000E+00 &/(+00) 4.200000001E+01 We now see output for our uppercased `A` variable, but what is that `&/` noise? Apparently "`foo`" somehow gets mangled into `&/` by FOCAL's command parser. We have not yet tried to investigate the reason `foo` gets saved into a mangled variable name and `a`, `b`, and `c` above do not, because the workaround is simple: keep <kbd>CAPS LOCK</kbd> engaged while typing FOCAL programs except when typing text you want FOCAL to send back out to the terminal: *1.1 TYPE "Hello, world!"! *G Hello, world! See the [Variables section][vars] of [`CARD2.DA`][card2] for more information on variable naming. [card2]: uwfocal-refcards.md#card2 [vars]: uwfocal-refcards.md#variables ## <a id="output-format"></a>Default Output Format FOCAL is primarily a scientific programming language. That, coupled with the small memory size of the PDP-8 family and the slow terminals of the day mean its default output format might not be what you initially expect. Consider these two examples pulled from the [U/W FOCAL Manual][uwfm]: *TYPE FSGN(PI), FSGN(PI-PI), FSGN(-PI) ! 1.000000000E+00 0.000000000E+00-1.000000000E+00 *TYPE 180*FATN(-1)/PI ! -4.500000000E+01 This may raise several questions in your mind, such as: 1. Why is there no space between the second and third outputs of the first command? 2. Why does the ouptut of the first command begin in the second column and the second begin at the left margin? 3. Is the second command giving an answer of -4.5°? If you've read the U/W FOCAL Manual carefully, you know the answer to all three of these questions, but those used to modern programming environments might have skimmed those sections and thus be surprised by the above outputs. The first two questions have the same answer: U/W FOCAL reserves space for the sign in its numeric outputs even if it doesn't end up being needed. This was done, no doubt, so that columns of positive and negative numbers line up nicely. It might help to see what's going on if you mentally replace the spaces in that first output line above with `+` signs. This then explains the apparent discrepancy between the first and second commands' outputs: the first output of the first command is positive, while the second command's output is negative, so there is a space at the beginning of the first output for the implicit `+` sign. As for the third question, the default output format is in scientific notation with full precision displayed: 4.5×10¹ = 45 degrees, the correct answer. ### Improving the Output Format The following changes to the examples as given in [the Manual][uwfm] show how you can get output more suitable to your purposes: *TYPE %1, FSGN(PI):5, FSGN(PI-PI):5, FSGN(-PI)! 1 0 -1 That sets the output precision to 1 significant digit, which is all we need for the expected {-1, 0, -1} ouptut set. The tabstop formatting options (`:5`) put space between the answers, but there is a trick which gives similar output with a shorter command: *TYPE %5.0, FSGN(PI), FSGN(PI-PI), FSGN(-PI)! 1 0 -1 That tells it to use 5 significant digits with zero decimal digits. Since the answers have only one significant digit, FOCAL right-justifies each output with 4 spaces. There are 5 spaces between the `1` and `0` outputs because of that pesky implicit `+` sign, though. The second example above can be improved thus: *TYPE %3.2, 180*FATN(-1)/PI ! -45.0 That tells FOCAL to display 3 significant digits, and to include up to 2 decimal places even if the traling one(s) would be 0, thus showing all 3 significant digits in an answer expected in degrees. If you'd wanted 4 significant digits with any trailing zeroes instead, you'd give `%4.3` instead. If you'd given `%3`, the output would be `-45`, the trailing zero being deemed unnecessary. ## <a id="ascii"></a>ASCII Character & Key Names Many of the common names for keys and their ASCII character equivalents have shifted over the years, and indeed they shifted considerably even during the time when the PDP-8 was a commercially viable machine. The following table maps names used in [the Manual][uwfm] to their decimal ASCII codes and their common meaning today. | Old Name | ASCII | Current Name | | ----------- | ----- | ------------- | | `RUBOUT` | 127 | Delete or Del | | `DELETE` | 127 | Delete or Del | | `BACKARROW` | 95 | Underscore | | `UNDERLINE` | 95 | Underscore | Beware that the ASCII values above differ from the values given in the U/W FOCAL Manual Appendix "Decimal Values for All Character Codes." FOCAL sets the 8th bit on ASCII characters for reasons unimportant here. Just add 128 to the values above if you need to get the FOCAL equivalent. Some terminals and terminal emulator software may remap Backspace and Delete, either making one equivalent to the other or swapping them. Without such remapping, if you hit the key most commonly marked Backspace on modern keyboards, U/W FOCAL will just insert an ASCII character 8 at that point in the program entry, almost certainly not what you want. You either need to remap Backspace to Delete or hit the key most commonly marked Del. The U/W FOCAL Manual also references keys that used to appear on some terminals, most especially teletypes, which no longer appear on modern keyboards: | Teletype Key | Modern Equivalent | | ------------ | ----------------- | | `LINE FEED` | <kbd>Ctrl-J</kbd> | | `FORM FEED` | <kbd>Ctrl-L</kbd> | ## <a id="overloading"></a>Command Overloading [The Manual][uwfm] tells you right up front that U/W FOCAL only pays attention to the first letter of each command when trying to decide what you're asking it to do, which is why we have strange commands like `YNCREMENT`: `I` was already taken by `IF`. What it *doesn't* make as clear is how the creators of U/W FOCAL began adding a second layer of overloading to this scheme after they began running out of letters in the English alphabet. Early examples of FOCAL's command overloading scheme are the `ON`, `OPEN` and `OUTPUT` commands. By looking at the first argument to the command, FOCAL can tell which of the three you mean. If you give a valid FOCAL expression in parentheses, it is clearly an `ON` command. If you give anything beginning with a letter, FOCAL decides whether it's an `OPEN` or `OUTPUT` command based on which letter that is; you will notice that the first letter of no `OPEN` sub-command is the same as the first letter of any `OUTPUT` sub-command. In later versions of U/W FOCAL, they added a third level to some commands. We have `OPEN RESTART READ` and `OPEN RESUME INPUT`, for example. It may help to abbreviate the commands, as the first letter of each word is all that really matter: `O R R` is clearly not the same as `O R I`. There are other examples of this, such as `LIBRARY` and `LIST`. It is the first letter of the first argument to these commands that determines what FOCAL does. In at least one case, you can see this feature of FOCAL used to talk about a single command under different names. Some FOCAL documents talk about a `ZVR` command, meaning Zero VaRiable. It's just another way of spelling the `ZERO` command: it does the same thing. FOCAL *only* checks the first letter of the command and any necessary disambiguating arguments. The following is therefore a perfectly legal FOCAL program: 01.10 SPEW I = 0 01.20 YGGDRASIL I 01.30 LOOGIE BRAIN 1.2 ; TARPIT I ! It does exactly the same thing as a program we will encounter [shortly](#lbranch). ## <a id="library"></a>`LIBRARY` The OS/8 version of U/W FOCAL includes a "library" feature modeled on a similar feature in OMSI PS/8 FOCAL. These features collectively allow the user access to FOCAL program files stored in the OS/8 file system from within a U/W FOCAL program or as immediate commands to U/W FOCAL. We showed how you can use some of these commands to save and load programs to disk [above](#ls-library), but there's a lot more to it. Coverage of this begins on page 34 of [the DECUS submission][uwfd]. ## `LIST ALL`, `LIST ONLY`, `ONLY LIST` These commands allow you to get OS/8 directory listings from within U/W FOCAL: * **<code>LIST ALL</code>** — Same as `DIR` under OS/8. Accepts an optional OS/8 device name, e.g. `L A SYS:` to show the contents of the `SYS:` device. * **<code>LIST ONLY</code>** — Same as `DIR *.FC` under OS/8. You can also give a device name, a file name, or both to be more specific. For example, you could check for the existence of a `FOO.FC` file on the first half of the second RK05 device with `L O RKA1:FOO`. * **<code>ONLY LIST</code>** — Same as `LIST ONLY` except for FOCAL data files, `*.DA`. The [DECUS submission][uwfd] says it looks for `*.FD`, but that does not appear to be correct in my testing. ## <a id="lbranch"></a>`LOGICAL BRANCH` Our distribution of U/W FOCAL includes the `LOGICAL BRANCH` feature, which is not documented in [the Manual][uwfm], but it *is* documented on page 37 of [the DECUS submission][uwfd]. Briefly, it acts like a `GOTO` command where the jump is only made if keyboard input is detected. The following program counts upward continuously until a key is pressed, then it prints how many iterations it ran: 01.10 SET I = 0 01.20 YNCR I 01.30 LOGICAL BRANCH 01.20 ; TYPE I ! The DECUS document suggests using this feature to turn the keyboard into a giant "switch register," allowing the user to control the behavior of a long-running program without stopping to wait for user input. Can you say "video games"? ## <a id="lexit"></a>`LOGICAL EXIT` Another addition to our version of U/W FOCAL as compared to the version documented in [the Manual][uwfm] is `LOGICAL EXIT` which immediately exits U/W FOCAL and returns you to OS/8, just as if you had hit <kbd>Ctrl-C</kbd>. ## <a id="fsf"></a>FOCAL Statement Functions This appears to be the same thing [the Manual][uwfm] calls Program Defined Functions. Therefore, you may look on the material beginning on page 63 of [the DECUS submission][uwfd] as just another take on the same issue. Some of the examples are more enlightening than the one in the manual. The first example in the DECUS submission, `F(EXP)`, is more robustly coded than the same function in the Manual; comparing the two is instructive. ## `FRA` Built-In Function This function is not documented in [the Manual][uwfm], but it is documented on page 60 of [the DECUS submission][uwfd]. It allows you to set up random access to a file, storing numbers in various raw binary formats directly to the file as if it were a large in-memory array. If you've been trying to use the `FCOM` function but have run into the limit on the size of a PDP-8 core memory field, switching to `FRA` is the logical next step. ## <a id="front-panel"></a>Front Panel Differences Whenever [the Manual][uwfm] refers to the PDP-8's front panel, it is speaking generically of all the models it ran on as of October 1978. The PDP-8 models introduced in the decade following the introduction of the PDP-8/I differ in many ways, and one of the greatest areas of difference is in their front panel controls and indicators. We do not intend to fully document all of the differences here, but only to clarify the differences brought up by the U/W FOCAL Manual. You normally will not need to use the front panel with the OS/8 version of U/W FOCAL we distribute with the PiDP-8/I software distribution since you start and stop U/W FOCAL through OS/8 rather than the front panel. However, we thought these matters could use clarification anyway. Beyond this point, when we refer to the PDP-8/e, we also mean the 8/f, which shared the same front panel design. We also include the 8/m, which normally came with a minimal front panel, but there was an optional upgrade for an 8/e/f style front panel. These three models are therefore interchangeable for our purposes here. ### <a id="clear-regs"></a>`START` vs. `CLEAR` + `CONTINUE` vs. `RESET` With the PDP-8/e, DEC replaced the `START` front panel switch of the preceding PDP-8/I with a `CLEAR` switch. Why did they do this? On a PDP-8/I, the difference between `START` and `CONTINUE` is sometimes confusing to end users, since in many cases they appear to do the same thing. Why have both? The difference is that `CONTINUE` simply resumes operation from the current point in the program where it is stopped, whereas `START` resets several key registers and *then* continues. The PDP-8/e change splits this operation up to avoid the confusion: the old `START` keypress is equivalent to `CLEAR` followed by `CONTINUE`. (This pair of switches also has a `START` label above them, a clear functional grouping.) The U/W FOCAL Manual also speaks of a `RESET` switch in conjunction with the FOCAL starting and restarting the computer. I haven't been able to track down which PDP-8 model has such a switch yet, but for our purposes here, I can say that it just means to load the starting address and hit `START` on a PDP-8/I. ### <a id="if-df"></a>`EXTD. ADDR LOAD` The PDP-8/e has many fewer switches on its front panel than the PDP-8/I, yet it is a more functional machine. One of the ways DEC achieved this is by removing the `IF` and `DF` switch groups and adding the `EXTD. ADDR LOAD` switch, which lets you set the `IF` and `DF` registers using the same 12-bit switch register used by the `ADDR LOAD` switch. The `ADDR LOAD` switch on a PDP-8/e does the same thing as the `Load Add` switch on a PDP-8/I. ### <a id="sw-dir"></a>Switch Direction DEC reversed the meaning of switch direction between the PDP-8/I and the PDP-8/e, and [the Manual][uwfm] follows the 8/e convention: on the 8/I, up=0=off, whereas on the 8/e, up=1=on. Keep this in mind when reading the U/W FOCAL Manual's references to front panel switch settings. ### <a id="sw-order"></a>Switch Ordering When [the Manual][uwfm] talks about the switch register (SR), it numbers the switches left to right, not by their logical bit number in the switch register. That is, "Switch 0" is the leftmost (high order bit) SR switch, not "bit 0" in the SR, which would be the rightmost SR switch. ## Error Codes The [U/W FOCAL Manual][uwfm] gives a somewhat different error code table than the one on `CARD4.DA` of the [U/W FOCAL reference cards][uwfr]. For the most part, the latter is just a simple superset of the former, and both apply. In some cases, though, the two tables differ, or one of them differs from the `UWF16K` program we ship on the OS/8 system disk. ### `?18.32` vs `?18.42` — `FCOM` index out of range The two error code tables give different error codes for this condition. However, since I have not been able to get this error to happen, I do not know which code is correct for our current version of FOCAL. ### `?31.<7` — Non-existent program area called by `LOOK` or `LINK` Our current implementation of U/W FOCAL removed those commands in favor of `LIBRARY`, so you can't make this one happen. An error in a `LIBRARY` command is most likely to give `?26.07` instead. ### Irreproducible Errors There are some errors listed in one or both tables that I have been unable to cause, though I have tried: | Code | Meaning | ------ | ------- | ?07.44 | Operator missing or illegal use of an equal sign | ?18.32 | `FCOM` index out of range (value given in the manual) | ?18.42 | `FCOM` index out of range (value given on the refcard) | ?27.90 | Zero divisor ### Untested Error Cases I have not yet created programs large enough to test the "out of space" codes `?06.41` (too many variables), `?10.50` (program too large), `?13.65` (insufficient memory for `BATCH` operation), `?23.18` (too much space requested in `OUTPUT ABORT` or `CLOSE`), `?23.37` (output file overflow), and `?25.02` (stack overflow). There are also some errors I simply have not yet tried to cause: `?01.03`, `?01.11`, `?12.10`, `?12.40`. ## <a id="miss-hw"></a>Missing Hardware Support The [U/W FOCAL reference cards][uwfr] and the [DECUS submission][uwfd] talk about features for hardware we don't have. Either the command/feature doesn't exist at all in the version of U/W FOCAL we distribute or it doesn't do anything useful, lacking support within the version of SIMH we distribute. Broadly, these features are for the PDP-12, the LAB-8/e, Tektronix terminals, and pen plotters. Should anyone extend SIMH with a way to control such hardware (or emulations of it) we may consider putting these features back into our distribution of U/W FOCAL. In the meantime, the following facilities do not work: * The `FADC`, `FJOY`, `FLS`, `FRS`, and `FXL` functions don't exist * There is no plotter support in SIMH, so the `PLOT` command doesn't exist * Although support for the VC8E point-plot display exists in SIMH, the `VIEW` command to drive it is not present in our version of U/W FOCAL. * Error code `?14.15` can't happen; we have no "display buffer" * Error codes `?14.50` and `?14.56` can't happen; SIMH doesn't simulate a PDP-12 or a LAB-8/e ## <a id="diffs"></a>Differences Between U/W FOCAL and Other FOCALs The [DECUS submission for U/W FOCAL][uwfd] lists the following advantages for the version of U/W FOCAL included with the PiDP-8/I software distribution as compared to FOCAL,1969, FOCAL-8, and OMSI PS/8 FOCAL: 1. Extended library features with device-independent chaining and subroutine calls between programs. 2. File reading and writing commands, 10 digit precision, full 32k memory support, 36 possible functions, 26 possible command letters. 3. Computed line numbers and unlimited line lengths. 4. Tabulation on output, format control for scientific notation. 5. Double subscripting allowed. 6. Negative exponentiation operators permitted. 7. `FLOG`, `FEXP`, `FATN`, `FSIN`, `FCOS`, `FITR`, and `FSQT` rewritten for 10-digit accuracy. 8. Character manipulations handled with `FIN`, `FOUT`, and `FIND`. 9. Function return improvements: * `FSGN(0)=0` in U/W FOCAL; `=1` in FOCAL,1969 * `FOUT(A)=0` in U/W FOCAL; `=A` in PS/8 FOCAL 10. n/a; see [above](#miss-hw) 11. 6 special variables are protected from the `ZERO` command: `PI`, `!`, `"`, `$`, `%`, and `#`. `PI` is initialized as 3.141592654. 12. The limit on the number of variables is 676 13. Text buffer expanded to 15 blocks 14. Two-page handlers permitted 15. Program and file names are wholly programmable. File size may be specified. OS/8 block numbers may be used in place of file names. 16. The `OPEN` and `DELETE` commands can have programmed error returns. 17. Improved distribution and random initialization of `FRAN`. 18. `ERASE`, `MODIFY`, and `MOVE` do not erase variables. 19. `WRITE` doesn't terminate a line; `MODIFY` doesn't echo form feed. 20. U/W FOCAL's starting address is 100 (field 0) or 10200 (field 1). ## <a id="converting"></a>Converting Programs from Other Versions of FOCAL Programs saved by other versions of FOCAL generally don't have the same format as the core images used by U/W FOCAL. You must therefore use one of the [text based loading methods](#loading) to save your program text out of the other FOCAL and load it into U/W FOCAL. Also, while the `ERASE` command may be used to zero variables in other FOCALs, you must use `ZERO` for that in U/W FOCAL. If your program starts off with `ERASE` commands to initialize its variables, there's a pretty good chance your program will just erase itself under U/W FOCAL. ## <a id="rationale"></a>Why Did We Write This? [The Manual][uwfm] is well written as far as it goes, but there are gaps: 1. It is written somewhat generically for the whole PDP-8 family as of late 1978, whereas the PiDP-8/I project is focused on a single model from 1968. Those not familiar with the differences can therefore be confused by some of its directions. 1. There are considerations in our simulated PiDP-8/I world that simply did not apply to those running U/W FOCAL on the real hardware. 1. There are multiple versions of U/W FOCAL; the version covered by [the Manual][uwfm] isn't the one we actually ship. Our two [other][uwfr] primary [sources][uwfd] also do not cover exactly the version of U/W FOCAL we ship. 1. It inspires questions in the reader's mind without providing an answer. Whether this was intentional — with the author intending that the user answer these questions on his own — or otherwise, some of these questions we felt needed answering here within the PiDP-8/I U/W FOCAL documentation. This document is our attempt to fill these gaps and to supplement those other documents. [Extensions and corrections][hack] are welcome. ## <a id="references"></a>References The primary sources for this supplement are: * [U/W FOCAL Manual][uwfm], October 1978, by Jim van Zee of the University of Washington. * [U/W FOCAL reference cards][uwfr] from the U/W FOCAL distribution, approximately contemporaneous with the Manual, but clearly for a different version of U/W FOCAL than is documented in the Manual. * [DECUS Submission for U/W FOCAL][uwfd], also by van Zee, from August 1978. This document describes the OS/8 version of U/W FOCAL rather than the paper tape version described by [the Manual][uwfm] we use as our primary document here within the PiDP-8/I project. We chose to convert the Manual to Markdown rather than this DECUS submission because the DECUS document's scan is terrible, resulting in nearly worthless OCR output; we *really* did not want to retype the whole thing! Additionally, we think the Manual is a better tutorial than the DECUS submission, though the DECUS submission is perhaps a better reference text. [df8]: http://www.ibiblio.org/pub/academic/computer-science/history/pdp-8/FOCL69%20Files/DEC-08-AJAD-D.pdf [f71]: http://svn.so-much-stuff.com/svn/trunk/pdp8/src/decus/focal8-177/ [hack]: https://tangentsoft.com/pidp8i/doc/trunk/HACKERS.md#patches [uwfd]: http://www.pdp8.net/pdp8cgi/query_docs/view.pl?id=191 [uwfm]: https://tangentsoft.com/pidp8i/doc/trunk/doc/uwfocal-manual.md [uwfr]: https://tangentsoft.com/pidp8i/doc/trunk/doc/uwfocal-refcards.md ### <a id="license"></a>License Copyright © 2017 by Warren Young and Bill Cattey. Licensed under the terms of [the SIMH license][sl]. [sl]: https://tangentsoft.com/pidp8i/doc/trunk/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 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 | # U/W FOCAL Manual V4E, October 1978 <code> UWFUWFU UWFUWFU UWFUWFU UWFUWFU UWFUWFUWFUWFUwFUWFUWFUWF WFUWFUW WFUWFUW WFUWFUW WFUWFUW WFUWFUWFUWFUWFUWFUWFUWFU FUWFUWF FUWFUWF FUWFUWF FUWFUWF FUWFUWFUWFUWFUWFUWFUWFUW UWFUWFU UWFUWFU UWFUWFU UWFUWFU UWFUWFUWFUWFUwFUWFUWFUWF WFUWFUW WFUWFUW WFUWFUW WFUWFUW WFUWFUW FUWFUWF FUWFUWF FWUFWUF FUWFUWF FUWFUWF UWFUWFU UWFUWFU UWFUWFU U UWFUWFU UWFUWFU WFUWFUW WFUWFUW WFUWFUW UWF WFUWFUW WFUWFUW FUWFUWF FUWFUWF FUWFUWF UWFUF FWUFWUF FUWFUWFUWFUWFUWFUW UWFUWFU UWFUWFU UWFUWFU WWFUWFU UWFUWFU UWFUWFUWFUWFUWFUWF WFUWFUW WFUWFUW WFUWFUW UWFUWFUWF WFUWFUW WFUWFUWFUWFUWFUWFU FUWFUWF FUWFUWF FUWFUWFUWFUWFUWFUWFUWFUWF FUWFUWFUWFUWFUWFUW UWFUWFU UWFUWFU UWFUWFUWFUWFUWFUWFUWFUWFU UWFUWFU WFUWFUW WFUWFUW WFUWFUWFUWFU FUWFUWFUWFUW WFUWFUW FUWFUWFW WFUWFUWF FUWFUWFUWFU WFUWFUWFUWF FUWFUWF UWFUWFUWFUWFUWFUWFUWFUWFU UWFUWFUWFU UWFUWFUWFU UWFUWFU FUWFUWFUWFUWFUWFUWFUWFU WFUWFUWFU FUWFUWFUW WFUWFUW WFUWFUWFUWFUWFUWFUWFU FUWFUWFU WFUWFUWF FUWFUWF UWFUWFUWFUWFU UWFWUFU UWFUWFU UWFUWFU </code> ## Index to Major Topics in This Manual * [Abbreviations](#abbreviations) * [Arithmetic operators](#operators) * [Break key](#ctrl-keys) * [Character codes](#character-codes) * Commands * [Summary](#commands) * [Direct, indirect](#dir-ind-cmd) * [`ASK`](#io-cmds) * [`BREAK`](#break) * [`COMMENT`](#comment) * [`DO`](#do) * [`ERASE`](#erase) * [`FOR`](#for) * [`GOTO`](#goto) * [`HESITATE`](#hesitate) * [`IF`](#if) * [`JUMP`](#jump) * [`KONTROL`](#kontrol) * [`LINK`](#link) * [`LOOK`](#look) * [`MODIFY`/`MOVE`](#modify) * [`NEXT`](#next) * [`ON`](#on) * [`OPEN`](#open) * [`PUNCH`](#punch) * [`QUIT`](#quit) * [`RETURN`](#return) * [`SET`](#set) * [`TYPE`](#io-cmds) * [`WRITE`](#write) * [`XECUTE`](#xecute) * [`YNCREMENT`](#yncrement) * [`ZERO`](#zero) * [Editing](#editing) * [Enclosures](#enclosures) * [Error messages](#error-messages) * [Formatting](#formatting) * Functions * [Summary](#function-summary) * [Program Defined](#pdfs) * [`FABS`](#fabs) * [`FATN`](#fatn) * [`FBUF`, `FCOM`](#fbuf) * [`FCOS`](#fcos) * [`FDIN`](#fdin) * [`FEXP`](#fexp) * [`FIN`](#fin) * [`FIND`](#find) * [`FITR`](#fitr) * [`FLOG`](#flog) * [`FMIN`, `FMAX`](#fmin) * [`FMQ`](#fmq) * [`FOUT`](#fout) * [`FRAC`](#frac) * [`FRAN`](#fran) * [`FSGN`](#fsgn) * [`FSIN`](#fsin) * [`FSQT`](#fsqt) * [`FSR`](#fsr) * [`FTRM`](#ftrm) * [Input echo](#input-echo) * [Input terminators](#input-terminators) * [I/O operators](#io-operators) * [Line numbers](#line-numbers) * [Loops](#loops) * [Numbers and variables](#numbers) * [Patches](#patches) * [Punctuation](#punctuation) * [Reading in programs](#punch) * [Symbol table dump](#symbol-table-dump) * [Trace feature](#trace) * [Variables](#variables) ## Introduction to U/W-FOCAL for the PDP-8 UWF is a powerful interactive language for the PDP-8¹ which combines ease of use with an extensive set of features, allowing one to perform complex calculations or control laboratory experiments with a minimum of effort. UWF is an advanced version of FOCAL,¹ a stack processing language which is somewhat similar to BASIC and FORTRAN but much easier to use! Programmers who are familiar with either of these languages should be able to write programs for UWF almost immediately, while those who are just learning will find that UWF's simplified commands and built-in editor make their progress very rapid. ### <a id="hardware"></a>Hardware Requirements The minimum system configuration for running UWF is an 8K machine capable of executing the PDP-8 instruction set and some sort of terminal. UWF will automatically take advantage of any additional memory present as well as permitting the use of high-speed I/O devices such as punched paper tape or an audio tape recorder for program and data storage. There is also a much more elaborate version available for systems licensed to use the OS/8 operating system¹ which provides complete device-independent file support. ### <a id="loading"></a>Loading UWF To load the binary tape containing UWF into your machine, proceed as follows: 1. Make sure that the BIN loader is resident in Field 0. 2. Set the Switch Register to 7777 and hit `ADDR LOAD`, then reset Switch 0 if input is from the High Speed reader (leaving 3777), otherwise go to the next step. 3. Place the tape in the reader so that the read-head is positioned over the leader section and hit the `START` (or `CLEAR` and `CONTINUE`) switches. The run light will go off when the tape has finished loading; check to be sure the display is zero, indicating a successful load. If not, repeat steps 1-3 above to see if you get the same checksum error each time. If you do, the tape you are using has probably been damaged and you should try again with another copy. ### <a id="starting"></a>Starting the Program In order to start UWF for the first time, do the following: 1. Set the Switch Register to 0100 (UWF's Starting Address) 2. Press the `ADDR LOAD` and `EXTD. ADDR LOAD` switches 3. Set switches 0-2 and 6-11 for any [options desired](#opt-switch) 4. Now set the `RUN/HALT` switch to `RUN`, and hit `CONTINUE` UWF should respond immediately with a congratulatory message and indicate the amount of memory available in your system. For installations with more than 8K, here is how the additional memory space is used: | Core | Features Allowed | | ---: | -------------------------------------------- | | 12K | Expanded symbol storage or `FCOM` | | 16K | One additional program area or `FCOM` | | ... | ... | | 32K | Five more program areas, or four plus `FCOM` | If you wish to limit the amount of memory available for any reason, you should set switches 9-11 in the switch register before proceeding with Step 4: > Switches 9-11 (octal): 0=All, 1=28K, 2=24K, 3=20K, 4=16K, 5=12K and 6 or 7=8K There are a number of other 'custom' features which can be installed automatically when the program is first started up. These options are controlled by the setting of bits 0-2 and 6-8 in the switch register. The first group (0-2) selects various terminal options while the second group (6-8) controls additional features. Switches 3-5 are ignored and may be set to any value. Once UWF has been started the first time, step 3 is unnecessary and the switches may remain set to '100'. <a id="opt-switch"></a> | Switch | Function | | -----: | -------------------------------------------------- | | 0 | Use 'CRT-style' rubouts instead of 'backslashes' | | 1 | Output four 'nulls' after every Carriage Return | | 2 | Print error messages on a new line | | 6 | Add three extra 'secret variables' (`&`, `:`, `\`) | | 7 | Add the `KONTROL` command and the `FDIN` function | | 8 | Add the `FCOM` and `FBUF` functions (requires 12K) | Example: A switch setting of '4134' limits the program to 16K, adds `FCOM`, `FBUF` and the digital I/O routines, and installs 'scope rubouts'. The '100' bit is ignored. Some of these patches can also be installed (or removed) after the program has been started; see [the Patches section below](#patches) for further details. Note that adding the `FCOM` function reduces the effective memory size by 1 field, hence users with 16K who add this option will normally lose the first additional program area. Since it might be more desirable in this particular case to have `FCOM` replace the extra variable storage, there is a 'magic location' which can be changed (*before* you start things up!) to effect this arrangement. (16K configurations only; see [the Patches section below](#patches) for details.) Note that UWF runs with the interrupt system *ON* which allows program execution to overlap certain I/O operations. The result is faster run times, a 'live' keyboard and the possibility of adding 'background' tasks which can be controlled by the program or 'high-level' interrupts in which an external event causes the execution of a specific group of statements within the program. With the interrupt system enabled, however, it is possible that an 'unknown' device will create a continuous interrupt and thus prevent UWF from running. If the `RUN` light goes on but there is no output as soon as you hit the `CONTINUE` switch, halt the machine, hit the `RESET` or `CLEAR` switch a few times, and then restart at location 100. If UWF still appears to be stuck in an endless loop, you will probably have to add an appropriate 'clear flag' instruction to the interrupt routine. See [the Patches section below](#patches) for the proper location. ### <a id="ctrl-keys"></a>UWF's Control Keys UWF recognizes the following control keys: 1. <kbd>CTRL/F</kbd> is the master program break key: it will restart UWF at any time, assuming that the program is still running. 2. <kbd>CTRL/C</kbd> is the monitor break key. It will eventually trap to a resident 'ODT' package which is not yet implemented. 3. <kbd>CTRL/S</kbd> (`XOFF`) stops output to the terminal. This provides users with video terminals time to inspect their results. 4. <kbd>CTRL/Q</kbd> (`XON`) resumes output to the terminal. Some terminals issue `XON`/`XOFF` codes automatically when the screen fills up. 5. The <kbd>RETURN</kbd> key is used to terminate all command lines. UWF will not recognize a command until the RETURN key is typed. 6. The <kbd>RUBOUT</kbd> or <kbd>DELETE</kbd> key is used to cancel the previous character. On hard-copy terminals, a `\` is echoed for each character deleted. On video terminals they just disappear! 7. The <kbd>LINE FEED</kbd> key is used to retype a command line *before* typing <kbd>RETURN</kbd> in order to verify that all corrections were made properly. This is mostly for hard-copy terminals. Remember: UWF can be interrupted at any time simply by typing <kbd>CTRL/F</kbd>. This is accomplished by holding down the <kbd>CTRL</kbd> key and then typing the letter `F`. UWF will respond by typing a question mark (`?`) followed by the line number where the program was interrupted and then print an asterisk to indicate that it is ready for further instructions: ?@ 05.13 UWF was interrupted at line 5.13 ## <a id="dir-ind-cmd"></a>Direct and Indirect Commands UWF prints an asterisk (`*`) whenever it is in command mode waiting for new instructions. You can then type in either 'direct commands' which are executed immediately, or 'indirect commands' which are saved for execution at a later time. To use UWF as a fancy calculator simply give it a 'direct command' and hit the RETURN key. For example, if you enter the command: *TYPE PI UWF will print the value '3.141592654E+00', correct to 10 significant figures. The Direct Command feature is the essence of interactive programming since it permits one to work through a long calculation a step at a time, or to try out several different ways of doing something. You can experiment with any of UWF's commands by simply typing them in as you read through this manual. Indirect Commands always begin with a line number which indicates the order in which they are to be executed. They may be entered in *any* order, however, and can be examined or changed at any time. Changes to indirect commands are facilitated by the use of UWF's built-in editor which allows lines to be modified, moved to a different part of the program, or deleted. Since indirect commands can be selectively executed by direct commands it is possible to build a very powerful set of 'macros' which can then be called with just a few keystrokes. Line numbers in UWF have a 'dollars and cents' format: `XX.YY` where `XX` may range from 00-31 (the 'group' number) and `YY` may have any value from 00-99 (the 'step' number). Group and Step both have special meanings in some commands, so the first line of the program is usually labeled `1.1`. Notice that leading and trailing zeros are not necessary, but one must always include a space after the line number to separate it from the commands on the rest of the line. Here are some sample indirect commands: *3.61 TYPE ! *12.7 COMMENT *1.99 QUIT A standard programming practice is to index sequential commands by an increment of either '.05' or '.1'. Thus line '1.2' would be used for the statement following line '1.1' rather than line '1.11'. This leaves room to insert up to 9 additional lines in case changes to the program are necessary. Of course lines can always be moved to make room, but it is a nuisance to have to do this and such changes might require alteration of other parts of the program as well. ### <a id="line-numbers"></a>Group and Relative Line Numbers Several UWF commands are capable of operating on all statements with the same group number. To reference an entire group of lines one simply specifies the group number without designating any particular program step: `WRITE 1`, for example, will list all the program steps in 'Group 1'. Since the number '1' and the number '1.00' are indistinguishable to UWF, it is not possible to write just line 1.00 without writing the rest of the lines in the same group as well. For this reason the first line in a group is generally reserved for comments in order to avoid any complications with group operations. UWF can also designate a 'sub-group' operation consisting of all the lines following a specified line in the same group. Such operations are indicated by a 'negative line number': 'WRITE -1.5', for instance, will list all of the lines in Group 1 starting from line 1.5 (if it exists). Line numbers in the range '.01-. 99" are termed 'relative line numbers', i.e. they refer to lines in the *current group*, rather than to lines in 'Group 0'. The use of such line numbers is encouraged because it makes the program more compact and also allows subroutines to be moved easily from one part of the program to another without having to worry about internal references. Lines with numbers less than 1.00 *can* be saved as part of the indirect program, but they can only be executed when the program is started from the beginning since there is no way to branch to them at a later time. Finally, references to line '0' also have a special meaning. A few commands interpret such references to mean 'the entire program', while most others regard 'line 0' as a reference to 'the next command'. Line 0 itself is the permanent comment line (the 'Header Line') at the beginning of the program. ### <a id="punctuation"></a>Punctuation It is a common practice to put several commands on the same line in order to reduce the amount of paper required for listing the program as well as to consolidate related operations. A 'semicolon' (`;`) is used to separate such commands: *SET A=5; TYPE A Commands which operate on more than one expression use a comma to separate the values. Thus the command `TYPE A,B` is equivalent to `TYPE A; TYPE B`. Spaces may be included to improve the readability of a program, but one must remember that 'space' is a terminator, equivalent to a comma, so the command `TYPE A B` is interpreted as `TYPE A,B`, not as `TYPE AB`. ## <a id="numbers-variables" name="numbers"></a>Numbers and Variables UWF can handle up to 10-digit numbers with a magnitude range of 10<sup>615</sup>. Numbers may be written as signed or unsigned quantities and may include a decimal fraction as well as a 'power-of-ten' exponent indicated by the letter `E`. All numbers are stored internally in a 'floating-point' format with 35 bits of mantissa and 11 bits of exponent. This is equivalent to more than 10-digit accuracy. UWF will respond with an error message if a user attempts to enter a number with too many digits. The following all represent the value 'sixty': * 60 * 60.00 * 6E1 * 600.0E-1 UWF also allows letters to be treated as numbers so that questions may be answered with a 'YES' or 'NO' response rather than with a numeric reply. When decoded in this manner, the letters 'A-Z' have the values '1-26', except that the letter 'E' always means 'power-of-ten'. Thus the answer 'NO' would have the numerical value '155' and the number 'sixty' could also be written as `0DT` or `0FEA`. Note that the leading '0' is only required when incorporating such 'numbers' into a program. It is not required as part of a user response. ### <a id="var-names" name="variables"></a>Variable Names Variables are used to store input values or to save intermediate results. Variables are thus like the storage registers on a calculator except that the programmer may make up his own names to designate the values stored. UWF allows variable names of any length, but only the first two characters are retained internally. Thus the names JOHN and JOE would both refer to the variable `JO`. The first character of a variable name must obviously not be a number, nor can it be the letter `F` since that letter is used to designate functions. However UWF does allow symbols such as `$` and `"` to be used as part of a variable name so you can have quantities such as `A$`, `A`, and `A"`. Variables are always stored as numeric quantities; UWF does not currently have 'string' variables. ### <a id="symbol-table"></a>The Symbol Table The names of the variables which have been used by the program are saved (along with their values) in a region of memory called the 'Symbol Table'. This area is completely independent of the area used to store the program so changes to the text buffer do not affect any of the values stored in the symbol table. This is extremely convenient since it allows a program to be interrupted, modified, and then restarted somewhere in the middle, knowing that any intermediate results obtained will still be available. Of course the programmer may examine any such values simply by `TYPE`ing them out, or he may change a few values with a direct command before restarting the program. Variables are always assumed to have the value 'zero' until another value has been assigned. The `TYPE $` command can be used to list all the values in the Symbol Table in the order they were defined by the program. The ZERO command is used to clear the table or to selectively set some of the variables to zero. Variables with the value '0' may be replaced by other non-zero variables when the symbol table fills up. This is transparent to the programmer since 'undefined' variables are always zero anyway. ### <a id="protected-vars"></a>Protected Variables The symbols {`!`, `"`, `#`, `$`, `%`} and optionally {`&`, `:`, `\`}, along with the value of `PI`, are 'protected' variables which cannot be replaced or removed by a ZERO command. This makes them useful for saving results which are needed by a second program. Since they cannot be input or output directly and do not appear in a symbol table dump, they are also sometimes called 'secret' variables. Note that UWF automatically sets `PI` equal to 3.141592654, so users should not use `PI---` as a variable name or this value will be lost. The variable `!` ('bang') is used as the dimension constant for [double subscripting](#dsub) and many of the remaining 'secret variables' serve as dummy arguments for [Program Defined Functions](#pdfs). To `TYPE` the values of these variables, you must prefix a `+` sign or enclose them in parentheses: `TYPE +!` or `TYPE (!)` will output the value of the first one. ### <a id="subscripted-vars"></a>Subscripted Variables Variables may be further identified by attaching a subscript enclosed in parentheses immediately after the name, e.g. `A(I)`. Such subscripts may consist of arithmetic expressions involving other subscripted variables, so quite intricate relations can be developed. Unlike many other high-level languages, UWF does not require any 'dimension' statements for processing subscripted variables, nor are the subscripts limited to only positive integers. (They are limited to 12 bits, however.) A variable such as `APPLE(-PIE)` is thus perfectly acceptable although UWF will view this more prosaically as simply `AP(-3)`. Non-subscripted variables are the same as those with a subscript of zero, i.e. `A` = `A(O)`. <a id="dsub"></a> To handle double subscripting, UWF *does* require a small amount of additional information. Before using a double subscripted variable the programmer must store the maximum value of the first subscript in the protected variable `!`. This value may be greater than the actual maximum without incurring any storage penalty, but if it is too small more than one array element will be stored in the same location. Since this single 'dimension constant' is used for all arrays it should be chosen for the largest array in cases where the program uses several different sizes. To illustrate: suppose that operations on a 5x5 array were necessary. Then `!` ('bang') should be set to 5. If 3x3 arrays were also needed simultaneously (which is not very likely) their elements would all be unique and only 9 storage locations would be used, not 25. Non-square arrays are handled just as easily: a 5x20 array would still only require that `!` be set to 5 since that is the maximum value of the *first* subscript. This method of storing two-dimensional arrays proves very convenient for a wide range of linear algebra problems. The value of `!` is generally used as a loop limit so that the routines can be used with any size array. ## <a id="operators"></a>Arithmetic Operators UWF recognizes 6 basic arithmetic, and 1 special 'character value' operator: 1. `+` Addition 2. `-` Subtraction 3. `*` Multiplication 4. `/` Division 5. `^` Signed Integer Powers 6. `=` Replacement 7. `'` Value of next character These 7 operators may be combined with explicit numbers and function or variable names to create 'Arithmetic Expressions' such as: X= -B/2*A + Y= FSQT(B^2-4*A*C) Such expressions can be used *anywhere* that explicit numbers appear in this writeup. In particular, they may be used to compute line numbers. All expressions are evaluated to 10-digit accuracy independent of the format used for output. Intermediate results are generally rounded off rather than being truncated. Most commands use, or operate on, arithmetic expressions. If such expressions are *omitted*, a value of 'zero' is always assumed. This occurs frequently when evaluating line numbers, hence you should recall the comments about line '00.00' mentioned [above](#line-numbers). ### <a id="operator-priority"></a>Priority of Arithmetic Operations Arithmetic operations are performed in the following sequence: | Priority | Op | Description | | -------: | ------------------------------ | | 1st | `^` | integer power | | 2nd | `*` | multiplication | | 3rd | `/` | division | | 4th | `-` | subtraction and negation | | 5th | `+` | addition | | Last | `=` | replacement | When UWF evaluates an expression which includes several operations, the order above is followed. For example, UWF evaluates the expression: X=5^2/5*2-Z=5/2 leaving `X` equal to 'zero' and `Z` equal to 2.5. Notice that multiplication has a higher priority than division. This is different from the convention in many other languages where these operations have equal priority. In most cases this difference is of no consequence. The effect of embedding replacement operators is to cause portions of the expression to be evaluated in a somewhat different order than would be the case if they were not included. In the example above, for instance, the quantity `5*2` is divided by the quantity `5*2` and then the quantity `Z` which is equal to `5/2` is subtracted from the result. However, if one were to add a `Y=` operator after the first `/` then the quantity `5*2` would be divided by `Y` which would be equal to `5*2-Z`. ### <a id="enclosures"></a>Enclosures The order of evaluation can also be changed by the use of enclosures. Three different kinds are allowed by UWF: Parentheses `()`, Square Brackets `[]`, and Angle Brackets `<>`. Subscripts and function arguments are common examples of expressions contained in enclosures. UWF treats all sets identically — they must be matched, of course! — except in some of the monitor commands in the OS/8 version. If the expression contains nested enclosures, UWF will evaluate it starting with the innermost set and working outward. For example: [A=5*<B=2+3>-5]^2 is evaluated as 'four hundred' with `A`=20 and `B`=5. ## <a id="abbreviations"></a>Abbreviations UWF doesn't care whether you tell it to `TYPE` or `TAKEOFF`! The reason is that only the *first* letter of the command is recognized, just as only the first *two* letters of a variable name have significance. So while we have been carefully spelling out all the commands in the examples so far, we could just as well have abbreviated them to their first letters. This feature of the language is both good and bad. On the one hand it greatly reduces the amount of typing required and at the same time increases the number of program steps possible. But on the other hand, a program containing hundreds of single letter commands looks more like a sheet of hieroglyphics than anything else. This makes it quite difficult for the beginner to understand the program logic until he himself has become more familiar with the meaning of all the symbols. For maximum clarity the examples in this writeup will generally be spelled out, but you should realize that the commands `T PI` and `TYPE PI` will produce *exactly* the same result. We will now turn to a detailed examination of all the commands available to the UWF programmer, beginning with the editing commands since they are required for further program development. ## <a id="editing"></a>Command Mode Editing When UWF is in command mode you can use the `RUBOUT` or `DELETE` key to correct any typing errors. Each time that you hit this key UWF will delete the preceding character and echo a `\` on the terminal. If you have a video terminal, and you set switch 0 up when you started UWF for the first time — or made the appropriate patch yourself — hitting <kbd>DELETE</kbd> will actually remove the character from the screen. This is obviously much nicer since 'what you see is what you've got'. On the other hand, users with a hard-copy terminal can always just hit the <kbd>LINE FEED</kbd> key to have the current input line retyped so that they can see just how it 'really' looks to UWF. There is no limit to the length of input lines; however, if your terminal does not handle 'wrap-around' automatically, the practical limit is the width of paper. In addition to <kbd>RUBOUT</kbd>, the <kbd>BACKARROW</kbd> (or <kbd>UNDERLINE</kbd> key as it is identified on newer terminals) may be used to delete all characters to the left, including the line number of an indirect command. You may then start over again. It is not necessary to hit <kbd>RETURN</kbd> although you may wish to do so to get back to the left margin again. Note that <kbd>LINE FEED</kbd> will not echo a blank link and <kbd>RUBOUT</kbd> will stop echoing a `\` when it reaches the beginning of the line. The use of <kbd>BACKARROW</kbd> as a 'line-kill' character necessarily means that this character (and <kbd>RUBOUT</kbd>, of course) cannot be part of the program, but all remaining ASCII characters, both upper and lower case, can be used. Control codes can also be used, but they should be scrupulously avoided since they are non-printing and are therefore impossible to find when they are embedded in a program. In fact, if you ever have a mysterious error in what appears to be a perfectly good command, just try retyping it in its entirety to eliminate any 'ghosts'. Once you hit the <kbd>RETURN</kbd> key, UWF will digest whatever you have typed, so subsequent changes require the use of the editing commands. The text buffer can hold approximately 7000 (decimal) characters — typically 3-4 pages of printout. To list any or all of this material you use the `WRITE` command; to eliminate some of it you use `ERASE`, and to make changes without having to retype the unchanged part, you use the `MODIFY` command. This command can also be used to `MOVE` parts of the program to a different location. ### <a id="write"></a>`WRITE` The `WRITE` command, without any modifier, will list all of the indirect commands currently saved in the text buffer. Lines are typed out in numerical sequence, no matter in what order they were entered, and are separated into the groups you have specified. For this reason it is very convenient to use a different group number for each major part of the program even if such a section only has a few program steps. Using the first line (line `XX.00`) for a `COMMENT` to describe the purpose of that section is also highly recommended. The `WRITE` command can also be qualified by a string of numbers to limit the listing to selected portions of the program. `WRITE 1`, for example, will print out just the commands belonging to Group 1, while `WRITE 2.2` will list only that single line. A command such as `WRITE 1,2,3.3,4.9,5` will list 3 groups and 2 single lines, in the order specified. Of course you should try to plan your program so that it executes smoothly 'from top to bottom', but if you do need to add a major section at the end, the `WRITE` command can be used to at least make a listing showing the logical program flow. Another convenient feature of the `WRITE` command is the ability to list a specific line and all lines following it within the same group. This is done by specifying a *negative* line number. Thus `WRITE -1.5` will list line 1.5 (if it exists) plus the remainder of Group 1. The `WRITE` command will not produce an error if the line or group you specified is missing — it will simply not list it: What you see is what you've got! ### <a id="erase"></a>`ERASE` The `ERASE` command is used to delete parts of the program. `ERASE` without a qualifier deletes the entire program, while `ERASE 2` will delete just Group 2. Other possibilities are `ERASE 9.1` which will only remove that single line, and `ERASE -4.5` which will eliminate the second half of Group 4. Since `ERASE 0` erases everything, you must use an `ERASE -.01` command to erase all of Group 0. There is no way to erase lines such as `2.00` without erasing the entire group at the same time; this is one restriction on the use of such lines. Unlike the `WRITE` command, only a single qualifier may be used with `ERASE`, and UWF will return to command mode immediately after executing the command. Typing in a new line with the same number as an old one will effectively erase the previous version. Entry of just a line number by itself will result in a 'blank line' which may be used to separate sub-sections of a program. Note that this treatment of blank lines differs from that used by BASIC. Blank lines will be ignored during program execution. ### <a id="modify" name="move"></a>`MODIFY`/`MOVE` To change a program line or to move it to a different part of the program, you must use the `MODIFY` or `MOVE` commands. `MODIFY` without a qualifier can be used to examine the header line, but it cannot be used to change this line. `MODIFY` with a single line number permits changes to the line specified while a `MODIFY` (or `MOVE`) with *two* line numbers allows similar changes, but saves the modified line with the new number. The old line, in this case, remains just as it was. `MODIFY` only operates on single lines at the moment, so a command such as `MODIFY 1` will allow changes to line `1.00`, not to all of Group 1. Similarly, `MOVE 2,3` will move line `2.00` to line `3.00`; it will not move all the lines in Group 2. Since UWF does not have a 're-number' command, moving lines and then erasing the old copy is the only way to add additional lines when you forget to leave enough room between sequential line numbers. After you have entered a `MODIFY` (or `MOVE`) command, UWF will optionally print out the line number and then pause until you enter a search character. As soon as you have done so, the line specified will be typed out through the first occurrence of this character. If you want to insert material at this point, just type it in; if you want to delete a few characters, simply use the `RUBOUT` or `DELETE` key. Other editing options may be invoked by typing one of the following control keys. Note: mistakes made while trying to modify a line often lead to embedded control codes, so if you do get confused, just type CTRL/F and try again. | Keystroke | Name | Description | | ----------------------------------------- | ---- | ------------------------------------------------- | | <kbd>CTRL/F</kbd> | — | Aborts the command — the line is unchanged | | <kbd>CTRL/G</kbd> | BELL | Rings bell and waits for a new search character | | <kbd>CTRL/J</kbd> | LF | Copies the rest of the line without changes | | <kbd>CTRL/L</kbd> | FF | Looks for the next occurrence of search character | | <kbd>CTRL/M</kbd> | CR | Terminates the line at this point | | <kbd>BACKARROW</kbd>/<kbd>UNDERLINE</kbd> | — | Deletes all chars to the left, except line number | | <kbd>RUBOUT</kbd>/<kbd>DELETE</kbd> | — | Deletes previous character, as in command mode | The last two operations are similar to those available during command mode except that <kbd>BACKARROW</kbd> or <kbd>UNDERLINE</kbd> does not delete the line number. To remove the first command on a line containing several commands, just enter a semicolon (`;`) as the search character, wait for the first command to be typed out, hit <kbd>BACKARROW</kbd> or <kbd>UNDERLINE</kbd> and then hit the <kbd>LINE FEED</kbd> key. <kbd>CTRL/G</kbd> and <kbd>CTRL/L</kbd> may be used to skip quickly to the part of the line requiring changes. If the change(s) you wish to make involve frequently used characters (such as an `=`), you can initially select a different symbol which occurs less frequently and then use <kbd>BELL</kbd> to change to the character you really wish to find. Or you can simply keep hitting the <kbd>FORM FEED</kbd> key to advance through the line. In case your terminal happens to respond to a <kbd>FF</kbd>, you will be pleased to know that UWF does not echo this character! If you just want to move a line from one location to another, type a <kbd>LF</kbd> as the initial search character. If you are adding new commands in the middle of a line, be sure to use the <kbd>LF</kbd> key — not the <kbd>RETURN</kbd> key — to finish copying the rest of the line. Otherwise you will lose the commands at the end of the line and you will have to `MODIFY` the line a second time in order to re-enter them! If you have a hard-copy terminal you may wish to `WRITE` out the line after you have modified it to check for additional errors. With a video terminal, on the other hand, the corrected line will be displayed just as it is. If you have many lines to move (say all the lines in Group 5), and you have a slow terminal, you can disable the printout during the Move in order to speed things up. To do this, simply disable the keyboard echo by using [the `O I` command](#echo-option). A disadvantage to this method is that not even the `MOVE` commands will be printed so you have to operate 'in the dark', but this is still the best way to make such a major program change. To restore the keyboard echo just hit CTRL/F. On video terminals, the number of the line being modified is printed out at the beginning so that the changes will be properly positioned on the screen. With a hard-copy terminal, however, the line number is not normally printed in order to leave as much room as possible for rubouts and insertions. [The Patches section below](#patches) indicates the location to change if you wish to add the line number printout in this case. ## <a id="text" name="look"></a>Expanded Text Storage If your machine has more than 12K of memory, UWF will automatically use Fields 3-7 for additional text buffers. This allows such systems to keep several different programs in memory at the same time, which is obviously a very convenient thing to do. The `LOOK` command is then used to select the desired 'area' for editing, program execution, etc. Programs in different areas are essentially independent and may use the same line numbers, but the symbol table and the 'stack' are shared by all areas. The `LOOK` command has the form: `LOOK Area`, where `Area` has the value `0` for the main text buffer and `1`, `2`, `3`, etc. (up to `5`) for the additional fields. `LOOK` always returns to command mode and is normally only used as a direct command. `L 1` will switch to Area 1 while `L 0` (or just `L`) will return to Area 0. For calls between program areas, see [the `LINK` command](#link). ## <a id="io-cmds" name="io-operators"></a>Input/Output Commands UWF's I/O commands are called `ASK` and `TYPE`, respectively. The `TYPE` command has appeared previously in a few of the examples; basically, it converts the value of an arithmetic expression to a string of ASCII characters which are then sent to the terminal, or to whatever output device has been selected as a result of an appropriate [`OPEN` command](#open). Similarly, the `ASK` command is used to input numeric values, either from the keyboard or from another input device. Both of these commands recognize 6 special operators for controlling the format of I/O operations. These operators are, in fact, just the symbols previously identified as 'protected variables', and it is because of their special significance in `ASK` / `TYPE` commands that they cannot be input or output directly. These operators and their meanings are as follows: | Op | Description | | --- | ----------------------------------------------------------- | | `!` | Generate a new line by printing a CR/LF | | `"` | Enclose character strings for labeling | | `#` | Generate a <kbd>RETURN</kbd> without a <kbd>LINE FEED</kbd> | | `$` | Print the contents of the Symbol Table | | `%` | Change the output format | | `:` | Tabulate to a given column or ignore input | You will notice that these are mostly 'output' operations. Nevertheless, they perform the same function during an `ASK` command that they do in a `TYPE` command. The `#` operator does not work on all I/O devices and is therefore seldom used. It was originally intended for overprinting on the same line, but may be [easily patched](#patches) to generate a <kbd>FORM FEED</kbd>, should that be desirable. The remaining operators will now be discussed in greater detail. ### <a id="bang"></a>The New Line `!` (Bang) Operator The `!` operator is used to advance to a new line. UWF never performs this function automatically, so output on a single line may actually be the result of several `ASK` or `TYPE` commands. 'Bang' operators can be 'piled together' to produce multiple blank lines: `TYPE !!!!!`, for example, would advance 5 lines. Note that to produce a single blank line, you may require either 1 or 2 `!`s depending upon whether anything has been written on the first line. ### <a id="quote"></a>The Quote `"` Operator UWF uses the `"` operator to enclose strings which are output just as they appear in the program. Thus the command: `TYPE "HELLO THERE, HOW ARE YOU TODAY?"` would simply print the message enclosed by the quote marks. The `ASK` command uses such output for prompting: `ASK "HOW OLD ARE YOU? ",AGE` will print the question and then wait for a response. In some cases the [`TRACE` operator (`?`)](#trace) is also useful for printing labels during an `ASK` or `TYPE` command. ### <a id="symbol-table-dump"></a>The Symbol Table Dump `$` Operator The Symbol Table Dump operator (`$`) has already been [mentioned briefly](#symbol-table). It prints all the symbols defined by the user's program in the order in which they were encountered. It does not print the values of the 'secret variables'. To conserve paper and to permit as many symbols as possible to be listed on a video terminal, the listing normally has three values per line. This format can be changed simply by specifying a different number after the `$`. Thus, `TYPE $5` will change the default value to 5, which is convenient on terminals which can print up to 132 characters per line. The total number of symbols possible depends upon the amount of memory available. In an 8K machine there will only be room for about 120 variables, while in a 12K machine one can have approximately 675. For internal reasons, a Symbol Table Dump always terminates execution of the command line it is on, hence commands following it on the same line will not be executed. ### <a id="formatting"></a>The Format `%` Operator The format operator (`%`) allows UWF to print numeric results in any of three standard formats: integer, mixed decimal, or 'floating-point' (scientific notation). A format remains in effect until another one is selected. Initially UWF is set to print all results in full-precision scientific notation so that all digits of a result will be output. However for many calculations a 'decimal' or 'integer' style of output is more desirable. Such formats are selected by the value of an arithmetic expression following the `%` operator which has the form: %ND.DP where `ND` is the Number of Digits to be printed (the result will be rounded off to this precision), and `OP` is the requested number of Decimal Places. `DP` should be smaller than `ND` unless `ND` is zero; if `DP` is zero the result will be an 'integer' format and no decimal point will be printed. Thus the command `TYPE %2,PI` will produce the result ' `3`'. Notice that the form of the format specification is similar to that used for line numbers. This may help to explain why it is necessary to use `%5.03`, rather than `%5.3`, when you wish to have 5 digits printed with up to 3 decimal places. The number of decimal places actually printed may not be exactly what you have requested. If UWF finds that the number being output is too big to fit the format you specified it will reduce the number of decimal places. For example, if you try the command: TYPE %5.04, 123.456 you will actually get the value ' `123.46` printed since it is not possible to show 4 decimal places with only 5 digits. Note however that UWF *did* print the 5 most significant digits in a format approximately like the one requested. Programmers accustomed to dealing with large powerful computers which print only a string of `*****`s under similar circumstances should find UWF's approach quite sensible. What happens if the number is so large that even the most significant part overflows the field specified? In that case UWF automatically switches to floating-point format for that value so you will be able to see an unexpected result without having to re-run the entire program! You can try this out simply by typing the value `123456` without changing the format from the previous setting. UWF will print: ' `1.2346E+05`. To purposefully select a floating-point format you should specify one with `ND` equal to 0. Thus the format `%.05` will print 5-digit numbers in proper scientific notation (1 digit before the decimal point). The default format when UWF is first loaded is `%.1` which prints all 10 digits. To return to this format you can simply specify `%`, since the value '0' is treated the same as `%.1`. Note that using an arithmetic expression for the format specification, rather than just a fixed number, permits the format to be changed dynamically while the program is running: `%VF` would select a format using the value of the variable `VF`. Finally, note that UWF will never print more than 10 significant digits, the limit of its internal accuracy. If the quantity `ND` is larger than this, spaces will be used to fill out the number. If the quantity `DP` is larger, zeros will be added. In any case, if the number is negative UWF will print a minus sign just ahead of the first digit. A plus sign is never printed — except as part of the exponent — but a space is reserved for it anyway. An additional space is also printed at the beginning in order to separate the number from any previous output. This space may be omitted (or changed to an `=` sign) by making the patch shown in [the Patches section below](#patches). To summarize the various output format settings: | Format | Description | | ------ | ---------------------------------------- | | `%N` | `N` digit integer format | | `%N.D` | `N` digits with up to `D` decimal places | | `%.D` | `D` digits in scientific (F.P.) notation | | `%` | the same as `%.1` — full precision F.P. | ### <a id="tab"></a>The Tab `:` Operator The tab (`:`) operator provides a convenient way to create column output. The expression following the colon is used to set the column, i.e. `:10` specifies column 10. The tab routines do not attempt to go backward if the column specified is to the left of the current print position; the command is simply ignored in this case. 'Tabs' are recommended in place of a string of spaces so that changes in the output format will not affect subsequent columns. There are two special cases: tabbing to column 0 and tabbing to a negative column. Neither is possible since columns are numbered from 1 to 2047, but both are useful operations. Expressions which have the value zero can be evaluated by the tab operator within a `TYPE` command *without* producing any output. This is convenient occasionally, especially for calling the [`FOUT` function](#fout). Tabbing to a negative column has been given a quite different interpretation, however. Since the current version of UWF can only input numeric values with the `ASK` command, there is a need for a method to skip over label fields when re-reading output produced by another program. This facility is provided by 'tabbing' to a negative column number which causes no output, but instead reads and ignores the specified number of characters. Thus the command `TYPE :-1` will *read* 1 character from the input device. This may well appear confusing, since we have an 'output' command waiting for input, so the `ASK` command may be used instead: `ASK :-1` performs the same function. This feature provides a simple way to get the program to wait for operator intervention. For example, the command `TYPE "TURN ON THE PUNCH":-1` would print the message and then wait for any keyboard character to be typed. An `ASK :-2000` command will let a visitor type almost anything s/he likes into the computer without danger of destroying a valuable program. ### <a id="ask-type-summary"></a>`ASK`/`TYPE` Summary Having discussed all the `ASK`/`TYPE` operators, there is really very little more to explain about the commands themselves. `TYPE` can evaluate a whole series of arithmetic expressions which are generally separated by commas or spaces or one of the above operators, while `ASK` can input values for a whole list of variables, again separated by commas or spaces. Here are a few examples: TYPE !!:10"TODAY IS"%2,15 %4" OCTOBER"1978! ASK "TYPE A KEY WHEN YOU ARE READY TO G0":-1 TYPE !"THE ROOTS ARE:" %5.02, R1 :20 R2 !! ASK !"WHAT IS THE INITIAL VALUE OF X? " IX Notice that the tab (`:`) and new line (`!`) operators can be included in an `ASK` command to help format the input. Thus `ASK X :10 Y !` would keep the input responses in two nicely aligned columns. It is quite convenient to be able to output the necessary prompting information with the `ASK` command; other languages frequently require separate commands (such as `PRINT` followed by `INPUT`) for these operations. The [trace operator](#trace) is also useful in `ASK` and `TYPE` commands when one is interested in a 'minimal effort' I/O structure. One other feature of a `TYPE` command should be noted: it is possible to save the value of a quantity being `TYPE`d just by including a replacement operator in the expression. Thus `TYPE X=5` will output the value '5' and also save it as the value of the variable `X`. Numeric input for the `ASK` command can take any of the forms [listed above](#numbers-variables); specifically: signed integers, alphabetic responses, decimal values or numbers containing a power-of-ten exponent. Because such numbers are processed as they are being input, it is not possible to use the <kbd>RUBOUT</kbd> key to delete an erroneous character. Rather, one must effectively hit the 'clear key' (as on a calculator) and then re-enter the entire number. The 'clear' function is indicated by typing a <kbd>BACKARROW</kbd> or <kbd>UNDERLINE</kbd> just as it is during command input. If you do attempt to use <kbd>RUBOUT</kbd>, no `\` will be echoed which serves as a reminder that this key is ignored during an `ASK` command. ### <a id="input-terminators"></a>Input Terminators UWF allows a variety of characters to serve as input terminators. In addition to the <kbd>RETURN</kbd> key, one may use a <kbd>SPACE</kbd> — spaces in front of a number are ignored, but may be used to format the input as desired; spaces following the number always act as a terminator — a <kbd>COMMA</kbd>, <kbd>SEMICOLON</kbd>, or other punctuation marks such as a <kbd>QUESTION MARK</kbd> or <kbd>COLON</kbd>. A <kbd>PERIOD</kbd> is, of course, recognized as a decimal point, but a second period also works as a terminator. Any of the arithmetic operators also serve as terminators; in particular, the <kbd>/</kbd> and <kbd>-</kbd> characters are often convenient. This allows responses such as `1/2` or `1-5` for the values of *two* different variables. In fact, any character *except* `0`-`9`, `A`-`Z`, <kbd>RUBOUT</kbd> and <kbd>LINE FEED</kbd> or <kbd>FORM FEED</kbd> can be used to terminate the response to an `ASK` command. More to the point, however, is the fact that the program can test to see which terminator was used. This allows a very simple input loop to read an indefinite number of items until a specific terminator — a `?`, for instance — is found. See the discussion of the [FTRM function](#ftrm). The <kbd>ALTMODE</kbd> or <kbd>ESCAPE</kbd> key is a special case: typing either of these keys leaves the previous value of the variable unchanged. This allows quick responses to repeated requests for the same value. The program, of course, can pre-set the value of the variable so that an <kbd>ALTMODE</kbd> response will merely confirm the expected value. ## <a id="arithmetic"></a>Arithmetic Processing Commands There are four commands in this group: `SET`, `XECUTE`, `YNCREMENT` and `ZERO`. ### <a id="set"></a>`SET` The most frequently used command in the UWF language is the `SET` command. This command evaluates arithmetic expressions without producing any output (except when the [trace feature](#trace) is enabled). Such expressions typically have the form: SET Variable Name = Arithmetic Expression But more general expressions, particularly those containing sub-expressions, are perfectly acceptable. Thus a command such as `SET A=B=C=5` could be used to set all three variables to the same value while `SET I=J+K=1` would initialize the value of `K` to 1 as well as set `I` to `J+1`. Expressions used with the SET command do not need to contain replacement operators: the command `SET FIN()` could be used, for instance, to input a single character. The value of the function would not be saved, however; this is sometimes useful when calling 'I/O' functions for their 'side-effects'. Note that the word `SET` (or its abbreviation `S`) is not optional as it is in some other languages. The flexible syntax employed by UWF makes it mandatory that every command begin with a command letter. One SET command, however, will process as many expressions as can fit on a single line. The expressions should be separated by commas or spaces; for instance: SET A=1,B=2,C=A+B which is equivalent to: SET C=(A=1)+B=2 Another point to remember is that the same variable may appear on both sides of an `=` sign. Thus `SET X=X+5` has the effect of redefining the value of `X` to be 5 more than the initial value. This can get to be tricky if the same variable appears several times in a single expression on both sides of replacement operators. The rule here is that in each instance the variable will have its current value until the entire expression to the *right* has been evaluated; then it will be replaced with the new value. To give a fairly simple yet intriguing example: SET A=B+A-B=A which is equivalent to: SET C=B+A,B=A,A=C-B This will interchange the values of `A` and `B`. Another expression which does the same thing is: `SET A=B+0*B=A`. Notice that the processing of this expression involves two different values of `B`: The first time `B` is encountered it is on the right side of an `=`, so its current value is used; the second time it is on the left side, so the rest of the expression is evaluated, the substitution made, and then processing of the first part is resumed. Thus `A` retains its original value until the very end (when it is replaced by the initial value of `B`, which was saved on the stack). ### <a id="zero"></a>`ZERO` The special case of 'SET Var=0' is conveniently handled by the `ZERO` command. A single `ZERO` command may be used to set several variables to zero, making it very convenient for initializing sums and 'flags': `ZERO A,#,C` will set those three variables to zero. As a special case, if no variables are specified, the `ZERO` command clears the entire symbol table. This effectively sets *all* the variables to zero since this is the default value for 'undefined' quantities. One other use of the `ZERO` command should be mentioned. When the Symbol Table fills up, UWF tries to replace any variables which have the value '0' with new variables. This procedure succeeds as long as there is at least 1 variable with this value, since that one will simply be renamed, and no matter what the name, it will always be zero. As a result of this scheme, programmers may regain symbol table space by `ZERO`ing unneeded variables when they are finished with them. ### <a id="yncrement"></a>`YNCREMENT` Another special case of the `SET` command — `SET Var = Var + 1` is handled by the `YNCREMENT` command. This command allows a list of variables to be either incremented or decremented by the value '1'. The command `Y K`, for example, is equivalent to `SET K=K+1` while `Y -J` is the same as `SET J=J-1`. Of course commands such as `Y N,O-P` are permitted; this one increments the variables `N` and `O` and decrements `P`. Either commas, spaces or minus signs may be used to separate the variable names. ### <a id="xecute"></a>`XECUTE` The `XECUTE` command has been included for compatibility with earlier versions of UWF. Its purpose was to evaluate arithmetic expressions without setting useless 'dummy' variables. This is now accomplished by the `SET` command itself simply by omitting the replacement operator. Thus `SET FOUT(7)` may be used to ring the bell on the terminal. Internally, `SET` and `XECUTE` are identical; it is recommended that `SET` be used in new programs. ## <a id="branch-control"></a>Branch and Control Commands This class of commands is used to test arithmetic results, set up loops and otherwise control the sequence of command execution. There are 11 commands in this category — UWF has a very rich control structure built around two fundamentally different types of transfers: the `GOTO` branch and the `DO` call. Both interrupt the normal sequence of command execution, but the `GOTO` is an unconditional branch while a `DO` call eventually returns to the next command following the call. The `DO` command is similar to the `GOSUB` in BASIC, but is considerably more flexible. ### <a id="goto" name="considered-harmful"></a>`GOTO` This command has the form `GOTO line number`. It causes an immediate transfer to the line specified. The `GO` command is the usual way of starting the indirect program at the lowest numbered line; it may be used to start the program at any other line as well: `G 2.1` will start at line '2.1'. An explicit line number may be replaced by an arithmetic expression to create what FORTRAN calls an 'Assigned Goto': `SET X=5.1 . . . GOTO X`. ### <a id="do"></a>`DO` The `DO` command is effectively a subroutine call. A `DO` command without a modifier (or equivalently, a `DO 0` command) calls the entire stored program. This may be used as a Direct Command in cases where you wish to follow such action with additional commands, e.g. `DO;TYPE FTIM()` might be used to check the running time of a benchmark program. `DO` also accepts a list of line and group numbers such as `DO -.7,8,9.1`, which would call the subroutine starting at line XX.70 in the current group, then Group 8, and finally line 9.1. `DO` is completely recursive: a DO may thus 'do' itself! Note that the commands called by a DO are not designated anywhere as subroutines — they may be, and usually are, just ordinary commands somewhere in the main program. This is one of the major differences between `DO` calls in UWF and `GOSUB`s in BASIC. Suppose, for example, that the program had a line such as: 1.3 ZERO A,B,C; SET D=5, E=6 which occurred in Group 1 as part of an initialization sequence. If the same set of commands were needed later in Group 12, one would only need to write `DO 1.3`. This facility for re-using common parts of the program is akin to writing 'macros' and is generally considered to be a good programming practice. The one feature missing from the `DO` command is the ability to explicitly pass arguments to the 'subroutine'; this must be handled by the use of 'common' variables. As you will see later on, [Program Defined Function calls](#pdfs) provide this capability in a somewhat limited form. A DO call may be terminated in one of four ways: 1. There are no more lines to execute in the range specified 2. A `RETURN` command is encountered 3. A loop containing a `DO` is terminated by a `NEXT` or `BREAK` 4. A `GOTO` transfers to a line outside the range of the `DO` The first condition is the most common, especially for single line calls. The second condition is explained below, while the third is explored in the discussion of the `NEXT` command. That leaves only the fourth possibility: `GOTO` branches can be used to terminate a `DO` call simply by transferring to a line outside of the range; however the line transferred to will be executed first, which can lead to slightly unexpected results. For instance, if the line branched to happens to immediately precede the group, no exit will occur because UWF will find itself back in the proper group again when it finishes the line. Another somewhat similar case occurs when calling a 'sub-group': `GOTO` transfers anywhere in the same group will be honored without causing a return. Thus if you wish to force a return from a `DO` call, do it with the [`RETURN` command](#return), not with a `GOTO`. ### <a id="return"></a>`RETURN` The `RETURN` command provides a way to selectively exit from a `DO` call in cases where the entire subroutine is not required. Since a `DO` call always specifies the implied range of the subroutine (a single line or an entire group), a `RETURN` command is normally not required. There are cases, however, especially when calling a 'sub-group', in which a `RETURN` is necessary to force an early exit. If there is no subroutine call to return from, `RETURN` will go back to command mode instead, i.e. it behaves just like a `QUIT` command. This is a useful feature, since programs which end with a `RETURN` can be run normally, but can also be called as subroutines via the [`LINK` command](#link). `RETURN` can also designate a line number, for example: `RETURN 5.3`. In this case the normal return to the calling point is aborted (except for [PDF calls](#pdfs)) and the program continues from the line specified. This is a very important feature since it effectively transforms a `DO` call into a `GOTO` branch. It is all the more useful since it can be 'turned on and off simply by making the return point an arithmetic expression which, when zero, indicates a normal return, but otherwise causes a branch to the line specified. This gives UWF a 'multiple return' feature which is found in only a few high-level languages. ### <a id="if"></a>`IF` The form of the `IF` command is: IF (Arithmetic Expression) negative, zero, positive where 'negative', 'zero', and 'positive' are line number expressions not containing commas. Depending upon the sign of the value being tested, the program will perform a `GOTO` branch to one of the three possibilities. The expression being tested must be enclosed in parentheses and must be separated from the command word by a space. Not all of the branch options need to be specified, and relative line numbers are especially useful for those which are. Here are some examples of `IF` commands: | Example | Meaning | | --------------------------- | ---------------------------------------- | | `IF (D=B^2-4*A*C) .2,.3,.4` | Tests for all 3 possibilities | | `IF (A-5) 5.1, 5.1` | Branches if A is less than or equal to 5 | | `IF (-X) .9 or IF (X),,.9` | Branches if X is greater than 0 | | `IF [I-J] , .2` | Branches only if I equals J | | `IF <W> .4,,.4` | Branches only if W is non-zero | These examples illustrate the flexible nature of the `IF` command. In commands with only 1 or 2 branch options, if the branch is *not* taken, the next sequential command will be executed — whether this command is on the same line or on the next line unless the `IF` is in a [`FOR` loop](#for). Here, then, is a case where 'line 0' is interpreted as the 'next command'. Also note (example 1 above) that the expression being tested may contain replacement operators so that the value may be saved for use elsewhere in the program. ### <a id="on"></a>`ON` The `ON` command is identical in form to the `IF` command: `ON (exp) N,Z,P`. The difference is that `DO` calls are used in place of `GOTO` transfers, so upon completion of the subroutine, the program will continue with the next command following the `ON` test.² This is often a very convenient thing to do since it allows additional processing for specific cases. As with the `IF` command, not all 3 calls need to be specified, so one can test just for equality (zero), or for some other condition. Notice that an entire group can be called by the `ON` command. ### <a id="jump"></a>`JUMP` The `JUMP` command has two distinct forms which have been designed to serve the needs of interactive programs: JUMP line number or: JUMP (expression) SI, S2, S3, S4, S5, . . . The first form is a conditional `GOTO` in which the branch is taken *unless* there is a character waiting in the input buffer. This form is used to test the keyboard for input without interrupting the program if there isn't any. This feature is essential in interactive programs which allow program flow to be controlled dynamically from operator response. For example: 1.1 YNCR I; JUMP .1; TYPE I will hang in a loop incrementing the variable `I` until a key is struck, then type the number of cycles. The character used to interrupt the program can be read with the [`FIN` function](#fin) and so used to further control program flow. If the example above simply called `FIN` to read the character directly, the program would hang in the input wait loop and nothing further could be accomplished until the operator struck a key. The second form of the `JUMP` command provides a computed subroutine (`DO`) call which is essentially similar in form to the `ON` command except that the actual *value* of the arithmetic expression being tested is used (rather than just the *sign* bit) to determine which subroutine to call. The call list is indexed from 1 to N, and any number of subroutines may be specified. Values of the expression which do not match up with a specified call are ignored. In the example shown above, Subroutine No. 4 will be called if the expression has the value 4.5, whereas if the expression has the value -1, 0, or 12.3, no subroutine at all will be called. As with the `IF` and `ON` commands, line numbers may be omitted (or set to zero) to avoid a call for certain values of the expression. Typically the expression is simply the ASCII value of a keyboard character which is used to select an appropriate subroutine. For example: JUMP (FIN()-'@> A,B,C,,E will call subroutine `A` if the letter `A` is typed, etc. Notice that typing the letter `D` is treated as a `NOP` by this particular command. As with the `ON` command, the program normally continues with the next sequential command following the subroutine call unless a `RETURN` command is employed to transfer elsewhere. ### <a id="link"></a>`LINK` The `LINK` command allows systems with more than 12K to call subroutines stored in different text 'areas',³ thus 'linking' such areas together as part of a 'main' program. The command has the form: LINK Area, Subroutine Pointer where 'Area' may have the values '0' or '1' in a 16K system, and up to '5' if sufficient memory is available. The 'Subroutine Pointer' is a line or group (or sub-group) number as described for the `DO`, `ON` and `JUMP` commands. A value of '0' specifies that the entire area is to be used as a subroutine. Examples: | Command | Meaning | | --------------: | ----------------------------------------------- | | `L,4` | Calls group 4 in Area 0 | | `L 1,-8.5` | Calls sub-group starting at line 8.5 in Area 1 | | `L,.3` | Calls line XX.30 in the same group in Area 0 | | `L 2,;T "DONE"` | Executes all of Area 2, then types `DONE` | Notice that the comma is required punctuation even when the second parameter is zero, as in the last example.⁴ To avoid returning to the calling area at the end of the subroutine, use a RETURN command with a non-zero line number, such as `R .9` to abort the normal return sequence. By using a computed line number in such a command the calling program can control the return. A [`QUIT` command](#quit) can also be used to cancel all returns. The variables created or used by a program in one area are shared by all areas, so be careful to avoid conflicts. Also, since each `LINK` saves its return on the 'stack', watch out for calls which never return, but simply chain from one area to another. This will eventually lead to a 'stack overflow' which can be cured by using a `QUIT X` command to cancel all pending returns. The `LINK` command functions properly for calls from within the same area, but the `DO` command is clearly preferable since, for one thing, it can handle multiple calls which the `LINK` command cannot. `LINK` can be used in direct commands; it is somewhat similar to the `LIBRARY GOSUB` command in the OS/8 version. ### <a id="quit"></a>`QUIT` The QUIT command stops program execution and resets the 'stack' pointers so that all pending operations (such as subroutine returns) are destroyed. CTRL/F as well as any execution error performs an effective `QUIT`, thereby returning to command mode. There are rare occasions, however, when it is desirable to be able to 'quit' and then simulate a keyboard restart so that the program will continue running without actually returning to command mode. This is accomplished by specifying a non-zero line number as a 'restart' point. Thus, `QUIT 1.1` will stop execution, clear the stacks, and then restart at line 1.1. To restart at the lowest numbered line of the program, use a `Q .001` command. `QUIT 0` or just `Q` will stop the program and return to command mode. It is also possible to use `QUIT` to specify a restart point for any error condition. This is accomplished by specifying a *negative* line number, i.e. something like `QUIT -9.1`. This command will not stop the program when it is executed; it will merely remember the line number and then continue with the next command. If an error subsequently occurs, however, the program will be automatically restarted at line 9.1 instead of returning to command mode. This provides UWF with a somewhat limited error recovery procedure, but one which can be used to take care of certain 'unexpected' conditions which might develop while the program was running unattended, Note that it is up to the user to determine which error caused the restart. One way that this could be accomplished is to select different restart points for different sections of the program where specific errors might be expected. This feature should be considered somewhat 'experimental' in the sense that it may not be included in later releases of UWF if other features appear to be more important. The error trap is automatically reset every time UWF returns to command mode in order to prevent conditions set by one program from causing an unexpected restart at a later time. ## <a id="loops"></a>Loop Commands UWF has 3 commands for constructing program loops. The `FOR` command sets up the loop, the `NEXT` command serves as an optional terminator, and the `BREAK` command provides a way to exit from a loop before it runs to completion. UWF's loops are slightly different from those in other languages, but the differences, once recognized, are easy to accommodate. Basically, UWF uses 'horizontal' loops which consist of only the statements following the `FOR` command on the same line. Most other algebraic languages use 'vertical' loops which consist of a number of contiguous program steps with some way to designate the end of the loop. UWF's approach is convenient for short loops since the commands to be repeated are simply coded on the same line with the `FOR` command and no 'end-of-loop' designation is required. Loops which require several lines of code are handled just as easily by putting a `DO` command in the main loop to call all the statements which cannot be placed on the same line. A `NEXT` command at the end of those statements then serves to designate both the end of the loop as well as the continuation point of the program. Symbolically, UWF's loops may thus have either of these two forms: FOR * * *; loop commands or: FOR * * *; DO -.YY XX.YY first loop command second loop command . . . last loop command; NEXT The latter form is practically identical to that used by BASIC or FORTRAN, with the mere addition of the `DO` call on the first line. ### <a id="for"></a>`FOR` This command initializes a loop, assigning a 'loop variable' to count the number of iterations. The form is: FOR Var = Initial Value, Increment, Final Value ; or, more generally: FOR expression 1, expression 2, expression 3 ; where the first variable to the left of a replacement operator in expression 1 will be used as the loop counter. The semicolon after expression 3 is required punctuation. An increment of +1 is assumed if only the initial and final values are given. Notice that the increment, if specified, is the *second* expression! This is different from the convention used by BASIC and FORTRAN. There are no restrictions on any of the expressions: they may be positive, negative or non-integer. Thus one can increment either 'forward' or 'backward', using any step size. The execution of the FOR command is such, however, that one pass will always occur even if the 'initial value' is greater than the 'final value'. In any case, the exit value of the loop variable will be one increment more than the value it had in the final iteration. Here are some examples: 1. `FOR I=J=1,10;` 2. `FOR L=1,N; FOR M=-L,L;` 3. `FOR X(I)= 10, -1, 1;` 4. `FOR A=0, PI/180, 2*PI;` 5. `FOR Q= P/2, Q, 5*Q;` Notice that loops may contain other loops (Ex. 2). Such 'nesting' is permitted to a depth of 15 or so, but in practice, loops are rarely nested more than 5 deep. Another point, illustrated in example 5, is that the initial value of the loop variable can be used by the expression for the increment and the final values; also notice that subscripted variables are permissible as loop indices (Ex. 3). In example 1, it may appear that both `I` and `J` will be used as control variables. This is not the case: only the first variable (in this case `I`) will be incremented. Other variables (such as `J`) may be given values by replacement operators in any of the three expressions, but these values will not change during the loop (unless commands within the loop change them). It is often quite convenient to use the `FOR` command to initialize several variables used in the loop along with the value of the loop index. The novice programmer who wishes to try writing a simple loop might begin with the following direct command: FOR I=1,10;TYPE I,I^2,! which will print out the first 10 squares in some (unspecified) format. The more experienced programmer will quickly appreciate UWF's loop structure; for one thing, no rules regarding branches into the middle of a loop are necessary since there is no way to branch to the middle of a line! ### <a id="next"></a>`NEXT` The normal termination for a loop is at the end of the line containing the `FOR` command. If the loop contains a `GOTO` branch, however, the end of the line branched to becomes the terminator. It is convenient at times, especially in direct commands, to terminate the loop in the middle of a line so that other commands which logically follow the loop can be placed on the same line. The `NEXT` command serves this purpose, as shown in the following example: FOR * * *; loop commands; NEXT; other commands which excludes 'other commands' from the loop. This construction also works in 'vertical' loops: FOR * * *; DO -.# # commands commands NEXT The commands executed by the `DO` will be terminated upon encountering the `NEXT` command. But more importantly, when the loop is finished, UWF will continue with the first command following the `NEXT`, thus skipping over the commands in the body of the loop. If this `NEXT` command were to be omitted or replaced by a `RETURN`, the program would simply 'fall through' to the first statement in the loop. (The one indicated by `#` in the example above.) Notice that the `NEXT` command contains no references to the loop variable. This is a little different from the way most versions of BASIC implement this command, but the effect is quite similar and since only the first letter of the command word is decoded, variations such as `NI` or `NEXT-J` may prove helpful to some programmers. Nested loops, of course, may require 'nested `NEXT`s': `N;N`. Here is an example which types out all the elements of a 5×5 array a row at a time with a CR/LF printed at the end of each row: FOR I=1,5; FOR J=1,5; TYPE A(I,J); NEXT; TYPE ! `NEXT` has one other feature: it may be used with a line number to specify a continuation point other than the next sequential command. Thus: `FOR * * *; commands; NEXT .8` will branch to line XX.80 when the loop runs to completion. **Note 1:** A `NEXT` command which is executed outside of a FOR loop is ignored unless it specifies a line number, in which case the branch will always be taken. A `NEXT` command may thus be placed at the beginning of any line and used as a target for a 'do nothing' branch from within a loop without affecting the normal execution of that line. **Note 2:** Loops which contain conditional branches (i.e. `IF` commands) should be careful that all paths end with an appropriate `NEXT` if it is desired to skip over the statements in the loop under all conditions. Whichever `NEXT` is executed on the final iteration will determine the program flow. ### <a id="break"></a>`BREAK` Once a loop has been initiated it must normally run to completion. Branching to a line outside of the loop is not effective: that line will simply be treated as a continuation of the main loop. (See [above](#next) comments about `GOTO`s in a loop.) One way to force an exit from a loop would be to set the loop variable to a value greater than the final value. This is obviously not very 'elegant', to say the least, so the `BREAK` command has been provided to solve this difficulty. A `BREAK` causes an immediate exit from the loop, preserving the current value of the loop index, and the program then continues with the next sequential command following the `BREAK`. As you might expect, `BREAK` may also specify a line number so you can branch to a different part of the program at the same time that you leave the loop. A `BREAK` without a line number is ignored (just like the `NEXT` command) if it is encountered outside of a loop, so lines containing `BREAK`s can be used by other parts of the program. Each `BREAK` exits from only a single loop, so to exit from nested loops it would be necessary to use multiple `BREAK` commands: `B;B 15.1` will exit from 2 loops and then transfer to line 15.1. ## <a id="misc"></a>Miscellaneous Commands We will now finish the alphabet: `C`, `H`, `K`, `P`, `U`, and `V` are the remaining command letters. `U` and `V` are not implemented in this version and may be used for whatever purpose the user desires. The '@' command is also available for expansion purposes. ### <a id="comment"></a>`COMMENT` Any command beginning with a `C` causes the rest of the line to be ignored. Such lines may thus be used for comments describing the operation of the program. In particular, line XX.00 (the first line in a group) should generally be reserved for comments. Branching to a comment line from within a loop will terminate that cycle of the loop. In this way a `COMMENT` is equivalent to the Fortran `CONTINUE` statement. A `NEXT` command performs the same function and in addition may be used to designate the continuation of the program. ### <a id="hesitate"></a>`HESITATE` The `HESITATE` command delays the program for a time specified by the command. The argument (which must be an integer) is nominally in milliseconds, so `H 1000` will generate approximately a 1 second delay. However, the exact delay is directly dependent upon the cycle time of the machine, so some calibration is necessary. Here is an example using the `H` command: FOR T=1,9; TYPE "*"; HESITATE 250*T ### <a id="punch"></a>`PUNCH` The `PUNCH` command allows the programmer to save a copy of the text buffer and the symbol table in binary format, ready to reload with the standard BIN loader. This command requires either a High Speed punch or an audio (cassette) recorder. Tapes created with the `PUNCH` command can only be read with the BIN loader since they are not punched as ASCII characters. The advantage to punching tapes in this format is that they tend to be somewhat shorter than ASCII tapes and they also contain a checksum so there is less probability of an error going undetected. The disadvantage, however, is that they are absolute memory dumps and so are not necessarily transportable between different versions of UWF. They also cannot be loaded by UWF itself from a remote location, but require access to the front panel of the computer in order to activate the BIN loader as well as to restart UWF once the tape is loaded. To use this command (assuming that you have a cassette recorder, but the same procedure applies to a HS paper tape punch), advance the tape to an unused area, turn on the recorder and then type `P` followed by a <kbd>RETURN</kbd>. Approximately 5 seconds of leader code will be punched, followed by the contents of the text buffer and then the symbol table. To restore a program (and any symbols in use at the time it was dumped), position the tape at the start of the leader, and while this section is being read, start the BIN loader from the front panel. If you start the loader before reaching the leader section, the computer will halt with a checksum error (`AC` not zero); hit the `CONTINUE` switch quickly, and if you are still in the leader, all will be well. After reading in the program tape you must manually [restart UWF at location 100](#starting). The `PUNCH` command always returns to command mode (like `MODIFY` and `ERASE`) so it cannot be followed by other commands, and should not be included in the program itself. In systems with more than 12K the `PUNCH` command will dump the contents of the *current* program area, so to save the program in Area 3, for example, use a `L 3` command to get to it and then type `P` to punch it out. A program can only be reloaded into the area that it came from, so if you wish to move a program to a different area, you must `WRITE` it out (rather than `PUNCH`ing it), and then read it in again as explained [below](#write-ascii-tape). ### <a id="open"></a>The `OPEN` Commands In addition to the `PUNCH` command described above, UWF has a series of `OPEN` commands which allow `ASK` and `TYPE` (or other I/O operations) to use something other than the terminal. These commands consists of *two* words (or two single-letter abbreviations) separated by a space. You may recall that the letter `O` has already been used for the `ON` command and wonder how it could also be used for `OPEN`. `OPEN` and `ON` can be distinguished, however, since `ON` must always be followed by an arithmetic expression. Here is a short summary of the `OPEN` commands currently available. The mnemonics, which were chosen in part to be compatible with the OS/8 version, are somewhat less than perfect! | Mnemonic | Command | Description | | -------------- | ------- | ----------------------------------------- | | OPEN INPUT | `O I` | Selects the Terminal as the Input device | | OPEN OUTPUT | `O O` | Selects the Terminal as the Output device | | OPEN READER | `O R` | Selects the High Speed Reader for Input | | OPEN PUNCH | `O P` | Selects the High Speed Punch for Output | | OUTPUT TRAILER | `O T` | Punches leader/trailer code (ASCII 200) | | OPEN ----,ECHO | `O -,E` | Connects the Input device to the Output | Only the first two commands (`O I` and `O O`) and the ECHO option are useful unless you have a high speed reader/punch (or an audio tape recorder). The list of `OPEN` commands could also be expanded to include things like `O L` (for selecting a line printer) or `O S` to send output to a 'scope display, etc. Such expansion is, however, entirely up to the user. ### <a id="io-sel"></a>I/O Device Selection The Input and Output devices are always reset to the terminal when you hit <kbd>CTRL/F</kbd>. To select a different device, use the appropriate `OPEN` command. For example, to read in a program from the High Speed Reader, simply type in an `O R` command, and henceforth, until this assignment is changed, all input to UWF will come from the reader rather than from the keyboard. In particular, even direct commands will be taken from the reader, so you can set up a program tape to run the machine while you are gone. Also, if the tape contains a listing of a program it will be read into the text buffer just as though you were typing it in yourself. This is an alternative method for saving programs which has the advantage that they are available as ASCII tapes which can be edited or processed by other programs. A 'time-out' trap in the reader routine normally senses when the end of the tape has been reached and then restores the terminal as the input device. A <kbd>BACKARROW</kbd> or <kbd>UNDERLINE</kbd> is printed on the terminal to indicate that it is the active input (and output) device once more. If you need to manually restore the terminal to its usual status, just hit <kbd>CTRL/F</kbd>. <a id="write-ascii-tape"></a> Similarly, to select the High Speed Punch (or Cassette Recorder) for use as the output device, just use an `O P` command. To dump the text buffer on tape, for example, enter the commands: O P,T; W; O T,O (do not hit RETURN) and then start the punch or recorder. Hit <kbd>RETURN</kbd> and then wait for the asterisk (`*`) to reappear on the terminal. To re-read such a tape at a later time, position it in the reader somewhere in the leader section, use the `ERASE` command to clear the program area, and then type `O R` followed by the <kbd>RETURN</kbd> key. If input is from a paper tape reader, the reader will now begin to read the tape. If input is from an audio recorder you should actually start the tape moving (in the leader section) before hitting the <kbd>RETURN</kbd> key, otherwise the first few characters are likely to be 'garbage' as the tape comes up to speed and UWF may well conclude that you have run out of the tape before you have even begun! It is also possible to use the reader/punch for data storage purposes. This works best with paper tape since the audio recorder lacks a 'stop-on-character' capability, making it difficult for UWF to keep up with the data once the tape has started moving. By way of an example, the following command will read in 50 numbers from the high-speed reader: O R; FOR I=1,50; ASK DATA(I); NEXT; O I,E Notice that an `O I,E` command is used at the end of the loop to restore input to the keyboard. If this command were omitted the H.S. reader would continue to be used for input, probably causing an error to occur since it is unlikely that the next data value on the tape would correspond to anything expected from the keyboard. The `,E` part of this command is explained more fully in the next section. ### <a id="echo-option" name="input-echo"></a>The ECHO Option The `,E` option may be added to either an `O I` or `O R` command to specify that the input characters are to be 'echoed' to the output device. Generally this option is *always* used with `O I` and *never* used with `O R`. The echo option may at first appear slightly confusing since UWF normally runs with the keyboard echo *on* and thus one comes to expect that whatever is typed will be printed on the terminal. This makes the terminal appear much like a simple typewriter and tends to obscure the fact that if UWF were not sending back each character it received, *nothing* would be printed! The `ECHO` option must be specified when selecting the input device, or *no echo* will be assumed. Thus an `O I` command will select the keyboard for input (it may already *be* selected) and effectively turn the echo off. An `O I,E` command is necessary to restore the echo under program control. Of course any program error or typing CTRL/F, will also restore the echo. The ability to disable the input echo is convenient at times since it allows a program to read one thing and possibly print something else. An example of this mode of operation occurs during command input: when you type the <kbd>RUBOUT</kbd> key you do not get this character printed, but rather a backslash (`\`), or on a video terminal, a three character sequence: <kbd>Backspace</kbd>, <kbd>Space</kbd>, <kbd>Backspace</kbd>, which effectively removes the character from the screen. UWF programs can also be written to use the keyboard for program control, and in such cases it is often desirable to have 'silent' input. You can try this out quickly by using a direct `O I` command to disable the echo. Now type in <kbd>O</kbd>, <kbd>Space</kbd>, <kbd>I</kbd>, <kbd>Comma</kbd> <kbd>E</kbd> and hit <kbd>RETURN</kbd> and the echo will return again. Another time when you will want to disable the echo is when reading in a program tape on the 'low-speed' reader. If you turn off the echo in this case you can avoid getting an unwanted listing while you relax to the rhythm of a quiet little 'burp, burp, burp' instead of a 'clackety clack clack'. Just hit <kbd>CTRL/F</kbd> at the end of the tape to turn on the echo again. Similarly, when reading a data tape from the high-speed reader it is generally undesirable to have it all printed on the terminal. Thus the `O R` command automatically disables the echo; but if you wanted to see what some of the data looked like, you could use an `O R,E` command. To make a copy of a program or data tape you would first switch output to the punch and then turn on the echo to 'print' each character received on the output tape, e.g. O P;O R,E;S FIND() The [`FIND` function](#find) keeps reading from the input device, looking for the character code specified. In this case a 'null' was used, which will never be found, so the effect of this command is to continue reading until the end of the tape is reached at which point the terminal will automatically be restored as the I/O device with the echo enabled. If only portions of a tape were to be copied, you could use the `FIND` function to search for an appropriate character and then switch I/O back to the terminal yourself. You can use the `ECHO` option to skip sections of the tape by disabling the echo until you 'find' the right character and then turning it back on to copy some more. ### <a id="leader-trailer"></a>The Leader/Trailer Option The `T` option punches leader/trailer code (ASCII 200). This is convenient (but not essential) for separating output on paper tape, and somewhat more important when using an audio recorder since there is no visual indication of breaks in the data. Blank tape may also be used as 'leader' and both are ignored each time the reader is selected as the input device. However, after the first valid input character has been read these same codes are interpreted as the 'end-of-tape' and cause both input and output to be restored to the terminal. A <kbd>BACKARROW</kbd> or <kbd>UNDERLINE</kbd> is also printed to indicate that the EOT was detected. This character serves the dual purpose of also removing any 'garbage' characters which might have been read after the last valid input. The `T` option can be used alone (`O T`) or in conjunction with another `OPEN` command. The number of L/T codes punched is determined by an optional arithmetic expression following the letter `T` (and separated by a space from it) with the previous specification being used as the default. The initial value is 512, which is about right for use with an audio recorder, but somewhat ridiculous for paper tape. (Over 4 feet of leader!) A value of 70 or so is more appropriate in this case. You can always just repeat the `T` option to get a slightly longer leader if you want to: `O T 100,T` will punch out 200 L/T codes but leave the default set at 100. Notice how this option was used in the [example above](#write-ascii-tape) for writing out all of the program buffer. The length specified by the `T` option is also used by the [`PUNCH` command](#punch). ### <a id="kontrol"></a>`KONTROL` This is an optional command which may be used to program the DR8-EA parallel I/O module. The `K` command is used to set and clear individual bits in the output register while the [`FDIN` function](#fdin) is used to read the corresponding bits in the input register. These options are added by the initialization routine if [Switch 7 is *UP*](#opt-switch). The `KONTROL` command uses *positive* numbers to turn bits on and *negative* numbers to turn them off. Each bit is directly controllable, independent of the setting of any of the others. Thus a `K 1` command, for example, will turn on bit '1' without changing the state of any of the other 11 bits, while a `K -1` command will turn it off again. In order for this scheme to work successfully, the bits must be numbered from 1-12 rather than from 1-11, which is the usual convention. This is because '-0' is not distinguishable from '+0'. In fact, '0' is interpreted to mean 'clear all bits', so a `K 0` command (or just `K` since '0' is the default for all arithmetic expressions) can be used to quickly initialize this register. More than one bit position can be set at a time, e.g. a command such as: K 1,-2,3 will set bit 1, clear bit 2, and finally set bit 3. In this form, each operation occurs sequentially with perhaps 10 milliseconds or so between operations. This allows a command such as `K 1,-1` to be used to generate a short pulse on line 1. If it is necessary for several signals to occur simultaneously, those operations can be enclosed in parentheses: K 1,(2,3,A),-1 will set bit 1, then bits 2, 3, and 4, then clear bit 1. Since for some purposes it is more convenient to be able to specify various bit combinations with a single arithmetic expression rather than setting and clearing each bit individually, a third mode of operation is also available. In this mode, the last 4 bits (bits 9-12) are set to the value of an expression preceded by an `=` sign. The remaining 8 bits are not changed. Thus a `K,=5` command would first clear all bits — the comma indicates a missing argument which is the same as '0' — then set bits 10 and 12 while clearing bits 9 and 11 (which were already clear in this case). To summarize the 3 different forms of the `KONTROL` command: | Command | Meaning | | ------------ | ----------------------------------------------------------------------------------------------------------- | | `K N,-N` | Turns a single bit on or off; N=0 turns *all* bits off | | `K (L,M,-N)` | Performs all operations in parentheses simultaneously instead of sequentially | | `K =N` | Sets the 4 least-significant bits to the binary value of `N`; this form may not be used inside parentheses. | ## <a id="error-messages"></a>Error Messages UWF traps any 'illegal' operation such as division by zero or an unknown command and prints a peculiar little message to tell you what the problem was and where in the program it occurred. If you type in the command: `SET 2=3` for example, UWF will reply with: '?07.44' which is its way of telling you that you have something besides a variable on the left side of an `=` sign. To decode the error message, you should look at the [error code table](#error-codes) below (or the Summary card) which lists all of the error diagnostics and their probable cause. If this same error had occurred while the program was running (i.e. not from a direct command), the error message would also indicate the line in the program containing the erroneous statement: ?07.44 @ 15.13 indicates 'operator missing or illegal use of an equal sign' in line 15.13. The program `QUIT`s whenever an error occurs, thus all pending operations are canceled, and in general it is impossible to resume *precisely* at the point of interruption, but it is often possible to make the necessary changes, perhaps update a few variables with direct commands, and then restart from a point close to where the error occurred. This version also has an 'auto-restart' feature which allows the program to continue after an error instead of returning to command mode. This feature is selected by [an option in the `QUIT` command](#quit). ## <a id="trace"></a>The `TRACE` Feature To further assist in finding the source of an error, UWF has a facility for printing out each program step as it tries to execute it. Thus, when an error occurs you can see exactly where the problem is. The 'trace' feature is turned on by the occurrence of a `?` in the program (not one which is preceded by a single quote or enclosed in double quotes, however) and turned off again by another `?`. Thus only the portion of the program between pairs of question marks will be output while the program is running. The `?` may be given in a direct command, so to trace the entire program, just use a `GO?` command to start it. Similarly, a `DO 5.2?` command will selectively trace that one line. As a further aid to finding logical errors (as opposed to simple programing mistakes), when the trace is on, UWF will print out the result of all expressions appearing in `SET` commands. Thus you can see the values of all the variables as well as the program steps which created those values. A video terminal is obviously preferable for program traces since rather voluminous output can be generated in quite a short time. A somewhat secondary use of the `TRACE` feature is for simplified input/output prompting. Whenever variables have names closely resembling their usage, it is a bit of a waste to have commands such as: ASK "AGE? "AGE or TYPE "COST="COST when, with only a small sacrifice in the punctuation, the following will do just as well: ASK ?AGE ? or TYPE ?COST? UWF will print out just the characters enclosed by the `?`s. For this reason it is preferable to use 'spaces' as separators rather than 'commas', i.e. ASK ?A B(I) C(J,K) ? will print out each variable name followed by a space and then wait for its value to be input. One small disadvantage to this 'trick' is that when such statements are *actually* being traced, the text enclosed by `?` marks will *not* be printed due to the 'toggling' nature of the trace switch. There is one other small anomaly associated with the trace feature: A command such as `SET !=5,$=10` will not set those two 'secret variables' when it is traced, but will instead first perform a CR/LF and then dump the symbol table! This is because during a program trace all `SET` commands are treated internally as though they were `TYPE`s and hence the secret variables take on their special roles as operators. There is a simple solution to this problem, however, and that is to simply prefix a `+` sign or otherwise embed such variables in the midst of an arithmetic expression so that they are no longer recognized as `ASK`/`TYPE` operators. Thus the command `SET +!=5,+$=10` would be traced properly. ## <a id="commands"></a>Command Summary The following table provides a quick review of UWF's entire command repertoire. | Command | Form | Example | | ------------------ | ------------------------------------------------ | -------------------- | | `@` | a not implemented in this version | | | `ASK` | list of variables, "prompts", formatting options | `A X,Y(I),Z(J,K)` | | `BREAK` | line number | `B` or `B 11.45` | | `COMMENT` | your programs whenever possible | `C FOR COMMENTS` | | `DO` | list of lines, groups, or sub-groups | `D .7, -9.5, 10` | | `ERASE` | line, group, sub-group, or 'all' | `E 5 or E 9.1` | | `FOR` | var = start, increment, finish | `F I=1,5;F J=I,-1,0` | | `GOTO` | line number | `G 11.8 or G .3` | | `HESTATE` | time delay desired | `H 1000` | | `IF` | (arithmetic expression) negative, zero, positive | `I (K=I-J), .5` | | `JUMP` | line number | `J .3;C WAIT LOOP` | | `JUMP` | (arithmetic expression) one, two, three, four... | `J (N) 1, .2, -3.4` | | `KONTROL` | bit positions | `K 1,(-1,2,3),=X` | | `LOOK` | program area | `L 1` | | `LOOK` | program area, subroutine pointer | `L 2,4.1 or L,10` | | `MODIFY` | line number | `M 5.1` | | `MOVE` | old line number, new line number | `M 3.3,6.3` | | `NEXT` | line number | `F I=1,10;N;T PI` | | `ON` | (arithmetic expression) negative, zero, positive | `O (A-5) -9.2, 9` | | `PUNCH` | punches program and variables in binary format | `P` | | `QUIT` | line number | `Q or Q 5.1` | | `RETURN` | line number | `R or R .2` | | `SET` | list of arithmetic expressions | `S A=5, B=C=A/2` | | `TYPE` | arithmetic expressions, "labels", formatting | `T !?A ?:10"B="B` | | `U` | available for user expansion | | | `V` | available for user expansion | | | `WRITE` | list of lines, groups, sub-groups, or 'all' | `W or W -1.5,2,3.1` | | `XECUTE` | list of arithmetic expressions (same as `SET`) | `X FSIN(#)/FCOS(#)` | | `YNCR` | list of variables | `Y I-J,K L` | | `ZERO` | list of variables or 'all' | `Z,#,A,B(I),C(J,K)` | | `OPEN INPUT, ECHO` | normal terminal input | `O I,E` | | `OPEN READER` | selects high-speed reader | `O R` | | `OPEN PUNCH` | selects high-speed punch | `O P` | | `OPEN OUTPUT` | selects terminal for output | `O O` | | `OUTPUT TRAILER` | punches leader/trailer code | `O T` | ## <a id="internal-functions"></a>Internal Functions In spite of the fact that only about 3.3K words have been used to implement UWF, there are nearly 20 built-in functions and a facility for adding a limitless number of Program Defined Functions. The 'internal' functions provide the user with full-accuracy ('10-digit') approximations for commonly used relations such as log, exponential, sine, cosine, square root, etc. Also included are simple numerical functions such as absolute value, integer, sign and fractional parts, maximum/minimum, etc. And finally, there are a few functions for character processing and special I/O operations such as reading the Switch Register and loading the MQ register. All function names in UWF begin with the letter `F`; thus, variables names may not begin with this letter. ### <a id="transcendentals"></a>Transcendental Functions This class of functions, so named because the relations they represent can only be expressed as infinite series, includes the natural log and exponential functions and the three most common trigonometric functions. The series approximations used by UWF have been optimized by a constrained least-squares procedure to reduce the error over the principal argument range to at worst a few parts in 10 billion. The transcendental functions can be removed if you wish to increase the number of variables available in the 8K version. Removing them creates space for another 55 variables — a total of 175 instead of only 120. Program Defined Functions can be incorporated in their place at the expense of greater execution time and slightly poorer accuracy. See [PDF example 6](#pdf-transcendentals) and [the Patches section](#patches) below for details. #### <a id="flog"></a>`FLOG` `FLOG(X)` returns the natural logarithm of the absolute value of the argument. An error occurs if `X` is zero since the theoretical result is infinite. No error occurs if `X` is negative, although the log function is, in fact, only defined for positive arguments. This implementation facilitates the use of `FLOG` for extracting roots and raising values to non-integer powers. The common (base-10) logarithm is easily obtained from the `FLOG` function just by dividing by `FLOG(10)`. Example: *TYPE %,"NATURAL LN(PI)="FLOG(PI) :45"COMMON LOG(PI)="FLOG(PI)/FLOG(10)! NATURAL LN(PI)= 1.144729886E+00 COMMON LOG(PI)= 4.971498727E-01 #### <a id="fexp"></a>`FEXP` `FEXP(x)` returns the value of *e<sup>x</sup>* where *e*=2.718281828... The value of 'e' is always available as `FEXP(1)`. This function is often used to extract roots and compute non-integer powers. For example, X<sup>3.5</sup> is found from the expression: `FEXP(3.5*FLOG(X))`. Similarly, the cube root of 27 may be found from the expression: `FEXP(FLOG(27)/3)`. The absolute value of the argument must be less than approximately 1400 in order to avoid numeric overflow. #### <a id="fsin" name="fcos"></a>`FSIN`/`FCOS` `FSIN(A)` and `FCOS(A)` return the value of the sine and cosine of the angle `A` when `A` is measured in *radians*. A radian is a unit of angular measure preferred for scientific and engineering work because it eliminates factors of π in many formulæ. One radian is <sup>1</sup>/<sub>2π</sub> of a full circle, or approximately 60°. To convert angles from degrees to radians you simply multiply by `PI/180`. The value of `PI` is a protected variable which is always available. Here is a short table of the values of `FSIN` and `FCOS` over the first quadrant as produced by the command shown. Notice how the radian value was saved for use in the second function call: *FOR A=0,10,90; TYPE %2,A %15.1, FSIN(R=A*PI/180), FCOS(R)! 0 0.0000000000 1.0000000000 10 0.1736481776 0.9848077530 20 0.3420201433 0.9396926207 30 0.5000000001 0.8660254037 40 0.6427876096 0.7660444431 50 0.7660444431 0.6427876096 60 0.8660254037 0.5000000001 70 0.9396926207 0.3420201433 80 0.9848077530 0.1736481778 90 1.0000000000 0.0000000000 #### <a id="ftan" name="fatn"></a>`FTAN`/`FATN` The tangent function is not provided as an internal function since it is just the ratio of `FSIN`/`FCOS` and is thus easy enough to compute. The user may implement his own FTAN function, however, as described in the discussion of [Program Defined Functions](#pdfs). The inverse tangent function (a.k.a arctan) is available, however. `FATN` accepts values of any magnitude and returns the *angle* (in radians) which would give that tangent. The range of answers is from <sup>-π</sup>/<sub>2</sub> (-90°) to <sup>+π</sup>/<sub>2</sub> (+90°). To convert from radians to degrees, just multiply by `180/PI`. For example, to check that the angle whose tangent is -1 is, in fact, -45°: *TYPE 180*FATN(-1)/PI ! -4.500000000E+01 #### Trigonometric Identities All other trig functions can be derived from these primary functions. For example: | Function | Identity | | ----------------- | --------------------- | | Cotangent |`FCOS(A)/FSIN(A)` | | Arcsine | `FATN(A/FSQT(1-A*A))` | | Arccosine |`FATN(FSQT(1-A*A)/A)` | | Hyperbolic sine |`(FEXP(A)-FEXP(-A))/2` | | Hyperbolic cosine |`(FEXP(A)+FEXP(-A))/2` | Consult any advanced algebra book for other such identities. ### Other Built-In Functions #### <a id="fsqt"></a>`FSQT` The `FSQT` function computes the square root of the argument using an iterative approximation which guarantees that no more than the last bit will be in error. Example: *TYPE FSQT(2), FSQT(2)^2! 1.414213562E+00 2.000000000E+00 #### <a id="fabs"></a>`FABS` `FABS` returns the absolute value of the argument: *TYPE FABS(-1), FABS(1)! 1.000000000E+00 1.000000000E+00 #### <a id="fsgn"></a>`FSGN` `FSGN` returns -1, 0, or +1 depending upon whether the argument was negative, zero or positive. Example: *TYPE FSGN(PI), FSGN(PI-PI), FSGN(-PI) ! 1.000000000E+00 0.000000000E+00-1.000000000E+00 #### <a id="fitr"></a>`FITR` `FITR` returns the InTegeR part of the argument. Thus `FITR(PI)` is `3` and `FITR(-5.5)` is `-5`. Note that some languages have an [entier][entier] function which is the 'integer less than or equal to the argument'. For positive numbers this produces the same result as UWF's `FITR` function, but for negative values it gives the next lowest number. If you are converting a program which was originally written in another language, be sure to watch for this subtlety! It should be noted that many functions and commands in UWF convert values to an integer form internally without requiring the programer to do so. Subscripts, for example, are always used in integer form, meaning that `A(1.5)` is legal, but is no different from `A(1)`. In general, a value which is used as an index or is stored in a hardware register is always converted to an integer before use. [entier]: https://en.wikipedia.org/wiki/Floor_and_ceiling_functions#Notation #### <a id="frac" name="me"></a>`FRAC` `FRAC` returns the fractional part of a number — the part which `FITR` discards! This may be used to do "modulo-N' arithmetic or to check for a remainder. The user is cautioned, however, that the value returned by `FRAC` may have only limited accuracy and hence checks for 'exact' values computed from expressions containing the `FRAC` function should generally be avoided. To illustrate, the fractional value of '.002' is .002, but the fractional value of 1.002 is off in the 8th place while that of 1000000.002 is only correct to 3 digits. This is simply the result of taking the difference between two large numbers. #### <a id="fmin" name="fmax"></a>`FMIN`/`FMAX` These functions compare two arguments, returning the algebraically smallest or largest value. Thus `FMIN(+1,-2)` would return -2 while `FMAX` would return +1. These functions have several uses. A simple example in connection with the `FLOG` function allows one to avoid the 'log-of-zero' error with a call such as `FLOG(FMAX(1E-10,X))`. Similarly, the `FMIN` function can be used to avoid typing nonexistent values when dumping an array in a multi-column format. In this example, `C` is the number of columns and `N` the number of data values in the array: FOR I=1,C,N; FOR J=I,FMIN(N,C+I-1); TYPE Q(J); NEXT; TYPE ! As a final example, an entire array can be scanned for its extrema simply by comparing each element with the previous best estimates: SET MIN=MAX=A(1); FOR I=2,N; SET MIN=FMIN(A(I),MIN), MAX=FMAX(A(I),MAX) A disadvantage of this method for locating the extremes is that no information is available as to which element is biggest or smallest, only the values are returned. #### <a id="fran"></a>`FRAN` The `FRAN` function returns a different pseudo-random number each time it is called. The numbers are limited to the range 0-1 and have an approximately 'flat' distribution. Other distributions, for instance Gaussian or Lorentzian functions, can be created as Program Defined Functions by using `FRAN` in an appropriate expression. The function is initialized by the input wait loop so the values you observe will appear to be truly random. The pair-wise and higher-order groupings do have a small correlation coefficient, but even so, a reasonable value of `PI` can be obtained using `FRAN` to generate a 2-dimensional scatter pattern. The principal use of `FRAN` appears to be for games. ## <a id="char-io"></a>Character and I/O Functions The remaining internal functions handle character manipulation and other special-purpose I/O operations. The character functions include `FIN`, `POUT`, `FIND` and `FTRM`, while `FSR`, `FMQ` and `FDIN` are 'I/O-type' functions. `FBUF` and `FCOM` provide access to extended memory for storing large data arrays. ### <a id="fin"></a>`FIN` The `FIN` function reads a single character from the Input Device and returns the numerical value of that character. A list of character values may be found in Appendix I, and the value of any character can be obtained within the program simply by preceding it with a single quote mark. Thus the expression `('A)` will have the value of the letter `A` (193) while `('A-'Z`)` will be the difference of the codes for `A` and `Z`. Character strings can be read with the `FIN` function and later output with `FOUT`; this is a bit slow, but it does provide UWF with a limited string-handling facility. ### <a id="fout"></a>`FOUT` The `FOUT` function generates a single character from the value of an arithmetic expression. It will thus output what `FIN` has input: `FOUT(193)` will generate the letter `A`. More commonly, however, `FOUT` is used to output special control characters which would otherwise be invisible if they were simply included in a `TYPE "..."` command. For instance, `FOUT(7)` is used to ring the 'bell', while `FOUT(140)` outputs a 'form-feed' character. `FOUT(27)` generates an <kbd>ESCAPE</kbd> code which is used by many terminals to initiate special functions such as reverse video, cursor movement, etc. `FOUT` expects arguments in the range 0-255; values beyond this range will be output, but should be avoided. Most terminals respond in the same way to values in the range 0-127 and 128-255. UWF's input routines, however, always return values in the higher range (128-255) in keeping with the standard established for the PCM-12. The value returned by `FOUT` is always *zero*, not the value of the character code! This was done to simplify calling the function as part of a command. For instance, you can output a form feed ahead of a program listing by using a `WRITE FOUT(12)` command instead of just `WRITE`. Similarly, since 'tabbing' to column zero is ignored, you can include `FOUT`s in `ASK` or `TYPE` commands just by putting them in 'tab expressions'. To print a 'double quote' mark, for instance, you could use the following: TYPE "THIS IS A ":FOUT('")" MARK!" which will produce: THIS IS A " MARK! ### <a id="find"></a>`FIND` `FIND` searches for a character equal to its argument, reading and echoing all characters it encounters until it finds a match. The echo is controlled by the setting of the input echo switch, as [described earlier](#echo-option). The character which matches is *not* echoed, however, but is returned as the value of the function. To output this character too, you may use a call such as `S FOUT(FIND('A))` where `A` is the search character. To read in a comment line, just search for a Carriage Return: `SET FIND(141)`. To read the same line in from a paper tape, however, you should search for the line feed following the CR: `SET FIND(138)`. This is due to different conventions for the 'end-of-line' character. `FIND` also checks continually for a <kbd>CTRL/Z</kbd>. This is recognized as an 'End-of-File' mark and causes `FIND` to return with the value 'zero' instead of with the value of the search character. ### <a id="ftrm"></a>`FTRM` As discussed [earlier](#input-terminators), the `ASK` command treats any input other than `0`-`9` and `A`-`Z` as a terminator, which means that data values may be conveniently 'flagged' by the use of a special terminating character. The purpose of the `FTRM` function is to then pass this information back to the program so that special action may be taken if necessary. For instance, a program might need to be able to work with either metric or English measurements, using an appropriate terminator to differentiate between them. Similarly one can devise a 'pocket calculator' program which accepts numbers terminated by one of the arithmetic operators and then performs the indicated function. One of the more common uses for this feature is to permit an indefinite number of data values to be read in, sensing a special terminator for the last value. A loop like the one in the example below (which checks for a `?`) is all that is required: 4.1 ZERO N;TYPE "ENTER QUIZ GRADES, TERMINATE THE LAST ONE WITH A '?'"! 4.2 ASK G(N=N+1); IF (FTRM()-'?) .2,,.2; TYPE %2"THERE WERE"N "GRADES"! ### <a id="fbuf" name="fcom"></a>`FBUF`/`FCOM` These functions allow UWF to use extra memory for data storage and are thus of interest only for systems with more than 12K. They may be added by setting Switch 8 *UP* when UWF is started for the first time. (See [above](#opt-switch).) FBUF is designed to handle 12-bit (signed) integer data while `FCOM` may be used for storing either 24-bit integers or 48-bit floating-point values. Both functions are called in the same manner: the first argument specifies the relative location in the storage area and the second argument (if any) is the value to be stored at that location. The function always returns the value at the location specified. Thus: | Function | Description | | ----------- | --------------------------------------------- | | `FCOM(I)` | returns the `I`th value in the `FCOM` area | | `FBUF(I,V)` | stores the value of `V` in the `I`th location | The range of the index is typically 0-4095 for FBUF and 0-1023 for `FCOM`. `FCOM` has another mode however, in which data is stored as two-word integers (rather than four-word floating point values) thereby doubling the amount of storage available but limiting the range of the data to ±2<sup>23</sup>. To use `FCOM` in this mode, specify a *negative* index. (The legal range is -1 to -2048.) Here is a loop which stores the square root of all numbers from 0-1023: FOR I=0,1023; SET FCOM(I,FSQT(I)) Although `FBUF` and `FCOM` share the same field, FBUF starts from the 'bottom up' while `FCOM` stores from the 'top down', so both functions may be used simultaneously. Furthermore, both functions are fully recursive, so calls such as `FCOM(I,FCOM(J))` may be used to move data from one location to another. ### <a id="fsr"></a>`FSR` The FSR function reads the value of the Switch Register. This may be used to control program options. The value is treated as a signed number, so the range is from -2048 (4000 octal) to +2047 (3777 octal). ### <a id="fmq">`FMQ`</a> The FMQ function displays the integer part of the argument in the MQ register. This is quite handy for 'spying' on the progress of a long calculation simply by displaying the value of a loop index. Since FMQ returns the integer part of the argument, it can be included in a subscript expression, such as 'A(FMQ(I))' which is functionally the same as 'A(I)' but also displays the index in the MQ. ### <a id="fdin"></a>`FDIN` This is an optional function for reading the input register of a DR8-EA parallel I/O module. It may be added (along with the `KONTROL` command) by setting Switch 7 *UP* the first time UWF is started. The interface may be wired to respond to either levels or pulses, the difference being that it will 'remember' a pulse, but 'forget' when a level changes. Each bit is separately addressable, and each may be wired for pulse or level sensing. For use with the `FDIN` ('Digital INput') function, the bits are considered to be numbered from 1-12 (rather than from 0-11), just as they are for the [`KONTROL` command](#kontrol). The value of `FDIN(0)` (or just `FDIN()` since 'zero' is always the default value of an argument) is simply the weighted sum of all input bits which have been 'set'. Bit '1' has the value 2048, bit '2' 'weighs' 1024, etc. The maximum value is thus '4095' if all the bits are turned on. Any bits which are read by the `FDIN` function will be reset if they are resettable, i.e. if they are wired for 'pulse' input. This ensures that only one occurrence of an event will be detected by the program. `FDIN` can be made to respond to only a single bit — or to a collection of bits — by including various arguments as the programmer desires. For instance, `FDIN(1)` will only sense the state of bit '1'. If bit 1 is on, `FDIN` will have the value 2048, while if it is off, the value 0 will be returned, regardless of the setting of any other bits. Furthermore, only bit 1 will be reset. The value of `FDIN(-1)` on the other hand, will be the status of all bits *except* bit 1, i.e. bits 2-12. Any bits which are read will be reset as described above. More complicated masks can be constructed by specifying multiple bits. Thus `FDIN(1,3)` will only look at bits '1' and '3', while `FDIN(-2,-5)` will look at *all but* bits 2 and 5, etc. ## <a id="pdfs"></a>Program Defined Functions UWF allows the user to define his own set of special functions within the program. Such 'Program Defined Functions' ('PDFs') may consist of any set of UWF commands, ranging from a single program step to as much as an entire group. A PDF is very similar to an ordinary subroutine (`DO`) call, but with 3 important differences: 1. a PDF may pass arguments to the subroutine 2. a PDF returns a numeric value: the value of the function 3. a PDF may occur in any command, not just `DO`, `ON`, `LINK`, etc. The last difference is especially important since it allows subroutine calls in some circumstances when they might not otherwise be possible. The form of a PDF call is: F( line number, argument list ) where the letter `F` identifies this as a function call and the line (or group) number identifies the function. This number can be replaced by a suitably chosen variable so that one may use a ['named' function call](#named-pdf) rather than a 'numeric' one. The argument list is not required, but may contain several arguments. Typically, only 1 or 2 are used although this is not a fundamental restriction. The arguments may consist of other PDF calls which do not themselves have arguments, or any other internal functions, with or without arguments. The use of nested PDF calls containing an argument list is restricted since the arguments are not stored recursively. Here are few examples of Program Defined Functions: | Call | Description | | ----------: | --------------------------------------------- | | `F(2,A*B)` | Calls Group 2, passing `A*B` as the argument | | `F(.9,X,Y)` | Calls line XX.90 in the current group | | `F(-9.5)` | Calls sub-group at line 9.5 with no arguments | Coding a PDF is no different from writing an ordinary subroutine, but the mechanism for passing argument values and returning the function result needs to be explained. The value of each arithmetic expression appearing in the argument list is saved in a specific 'protected variable'. The first argument is saved in the variable `#`, the second one in the variable `$`, and the third in the variable `%`. Additional arguments are possible, and if necessary more protected variables should be defined when [initializing UWF](#initializing). The ordinary variables created by the program may also be used as 'common' variables (those appearing in both the 'main' program and the definition of the function) for passing information to the subroutine. PDF calls are not required to always have the same number of arguments, so infrequently used parameters can be placed after frequently used ones. These will not be changed unless they are modified by the subroutine itself. In the first example, the value of `A-times-B` is placed in the variable `#`. In the second example, `X` is placed in `#`, and `Y` goes into `$`. If this function were called subsequently with only a single argument, the value placed in `$` would not be disturbed. No arguments are used in the third example, but any variables defined by the program may be used by the subroutine. This is the only reasonable way to handle arrays. The subroutine must then be written to use the appropriate protected variable whenever it needs the value of the corresponding argument. A routine to compute the length of a vector, for instance, might use an expression such as `FSQT(#*#+$*$)`. The value returned by the function is just the result of the last arithmetic expression processed by the subroutine. This expression may be evaluated by any suitable command, but typically the `SET` command is employed. To begin with a very simple example, here is how you could code the tangent function: 9.9 SET FSIN(#)/FCOS(#); COMMENT: THIS IS THE TANGENT FUNCTION You could also include a replacement operator to save the result in a variable, or you could use the `TYPE` command to output the result of the expression, or whatever. Since it is the *last* result which is returned as the value of the function, however, if other calculations are necessary for checking the result or performing ancillary calculations, the value desired must be saved and then `SET` again just before returning. There are a number of UWF commands which do not disturb a PDF result and so may be used without caution in the definition of the function. These are `COMMENT`, `RETURN`, `YNCREMENT` and `ZERO`. On the other hand, branching commands always evaluate a line number (which may be zero), and so cannot be used to terminate a PDF without destroying the (expected) function result. It should also be pointed out that the line number option in a [`RETURN` command](#return) will be ignored by a PDF call. This is necessary to ensure that the program returns to complete the function call. <a id="named-pdf"></a>While most PDF calls just use an explicit line or group number to identify the function, it is possible to be somewhat more elegant! By using a variable with a nicely selected name you can specify the `F(TAN,X)` function rather than the `F(9.9)` function. To do this, just set the variable `TAN` to the value 9.9. This has the additional advantage that you can easily move the subroutine to a different part of the program without having to change all the function calls. ## <a id="pdf-examples"></a>Examples of Program Defined Functions Here are a few interesting PDFs which illustrate some of the things you can do. A symbolic name has been used in most cases; it must be set to the value of the line or group actually used to code the function. 1. `F(PWR,X,Y)` — raises `X` to the `Y` power when `Y` is non-integer: SET FEXP($*FLOG(#)) Sample call: `TYPE F(PWR,27,1/3) 3.000000000` 2. `F(!,N)` — computes the Nth factorial (maximum value of N is about 300) FOR I=$=1,#; SET $=$*I Sample call: `TYPE F(!,5) 120.0000000` 3. `F(SUM)` — computes the sum of the subscripted array `G(I)` ZERO $; FOR I=1,N; SET $=$+G(I) Sample call: `SET AVE=F(SUM)/N` 4. `F(PN,X)` — evaluates the polynomial `Y=C(0)+C(1)*X+C(2)*X^2+...+C(N)*X^N` FOR I=N,-1,$=0; SET $=$*#+C(I) This function is useful for computing series approximations 5. `F(OCTAL,VALUE)` — converts a number from decimal to octal FOR I=N=0,4,SET N=N+(#-8*#=FITR(#/8))*10^I Sample call: `TYPE F(OCTAL,1000) 1750` This is the most interesting of the functions shown so far, if for no other reason than that it uses all the arithmetic operators in a single SET command as well as some fancy redefinitions within the loop. The technique employed is quite general for changing from one number base to another, so simply by interchanging the 8s and 10s in the definition you can construct a function to give you the decimal equivalent of an octal number: TYPE F(DECIMAL,1000) 512 To be still more elegant you can rewrite the function to use the value of `$` in place of the number 8 shown above and thus have a general-purpose routine for converting to any number base less than or equal to 10. A fun thing to do once you have made this change is to try it out with a direct command such as: FOR J=2,10; TYPE F(BASE, 99, J)! which will then type out the value of 'ninty-nine' in all number bases from 2-10. The loop limit represents the maximum number of digits required to represent the number, so if you try this with large numbers and small number bases you will probably need to increase the limit to something more than '4'. 6. <a id="pdf-transcendentals"></a>PDF replacements for the transcendental functions: These functions may be used in place of the internal functions in the event that you wish to delete some of them to increase the number of variables available on an 8K machine. F(EXP)= 25.1 IF (#*#-.01).2; SET #=F(EXP,#/2)^2 EXP=25.1 25.2 SET #=1+#+#*#/2+#^3/6+#^4/24+#^5/120 F(LOG)= 26.1 IF (#*#-2.04*#+1).2; SET #=2*F(LOG,FSQT(#)) LOG=26.1 26.2 SET #=(#-1)/(#+1), #=2*(#+#^3/3+#^5/5+#^7/7) F(ATN)= 27.1 IF (#*#-.01).2; SET #=2*F(ATN,#/(1+FSQT(1+#*#))) ATN=27.1 27.2 SET #=#-#^3/3+#^5/5-#^7/7 F(SIN)= 28.1 IF(#*#-0.1).2; SET #=F(SIN(#/3), #=3*#-4*#^3 SIN=28.1 28.2 SET #=#-#^3/6+#^5/120 F(COS)= 28.3 SET F(SIN, PI/2-#) F(TAN)= 29.1 IF (#*#-.01).2;S #=F(TAN,#/2), #=2*#/(1-#*#+1E-99) TAN=29.1 29.2 SET #=#+#^3+#^5/7.5+#^7/315 F(ASIN)= 30.1 IF (#*#-.01).2;S #=2*F(.1,#/(FSQT(1+#)+FSQT(1-#))) ASIN=30.1 30.2 SET #=#+#^3/6+.075*#^5+#^7/22.4 F(ACOS)= 30.3 SET PI/2-F(ASIN) F(HSIN)= 31.1 IF (#*#-.01).2; SET #=F(HSIN,#/3), #=3*#+4*#^3 HSIN=31.1 31.2 SET #=#+#^3/6+#^5/120 F(HCOS)= 31.3 SET FSQT(F(HSIN)*#+1) The method used in these functions is to recursively reduce the argument to a value typically less than .1, evaluate a series approximation which is reasonably accurate for an argument of this magnitude, and then 'bootstrap' back using an identity such as e<sup>2X</sup>=(e<sup>X</sup>)<sup>2</sup>. Thus the approximation for `F(EXP)` is evaluated after reducing the argument to the proper range and then the result is squared enough times to return to the original value. This clever method was devised by A.K. Head. 7. In many cases a PDF call is preferable to a simple `DO` because it can pass a parameter or two to the subroutine at the same time and can also return a 'status' value. As an example of such a use, consider a subroutine for finding the roots of a quadratic equation. There are three possible cases: the roots are equal, the roots are real but unequal, or the roots are complex numbers. If the values produced by the subroutine are stored in `R1` and `R2`, then after calling the routine one must still decide how to interpret the results. If the subroutine were to return the value of the 'discriminant' this could be accomplished as follows: ON (F(QR)) complex, equal, unequal where `QR` is the group number of the Quadratic Root subroutine and 'complex', 'equal', 'unequal' are line or group numbers associated with the `ON` command which serves both to call the subroutine and to test the result at the end. Other such examples will undoubtedly occur to the reader. ## <a id="function-summary"></a>Function Summary Here is a list of all the functions implemented in the standard version of UWF. Since up to 36 internal functions are possible, it should be clear that this list is not exhaustive. | Function | Description | | ------ | ------------------------------------------------------------ | | `FABS` | Returns the absolute value of the argument | | `FATN` | Returns the angle in radians whose tangent is given | | `FBUF` | Optional: stores or retrieves 12-bit signed integers | | `FCOM` | Optional: accesses additional memory for data storage | | `FCOS` | Returns the cosine of an angle measured in radians | | `FDIN` | Optional: returns value of digital input register | | `FEXP` | Returns value of e<sup>X</sup> where \|X\| is less than 1418 | | `FIN` | Reads and returns the value of a single character | | `FIND` | Searches for a given character code | | `FITR` | Returns integer value of the argument | | `FLOG` | Returns the natural logarithm of the argument | | `FKAX` | Returns the maximum value of two arguments | | `FMIN` | Returns the minimum value of two arguments | | `FMQ` | Displays the argument in the MQ register, returns same | | `FOUT` | Outputs a single character value | | `FRAC` | Returns the fractional part of the argument | | `FRAN` | Returns a random number in the range 0-1 | | `FSGN` | Returns the sign value of the argument: -1,0,+1 | | `FSIN` | Returns the sine of an angle measured in radians | | `FSQT` | Returns the square root of a positive number | | `FSR` | Returns the signed value of the switch register | | `FIRM` | Returns the value of the last `ASK` terminator | | `F` | Program Defined Functions | ## Appendix Ⅰ ### <a id="character-codes" name="ascii-table"></a>Decimal Values for All Character Codes | Code | Character | Name | Code | Char | Code | Char | Code | Char | | ---- | --------- | ---- | ---- | ------- | ---- | ---- | ---- | ----------- | | 128 | `Ctrl/@` | NULL | 160 | `SPACE` | 192 | `@` | 224 | <code>\`</code> | | 129 | `Ctrl/A` | SOH | 161 | `!` | 193 | `A` | 225 | `a` | | 130 | `Ctrl/B` | STX | 162 | `"` | 194 | `B` | 226 | `b` | | 131 | `Ctrl/C` | ETX | 163 | `#` | 195 | `C` | 227 | `c` | | 132 | `Ctrl/D` | EOT | 164 | `$` | 196 | `D` | 228 | `d` | | 133 | `Ctrl/E` | ENQ | 165 | `%` | 197 | `E` | 229 | `e` | | 134 | `Ctrl/F` | ACK | 166 | `&` | 198 | `F` | 230 | `f` | | 135 | `Ctrl/G` | BELL | 167 | `'` | 199 | `G` | 231 | `g` | | 136 | `Ctrl/H` | B.S. | 168 | `(` | 200 | `H` | 232 | `h` | | 137 | `Ctrl/I` | TAB | 169 | `)` | 201 | `I` | 233 | `i` | | 138 | `Ctrl/J` | L.F. | 170 | `*` | 202 | `J` | 234 | `j` | | 139 | `Ctrl/K` | V.T. | 171 | `+` | 203 | `K` | 235 | `k` | | 140 | `Ctrl-L` | F.F. | 172 | `,` | 204 | `L` | 236 | `l` | | 141 | `Ctrl-M` | C.R. | 173 | `-` | 205 | `M` | 237 | `m` | | 142 | `Ctrl/N` | SO | 174 | `.` | 206 | `N` | 238 | `n` | | 143 | `Ctrl/O` | SI | 175 | `/` | 207 | `O` | 239 | `o` | | 144 | `Ctrl/P` | DLE | 176 | `0` | 208 | `P` | 240 | `p` | | 145 | `Ctrl/Q` | XON | 177 | `1` | 209 | `Q` | 241 | `q` | | 146 | `Ctrl/R` | DC2 | 178 | `2` | 210 | `R` | 242 | `r` | | 147 | `Ctrl/S` | XOFF | 179 | `3` | 211 | `S` | 243 | `s` | | 148 | `Ctrl/T` | DC4 | 180 | `4` | 212 | `T` | 244 | `t` | | 149 | `Ctrl/U` | NAK | 181 | `5` | 213 | `U` | 245 | `u` | | 150 | `Ctrl/V` | SYNC | 182 | `6` | 214 | `V` | 246 | `v` | | 151 | `Ctrl/W` | ETB | 183 | `7` | 215 | `W` | 247 | `w` | | 152 | `Ctrl/X` | CAN | 184 | `8` | 216 | `X` | 248 | `x` | | 153 | `Ctrl/Y` | EM | 185 | `9` | 217 | `Y` | 249 | `y` | | 154 | `Ctrl/Z` | SUB | 186 | `:` | 218 | `Z` | 250 | `z` | | 155 | `Ctrl/[` | ESC | 187 | `;` | 219 | `[` | 251 | `{` | | 156 | `Ctrl/\` | FS | 188 | `<` | 220 | `\` | 252 | <code>\|</code> | | 157 | `Ctrl/]` | GS | 189 | `=` | 221 | `]` | 253 | `} ALTMODE` | | 158 | `Ctrl/^` | RS | 190 | `>` | 222 | `^` | 254 | `~ PREFIX` | | 159 | `Ctrl/_` | US | 191 | `?` | 223 | `_` | 255 | `⌑ DELETE` | `FOUT(141)` will output a <kbd>RETURN</kbd>/<kbd>LINE FEED</kbd> while `FOUT(13)` will just do a <kbd>RETURN</kbd>. Codes 225 through 255 are lower case letters, some of which serve other functions on keyboards without lower case. Many keyboards use <kbd>SHIFT/K</kbd> for `[`, <kbd>SHIFT/L</kbd> for `\`, and <kbd>SHIFT/M</kbd> for `]` and corresponding combinations for the control codes following <kbd>CTRL/Z</kbd>. These symbols are often not printed on the key tops. Codes 0-127 are the same as codes 128-255 except for the parity bit. UWF always forces the parity bit during input. ## <a id="patches" name="we don’ need no steenkin’ patches!"></a>U/W FOCAL V4E Patches Here is a list of patches for adding a number of special features to UWF. They are shown in the format: `FLLLL/ CCCC PPPP; QQQQ` where `FLLLL` is the Field + Memory location, `CCCC` is the original contents, and `PPPP` is the patch. In cases where several successive locations are to be changed, a semicolon is shown, followed by the next patch `QQQQ`. Note that the `FCOM` patch shown below is for 16K versions only and must be added *before* UWF is started the first time. ### Field 0 `00045/ 4463 4442` — Replace extra variable storage with `FCOM` ([16K only](#starting)) `00061/ 7610 6213` — Print a CR/LF before printing an error message ### Field 1 `10402/ 4547 0000` — Eliminate the line number printout in `MODIFY` `11216/ 7000 4533` — Make the `ASK` command print a `:` each time `11241/ 1377 7040` — Use the `#` operator to output a Form Feed `12471/ 1000 1177; 4533` — Change 'rubout' for video terminals `13070/ 7106 7107` — Increase the delay after a Carriage Return `13134/ 7000 6xxx` — Clear an unwanted interrupt (next 3 locations too) `15665/ 1103 1213` — Make `TYPE` print an `=` ahead of each value `15666/ 4534 7200` — Remove the initial space (or `=`) printed by `TYPE` `14503/ 62X1 62Y1` — Change the data field used by `FCOM` (`X`,`Y` may be 2-7) `14545/ 62X1 62Y1` — Ditto for the `FBUF` function (`X` is set at startup) `10033/ 4566 5200` — Remove the `FLOG`, `FEXP` and `FATN` functions to increase the<br> `12371/ 5020 1754; 1754; 1754` — size of the symbol table in the 8K version `10033/ 5200 5303` — Remove `FSIN` and `FCOS` to increase the symbol table size a<br> `12367/ 5205 1754; 1754` — little bit more (8K only) ## <a id="error-codes"></a>Error Codes for UWF (V4E) October 1978 | Code | Meaning | | -----: | --------------------------------------------------------------------- | | ? | Keyboard interrupt (<kbd>CTRL/F</kbd>) or restart from location 10200 | | ?01.50 | Group number greater than 31 | | ?01.93 | Non-existent line number in a `MODIFY` or `MOVE` command | | ?03.10 | Non-existent line called by `GOTO`, `IF`, `NEXT`, `BREAK` or `QUIT` | | ?03.30 | Illegal command | | ?03.47 | Non-existent line or group: `DO`, `ON`, `JUMP`, `LINK` or `PDF` call | | ?04.35 | Missing or illegal terminator in a `FOR` command | | ?06.03 | Illegal use of a function or number: `ASK`, `YNCR`, or `ZERO` | | ?06.41 | Too many variables (`ZERO` unnecessary ones to recover space) | | ?07.44 | Operator missing or illegal use of an equal sign | | ?07.67 | Variable name begins with `F` or improper function call | | ?07.76 | Double operators or an unknown function | | ?08.10 | Parentheses don't match | | ?10.50 | Program too large (sorry, you'll have to erase some of it) | | ?18.32 | `FCOM` index out of range | | ?19.72 | Logarithm of zero | | ?21.57 | Square root of a negative number | | ?22.65 | More than 10 digits in a number | | ?25.02 | Stack overflow: reduce nested subroutines and expressions | | ?27.90 | Zero divisor | | ?31.<7 | Non-existent program area called by `LOOK` or `LINK` | | <span style="white-space: nowrap;">← or \_</span> | End of input sensed, I/O switched back to the terminal ## <a id="fpal"></a>`FPAL` `FPAL` allows the user to code short 'machine language' functions directly into his program. This provides 'keyboard control' of special devices which are not supported by any of the normal functions or commands, and also permits operations requiring only 12-bit arithmetic to proceed at full machine speed. Routines as long as 32<sub>10</sub> instructions can (in theory) be incorporated, but in practice, `FPAL` routines are seldom longer than about 5-10 instructions — just enough to execute a short sequence of `IOT`s to pulse a control line, for instance. The form of the function call is: `FPAL(AC,inst,inst,inst...)` where `AC` is an arithmetic expression, the value of which will be placed in the AC prior to calling the routine, and the remaining arguments are construed as a list of *octal* numbers which represent the desired machine instructions. These are stored in Field 3 such that the first instruction is at 'page+1' , the second at 'page+2', etc. After the last instruction has been tucked away, `FPAL` loads the `AC` with the integer part of the first argument, clears the `Link`, and calls the routine. The final value of the `AC` is then returned to the program as the value of the function. Note that the user does not have to worry about any of the 'calling' instructions — he only has to write the essential machine code. Here are a few examples which may help clarify how the `FPAL` function works and illustrate some of the things it can do: 1. UWF has an `FMQ` function for loading a number into the `MQ` register (where it is preserved by all internal arithmetic operations), but no corresponding function for finding out what is already there. The following `FPAL` function will not only do this, but will also increment the value in the `MQ` at the same time: TYPE MQ=FPAL(,7501,7001,7521) Note that the first argument has been omitted in this example, since no information is being passed *to* the function. The first instruction (`7501=MQA`) reads the `MQ`, the next (`7001=IAC`) increments this value and the third (`7521=SWP`) interchanges the new and old values, saving the new value for a subsequent call and returning the old value to the program. Machines based on the 6100 microprocessor may not be able to display the `MQ` while UWF is running. Using this function however, the value of the hardware register can be saved in the variable `MQ` and output by the `TYPE` command as well. So being able to actually 'see' this register is not a necessity. 2. Several variations of this routine come to mind almost immediately. For instance, we could use the hardware `SWP` instruction to interchange two values: SET MQ=FPAL(AC,7521) or we could take advantage of the `MQA` instruction to perform an 'inclusive OR' between a value in the `MQ` and one in the `AC`: SET FMQ(A),AB=FPAL(B,7501) 3. As a final example, suppose that we have constructed an A/D converter interface which uses the same instruction set as the AD8-EA. In order to test it out we can use the following `FPAL` routine to implement the `FADC` function: SET CH(N)=FPAL(N,6531,6532,6534,5203,6533) The channel number (`N`) will be placed in the `AC` at the beginning and can be used to control the multiplexer via a `6531=ADLM` instruction. The converter is then started (`6532=ADST`) and we begin testing the 'done' flag (`6534=ADSD`) to see when it is finished. This involves a `JMP .-1` instruction which means that the location of the `ADSD` instruction (relative to a page boundary) must be known. Since `FPAL` routines always start at 'page+1', (location 'page+0' can be used as a 'temporary'), a jump to the *third* instruction becomes `5203`. When the conversion is finally done, the result is read into the `AC` (`6533=ADRD`) and returned to the program. It goes almost without saying that such easy access to machine-level code is both powerful *and* dangerous! No error checking can be performed, so a single 'typo' can lead to instant disaster! Always be sure, therefore, to save a copy of a valuable program *before* you try out any sort of 'wild' `FPAL` function, and be especially careful with `ISZ`s, `DCA`s, `JMP`s and `JMS`es since they can modify memory or send the program off 'into the wild blue yonder'. Similarly, give special consideration to any `IOT` which might cause a hardware interrupt since UWF runs with the interrupt system enabled! Most interfaces have an 'interrupt disable' instruction, but if it is necessary to use an `IOF` in order to protect UWF from a spurious interrupt, be sure to clear the flag and then issue an `ION` before exiting from the function — otherwise it may be necessary to [restart the interpreter](#starting) in order to activate the interrupt system again. ### Advanced Considerations While it is clearly possible to use `FPAL` to implement patches to UWF itself, this practice is *strongly* discouraged — and no help with such folly will be offered — since this makes programs 'version dependent'. On the other hand, there *are* a few 'tricks' which could prove useful at various times: 1. The value of the first parameter is actually converted into a 24-bit integer, of which only the lower 12-bits are loaded into the `AC` at the beginning of the routine. This means that the values `4095` and `-1` will both load 7777<sub>8</sub> into the AC. The high-order part of the number can be accessed with a `TAD 45` (1045) instruction, while the low-order half can always be recalled with a `TAD 46` (1046) if it is needed later on in the function. 2. The value of the AC is normally returned as a signed number; if it is more desirable to have an 'unsigned' result you can simply code an `ISZ .+1` instruction as the last step of the routine. Thus: `TYPE FPAL (4095)` will return `-1`, whereas `TYPE FPAL (4095,2202)` will return `4095`. The `2202` instruction is `ISZ .+1` when located at 'page+1'. Notice that numbers appearing in the *first* argument of an `FPAL` call are treated as 'decimal' values and can be replaced by variables and/or other functions. The remaining arguments, however, are processed as character strings and so cannot be replaced by arithmetic expressions. --------------------------------- **End Notes** 1. FOCAL, PDP-8 and OS/8 are trademarks of Digital Equipment Corp., Maynard, Mass. 2. The automatic return can be aborted if desired — see the [`RETURN` command](#return) for further details. 3. For more information on storing programs in different areas, see the [expanded text storage](#etext) discussion. 4. `LINK` and `LOOK` differ only in the presence or absence of a second parameter. If only the area is specified, UWF returns to command mode (`LOOK`), otherwise it executes a subroutine call (`LINK`). ----------------------------- **Formatter's Note** This document is based on the [OCR'd text][ocr] of the [scanned U/W FOCAL Manual V4E from October 1978][scan]. The following edits have been made to the original text as presented here: 1. Fixed some grammar, OCR, and heading nesting level errors. Some new errors have doubtless been added in this process. [Bug reports][tkt] and [patches][hack] are welcome. 2. "PDP8" and "PDP/8" are stylized as "PDP-8", and "Binary loader" changed to "BIN loader" to match DEC documentation. 3. Asterisk-marked page notes are now numbered end-notes. 4. Removed page numbers and replaced prose page references with internal hyperlinks. This version is intended to be read on a computer screen, not on paper; even if printed, the original pagination would no longer apply. 5. Replaced instances of the obscure Latin initialism [v.i.][videf] (*vide infra*, meaning "see below") with hyperlinks to the referenced section. 6. The original document used typewriter formatting. Where sensible, we use the slightly upgraded formatting possible with Markdown. Examples: - Replaced emphasis indicated via `-dashes-` with *italics* - Headlines are rendered with larger and bolder fonts rather than CENTERED ALL CAPS TEXT - FOCAL program text, keywords within running prose, and computer output are marked up appropriately - Removed hard hyphenation and primitive line justification; that is done by the Markdown renderer, if at all 7. Due to the differences between documents made on and transmitted in paper form — as compared to Markdown with HTML rendering — several of the input commands and their resulting outputs are presented differently in this version of the manual. A good example is the documentation for the [`FATN`](#fatn) function, where in the original, the example input was given inline in the prose, and the output was shown centered on the page. I've chosen instead to present it as a terminal transcript, with the command and its output shown just as you'd see it on your terminal. This in turn means that in some places I've added the `*` FOCAL prompt to make it clearer which line(s) are input and which are output. I've also added `!` operators where necessary to avoid questions about why you get `*` prompts at the end of program ouput. — [Warren Young][wy], September & October 2017, Aztec, NM, USA [hack]: https://tangentsoft.com/pidp8i/doc/trunk/HACKERS.md [ocr]: https://archive.org/stream/bitsavers_decpdp8focct78_4144912/UW_FOCAL_Manual_V4E_Oct78_djvu.txt [scan]: https://archive.org/details/bitsavers_decpdp8focct78_4144912 [tkt]: https://tangentsoft.com/pidp8i/tktnew [videf]: https://en.wiktionary.org/wiki/vide_infra#Latin) [wy]: https://tangentsoft.com/ --------------------------- Original document © 1978 by LAB DATA SYSTEMS<br> Seattle, Washington 98125<br> All rights reserved (JvZ) Edits © 2017 by Warren Young<br> Released under the terms of the [SIMH License](https://tangentsoft.com/pidp8i/doc/trunk/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 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 | # U/W FOCAL V4E Reference Cards ### Introduction The following material is reformatted from the `CARD[1-4].DA` files contained within the U/W FOCAL V4E distribution which we used in creating the PiDP-8/I software project's U/W FOCAL feature. Some minimal effort has been made to make this document print well, though it doesn't paginate the same as the original material. Since these files were likely created [before 1978][cl78] and probably did not have their copyright renewed — if it was in fact applied for, not an automatic thing at the time in the United States — we believe this text to be in the public domain. If the authors of the text below request it, we will remove this file from the PiDP-8/I software distribution. [cl78]: https://en.wikipedia.org/wiki/Copyright_law_of_the_United_States#Works_created_before_1978 <style type="text/css"> @media print { h2 { page-break-before: always; } h1, h2, h3 { page-break-after: avoid; } p { page-break-before: avoid; } div.header, div.mainmenu, div.footer { display: none; visibility: hidden; } } </style> ## <a id="card1"></a>U/W FOCAL Quick Reference Card (`CARD1.DA`) ### Single Letter Commands | `A` | Ask [`"QUERY"`,`X`,`:`,`!`] | Accepts value of `X` from input device | | `B` | Break [_L1_]% | Exits from a FOR loop, continuing at _L1_ | | `C` | Comment | Ignores the rest of the line | | `D` | Do [_G1_,_G2_,_G3_,etc.] | Calls a line or a group as a subroutine | | `E` | Erase [_G1_] | Deletes all or part of the program | | `F` | `For X=`_E1_`,`[_E2_`,`] _E3_`;`(_commands_) | Executes line `1+(_E3_-_E1_)/_E2_` times | | `G` | Goto [_L1_] | Branches to line _L1_ | | `H` | Hesitate [_E1_]\* | Delays (or synchronizes) the program | | `I` | If `(E1)` [_L1_,_L2_,_L3_]% | Transfers to _L1_,_L2_,_L3_ on sign of _E1_ | | `J` | Jump `(`_E1_`)` [_G1_,_G2_,_G3_,_G4_...]% | Calls the subroutine selected by _E1_ | | `K` | Kontrol [_E1_,_E2_,etc]\* | Controls relays or other digital output | | `L` | Library/List | Two-letter commands, see the next page | | `M` | Modify [_L1_,_L2_] | Edits and/or Moves line L1 - see below | | `N` | Next [_L1_]% | Ends a `FOR` loop, branches to _L1_ when finished | | `O` | On `(`_E1_`)` [_G1_,_G2_,_G3_]% | Calls subroutine selected by sign of _E1_ | | `P` | Plot [_X_,_Y_,_L_,_M_]\* | Controls an analog or digital plotter | | `Q` | Quit [_L1_]% | Stops program, allows restart at _L1_ | | `R` | Return [_L1_]% | Exits from a subroutine call, continuing at _L1_ | | `S` | Set [_E1_,_E2_,_E3_,etc.] | Evaluates arithmetic expressions | | `T` | Type [_E1_,`"TEXT"`,`!`,`#`,`:`,`%`,`$`] | Generates alphanumeric output | | `U` | User | | | `V` | View [_X_,_Y_,_Z_]\* | Generates graphic output on a CRT | | `W` | Write [_G1_,_G2_,_G3_,etc.] | Lists all or part of a program | | `X` | Xecute | Equivalent to SET | | `Y` | Yncrement [_X_,_Y_`-`_Z_] | Increments or decrements variables | | `Z` | Zero [_X_,_Y_,...] | Sets some or all of the variables to zero | \* Indicates a non-standard (installation dependent) feature % If the line number is omitted (or=0) no branch will occur _En_ are Arithmetic Expressions - - [] Enclose optional items _Ln_ are Line Numbers from `0.01` to `31.99` - excluding integers _Gn_ are Line or Group Numbers from `0` to `+31` (`0` = next or all) Line numbers `.01` to `.99` refer to lines in the current group Negative or Integer line numbers denote a 'Group' operation. Arithmetic expressions may be used as Line or Group numbers ### Arithmetic Operators | | ( ) [ ] < > | Three equivalent sets of enclosures | | ' | Character value | `'A` is the value of the letter `A` | | ^ | Exponentiation | Positive or negative integer powers | | * | Multiplication | Note especially that multiplication | | / | Division | has a higher priority than division | | - | Subtraction or Negation | Example: (to illustrate priorities) | | + | Addition | `-5^4/3*A=2+1` is `0-<5^4>/[3*(A=2+1)]` | | = | Replacement | May be used anywhere in expressions | ### Ask/Type Operators | , | COMMA or SPACE | Separates variables and/or expressions | | ! | Carriage return/linefeed | Starts a new line for input or output | | " | String delimiter | Case shift option uses `\`: `"A\B\C"=AbC` | | # | Return or Clear Screen | Used for plotting or overprinting | | $ | Symbol table listing | `TYPE $4` prints 4 variables per line | | : | Tabulation | `ASK :-15` skips over the next 15 characters | | | (:0 is ignored) | `TYPE :15` spaces to column 15 if not beyond | | % | Format control | `%3` Produces 3 Digits in an integer format | | | (for output only) | `%0.04` = 4 Digits using scientific notation | | | (input is unformatted) | `%5.02` = 5 Digits, 2 decimal places maximum | Letters (but only one E) are legal numeric input: `YES=25E19`. `ALTMODE` or `ESCAPE` aborts input, with the variable unchanged. `_` deletes all digits during input — `RUBOUT` is ignored. ### Modify / Move Operators | `CTRL/F` | Aborts the command leaving the line unchanged | | `CTRL/G` (bell) | Selects a new search character | | `CTRL/L` (does not echo) | Searches for next occurrence of character | | `_` (backarrow or underline) | Deletes all characters to the left | | `RETURN` | Terminates the line at the current position | | `LINEFEED` | Copies the remainder of the line unchanged | | `RUBOUT`/`DELETE` | Removes the previous character, echos a `\` | `RUBOUT` or `DELETE` and `_` also work during command input `LINEFEED` retypes the corrected input line for verification ## <a id="commands" name="card2"></a>Command Summary (`CARD2.DA`) In the descriptions below, arguments in square brackets are optional. Specify the argument, but don't include the square brackets. If a space is in the square brackets, a space is required to provide the argument. ### Miscellaneous Commands | `O D` | Output Date | Prints system date in the form `DD.MM.YY` | | `L E` | Logical Exit | Returns to the OS/8 keyboard monitor | | `L B` | Logical Branch _L1_ | Branches to _L1_ if -no- input from TTY | | `J ` | Jump _L1_. | Equivalent to the Logical Branch command | ### Filesystem Directory Commands | `L A,E` | List All [name][`,E`] | Lists all files after the one specified | | `L O` | List Only [_name_]\* | Verifies the existence of one `.FC` file | | `O L` | Only List [_name_]\* | Verifies the existence of one `.DA` file | | `L L` | Library List [_name_]% | Shows files with the same extension | | `L D` | Library Delete name [ _L1_] | Removes a name from the directory | | `L Z` | Library Zero dev:[_length_] | Zeros directory using length given | Notes on Directory Commands: `E` Adding the phrase `,E` will list all of the 'empties' too * Omitting the name lists all files with the same extension % A null extension will list all files having the same name ### Program Commands | `L C` | Library Call name | Loads a program, then Quits | | `L G` | Library Gosub name [ _G1_] | Calls a program as a subroutine | | `L R` | Library Run name [ _L1_] | Loads a program and starts at _L1_ | | `L N` | Library Name [_name_] | Changes the program header | | `L S` | Library Save name [ _L1_] | Saves the current program | [ _G1_] indicates which line or group will be called by `L G` [ _L1_] specifies an error return, except for the `L R` command ### Input / Output Commands | `O A` | Output Abort [_E1_] | Terminates output file with length _E1_ | | `O B` | Output Buffer | Dumps buffer without closing the file | | `O C` | Output Close [_E1_] | Ends output, saves file with length _E1_ | | `O I,E` | Open Input [`,Echo`] | Selects the terminal for input | | `O O` | Open Output | Selects the terminal for output | | `O S` | Output Scope | Selects CRT for output (if available) | | `O I -` | Open Input name [`,E`] [ _L1_] | Switches input to an OS/8 device | | `O S -` | Open Second name [`,Echo`] [ _L1_] | Selects a second input file | | `O O -` | Open Output name [`,Echo`] [ _L1_] | Initiates OS/8 (file) output | | `O E -` | Output Everything device [`,Echo`] | Changes error/echo device | | `O R R` | Open Restart Read [`,Echo`] | Restarts from the beginning | | `O R I` | Open Resume Input [`,Echo`] [ _L1_] | Returns to file input | | `O R O` | Open Resume Output [`,Echo`] [ _L1_] | Returns to file output | | `O R S` | Open Resume Second [`,Echo`] [ _L1_] | Returns to second input file | The `INPUT ECHO` sends characters to the current `OUTPUT` device The `OUTPUT ECHO` sends characters to the current 'O E' device ### Filename Expressions Device and filenames may be written explicitly: `RXA1:`, `MYSTUF`, `0123.45`. Numeric parts can be computed from (expressions): `DTA(N):PROG(X).(A+B)`. Negative values specify single characters: `F(-201)L(-197,.5,PI)=FILE03`. An \<OS/8 block number\> can be substituted for the name: `LTA1:<20*BN+7>`. Expressions in square brackets indicate the size: `TINY[1]`, `<LOC>[SIZE]`. ### <a id="variables"></a>Variables Variable names may be any length, but only the first two characters are stored; the first character may not be an `F`. Both single and double subscripts are allowed - a subscript of 0 is assumed if none is given. The variables `!`, `"`, `#`, `$`, `%` and `PI` are protected from the `ZERO` command and do not appear in table dumps. `!` is used for double subscripting and should be set to the number of rows in the array. `#`, `$`, `%` are used by [FOCAL Statement Functions](#fsf). The `ZVR` feature permits non-zero variables to replace any which are zero. This includes `FOR` loop indices, so use a protected variable if the index runs through zero. Undefined or replaced variables are automatically set to zero before their first use. ### <a id="fsf"></a>FOCAL Statement Functions `F(G1,E1,E2,E3)` executes line or group `G1` after first setting the variables `#`,`$`,`%` to the values of `E1`,`E2`,`E3` (if any). The function returun with the value of the last arithmetic expression processed by the sub routine, including line number & subscript evaluations. For example: 8.1 S FSIN(#)/FCOS(#) is the TANGENT function = F(TAN,A) if 'TA' = 8.1 9.1 S FEXP($*FLOG(#)) computes X^Y for any value of Y using F(9.1,X,Y) ## <a id="misc" name="card3"></a>Miscellaneous Material (`CARD3.DA`) ### Internal Functions | `FABS(`_E1_`)` | Returns the absolute value of the argument | | `FADC(`_N_`)` | Reads A/D converter channel N (LAB/8e or PDP12`)` | | `FATN(`_A_`)` | Computes the arctangent of _A_, result in radians | | `FBLK(``)` | OS/8 block number of the current input file | | `FBUF(`_I_`,`_V_`)` | Display buffer storage (single-precision) | | `FCOM(`_I_`,`_V_`)` | Extended data storage in Fields 2 and 4-7 | | `FCOS(`_A_`)` | Computes the cosine of _A_ (_A_ is in radians) | | `FCTR(`_N_`)` | Reads a frequency counter using timebase _N_ | | `FDAC(`_N_`,`_V_`)` | Sets D/A converter channel _N_ to the value _V_ | | `FDAY(`_MONTH*256+DAY*8+YEAR-78_`)` | Reads/Sets the OS/8 system date | | `FDIN(`_B1_`,`_B2_`,`...`,`_Bn_`)` | Reads selected bits from the input register | | `FDVM(`_N_`,`_R_`)` | Reads a digital voltmeter, channel _N_, range _R_ | | `FEXP(`_E1_`)` | Base 'e' exponential function `\|`_E1_`\|<1420` | | `FIN()` | Reads a single character, returns the ASCII value | | `FIND(`_C_`)` | Searches for code _C_, returning _C_ if found, 0 if `EOF` | | `FITR(`_E1_`)` | Returns the integer part of the argument | | `FJOY(`_I_`)` | Places the cursor (joystick) coordinates in _XJ_,_YJ_ | | `FLEN(`_I_`)` | File length: _I_=`0` for `O`utput, _I_=`1` for `I`nput | | `FLOG(`_E1_`)` | Natural logarithm of the absolute value of _E1_ | | `FLS()` | Returns unsigned value of the Left Switches (PDP12) | | `FMIN(`A_`,`_B`)` | Returns the minimum or argument | | `FMAX(`A_`,`_B`)` | Returns the maximum argument | | `FMQ(`_N_`)` | Displays the lower 12 bits of _N_ in the `MQ` register | | `FOUT(`_C_`)` | Outputs character code _C_, returns the value `0` | | `FRA(`_I_`,`_V_`)` | Reads or writes in a binary file at location I | | `FRAC(`_E1_`)` | Returns the fractional part of the argument | | `FRAN(``)` | Pseudo-random number function, range 0-1 | | `FSAM(`_N_`)` | Samples _N_ channels and stores results in buffer | | `FSGN(`_E1_`)` | Returns `-1`,`0`,`+1` for _E1_ negative, zero, positive | | `FSIN(`_A_`)` | Computes the sine of _A_ (_A_ is in radians) | | `FSQT(`_E1_`)` | Finds the square root using Newton's method | | `FSR()` | Reads the Switch Register | | `FRS()` | Reads the Right Switches on a PDP-12 | | `FSS(`_N_`)` | Tests Sense Switch _N_: `-1` = `OFF`, `+1` = `ON` | | `FTIM(`_N_`)` | Reads, sets or clears the elapsed time counter | | `FTRG(`_N_`)` | Returns status and clears Schmitt trigger _N_ | | `FTRM(``)` | Returns the last input terminator | | `FXL(`_N_`)` | Tests external level _N_ (PDP12) returning `-1` or `+1` | And others. There are a total of 36 possible function names Functions indicated by a * are not available in all versions. The functions `FBLK` & `FLEN` are useful in filename expressions. `FIN`, `FOUT`, `FIND` and `FTRM` use decimal ASCII codes - see below. ### <a id="ascii"></a>Decimal ASCII Character Codes | Code | Character | Code | Char | Code | Char | Code | Char | | ---- | -------------------- | ----- | ---------------- | ----- |------- | ----- | --------- | | 128 | `CTRL/@` (leader/ | 152 | `CTRL/X` | 176 | `0` | 201 | `I` | | | trailer-ignored) | 153 | `CTRL/Y` | 177 | `1` | 202 | `J` | | 129 | `CTRL/A` | 154 | `CTRL/Z` (`EOF`) | 178 | `2` | 203 | `K` | | 130 | `CTRL/B` | 155 | `ESCAPE` or | 179 | `3` | 204 | `L` | | 131 | `CTRL/C` (OS/8) | | `CTRL/[` | 180 | `4` | 205 | `M` | | 132 | `CTRL/D` | 156 | `CTRL/\` | 181 | `5` | 206 | `N` | | 133 | `CTRL/E` | 157 | `CTRL/]` | 182 | `6` | 207 | `O` | | 134 | `CTRL/F` (`BREAK`) | 158 | `CTRL/^` | 183 | `7` | 208 | `P` | | 135 | `CTRL/G` (`BELL`) | 159 | `CTRL/_` | 184 | `8` | 209 | `Q` | | 136 | `CTRL/H` (`BACKSP`) | 160 | `SPACE` | 185 | `9` | 210 | `R` | | 137 | `CTRL/I` (`TAB`) | 161 | `!` | 186 | `:` | 211 | `S` | | 138 | `LINEFEED` | 162 | `"` | 187 | `;` | 212 | `T` | | 139 | `CTRL/K` (`LINEUP`) | 163 | `#` | 188 | `<` | 213 | `U` | | 140 | FORMFEED | 164 | `$` | 189 | `=` | 214 | `V` | | 141 | RETURN | 165 | `%` | 190 | `>` | 215 | `W` | | 142 | `CTRL/N` | 166 | `&` | 191 | `?` | 216 | `X` | | 143 | `CTRL/O` | 167 | `'` (`APOST`) | 192 | `@` | 217 | `Y` | | 144 | `CTRL/P` | 168 | `(` | 193 | `A` | 218 | `Z` | | 145 | `CTRL/Q` (`X-ON`) | 169 | `)` | 194 | `B` | 219 | `[` | | 146 | `CTRL/R` | 170 | `*` | 195 | `C` | 220 | `\` | | 147 | `CTRL/S` (`X-OFF`) | 171 | `+` | 196 | `D` | 221 | `]` | | 148 | `CTRL/T` | 172 | `,` (comma) | 197 | `E` | 222 | `^` | | 149 | `CTRL/U` | 173 | `-` (minus) | 198 | `F` | 223 | `_` | | 150 | `CTRL/V` | 174 | `.` (period) | 199 | `G` | 253 | `ALTMODE` | | 151 | `CTRL/W` | 175 | `/` | 200 | `H` | 255 | `RUBOUT` | Codes 224-250 are lower case letters. Codes 000-127 are similar to codes 128-255 except that the parity bit has been eliminated. Many keyboards use `SHIFT/K`, `/L`, `/M`, `/N`, `/O` for `[`, `\`, `]`, `^` and `_` A single quote before a character indicates the-value-of: `'A=193` Use `CTRL/@` to page the TV display to avoid getting error `12.40` To erase the screen on a Tektronix terminal: `S FOUT(27) FOUT(12)` To make a copy: `S FOUT(27) FOUT(23)`. Note: `FOUT(27)` = `ESCAPE` To make bold letters on a Centronics printer: `T :FOUT(14) "text"` To set 'Hold Screen' mode (VT50 terminals): `S FOUT(27) FOUT(91)` To rubout the last character on the PDP12/LAB8e display `FOUT(92)` ## <a id="errors" name="card4"></a>Error Code Table (`CARD4.DA`) For extreme economy of memory, FOCAL does not print error message strings. Instead, an error routine prints a question mark followed by a four digit fixed point number corresponding to where in the FOCAL runtime executable the error was encountered. I.E. If an error was encountered in the FOCAL interpreter's parsing of a variable name, the error message prints out the error message traceable to that parser within FOCAL. This means that an error table must be produced, and every time code shifts around, the error table must be updated. The U/W FOCAL manual contains an error table, but it is incomplete. Here is a complete one which comes from the file CARD4.DA in the U/W FOCAL archive from which this distribution is taken. Errors appearing in bold face denotes an error from a command with an optional error return. | Error | Meaning | | ------------- | ------------------------------------------------------------- | | `?` | Keyboard interrupt or restart from location 10200 | | __`?01.03`__ | Secondary input file missing | | __`?01.11`__ | No secondary input file to resume | | `?01.50` | Group number greater than 31 | | `?01.93` | Non-existent line number in a MODIFY or MOVE command | | `?03.10` | Line called by `GO`, `IF`, `J`, `R`, `Q`, `L` `B`, or `L R` is missing | | `?03.30` | Illegal command | | `?03.47` | Line or group missing in `DO`, `ON`, `JUMP`, `L GOSUB` or a `FSF` | | | | | `?04.35` | Bad syntax in a `FOR` command (missing semicolon?) | | `?06.03` | Illegal use of a function or number: `ASK`, `YNCREMENT`, `ZERO` | | `?06.41` | Too many variables (ZERO unnecessary ones) | | `?07.44` | Operator missing or illegal use of an equal sign | | `?07.67` | Variable name begins with `F` or improper function call | | `?07.76` | Double operators or an unknown function | | `?08.10` | Parentheses don't match | | `?10.50` | Program too large | | | | | `?12.10` | Error detected in the `BATCH` input file | | `?12.40` | Keyboard buffer overflow (eliminated in 8/e versions) | | `?13.65` | Insufficient memory for `BATCH` operation | | `?14.15` | Display buffer overflow | | `?14.50` | Bad Sense Switch number on a PDP12 (range is 0-5) | | `?14.56` | Illegal external sense line (PDP12 range is 0-11) | | `?17.22` | `FRA` not initialized | | `?17.33` | `FRA` index too large (exceeds file area) | | `?17.62` | `FRA` mode error: only modes 0,1,2,4 allowed | | | | | `?18.42` | `FCOM` index too large: reduce program size | | `?19.72` | Logarithm of zero | | `?21.57` | Square root of a negative number | | `?22.65` | Numeric overflow: too many digits in a string | | `?23.18` | `OUTPUT` `ABORT` or `CLOSE` requested too much space | | `?23.37` | Output file overflow: recover with: `O O name;O A FLEN()` | | __`?23.82`__ | Cannot open output file (file open, too big or no name) | | __`?24.05`__ | No output file to resume | | | | | `?24.25` | Illegal `OPEN` command | | `?24.35` | Illegal `RESUME` command | | __`?24.40`__ | Input file not found (wrong name? wrong device?) | | `?24.47` | No input file to restart | | __`?24.52`__ | No input file to resume | | `?25.02` | Stack overflow: reduce nested subroutines and expressions | | __`?25.60`__ | Device does not exist or illegal 2-page handler | | `?26.07` | Illegal `LIBRARY` command | | `?26.32` | File specified is already deleted (wrong extension?) | | | | | `?26.39` | File loaded is not a FOCAL program - __better reload UWF!__ | | `?26.56` | Program requested is missing (wrong device?) | | `?26.66` | `LIBRARY SAVE` error: no name, device full, or no directory | | `?27.18` | Attempted `LIBRARY` operation on a device without a directory | | `?27.75` | No length specified in a `LIBRARY ZERO` command | | `?27.90` | Zero divisor | | `?29.25` | Cannot use the '<>' construction with `OPEN OUTPUT` | | `?29.38` | Device error (write-lock, bad checksum or illegal request) | `_` Indicates EOF detected in input - I/O continues from terminal `?....?` TRACE feature: Text enclosed by `?` marks is typed during execution to help find the source of an error. The value of each expression in a SET command is also printed |
︙ | ︙ | |||
28 29 30 31 32 33 34 | ## How to Use the BASIC Examples To use the example BASIC program, simply transcribe it into OS/8 BASIC: .R BASIC | | | | | | | | | | | | | | | | | | | | | | | | | | | | > < | > | > > | | 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 | ## 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--PEP001.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 PEP001 BA 5A 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 `src/asm/*.pal` or `examples/*.pal`, the build process produces several output files: | Extension | Meaning | --------------- | --------------- | `*.pal` | the PAL8 assembly source code for the program; input to the process | `obj/*.lst` | the human-readable assembler output | `bin/*-pal.pt` | the machine-readable assembler output (RIM format) | `boot/*.script` | a SIMH-readable version of the assembled code Each of those files has a corresponding way of getting the example running in the simulator: 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 `*-pal.pt` file to a USB stick and use the PiDP-8/I's [automatic media mounting feature][howto]. This is the fastest method. 4. Boot SIMH with the example in core, running the program immediately. 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< |
︙ | ︙ | |||
164 165 166 167 168 169 170 | `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 | | | > | | | | | 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 | `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, then Escape to return to OS/8 from PIP. 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 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: |
︙ | ︙ | |||
198 199 200 201 202 203 204 | 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: | | | | | | | | | | | | | 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 | 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... | Because... |--------------------------------------- | ---------- | 000 010 000 000 | `Load Add` | 000010000000 is binary for octal 0200, the program's start address | 111 011 000 000 | `Dep` | the first instruction, 7300 octal, is 111011000000 in binary | 001 010 000 101 | `Dep` | 1205 octal in binary | 001 010 000 110 | `Dep` | etc, etc. | 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 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 |
︙ | ︙ | |||
235 236 237 238 239 240 241 | 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. | | | | > > > > > > > > > > > > > | 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 | 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/-pal*.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 `*-pal.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. ### Option 4: Booting SIMH with the Example in Core As part of the PiDP-8/I software build process, a `boot/*.script` file for each `examples/*.pal` file is created by translating `obj/*.lst` into a series of "deposit" commands to SIMH. You can thus load and run each example at the Linux command line with a command like this: $ bin/pidp8i-sim boot/add.script That runs the `examples/add.pal` program's assembled binary code under the simulator, just as if you'd loaded it there with option #3 above. ## 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 |
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | DO 10 I = 3, 999 IF (IREM(I / 3)) 5, 15, 5 5 IF (IREM(I / 5)) 10, 15, 10 15 J = J + I IF (J - 1000) 10, 18, 18 18 WRITE (1,19) J 19 FORMAT (I4, ' + ') J = 0 10 CONTINUE WRITE (1,20) J 20 FORMAT (I4) END |
> > > > | 1 2 3 4 | DO 10 I = 3, 999 10 IF (MOD(I, 3) .EQ. 0 .OR. MOD(I, 5) .EQ. 0) ITOTAL = ITOTAL + I WRITE (4,20) ITOTAL 20 FORMAT (' TOTAL: ', I6) |
> > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include <init.h> #include <libc.h> ire0 (n, d) { while (n > 0) n = n - d; return n == 0; } main () { int i, st; st = 0; for (i = 3; i < 1000; i++) { if (ire0 (i, 3) | ire0 (i, 5)) st = st + i; if (st > 1000) { printf("%d + ", st); st = 0; } } printf("%d\n", st); } |
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <init.h> #include <libc.h> main () { int i, st; st = 0; for (i = 3; i < 1000; i++) { if ((i % 3 == 0) | (i % 5 == 0)) st = st + i; if (st > 1000) { printf("%d + ", st); st = 0; } } printf("%d\n", st); } |
> > > > > > > | 1 2 3 4 5 6 7 | 01.10 SET TOTAL = 0 01.20 FOR I = 3, 999 ; DO -.3 01.30 IF (FRAC(I / 3)) , 1.5 01.40 IF (FRAC(I / 5)) , 1.5, 1.6 01.50 SET TOTAL = TOTAL + I 01.60 NEXT 01.70 TYPE "TOTAL: ", %6, TOTAL, ! |
> > > > > > | 1 2 3 4 5 6 | C Print transcendental function tables. C Example from DEC FOCAL-8 Manual, July 1969, page 4-2. 01.05 T " I SINE COSINE LOG E" ! 01.10 FOR I=1,.00001,1.0001; DO 2.05 01.20 QUIT 02.05 T %7.06,I," ",FSIN(I)," ",FCOS<I>," ",%,FLOG[I]," ",FEXP(I),!! |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # -*- coding: utf-8 -*- ######################################################################## # __init__.py - mkos8 module initialization # # 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. ######################################################################## __all__ = [ 'argparser' ] |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/python # -*- coding: utf-8 -*- ######################################################################## # argparse.py - Extend ArgumentParser to add mkos8 bits. # # 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. ######################################################################## import argparse import opts class ArgParser (argparse.ArgumentParser): def __init__ (self, allowed_acts): # Call parent class ctor to initialize the arg parser argparse.ArgumentParser.__init__ (self, description = 'Build OS/8 RK05 disk images') # Add general-purpose args self.add_bool ('-d', '--debug', help = 'add extra debugging output, normally suppressed') self.add_bool ('-v', '--verbose', help = 'verbose SIMH output instead of progress messages') # Add arguments corresponding to --*-os8-* configure script options for obn, vals in opts.opts.iteritems(): od = 'dis' if vals[0] else 'en' self.add_bool ('--' + od + 'able-' + obn, help = vals[1]) # Add options that do not exactly mirror configuration options self.add_bool ('--disable-lcmod', help = 'disable the OS/8 command upcasing patch; best set ' + 'when SIMH is set to tti ksr mode') # Add trailing "what do do" argument self.add_argument ( 'what', choices = allowed_acts, help = 'select which RK05 media gets built; default is "all"', nargs = argparse.REMAINDER) # Finish initializing self.args = self.parse_args() if len (self.args.what) == 0: self.args.what = [ 'all' ] def add_bool (self, *args, **kwargs): kwargs['action'] = 'store_true' kwargs['default'] = False self.add_argument (*args, **kwargs) |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # -*- coding: utf-8 -*- ######################################################################## # __init__.py.in - pidp8i module initialization # # This file is a *.in file only because dirs.py.in is in this directory, # and both *.in outputs need to land in the same directory for Python # to find it. That happens naturally when building in-tree, but we # need this bit of *.in trickery when building out-of-tree. # # 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. ######################################################################## __all__ = [ 'dirs', 'ips' ] |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # -*- coding: utf-8 -*- ######################################################################## # dirs.py.in - Declare constants for directory names subbed in by # autosetup, partly so we don't have to do this in multiple modules # but also so that those files don't keep getting touched whenever # other *.in files get touched, thus forcing an OS/8 RK05 rebuild. # # 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. ######################################################################## import os # Anchor directories. These have to be statically defined for the # development vs installation cases because chances are high that both # trees exist on the disk, and these are absolute paths, so we can't # just do a "path exists" test to determine which we should be using. # So, autosetup subs in the proper values into the .py version of this # file in the development tree and the install script overwrites these # for the installation tree. build = "@builddir@" src = "@abs_top_srcdir@" # Derived directories. Where it matters, these are the development tree # paths, overridden or adjusted below if we're installed. bin = os.path.join (build, "bin/") log = os.path.join (build, "obj/") media = os.path.join (src, "media/") os8mi = os.path.join (media, "os8/") # mkos8 inputs os8mo = bin # mkos8 outputs # Adjust paths for the "installed" case if not os.path.exists(log): # The obj/ dir doesn't exist in the install tree log = "/tmp/" if not os.path.exists(media): # We bury media one extra level deeper in the install tree media = media.replace('/media/', '/share/media/') # mkos8 outputs *.rk05 into bin/ at build time, but then they're # copied next to the os8/*.tu56 source tapes for installation. # If we're building or modifying the OS/8 media in the installation # tree, though, we need to write straight to the media directory. os8 = media |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # -*- coding: utf-8 -*- ######################################################################## # ips.py.in - Defines the default instructions per second value. # # This file is a .in file purely to provide the default version of # ips.py which can be appended to by running bin/teco-pi-demo -b on # the target hardware to provide a better local IPS value. # # 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. ######################################################################## # Approximate IPS rate for a PDP-8/I based on one fact: # # 1. The core cycle time of a PDP-8/I is 1.5 µs. # # ...and one assumption: # # 2. PDP-8 systems execute instructions at varying rates from roughly 1 # core cycle time up to many core cycle times. Most of the core # PDP-8 instructions not involving I/O take 1-2 cycles, with I/O # taking longer, so we assume that the average for typical real # world PDP-8 code will average to 2 cycles per instruction. # # Thus, this value is the inverted cycle time divided by 2. pdp8i = 333333 # A Raspberry Pi B+ running pidp8i-sim unthrottled executes PDP-8 code # faster than a real PDP-8/I by the factor given, so that running the # teco-pi-demo benchmkark (-b) it shows a factor of about 1.0. This # gives us the lowest possible IPS value short of throttling the sim, # underclocking the Pi, or starving the simulator of CPU power. raspberry_pi_b_plus = pdp8i * 5.6 # Initial value; teco-pi-demo -b appends overrides for this current = raspberry_pi_b_plus # Benchmark results: |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/python # -*- coding: utf-8 -*- ######################################################################## # simh/__init__.py - A wrapper class around pexpect for communicating # with an instance of the PiDP-8/I SIMH simulator running OS/8. # # See ../doc/class-simh.md for a usage tutorial. # # Copyright © 2017 by Jonathan Trites, William Cattey, 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. ######################################################################## import os.path import pexpect import pkg_resources import subprocess import tempfile import time import pidp8i class simh: # pexpect object instance, set by ctor _child = None # Constant used by os8_kbd_delay, assembled in stages: # # 1. PDP-8 RS-232 bits per character: 7-bit ASCII plus necessary # start, stop, and parity bits. # # 2. The ratio of the instructions per second ratios of a PDP-8/I to # that of the host hardware running the simulator. The former is # an approximate value; see lib/pidp8i/ips.py.in for the value and # its defense. The latter is either the IPS rate for: # # a) a Raspberry Pi Model B+, that being the slowest host system # we run this simulator on; or # # b) the IPS rate of the actual host hardware if you have run the # "bin/teco-pi-demo -b" benchmark on it. # # 2. The fact that real PDP-8s ran OS/8 reliably at 300 bps, and have # been claimed to get flaky as early as 600 bps by some. (Others # claim to have run them up to 9,600 bps.) # # 3. The "safe BPS" value is the fastest bit per second speed actual # PDP-8 hardware was known to run OS/8 terminal I/O at. In this # case, it is the high-speed tape reader. # # TODO: We may be able to increase this. # # We have one report that OS/8 was tested with terminals up to # about ~600 bps before becoming unreliable. # # We have another report that OS/8 could run under ETOS with # 9,600 bps terminals, but we don't know if that tells us anything # about OS/8 running without the ETOS multitasking hardware. # # 4. Given above, calculate safe characters per second for host HW. # # 5. Invert to get seconds per character, that being the delay value. _bpc = 7 + 1 + 1 + 1 # [1] _ips_ratio = float (pidp8i.ips.current) / pidp8i.ips.pdp8i # [2] _pdp8i_safe_bps = 300 # [3] _host_safe_cps = _pdp8i_safe_bps * _ips_ratio / _bpc # [4] _os8_kbd_delay = 1 / _host_safe_cps # [5] #### ctor ############################################################ # The first parameter must be given as the parent of bin/pidp8i-sim. # # The second defaults to false, meaning that a failure to lock the # GPIO for the caller's exclusive use is a fatal error. If you pass # True instead, we just complain if the GPIO is already locked and # move on. This tolerant mode is appropriate for programs that need # the simulator alone, not actually the PiDP-8/I front panel display. def __init__ (self, basedir, ignore_gpio_lock = False): # Start the simulator instance self._child = pexpect.spawn(basedir + '/bin/pidp8i-sim') # Turn off pexpect's default inter-send() delay. We add our own as # necessary. The conditional tracks an API change between 3 and 4. pev4 = (pkg_resources.get_distribution("pexpect").parsed_version > pkg_resources.parse_version("4.0")) self._child.delaybeforesend = None if pev4 else 0 # Wait for either an error or the simulator's configuration line. if not self.try_wait (\ '^PiDP-8/I [a-z].*\[.*\]', \ 'Failed to lock /dev/gpiomem', timeout = 3): if ignore_gpio_lock: print "WARNING: Failed to lock GPIO for exclusive use. Won't use front panel." else: raise RuntimeError ('GPIO locked') #### back_to_cmd ###################################################### # Pause the simulation and return to the SIMH command prompt when the # simulated software emits the given prompt string. Typically used to # wait for OS/8 to finish running a command so we can do something # down at the SIMH layer instead. def back_to_cmd (self, prompt): self._child.expect ("\n%s$" % prompt) self.os8_kbd_delay () self._child.sendcontrol ('e') #### os8_get_file #################################################### # Rough inverse of os8_send_file. # # Both paths must be given and are used literally. (Contrast our # inverse, where the destinatinon file name is produced from the # source if not given.) # # When this function is called to pull a file sent by our inverse, the # conversion should be lossless except for the transforms done by our # underlying utility tools, such as the LF -> CR+LF done by txt2ptp # but not undone by ptp2txt. # # Entry context should be inside OS/8. Exit context is inside OS/8. def os8_get_file (self, intname, extname): # Attach a blank paper tape to the simulator. ptf = tempfile.NamedTemporaryFile (suffix = '.pt', delete = False) ptf.close () ptn = ptf.name self.back_to_cmd ('\\.') self.send_cmd ('attach ptp ' + ptn) # Punch internal file to external paper tape image self.os8_restart () self.os8_send_cmd ('\\.', 'PUNCH ' + intname); self.back_to_cmd ('\\.') # wait for transfer to finish # Convert text file from SIMH paper tape format tool = os.path.join (pidp8i.dirs.build, 'bin', 'ptp2txt') self.send_cmd ('detach ptp') subprocess.call (tool + ' < ' + ptn + ' > ' + extname, shell = True) # Return to OS/8, just because that's where we were on entry, so we # should not change that. self.os8_restart () #### os8_kbd_delay ################################################### # Artificially delay the media generation process to account for the # fact that OS/8 lacks a modern multi-character keyboard input buffer. # It is unsafe to send text faster than a contemporary terminal could, # though we can scale it based on how much faster this host is than a # real PDP-8. See the constants above for the calculation. def os8_kbd_delay (self): time.sleep (self._os8_kbd_delay) #### os8_send_cmd #################################################### # Wait for an OS/8 command prompt running within SIMH, then send the # given line. # # The prompt string is passed in because OS/8 has several different # prompt types. def os8_send_cmd (self, prompt, line): self._child.expect ("\n%s$" % prompt) self.os8_send_line (line) #### os8_send_ctrl ################################################### # Send a control character to OS/8 corresponding to the ASCII letter # given. We precede it with the OS/8 keyboard delay, since we're # probably following a call to os8_send_line or os8_send_cmd. def os8_send_ctrl (self, char): self.os8_kbd_delay () self._child.sendcontrol (char[0].lower ()) #### os8_send_file ################################################### # Send a copy of a local text file to OS/8. The local path may # contain directory components, but the remote must not, of course. # # If the destination file name is not uppercase, it will be so forced. # # If the destination file name is not given, it is taken as the # basename of the source file name. # # The file is sent via the SIMH paper tape device through PIP in its # default ASCII mode, rather than character by character for two reasons: # # 1. It's faster. It runs as fast as the simulator can process the # I/O instructions, without any os8_kbd_delay() hooey. # # 2. It allows lowercase input regardless of the way the simulator is # configured. ASCII is ASCII. # # Entry context should be inside OS/8. Exit context is inside OS/8. def os8_send_file (self, source, dest = None): # Create path and file names not given bns = os.path.basename (source) if dest == None: dest = bns dest = dest.upper () # Convert text file to SIMH paper tape format bdir = pidp8i.dirs.build pt = os.path.join (bdir, 'obj', bns + '.pt') tool = os.path.join (bdir, 'bin', 'txt2ptp') subprocess.call (tool + ' < ' + source + ' > ' + pt, shell = True) # Paper tape created, so attach it read-only and copy it in. We're # relying on txt2ptp to insert the Ctrl-Z EOF marker at the end of # the file. self.back_to_cmd ('\\.') self.send_cmd ('attach -r ptr ' + pt) self.os8_restart () self.os8_send_cmd ('\\.', 'R PIP') self.os8_send_cmd ('\*', dest + '<PTR:') self._child.expect ('\\^') self.os8_send_ctrl ('[') # finish transfer self._child.expect ('\\*') self.os8_send_ctrl ('[') # exit PIP #### os8_send_line ################################################### # Core of os8_send_cmd. Also used by code that needs to send text # "blind" to OS/8, without expecting a prompt, as when driving EDIT. def os8_send_line (self, line): self.os8_send_str (line) self._child.send ("\r") #### os8_send_str ######################################################## # Core of os8_send_line. Also used by code that needs to send text # "blind" to OS/8, without expecting a prompt and without a CR, as # when driving TECO. def os8_send_str (self, str): for i in xrange (0, len (str)): self._child.send (str[i]) self.os8_kbd_delay () #### os8_restart ####################################################### # Called while in the SIMH command prompt, this restarts OS/8. # # This one-line function exists to abstract the method we use and to # document the reason we do it this way. # # Currently we do this by calling the OS/8 command entry point, which # has the virtue that it forces another . prompt, which keeps the # send/expect sequencing simple when switching between OS/8 and SIMH # command modes. # # That is why we don't use "cont" here instead: it requires that the # caller always be aware of when the . prompt went out; complicated. # # Another simple alternative is "boot rk0", which actually benchmarks # a smidge faster here. We choose this method instead because we # expect that some of our callers will want to do several different # things in a single OS/8 session, which rebooting would screw up. def os8_restart (self): self.send_cmd ("go 7600") #### os8_squish ######################################################## # Wraps the OS/8 SQUISH command for a given device. def os8_squish (self, device): self.os8_send_cmd ("\.", "SQUISH " + device + ":") self.os8_kbd_delay () self._child.send ("Y\r"); #### quit ############################################################ # Quits the simulator and waits for it to exit def quit (self): self.send_cmd ("q") self._child.expect (pexpect.EOF) #### read_tail ####################################################### # Watch for a literal string, then get what follows on that line. def read_tail (self, head, timeout = -1): self._child.expect_exact ([head], timeout) return self._child.readline () #### send_cmd ######################################################## # Wait for a SIMH command prompt and then send the given command def send_cmd (self, cmd): self._child.expect ("sim> $") self._child.sendline (cmd) #### send_line ####################################################### # Sends the given line "blind", without waiting for a prompt. def send_line (self, line): self._child.sendline (line) #### set_logfile ##################################################### def set_logfile (self, lf): self._child.logfile = lf #### spin ############################################################ # Let child run without asking anything more from it, with an optional # timeout value. If no value is given, lets child run indefinitely. def spin (self, timeout = None): self._child.expect (pexpect.EOF, timeout = timeout) #### try_wait ######################################################## # Wait for one of two strings to come back from SIMH, returning true # if we get the first, else false. def try_wait (self, success, failure, timeout = -1): return self._child.expect ([success, failure], timeout = timeout) == 0 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/python # -*- coding: utf-8 -*- ######################################################################## # mkos8 - Build bin/os8v3d-*.rk05 from media/*/*.tu56 by scripting # commands to SIMH and OS/8. # # Copyright © 2017 by Jonathan Trites, William Cattey, 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. ######################################################################## # Bring in just the basics so we can bring in our local modules import os import sys sys.path.insert (0, os.path.dirname (__file__) + '/../lib') sys.path.insert (0, os.getcwd () + '/lib') # Remaining Python core modules import re import shutil import subprocess # Our local modules from mkos8 import * from pidp8i import * from simh import * #### globals and constants ############################################# # Flag set when -v is *not* given. Causes make_*() and the functions # called thereby to print progress messages to the console since SIMH # and OS/8 output is not being sent there to clue the user into the # script's progress. progmsg = True # Name of the RK05 disk image files we create _bin_rk05 = "os8v3d-bin.rk05" _src_rk05 = "os8v3d-src.rk05" _patched_rk05 = "os8v3d-patched.rk05" # Parser regexps used in patcher _com_os8_parse_str = "^\.([a-zA-Z]+)\s?(.*)$" _com_os8_parse = re.compile(_com_os8_parse_str) _com_split_str = "^([a-zA-Z]+)\s?(.*)$" _com_split_parse = re.compile(_com_split_str) _odt_parse_str = "^([0-7]+)\s?/\s?(\S+)\s+([0-7;]+)" _odt_parse = re.compile(_odt_parse_str) #### mkos8_abort ###################################################### # Fatal error. Abort mkos8 def mkos8_abort (s): print "Fatal Error. Cannot proceed." s.quit () exit (-1) #### check_exists ###################################################### # Check existence of all files needed def check_exists (s, image_copyins): for copyin in image_copyins: image = copyin[1] image_path = dirs.os8mi + image if (not os.path.isfile(image_path)): print "Required file: " + image_path + " not found." mkos8_abort(s) # else: print "Found " + image_path #### Data Structures ################################################## # # The make procedures use helper procedures # to confirm that the relevant input image file exists and # to perform the file copies. # # A data structure called "image copyin" # describes the image file pathname relative to an implied root, # provides a message string when the action is run, # names a default destination device for whole image content copies, # offers an optional array of specific file copy actions. # # FUTURE: Parse source path for ".tu56" vs. ".rk05" for more general use. # Currently all code assumes a copyin comes from a DECtape image. # # Example: We Install all files for ADVENT, the Adventure game: # # advent_copyin = ['RKB0:', 'subsys/advent.tu56', "Installing ADVENT...", None] # # A DECtape device is chosen for attachment in SIMH and # a 'COPY *.*' command is filled in with the Destination device, and the chosen DECtape. # # A data structer called "file copyin" # provides override destination to allow renames or varied destinations. # names individual files within a copyin to use # # Example: To copy the C compiler we want all .SV files on SYS # but everything else to RKB0: # (Note the useful /V option to invert the match.) # # cc8_sv_file_copyin = ['SYS:', '*.SV'] # cc8_rest_file_copyin = ['RKB0:', '*.SV/V'] # # A 'COPY' command is filled in with the override destination and # The file spec is used with the chosen dectape instead of "*.*" # #### copyin_pair ####################################################### # Copy two images into two destinations with two messages # # Assumes our context is "in simh". # Assumes dt0 and dt1 are free. # Assumes rk0 is the boot device # Detaches dt0 and dt1 after using them. # copyin0 mounts on dt0. copyin1 mounts on dt1. # Either copyin or both can be None def copyin_pair (s, copyin0, copyin1, debug): if debug: if copyin0: print "Copying: " + copyin0[1] + " to: " + copyin0[0] + "from dt0" else: print "copyin0 is empty." if copyin1: print "Copying: " + copyin1[1] + " to: " + copyin1[0] + "from dt1" else: print "copyin1 is empty." if not copyin0 and not copyin1: return # Nothing to do. # The order of events here is a bit funky because we want # to use both DECtape drives but also # switch between SIMH and OS/8 as infrequently as possible. if copyin0: s.send_cmd ("attach -r dt0 " + dirs.os8mi + copyin0[1]) if copyin1: s.send_cmd ("attach -r dt1 " + dirs.os8mi + copyin1[1]) s.os8_restart() if copyin0: if progmsg: print copyin0[2] if copyin0[3]: # We have specific files to do. for file_copyin in copyin0[3]: s.os8_send_cmd ("\\.", "COPY " + file_copyin[0] + "<DTA0:" + file_copyin[1]) else: s.os8_send_cmd ("\\.", "COPY " + copyin0[0] + "<DTA0:*.*") if copyin1: if progmsg: print copyin1[2] if copyin1[3]: # We have specific files to do. for file_copyin in copyin1[3]: s.os8_send_cmd ("\\.", "COPY " + file_copyin[0] + "<DTA1:" + file_copyin[1]) else: s.os8_send_cmd ("\\.", "COPY " + copyin1[0] + "<DTA1:*.*") s.back_to_cmd("\\.") if copyin0: s.send_cmd ("detach dt0") if copyin1: s.send_cmd ("detach dt1") #### do_all_copyins #################################################### def do_all_copyins (s, copyins, debug): pair_idx = 0 pair_ct = int(len(copyins) / 2) while pair_idx < pair_ct: copyin_pair(s, copyins[pair_idx * 2], copyins[pair_idx * 2 + 1], debug) pair_idx += 1 if pair_ct * 2 < len(copyins): copyin_pair(s, copyins[len(copyins) - 1], None, debug) #### make_bin ########################################################## # Top-level driver for the "make binary OS/8 RK05 disk image" process. # # If there is already an RK05 binary destination image, moves it aside # to a ".save" instance, overwriting the previous .save if it exists. # # One of the input images is used as a bootable DECtape. # That DECtape gets written on. # It needs stuff from tape #2 # So the first two DECtapes # are treated separately and specially. # All the other DECtape images used are read only. def make_bin (s, args): ro_boot_tape = "al-4711c-ba-os8-v3d-1.1978.tu56" ro_boot_tape_path = dirs.os8mi + ro_boot_tape driver_tape = "al-4712c-ba-os8-v3d-2.1978.tu56" driver_tape_path = dirs.os8mi + driver_tape local_tape = "local.tu56" local_tape_path = dirs.os8mi + local_tape boot_dt_path = dirs.os8mo + "bootable-al-4711-c-ba-os8-v3d-1.1978.tu56" special_bin_copyins = [ ["", ro_boot_tape, "", None], ['RKA0:', driver_tape, "Device Drivers...", None], ] music_copyin = ['RKB0:', 'subsys/music.tu56', "Copying in Music score files and source code...", None] ba_copyin = ['RKB0:', 'subsys/ba.tu56', "Installing *.BA BASIC games and demos...", None] cc8_files = [['SYS:', '*.SV'], ['RKB0:', '*.SV/V']] cc8_copyin = ['RKB0:', 'subsys/cc8.tu56', "Installing Ian Schofield's CC8 compiler...", cc8_files] k12_copyin = ['RKA0:', 'subsys/k12.tu56', "Installing Kermit-12...", None] focal69_files = [ ['RKB0:', 'FOCAL.BN'], ['RKB0:', '4WORD.BN'], ['RKB0:', '4KVT.BN'], ['RKB0:', '8KVT.BN'], ['RKB0:', '8KNOVT.BN'] ] focal69_copyin = ['RKA0:', 'subsys/focal69.tu56', "Installing FOCAL 69...", focal69_files] fiv_copyins = [ ['RKA0:', "subsys/al-4549d-ba-fr4-v3d-1.1978.tu56", "Installing FORTRAN IV ...", None], ] # Specify files explicitly. There's a README.TX we don't want copied. # We may decide to leave FUTIL.SV out. macrel_files = [ ['SYS:', 'MACREL.SV'], ['SYS:', 'LINK.SV'], ['SYS:', 'KREF.SV'], ['SYS:', 'OVRDRV.MA'], ['SYS:', 'FUTIL.SV'] ] macrel_copyin = ['RKA0:', "al-5642c-ba-macrel-v2-futil-v8b-by-hand.tu56", "Installing MACREL V2 and new FUTIL V8B ...", macrel_files] uwfocal_files = [['SYS:', 'UWF16K.SV']] uwfocal_copyin = ['RKA0:', 'subsys/uwfocal-v4e-2.tu56', "Installing U/W FOCAL...", uwfocal_files] advent_copyin = ['RKB0:', 'subsys/advent.tu56', "Installing ADVENT...", None] bin_copyins = [ ['RKA0:', "al-4761c-ba-os8-v3d-ext.1978.tu56", "Copying in OS/8 V3D extensions...", None], ] local_files = [] local_stat_str = "Performing copyins from " + local_tape + ":\n" # Case Conversion scripts from local.tu56. local_stat_str += " Case Conversion batch scripts.\n" local_files.append(['RKA0:', '?CSYS.BI']) local_files.append(['RKA0:', '?CBAS.BI']) if not args.disable_chess: local_stat_str += " CHESS.SV binary and CHESS.TX documentation...\n" local_files.append(['RKA0:', 'CHESS.*']) if args.enable_vtedit: local_stat_str += " TECO VTEDIT setup...\n" local_files.append(['RKA0:', 'VTEDIT.*']) local_files.append(['RKA0:', 'TECO.IN']) if not args.disable_dcp: # Should we also install DCP.WU on RKB0:? local_stat_str += " DCP Disassembler: DCP24.SV, and DCP16.SV as DCP.SV.\n" local_files.append(['RKA0:', 'DCP24.SV']) local_files.append(['RKA0:DCP.SV', 'DCP16.SV']) if args.enable_music: bin_copyins.append(music_copyin) if not args.disable_advent: bin_copyins.append(advent_copyin) if not args.disable_ba: bin_copyins.append(ba_copyin) if not args.disable_cc8: bin_copyins.append(cc8_copyin) if not args.disable_k12: bin_copyins.append(k12_copyin) if not args.disable_fortran_iv: bin_copyins.extend(fiv_copyins) if not args.disable_macrel: bin_copyins.append(macrel_copyin) if local_files != []: local_copyins = ['RKA0:', local_tape, local_stat_str, local_files] bin_copyins.append(local_copyins) if args.enable_focal69: bin_copyins.append(focal69_copyin) if not args.disable_uwfocal: bin_copyins.append(uwfocal_copyin) check_exists(s, special_bin_copyins) check_exists(s, bin_copyins) print "Generating " + _bin_rk05 + " from " + str(len(bin_copyins) + 2) + \ " source tapes..." image_path = dirs.os8mo + _bin_rk05 if os.path.isfile(image_path): save_path = dirs.bin + _bin_rk05 + ".save" print "Pre-existing " + _bin_rk05 + " found. Saving as " + _bin_rk05 + ".save" if os.path.isfile(save_path): print "Overwriting old " + _bin_rk05 + ".save" os.remove(save_path) os.rename(image_path, save_path) global progmsg if progmsg: print "Building initial OS/8 system..." if progmsg: print "Making a writeable copy of boot DECtape..." try: shutil.copyfile(ro_boot_tape_path, boot_dt_path) except shutil.Error as e: print "Bootable DECtape copy failed with error: " + e mkos8_abort (s) except IOError as e: print "Bootable DECtape copy failed with IOError: " + e mkos8_abort (s) s.send_cmd ("attach rk0 " + image_path) s.send_cmd ("attach dt0 " + boot_dt_path) s.send_cmd ("attach -r dt1 " + driver_tape_path) if progmsg: print "Performing config with BUILD..." s.send_cmd ("boot dt0") # By default, we're going to have an INIT.CM script, but we don't want # to set it up this early for two reasons. First, we don't want the # "boot rk0" commands below to emit this message, since its text # varies depending on the host system, which would create unnecessary # differences in our output over time. Second, OS/8 is alleged not to # always build properly if INIT is enabled in these early stages. s.os8_send_cmd ("\\.", "SET SYS NO INIT") s.os8_send_cmd ("\\.", "RUN SYS BUILD") s.os8_send_cmd ("\$", "LOAD DTA1:RK8ESY.BN") s.os8_send_cmd ("\$", "LOAD DTA1:PT8E.BN") s.os8_send_cmd ("\$", "DELETE SYS") s.os8_send_cmd ("\$", "SYSTEM RK8E") s.os8_send_cmd ("\$", "DELETE RXA1") s.os8_send_cmd ("\$", "INSERT PT8E,PTR") s.os8_send_cmd ("\$", "INSERT PT8E,PTP") s.os8_send_cmd ("\$", "DELETE RKA0") s.os8_send_cmd ("\$", "DELETE RKB0") s.os8_send_cmd ("\$", "INSERT RK8E,RKA0,RKB0") s.os8_send_cmd ("\$", "INSERT RK05,RKA2,RKB2") s.os8_send_cmd ("\$", "DELETE DTA0") s.os8_send_cmd ("\$", "INSERT TC,DTA0") s.os8_send_cmd ("\$", "DSK RK8E:RKB0") s.os8_send_cmd ("\$", "PRINT") s.os8_send_cmd ("\$", "BOOT") s.os8_send_cmd ("WRITE ZERO DIRECT\?", "Y") # SYS is now RK0; if we SAVE SYS we will overwrite with wrong BUILD.SV s.os8_send_cmd ("\\.", "SAVE DTA0 BUILD") s.back_to_cmd("\\.") if progmsg: print "Copying OS/8 system files from TU56 source to RK05 image..." if progmsg: print "Copying in system tape 1 of 2..." s.send_cmd ("boot dt0") s.os8_send_cmd ("\\.", "COPY RKA0:<DTA0:*.*") # There are not enough directory entries to put everything # Including all device drivers on the running packs. # So we DONT copy in the device drivers, nor TDINIT.SV, # nor the two TD8E-based DECtape system area files. # CCL.PA and KL8E.PA will be on the source disk. # However DECtape 2 has HELP.HL and .RL files that ARE needed. # if progmsg: print "Copying in system tape 2 of 2..." # s.os8_send_cmd ("\\.", "COPY RKA0:<DTA1:*.*") if progmsg: print "Copying in help files..." s.os8_send_cmd ("\\.", "COPY RKA0:<DTA1:*.HL") if args.disable_fortran_ii: files = [ 'RKA0:{0}.SV'.format(f) for f in [ 'FORT', 'LIBSET', 'SABR' ] ] s.os8_send_cmd ("\\.", 'DEL ' + ','.join (files)) else: if progmsg: print "Installing FORTRAN II libraries..." s.os8_send_cmd ("\\.", "COPY RKA0:<DTA1:*.RL") s.os8_send_cmd ("\\.", "ZERO RKB0:") # must precede subsys/* copies s.back_to_cmd("\\.") if progmsg: print "Deleting bootable copy of DECtape image and" if progmsg: print "rebooting into freshly-built RK05 OS/8 system..." s.send_cmd ("detach dt0") s.send_cmd ("detach dt1") s.send_cmd ("boot rk0") # must do: boot media just went away s.back_to_cmd("\\.") os.remove(boot_dt_path) if progmsg: print "Performing remaining copies/installs..." do_all_copyins (s, bin_copyins, args.debug) # Any further initialization of installed software is done here. s.send_cmd ("boot rk0") if progmsg: print "Configuring for 3-column DIRECT listings..." s.os8_send_cmd ("\\.", "SET TTY COL 3") if not args.disable_crt: # NO SCOPE mode is the default on distribution tapes. if progmsg: print "Configuring scope-style rubout processing..." s.os8_send_cmd ("\\.", "SET TTY SCOPE") # Make sure Scripts are included in local_files array! # Or this will fail. if not args.disable_lcmod: if progmsg: print "Patching OS/8 to upcase commands only; SIMH is set not to auto-upcase." s.os8_send_cmd ("\\.", "SUBMIT SYS:LCSYS.BI") if progmsg: print "Patching OS/8 BASIC to cope with lower case input" s.os8_send_cmd ("\\.", "SUBMIT SYS:LCBAS.BI") # Create a banner message and optionally set it to show on boot. # This message is always upcased, even if you do this before calling # LCSYS.BI. Is it a limitation of EDIT? # # Note that we do not read this file from dirs.os8mi: it is either an # output of autosetup or overwritten by test-mkos8 in the *build* # tree, so that when building out of tree, reading from os8mi would # either give an empty file if the source tree was "clean" or a # mismatched version of the file from the soruce tree rather than the # one we want, which is in the *build* tree. if progmsg: print "Setting INIT message..." s.os8_send_file ('media/os8/init.tx') s.os8_send_cmd ("\\.", "CREATE INIT.CM") s.os8_send_cmd ("#", "A") s.os8_send_line("TYPE INIT.TX") s.os8_send_ctrl('L') s.os8_send_cmd ("#", "E") if not args.disable_init: # Set the message to display only if the user did not suppress it. # We do it this way so the user can turn it on later without # rebuilding their OS/8 media. s.os8_send_cmd ("\\.", "SET SYS INIT") # Finish up if progmsg: print "Cleaning up..." s.os8_squish ("SYS") s.os8_squish ("DSK") s.back_to_cmd("\\.") s.send_cmd ("detach rk0") #### make_src ########################################################## # Source-disk version of make_bin() above. def make_src (s, args): src_copyins = [ ["RKA1:", "al-4691c-sa-os8-v3d-1.1978.tu56", "...part 1 of 7...", None], ["RKA1:", "al-4692c-sa-os8-v3d-2.1978.tu56", "...part 2 of 7...", None], ["RKA1:", "al-4693d-sa-os8-v3d-3.1978.tu56", "...part 3 of 7...", None], ["RKA1:", "al-4694c-sa-os8-v3d-4.1978.tu56", "...part 4 of 7...", None], ["RKB1:", "al-4695c-sa-os8-v3d-5.1978.tu56", "...part 5 of 7...", None], ["RKB1:", "al-4696c-sa-os8-v3d-6.1978.tu56", "...part 6 of 7...", None], ["RKB1:", "al-4697c-sa-os8-v3d-7.1978.tu56", "...part 7 of 7...", None], ["RKB1:", "al-4759c-sa-os8-ext-1.1978.tu56", "extensions part 1 of 3...", None], ["RKB1:", "al-4760c-sa-os8-ext-2.1978.tu56", "...part 2 of 3...", None], ["RKA1:", "al-5586c-sa-os8-ext-3.1978.tu56", "...part 3 of 3...", None], ] check_exists (s, src_copyins) print "Generating " + _src_rk05 + " from " + str(len(src_copyins)) + \ " source tapes..." bin_path = dirs.os8mo + _bin_rk05 if (not os.path.isfile(bin_path)): print _bin_rk05 + " is needed to build src. Creating..." make_bin(args) src_path = dirs.os8mo + _src_rk05 if os.path.isfile(src_path): save_path = src_path + ".save" print "Pre-existing " + _src_rk05 + " found. Saving as " + _src_rk05 + ".save" if os.path.isfile(save_path): print "Overwriting old " + _src_rk05 + ".save" os.remove(save_path) os.rename(src_path, save_path) if progmsg: print "Copying OS/8 source distribution:" s.send_cmd ("attach rk0 " + bin_path) s.send_cmd ("attach rk1 " + src_path) s.send_cmd ("boot rk0") s.os8_send_cmd ("\\.", "ZERO RKA1:") s.os8_send_cmd ("\\.", "ZERO RKB1:") s.back_to_cmd("\\.") do_all_copyins (s, src_copyins, args.debug) if progmsg: print "Cleaning up..." s.send_cmd ("detach rk0") s.send_cmd ("detach rk1") #### parse_odt ######################################################### def parse_odt (s, com, line, debug): if debug: print line if line == "\\c": return "break" match = _odt_parse.match(line) if match == None: print "Aborting because of bad ODT line: " + line s.os8_send_ctrl('C') return "err" loc = match.group(1) old_val = match.group(2) new_val = match.group(3) expect_val_str = "\s?[0-7]{4} " if debug: print "Loc: " + loc + ", old_val: " + old_val + ", new_val: " + new_val s.os8_send_str (loc + "/") s._child.expect(expect_val_str) if old_val.isdigit(): # We need to check old value found_val = s._child.after.strip() if found_val != old_val: print "Old value: " + found_val + " does not match " + old_val + ". Aborting patch." # Abort out of ODT back to the OS/8 Monitor s.os8_send_ctrl('C') return "err" s.os8_send_line (new_val) return "cont" #### futil_exit ######################################################## def futil_exit (s, com, line): s.os8_send_line(line) return "break" #### futil_file ######################################################## def futil_file (s, com, line): # Redundant re-parse of line but nobody else wants args right now. match = _com_split_parse.match(line) if match == None: print "Aborting because of mal-formed FUTIL FILE command: " + line s.os8_send_ctrl('C') return "err" fname = match.group(2) expect_futil_file_str = "\n" + fname + "\s+(.*)$" s.os8_send_line (line) s._child.expect(expect_futil_file_str) result = s._child.after.strip() match = _com_split_parse.match(result) if match == None: print "Aborting because unexpected return status: " + result + " from: " + line s.os8_send_ctrl('C') return "err" if match.group(2).strip() == "LOOKUP FAILED": print "Aborting because of FUTIL lookup failure on: " + fname s.os8_send_ctrl('C') return "err" else: return "cont" #### parse_futil ######################################################### # # Very simple minded: # If first char on line is an alpha, run the command. # If the first char on line is number, do the substitute command. # # Substitute command acts like ODT. # Future version should support the IF construct. # # When we encounter the EXIT command, we return success. def parse_futil (s, com, line, debug): futil_specials = { "EXIT": futil_exit, "FILE": futil_file } if line[0].isdigit(): # Treat the line as ODT return parse_odt(s, com, line, debug) else: match = _com_split_parse.match(line) if match == None: print "Ignoring failed FUTIL command parse of: " + line return "cont" fcom = match.group(1) rest = match.group(2) if fcom not in futil_specials: # Blind faith and no error checking. s.os8_send_line(line) return "cont" else: return futil_specials[fcom](s, fcom, line) #### do_patch_file ##################################################### def do_patch_file (s, filename, debug): global progmsg try: patch_file = open(dirs.os8mi + "patches/" + filename, "r") except IOError: print filename + " not found. Skipping." return -1 special_commands = { "ODT": parse_odt, "R": None, # Get next parser. "FUTIL": parse_futil } inside_a_command = False the_command = "" the_command_parser = None for line in patch_file: line = line.rstrip() if line == "": continue elif line[0] == '#': continue # Ignore Comments elif inside_a_command: retval = the_command_parser (s, the_command, line, debug) if retval == "break": inside_a_command = False s.os8_send_ctrl('C') elif retval == "err": patch_file.close() return -1 elif line[0] == '.': # New OS/8 Command match = _com_os8_parse.match(line) if match == None: print "Aborting patch on failed OS/8 command parse of: " + line return -1 com = match.group(1) rest = match.group(2) if com in special_commands: if com == "R": # Run command is special. Take arg as the command and run it. com = rest inside_a_command = True the_command = com the_command_parser = special_commands[com] # We carefully separate com and args # But don't make much use of that yet. if progmsg and debug: print line s.os8_send_cmd ("\\.", line[1:]) # Skip Prompt. patch_file.close() # Done. Signal success. return 0 #### skip_patch ######################################################## # Returns true if the given filename matches one of the regex string # keys of the given skips dict and the flag value for that key is set. # See skips definition in make_patch, which calls this. def skip_patch (fn, skips): for p in skips: if re.search (p, fn) and skips[p]: return True return False #### make_patch ######################################################## def make_patch (s, args): global progmsg manifest_filename = "patch_list.txt" # Declare which patches to skip based on patch file name RE patterns # and command line options. All patches not matching these patterns # apply to OS/8 files that always get installed. skips = { '^F4': args.disable_fortran_iv, '^FRTS': args.disable_fortran_iv, '^FUTIL.*v7': not args.disable_macrel, # MACREL includes FUTIL V8B '^SABR': args.disable_fortran_ii, } print "Generating " + _patched_rk05 + " from " + _bin_rk05 image_path = dirs.os8mo + _patched_rk05 if os.path.isfile(image_path): save_path = dirs.bin + _patched_rk05 + ".save" print "Pre-existing " + _patched_rk05 + " found. Saving as " + _patched_rk05 + ".save" if os.path.isfile(save_path): print "Overwriting old " + _patched_rk05 + ".save" os.remove(save_path) os.rename(image_path, save_path) if progmsg: print "Copying original " + _bin_rk05 + " to " + _patched_rk05 try: shutil.copyfile(dirs.os8mo + _bin_rk05, image_path) except shutil.Error as e: print "Creation of " + _patched_rk05 + " failed with error: " + str(e) mkos8_abort(s) except IOError as e: print "Creation of " + _patched_rk05 + " failed with IOError: " + str(e) mkos8_abort(s) s.send_cmd ("attach rk0 " + image_path) s.send_cmd ("boot rk0") # We're running OS/8. Let's patch! manifest = open (dirs.os8mi + "patches/" + manifest_filename, "r") for line in manifest: if line == "": continue if line[0] == '#': continue # Allow commenting out files filename = line.strip() if skip_patch (filename, skips): if progmsg: print "Skipping patch file: " + filename + "." else: if progmsg: print "Applying patch file: " + filename + "...", success = do_patch_file (s, filename, args.debug) == 0 if progmsg: if success: print "success." else: print "FAILED!" # If we have installed FORTRAN IV, install the patched FORLIB.RL # to be found on local.tu56 if not args.disable_fortran_iv: forlib_tape = "local.tu56" forlib_tape_path = dirs.os8mi + forlib_tape if progmsg: print "FORLIB 51.10.1M: Replacing FORLIB.RL with patched version from " + forlib_tape + "..." # Normally we'd use check_exists, but failure to find the file is fatal. # With a patch, we abort but keep going. if (not os.path.isfile(forlib_tape_path)): print "Can't find tape with patch FORLIB.RL. FAILED!" else: s.back_to_cmd("\\.") # return to simh and mount the tape. s.send_cmd ("attach -r dt0 " + forlib_tape_path) s.os8_restart () # return to OS/8 s.os8_send_cmd ("\\.", "DEL SYS:FORLIB.RL") s.os8_send_cmd ("\\.", "COPY SYS:<DTA0:FORLIB.RL") s.back_to_cmd("\\.") # return to simh and mount the tape. s.send_cmd ("detach dt0") s.os8_restart () # return to OS/8 # Finish up if progmsg: print "Cleaning up..." s.os8_squish ("SYS") s.os8_squish ("DSK") s.back_to_cmd("\\.") s.send_cmd ("detach rk0") #### main ############################################################## # Program entry point. Parses the command line and drives the above. def main (): # Parse the command line allowed_acts = ["all", "bin", "src", "patch"] do_all_acts = ["bin", "src"] # Just do bin and src if act is "all". ap = argparser.ArgParser (allowed_acts) global progmsg progmsg = not ap.args.verbose # Initialize our acts dict. acts = {} first_act = None for this in allowed_acts: acts[this] = False for act in ap.args.what: if act not in allowed_acts: print "Invalid act: " + act + " ignored." continue if first_act == None: first_act = act if act == "all": for this in do_all_acts: acts[this] = True break acts[act] = True # Log SIMH and OS/8 output to a file by default, but send it to the # console instead of the progress messages if -v was given using the # trick from https://stackoverflow.com/questions/21239338 s = simh (dirs.build, True) s.set_logfile (open (dirs.log + 'mkos8-' + first_act + '.log', 'w') \ if progmsg else os.fdopen (sys.stdout.fileno (), 'w', 0)) if acts["bin"]: make_bin (s, ap.args) if acts["src"]: make_src (s, ap.args) if acts["patch"]: make_patch (s, ap.args) s.quit () if progmsg: print "Done!" if __name__ == "__main__": main() |
> > > | 1 2 3 | *.tu56 *.rk05 *.rk05.save |
> | 1 | .agignore |
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | PiDP-8/I @VERSION@ - OS/8 V3D - KBM V3Q - CCL V1F Configured by @BUILDUSER@ on @BUILDTS@ Restart address = 07600 Type: .DIR - to get a list of files on DSK: .DIR SYS: - to get a list of files on SYS: .R PROGNAME - to run a system program .HELP FILENAME - to type a help file |
cannot compute difference between binary files
cannot compute difference between binary files
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Supersedes article dated June/July 1980 # # LOADER PROBLEM WITH SAVE IMAGE FILES (BS) # # There is a problem in that Loader does not work with Save Image files. # The following patch, applied via FUTIL, will correct this problem. .R FUTIL SET DEV SYS SET MODE SAVE FILE ABSLDR.SV 14105/1757 7000 14106/7004 7000 14107/7110 7000 14110/3757 7000 12200/6602 6603 WRITE EXIT # Note that the above patch upgrades ABSLDR from Version 6B to Version 6C, |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # BASIC. UF V5A # BASIC. UF INCOMPATIBLE FROM OS/8 V3C (SPR 8-2537 JG) # BASIC. UF is incompatible with OS/8 V3D BASIC due to PAGE ZERO references # that were not updated. # The following binary patch or source change can be made to fix this # problem. # This patch upgrades BASIC.UF to V5B. .GET SYS:BASIC.UF .ODT 3447/1073 1177 3467/4514 4556 3474/4514 4556 3523/4514 4556 3525/1074 1171 3531/1074 1171 3561/1073 1177 3607/4535 4526 3624/4514 4556 3636/4514 4556 3716/1073 1177 3752/4536 4524 4012/4514 4556 4021/1074 1171 # The next line appears in the patch but no such subroutine # Call is present. Reviewing the source code of the patch: # This location contains 1273 TAD NSAM # The patch says change it to 4556 JMS I FIXP # I think this location should be left unchanged. # 4044/4514 4556 4060/1073 1177 4067/1077 1172 4160/3064 3056 4162/4534 4557 4163/0307 0311 4207/4535 4526 4216/4514 4556 4225/4514 4556 4275/4514 4556 4312/4514 4556 4403/4514 4556 4433/4514 4556 4444/4514 4556 4451/1073 1177 4476/4556 4573 4504/4514 4556 4507/4514 4556 4513/4514 4556 4532/1073 1177 \c .SAVE SYS:BASIC.UF |
> > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # OS/8 EXTENSION KIT V3D Seq 31. 23. 1 M # BATCH V7A # MANUAL INTERVENTION REQUIRED ERRONEOUSLY (SR) # Problem: The message MANUAL HELP NEEDED is sometimes printed even # though no use is made of a terminal, paper tape reader or # card reader in the BATCH stream. (The message does not # hurt, the system continues to function properly.) # Diagnosis: This problem was fixed in BATCH V5D and V6A for KBM # commands that called the CD in special mode. This fix was # incorporated in BATCH V7A. However, a similar problem # exists if a CCL command does a special mode decode. The # problem is that routine CDSCN at location 7200 (in the # field of BATCH) is being called with a 5200 in the AC (the # special mode indicator), but CDSCN thinks 0 means special # mode. The solution is to allow either 0 or 5200 to mean # special mode. # Cure: Install the following patch which upgrades BATCH to V7B: .GET SYS:BATCH .ODT 7201/3340 5344 7344/xxxx 1351;7440;1352;3340;5202;2600;5200 7326/4752 7000 1701/0137 0237 \c .SAVE SYS:BATCH |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # BLOAD WILL NOT BUILD CCB PROPERLY (JR) # On some very large programs, BLOAD will not build the CCB properly when the # /K option is used. The following patch corrects this: .GET SYS BLOAD .ODT 2155/xxxx 0000 2156/xxxx 6203 2157/xxxx 7000 2160/xxxx 1000 2775/2534 2154 3027/6501 6502 \c .SAVE SYS BLOAD # This patch upgrades BLOAD to V5B. |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # IOTABLE OVERFLOW (SPR 8-2431 JR) # Problem: The size of the IOTABLE is 15 (Octal). # This was misread as 15 (Decimal) making entry #4 overflow into the handler. # # The following patch will fix the problem and upgrades BRTS.SV to V5B. .GET SYS BRTS .ODT 2010/ 7106 7104\n 2011/ 7006 1065\n 2012/ 7041 7006\n 2013/ 1065 1065\n 2014/ 7041 7000 1116/ 0301 0302 \c .SAVE SYS BRTS |
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | # BRTS.SV V5B Supersedes article dated Mar 78 # BASIC PNT FUNCTION (JR) # Presently the OS/8 BASIC PNT function forces the parity bit on. # Therefore, it is impossible to output octal codes 000-077. # The following patch removes this limitation. .GET SYS BRTS .ODT 1761/0162 7000 1762/1172 0174 \c .SAVE SYS BRTS # This is an optional patch. Optional patches do not change the version # levels. |
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # LINE SIZE ON OUTPUT OF BASIC (JR.) # There seems to be great interest in extending basic output to 133 # characters. The following patch will extend the output line width to # 132 chars (9 columns of number data). Basic console input will remain # at 72 chars max - that is not easily patched since the buffer ? other # code + data. This restriction does not apply to file I/O - only the # tty. .GET SYS BRTS .ODT 2570/7774 7767 2573/7660 7574 3375/7660 7574 \c .SA SYS BRTS |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # BRTS.SV V5B Seq. 31.11.5 M # PATCH TO BRTS FOR ADDRESSING LAB 8/B FUNCTIONS (JR) # The correct patch to BRTS.SV for proper addressing of LAB 8/E functions for # 0S/8 BASIC is as follows: # 1. Make the patch to BASIC/UF as described in the # August-September 1978 DSN. Note that, location 4044 contains # 1273 and not 4514 before being changed to 4556. # 2. Patch BRTS.SV. This patch replaces the patch described in # the OS/8 Language »«ftr»B1!i Hanuiil (A A-H609A-TA) , BASIC # chapter, page 5-2. .GET SYS BRTS .ODT 00001/xxxx 5402 FUNCTION 00002/xxxx 4456 01560/xxxx 3400 INI 01561/xxxx 3454 PLY 01562/xxxx 3473 DLY 01563/xxxx 3600 DIS 01564/xxxx 4000 SAM 01565/xxxx 4077 CLK 01566/xxxx 3542 CLH 01567/xxxx 3522 ADC 01570/xxxx 4400 GET 01571/xxxx 4432 PUT 01572/xxxx 4267 DRI 01573/xxxx 4311 DR0 \c .SA SYS BRTS |
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | # Problem: CREF dies on source files containing a FIXTAB directive. # Diagnosis: Patch V4B incorrectly installed into CREF V5A. # Solution: Apply the following patch: .GET SYS:CREF .ODT 6063/2022 5270 6070/2025 2022;5314 6114/xxxx 1363;1025;3025;3425;2025;5252 2576/0301 0302 \c .SAVE SYS:CREF |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # INPUT AND OUTPUT FILE SPECIFICATIONS (RY) # # The following patch allows you to specify two non-system handlers, where previously # only one non-system handler and one system handler were required. .GET SYS CREF .ODT 0264/1773 1327 0327/xxxx 0000 4234/3352 3752 4352/0000 0327 2576/0302 0303 \c .SAVE SYS CREF.SV # This patch upgrades CREF.SV from V5B to V5C. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | / / / D L O G / - - - - / / VERSION 5A 4-27-77 PT / /LOGE(X) / /X=2^N*F / /LOGE(X) /= N*LOGE(2)+LOGE(F) / / SECT DLOG JA #DALOG DPCHK / /IF X<=0 - IT IS AN ERROR EXTERN #ARGER DALERR, TRAP4 #ARGER / TEXT +DLOG + DALXR, SETX XRDAL SETB BPDAL BPDAL, F 0.0 XRDAL, F 0.0 F 0.0 ORG 10*3+BPDAL FNOP JA DALXR 0 DALRTN, JA . N, F 0.0 F 0.0 F, F 0.0 F 0.0 DAL1, F 1.0 F 0.0 / DT7, 7776 /1/7 2222 2222 2222 2222 2221 DT6, 7776 /-1/6 5252 5252 5252 5252 5252 DT5, 7776 /1/5 3146 3146 3146 3146 3146 DT4, 7776 /-1/4 4000 0 0 0 0 DT3, 7777 /1/3 2525 2525 2525 2525 2524 DT2, 7777 /-1/2 4000 0 0 0 0 / A0, F 1.84375 F 0.0 A1, F 1.65625 F 0.0 A2, F 1.500 F 0.0 A3, F 1.375 F 0.0 A4, F 1.250 F 0.0 A5, F 1.1875 F 0.0 A6, F 1.09375 F 0.0 A7, F 1.03125 F 0.0 LA0, 0 /.6118015411059928976 2344 7603 2325 4250 3144 LA1, 0 /.5045560107523952859 2011 2512 4551 3503 7657 LA2, 7777 /.4054651081081643810 3174 6217 5457 7141 1370 LA3, 7777 /.3184537311185346147 2430 3057 0207 0573 0232 LA4, 7776 /.2231435513142097553 3443 7737 0746 5150 4146 LA5, 7776 /.1718502569266592214 2577 6301 6051 7117 2356 LA6, 7775 /.08961215868968712374 2674 1512 1271 2655 1272 LA7, 7773 /.030771658666753687 3740 5154 1636 0313 7764 D16, F 16.0 F 0.0 D8, F 8.0 F 0.0 CUM, F 0.0 F 0.0 DLOGE2, 0 2613 4413 7676 4347 5715 / /PICK UP X BASE 0 #DALOG, STARTD FLDA 10*3 FSTA DALRTN FLDA 0 SETX XRDAL SETB BPDAL BASE BPDAL LDX 1,1 FSTA BPDAL FLDA% BPDAL,1 /ADDRESS FSTA BPDAL STARTE FLDA% BPDAL /AND X JLE DALERR /X <= 0 IS ERROR FSUB DAL1 /SUB 1.0 JNE DALA FCLA /LOG(1)=0 JA DALRTN / DALA, FLDA% BPDAL /GET ARGUMENT BACK FSTA XRDAL /STORE AT X /EXPONENT STORED IN XR0 /MANTISSA STORED IN XR1-5 /PICK UP EXP + MULTIPLY BY LOGE(2) / XTA 0 FMUL DLOGE2 FSTA N /N*LOGE(2) /XRDAL IS NOW FRACTION IN RANGE .5<=F<1.0 /COMPUTE LOG(F) BY /LOG(F)=LOG(A(K1)*A(K2)...(F))-(LOG(A(K1))+ / LOG(A(K2))...) /FIT F IN A 1/16 RANGE /I.E. 1/2-9/16,9/16-10/16,ETC. /MULTIPLY F BY APPROPRIATE A(K) MULTIPLIER /KEEP RUNNING SUM OF LOG(A(K)) /CONTINUE UNTIL F>1 / LDX 0,0 FLDA XRDAL FSTA F FCLA FSTA CUM DALB, FLDA F FMUL D16 /16 REAL PARTS FSUB D8 /NEED JUST 8 ATX 1 FLDA A0,1 /GET MULTIPLIER FMULM F FLDA LA0,1 /ADD LOG(A(K)) TO SUM FADDM CUM FLDA F FSUB DAL1 JLT DALB /NOW F>1. USE TAYLOR SERIES /LOG(T)=Z-(Z^2)/2+(Z^3)/3+... WHERE Z=T-1 FLDA F FSUB DAL1 /F-1.0 FSTA F FMUL DT7 FADD DT6 FMUL F FADD DT5 FMUL F FADD DT4 FMUL F FADD DT3 FMUL F FADD DT2 FMUL F FADD DAL1 FMUL F FSUB CUM FADD N JA DALRTN |
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | # Problem: EDIT sometimes loses its TAB characters in multi-page files # if file is exited on other than the last page. # # Solution: Make the following patch to OS/8 V3D of EDIT.SV. # This raises the patch level to V12B .GET SYS:EDIT.SV .ODT 2014/1301 1357 2372/0301 0302 \c .SAVE SYS:EDIT.SV |
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # EDIT V12B 21.17.2 M # EDIT Q COMMAND AFTER L COMMAND (RY) # # Problem: When a "Q" command is issued after an "L" command, the output # is sent to the terminal instead of the file. # # Diagnosis: The "Q" command has bypassed the code that resets the # variable 'OUTDEV in its attempt to clear the variable # 'TABIND' # # Solution: Install the following patch, that upgrades EDIT to Version # 12C. .GET SYS:EDIT .ODT 2372/0302 0303 2014/nnnn 2774 2774/nnnn 3112;5776;1301 \c .SAVE SYS:EDIT |
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | # EDIT V12C Seq 21.17.3 M # EDIT Q COMMAND PATCH (RY) # # Problem: The "Q" command does not output the first page of a file. # # Solution: Install the following patch and EDIT is upgraded to Version # 12D. .GET SYS:EDIT .ODT 1360/5304 5301 2372/0303 0304 \c .SAVE SYS:EDIT |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # EDIT.SV "V" OPTION WILL NOT WORK WITH LPT (RY) # # The "V" option of EDIT.SV will not work when the LPT interface is the # parallel port of the DKC8-AA I/O option board. Install the following patch # and EDIT will be upgraded from V12B to V12C. # Correction: This is the 4th patch in the sequence, and upgrades EDIT # from V12D to V12E .GET SYS EDIT .ODT 2713/6666 5374 2774/xxxx 7040;6574;5314 2714/6661 6570 2372/0304 0305 \c .SAVE SYS EDIT.SV |
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Updated in Dec/Jan 1978 SEQ 21.1.2 N to correct referencee to F4 not FRTS. # F4.SV V4A Seq 2 M # EQUIVALENCE STATEMENT (MH) # The EQUIVALENCE statement does not always work correctly in OS/8 FORTRAN IV V3D. # Install the following patch to correct the problem. .GET SYS F4.SV .ODT 2067/1471 1367 2070/1071 5363 2163/**** 2071 2164/**** 7000 2165/**** 1071 2166/**** 5271 2167/**** 2 1130/6401 6402 \c .SAVE SYS F4.SV .GET SYS PASS3.SV .ODT 712/6401 6402 \c .SAVE SYS PASS3.SV # This patch upgrades F4.SV to V4B. |
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # Supersedes article dated Mar 78 # FORTRAN COMPILER FAILS TO RECOGNIZE " AS AN ERROR (SPR 8-2428 JB) # Problem: The F4 compiler fails to recognize the double quotes (") as # an incorrect character in a subroutine call argument. # Instead, it generates an argueless call. # Solution: The following patch corrects this problem and should be # installed: .GET SYS F4 .ODT 3343/ 7440 7640 1130/ 6402 6403 \c .SAVE SYS F4 # This patch corrects this problem and upgrades the F4.SV to V4C. |
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | # F4 V4A # FORTRAN COMPILER NOT RECOGNIZING SYNTAX ERROR (JB) # F4 compiler does not recognize syntax error in type declaration # statement. # The following patch will resolve this situation. .GET SYS F4.SV .ODT 2520/4557 5326 2521/2200 7000 2522/5600 7000 2541/5320 5326 \c .SAVE SYS F4.SV |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # FORTRAN IV DLOG PATCH (JR) # # There is a problem with DLOG where it could not handle numbers smaller than # 1.E-018 correctly. The following patch fixes this problem. # # Make a source change to DLOG.RA using either EDIT or TECO. Replace # this line: # # Published patch has a typo. There is no "EADD" function. It is "FADD". # DALA, EADD DAL1 /ADD BACK # with : # DALA, FLDA% BPDAL /GET ARGUMENT BACK # .R RALF # *DLOG.RL<DLOG.RA # .R LIBRA # *FORLIB.RL<FORLIB.RL,DLOG.RL/Z/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 | # FOTP V9A Seq 21. 19. 1 M # INCORRECT DIRECTORY VALIDATION (SR) # Problem: # If a device contains many files and the directory contains no # additional information words (i.e., no dates) then FOTP may # think the directory is invalid. # Diagnosis: # FOTP checks the validity of a directory by several means. One # method is a range check on the number of file entries in the # first directory segment. If the directory had been built with # 0 additional information words (/Z=100), then the segment can # contain more entries than FOTP believes is possible. # Solution: # Modify FOTP so that it permits a directory segment with as many # as 71 entries. To do this, install the following patch: .GET SYS:FOTP .ODT 12375/7700 7671 14346/7700 7671 15036/7101 7102 \c .SAVE SYS:FOTP # This patch upgrades FOTP to Version 9B. # Most users are not affected by this patch. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # OS/8 FORTRAN IV KIT V3D Seq 51.3.3 0 # FRTS. SV V5 # FORTRAN RUNTIME SYSTEM 2 PAGE HANDLER (JM) # The FORTRAN Run-Time System has worked wih the TD8E 2 page system handler. # To add it to work with other 2 page system handlers and, in particular the # RL01, the following patch must be installed. .GET SYS:FRTS .ODT 12675/7001 0342 12742/XXXX 7770 17526/0000 0000 17527/3763 3307 17530/1763 1333 17531/3762 3363 17532/1763 5346 17533/7001 7635 17534/3761 1570 17535/5726 7710 17546/XXXX 1763 17547/XXXX 1334 17550/XXXX 7100 17551/XXXX 1335 17552/XXXX 7630 17553/XXXX 5360 17554/XXXX 1763 17555/XXXX 0341 17556/XXXX 1307 17557/XXXX 3763 17560/XXXX 2363 17561/7642 5346 17562/7727 5726 17563/7721 0 17566/0212 6220 \c .SAVE SYS:FRTS This patch is optional and does not change the patch level. |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # The patch given below upgrades FUTIL V7A to V7B. It corrects the # following problems: # 1. Typing CTRL/U crashes FUTIL if the current partiall-typed # line contains a semicolon. # 2. Overlay mapping (in SAVE mode) is not done correctly. .GET SYS FUTIL .ODT 0310/3523 3536 0333/1523 1536 3342/3357 3362 3343/1357 1362 3351/1361 1357 3354/2357 2362 12520/0100 0200 \c .SAVE SYS FUTIL |
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # OS/8 EXTENSION KIT V3D # FUTIL V7B Seq 31.21.2 M # PATCH TO FIX 'SHOW CCB' AND MAPPING OF 'CD' MODULES (SPR 8-2550) # The following contains the corrections to both of these problems. .GET SYS FUTIL .ODT 12024/3242 5345 12025/1642 7650 12026/7450 5236 12027/5236 1642 12145/XXXX 3242 12146/XXXX 1242 12147/XXXX 1351 12150/XXXX 5225 12151/XXXX 1175 12075/7040 7000 12520/0200 0400 \c .SAVE SYS:FUTIL # This patch upgrades FUTIL to V7D. |
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # -237 PATCH (SR) # The XS format in FUTIL is useful for dumping data stored in excess 240 # packed six bit. This is the format of PAL12 six bit strings. # Users who would prefer the XS format to dump data stored in excess 237 # packed six bit may install the following optional patch: .GET SYS:FUTIL .ODT 5355/4532 4770 5360/4532 4770 5370/xxxx 5761 5762/xxxx 1365;4532;5761;7777 \c .SAVE SYS FUTIL # Excess 237 packed six bit is the format used by COS data files. # Optional patches do not change FUTIL's version number. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # THIS PATCH FIXES THE FOLLOWING BUGS: # 1. THE WRONG 2 WORD PAIR IN THE MEMORY CONTROL BLOCK FOR A FULL 4K # MEMORY IMAGE. # 2. ACCESSING THE WRONG GST SYMBOL WHEN USING LOADER CODE 11 (POP AND # STORE INTO GST). # 3. LINK MEMORY ALLOCATION BUG WHEN DEALING WITH RESTRICTED PROGRAM # SECTIONS. # THIS PATCH UPGRADES LINK TO VlD .R EPIC *LINK.SV</1<esc> R,1\r O,111\r 0340/ 440\r W\r R,3\r O,352 \r 5356/ 5364\r O,355\r 1443/ 6211\n 5747/ 5363\r O,363\r 0000/ 1443 \n 0000/ 5747\r W\r R,24\r O,222\r 2441/ 7000\r W\r R,25\r O,305\r 3162/ 3055\r O,336\r 1562/ 1455 \n 3562/ 3455\r W\r R,46\r O,254\r 7001/ 5271\r O,271\r 0000/ 7450 \n 0000/ 1370\n 0000/ 7001\n 0000/ 5255\r W\r \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 | # THIS PATCH FIXES THE FOLLOWING BUGS: # 1. ERROR IN COMPUTING JOB STATUS WORD FOR MEMORY IMAGE # 2. EAD TECHNIQUE IN COMBINING MULTIPLE NULL PAGES # 3. BAD FIELD NUMBER IN OVERLAY DATA TABLE FOR OVRDRV # 4. BAD OVERLAY/LEVEL LENGTH IN OVERLAY DATA TABLE FOR OVRDRV # # THIS PATCH UPGRADES LINK TO VIE .R EPIC *LINK.SV</1<esc> R,1\r O,111\r 0440/ 0540\r W\r R,24\r O,31\r 1227/ 1775\n 3776/ 7450\n 1775/ 5257\n 7450/ 7041\n 5257/ 3244\n 7041/ 7344\n 3244/ 3137\n 7344/ 1227\n 3137/ 3776\n O,56\r 5242/ 5240\r O,314\r 1035/ 5715\n 3035/ 5065\r W\r R,25\r O,57\r 7450/ 1043\n 5265/ 7450\n 1043/ 5271\r O,64\r 7100/ 5246\r O,70\r 7630/ 400 \n 5305/ 7100\n 1341/ 1043\n 1371/ 1270\n 7041/ 3043\n 3043/ 7430\n 7100/ 5337\r O,100\r 7041/ 7161\r O,102\r 7620/ 7670\r O,111\r 5332/ 5246\r O,117\r 7100/ 1341\n 1341/ 7041\n 1044/ 7100\n 7620/ 5273\r W\r R,31\r O,2\r 7041/ 376\n 1063/ 7041\n 0376/ 1063\r O,65 \r 0000/ 3275\n 0000/ 1275\n 0000/ 7040\n 0000/ 35\n 0000/ 1275\n 0000/ 3035\n 0000/ 5674\n 0000/ 2716\r W\r R,42\r O,50\r 1042/ 1542\n 7041/ 7001\n 1542/ 5360\n 7710/ 7700\r O,160\r 0000/ 7110\n 0000/ 7041\n 0000/ 1042\n 0000/ 5253\r W\r R,46\r O,111\r 7112/ 7000\n 7010/ 7000\r O,125\r 7001/ 7000\n 7110/ 7000\r O,264 \r 1041/ 1042\r O,273\r 7001/ 3042\n 5255/ 1042\n 0000/ 7001\n 0000/ 5255\r W\r R,50\r O,214\r 1411/ 5243\r O,243\r 0000/ 1411\n 0000/ 7001\n 0000/ 7110\n 0000/ 5215\r W\r ? # (Question mark, if output by EPIC here, may be ignored) \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 | # THIS PATCH FIXES THE FOLLOWING BUGS: # 1. LOSS OF DATA IN THE .SV IMAGE # 2. BUG IN COMPUTATION OF RSECTS ON THE SAME PAGE AS ANOTHER PROGRAM # 3. BAD MEMORY CONTROL BLOCKS WHEN USING /M OPTION # 4. NEW SYSTEM ERROR (2760) FOR BAD SYMBOL TYPE # THIS PATCH UPGRADES LINK TO VlF .R EPIC *LINK.SV</1<esc> R,1\r O,111\r 0540/ 640\r W\r R,24\r O,357\r 0000/4514\n 0000/5357\r W\r R,25\r O,147(CP) 1101/2757\n 1101/2757\n W\r R,26\r O,74\r 5235/5250\r O,301\r 7041/7161\r O,303\r 7740/7660\r W\r R,46\r O,35 \r 0374/7200\r W\r R,47\r O,326 \r 7041/5342\n 7100/7141\r O,340\r 1411/5741\n 7041/5524\n 7100/7440\n 1410/5327\n 7640/5765\n 7420/7670\r 0,365 \r 0000/5537(DR) 0,367 \r 1401/1201\r W\r R,50\r O,124\r 0000/7320\n 0000/1411\n 0000/7440\n 0000/7041\n 0000/3013\n 0000/1410\n 0000/7450\n 0000/7020\n 0000/1013\n 0000/5736\n 0000/5345\n 0000/2010\n 0000/2010\n 0000/5742\n 0000/5355\n W\r ? # (Question mark, if output by EPIC here, may be ignored) \c |
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Supersedes article dated March 1978 # # LQP01 HANDLER FAILS TO RECOGNIZE TABS (SPR 8-2441 JM) # # The LQP.BN handler as distributed does not recognize the TABS character. Any # listing or text that uses TABS will not be printed correctly. # # The method to patch this problem is through the BUILD procedure. This will # fix this problem and maintain the correct version in the saved copy of BUILD. # This is done as follows: .R BUILD LOAD DSK:LQP.BN # (OR DEVICE THAT DISTRIBUTED LQP.BN IS ON) $ALTER LQP,324=7640 $BOOT .SAVE SYS BUILD # This patch corrects this problem and upgrades the LQP.BN to VB. |
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # IN MACREL V1C, SECT LENGTHS ARE WRONG FOR SECTS WHICH CONTAIN RELOC # STATEMENTS AND CURRENT PAGE LITERALS. THE FOLLOWING PATCH CORRECTS # THIS PROBLEM AND UPGRADES MACREL TO VlD. .GET SYS:MACREL .ODT 305/3303 5325 320/4772 5772 372/5546 5547 322/3036 1044;1106;5721 356/1044 4321 363/1044 4321 5455/0000 303 5546/0000 364 5552/5746 5356 5555/1044 5762;1655;3036;1655;5746;363 325/0000 1106;3303;5306 13136/0303 304 \c .SAVE SYS:MACREL |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # PATCH VIE TO MACREL (SR) # THIS PATCH FIXES THE FOLLOWING BUGS: # 1. THE 'DEVICE' DIRECTIVE SOMETIMES PRODUCES RELOCATABLE TEXT. THE # TEXT PRODUCED SHOULD ALWAYS BE ABSOLUTE. # 2. AN UNKNOWN KEYWORD AFTER A .LIST DIRECTIVE FAILS TO PRODUCE THE # ERROR MESSAGE: "UNKNOWN LIST CONDITION". # 3. > AT THE END OF A DECLARATION CAUSES AN ERRONEOUS ERROR MESSAGE TO # BE PRINTED. # 4. CERTAIN DIRECTIVES DO NOT PRINT IN THE LISTING WHEN THEY CONTAIN A # SYNTACTIC ERROR. # 5. DATES LATER THAN DECEMBER 31, 1977 DO NOT PRINT CORRECTLY IN THE # HEADER LINE. # 6. THE THIRD CHARACTER IN OS/8 TEXT PACKING IS COMING OUT AS THE FIRST # CHARACTER OF THE TRIPLE. # 7. EVERY THIRD CHARACTER IN OS/8 TEXT PACKING IS IGNORING THE # 7BIT/8BIT ENABLE CONDITION. # THIS PATCH UPGRADES MACREL TO VIE. # .GET SYS:MACOVR .ODT 11531/1033 5345 11545/xxxx 3030;1033;5332 12541/xxxx 1026;1347;7650;5763;1026;5740;7702 12637/1026 4763 12763/xxxx 2140 10763/1302 1333 10553/7775 7774 10751/7006 0173;4767 10767/5762 2156 10557/1137 7440;1764;7006;7006;5756;2332 \c .SAVE SYS:MACOVR .GET SYS:MACREL .ODT 13136/0304 305 0242/5566 5301 7220/0177 4621;2112 2113/xxxx 0177;3725;1726;7012;7012;0327;1725;3725;2312;5712;7342;7777;30 \c .SAVE SYS:MACREL .GET SYS:MACERR .ODT 21335/5544 5542 \c .SAVE SYS:MACERR |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # Problem: New files created by MCPIP on a magtape or cassette after # January 1, 1978 will be entered with the wrong creation date. # (New files created on other devices will have their dates correct.) # MCPIP fails to look at the date extension bits when writing a magtape # or cassette header record. # # The following patch fixes this problem and upgrades MCPIP to V6B: .GET SYS MCPIP .ODT 14031/ 6601 6602 07464/ 1360 5342 07542/ xxxx 3302;4747;1302;1360;5265;6137 06140/ xxxx 1745;7012;7012;0346;5737;7777;0030 \c .SAVE SYS MCPIP |
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # MSBAT V3A SEQ. 31.22.1 M # DIM STATEMENT NOT WORKING IN MSBAT (SR) # PROBLEM: # MSBAT V3A is converting a 'DIM' punch in a mark sense # card into a dimension statement. This statement is not # recognized by BASIC. # DIAGNOSOS: # The punch should be translated to 'DIM', not # 'DIMENSION'. # SOLUTION: # Apply the following patch: .GET SYS:MSBAT .ODT 4015/1505 1500 3671/6301 6302 \c .SAVE SYS:MSBAT # This patch upgrades MSBAT to V3B. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | PATCH V1B TO OVRDRV.MA (ES) THE FOLLOWING IS A SOURCE COMPARE OF THE DISTRIBUTED OVERLAY-DRIVER (OVRDRV.MA) VERSES THE CHANGES NECESSARY TO MAKE IT COMPATIBLE WITH THE BUG FIXES CORRECTED IN PATCH IE OF LINK.SV. THE CHANGES TO OVRDRV.MA ONLY HAVE TO BE MADE IF YOU ARE USING THE LINK OVERLAY STRUCTURE. SRCCOM V4A 1) /OVRDRV - OVERLAY DRIVER 2) /OVRDRV - OVERLAY DRIVER 1)001 /COPYRIGHT (C) 1977 BY DIGITAL EQUIPMENT CORPORATION 1) / **** 2)001 /COPYRIGHT (C) 1977,1978 BY DIGITAL EQUIPMENT CORPORATION 2) / ******** 1)002 /VIA 1) /THIS SECT IS TWO LOCATIONS AND CONTAINS THE TRANSFER VECTOR TO SWAPER **** 2)002 /V1B 2) /THIS SECT IS TWO LOCATIONS AND CONTAINS THE TRANSFER VECTOR TO SWAPER ******** 1)002 SWAP, 6101 /VERSION NUMBER 1) DCA AC /SAVE CALLING AC **** 2*002 SWAP, 6102 /VERSION NUMBER 2) DCA AC /SAVE CALLING AC ******** 1)003 ISZ TEMP /TIMES (THE NUMBER OF THE OVERLAY) 1) JMP .-2 1) LOAD2, TAD I RELBLK /PLUS (RELATIVE BLOCK OF LEVEL) **** 2)003 JMP I .+1 /TIMES (THE NUMBER OF THE OVERLAY) 2) PATCH 2) LOAD2, TAD I RELBLK /PLUS (RELATIVE BLOCK OF LEVEL) ******** 1)003 RTR /POSITION 1)004 TAD I LENGTH /GET LENGTH 1) RTR 1) RTR 1) RTR 1) DCA REDCNT /FORM CONTROL WORD **** 2)003 RAR /POSITION 2)004 TAD I LENGTH /GET LENGTH 2) RTL 2) RTL 2) RTL 2) DCA REDCNT /FORM CONTROL WORD ******** 1)006 /THIS AREA CONTAINS OVERLAY DATA FOR MAIN AND THE 7 LEVELS **** 2)006 /PATCH TO FIX BLOCK POSITION CALCULATION 2) PATCH, IAC /CONVERT PAGES TO BLOCKS 2) CLL RAF 2) DCA PTEMP 2) TAD PTEMP /MULTIPLY BLOCK LENGTH 2) ISZ I PPNT /BY OVEFLAY NUMBER 2) JMP .-2 2) JMP I .+1 2) LOAD 2 2) PPNT, TEMP 2) PTEMP, 0 2) /THIS AREA CONTAINS OVERLAY DATA FOR MAIN AND THE 7 LEVELS ******** |
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # PAL8 V10A Seq 21. 22. 1 M # INCORRECT CORE SIZE ROUTINE (SR) # Problem: PALS's core size routine fails on certain machines such as # an 8K PDP-8L. # Diagnosis: There was no room in PAL8 for the standard size routine. # The routine used by PAL8 includes a typo. # TAD I (FLD4 should read TAD I FLD4 and, # DCA I (FLD4 should read DCA I FLD4. # Solution: Apply the following patch: .GET SYS:PAL8 .ODT 5675/3755 3715 5677/1755 1715 1533/0301 302 \c .SAVE SYS:PAL8 # This patch upgrades PAL8 to V10B. |
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # PAL8 V10B Seq 21. 22. 2 M # ERRONEOUS LINK GENERATION NOTED ON PAGE DIRECTIVE (SR) # Problem: # An apostrophe (') is sometimes printed to the right of # the binary column on the listing line for a PAGE # directive (pseudo-op). Such a symbol is meaningless # in this case. # Diagnosis: # This occurs if the previous line had a link generated # in it. The PAGE directive code fails to reset the # links generated flag (LININD). # Cure: # Install the following patch which upgrades PAL8 to V10C: .GET SYS:PAL8 .ODT 0463/5550 5367 0567/xxxx 3070;5550 1533/0302 0303 \c .SAVE SYS PAL8 |
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # EXPUNGE PATCH TO PAL8 (DBB) # # Problem: A symbol definition following an EXPUNGE directive causes a # symbol table exceeded (SE) error in some cases. # # Diagnosis: The EXPUNGE directive code in PAL8 improperly counts the # number of symbols that it deletes from the symbol table. # # Solution: Install the following patch which upgrades PAL8 to V10D. .GET SYS PAL8 .ODT 1471/4572 5373;7106;7650;5307 1573/xxxx 4572;1020;5272 1533/0303 0304 \c .SAVE SYS PAL8 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # Supersedes article dated June/July 1980 # TABS ARE TRANSLATED INCORRECTLY (KW) # # Problem: Tabs following a label (PAL8) that are 6 characters long # are translated into spaces incorrectly. # # Diagnosis: This problem is evident only when CREF listings are # requested during a PAL8 assembly. # # Solution: The following optional patch will correct this problem, # improving the appearance of CREF output listings. Since # this patch is optional, no change has been made to the # version number of PAL8.SV. .R FUTIL SET DEV SYS SET MODE SAVE FILE PAL8.SV 1363/7440 5764 1364/4527 4321 4321/XXXX 7200 4322/XXXX 1363 4323/XXXX 4762 4324/XXXX 7200 4325/XXXX 4761 4326/XXXX 5760 4360/XXXX 1372 4361/XXXX 0735 4362/XXXX 1000 4363/XXXX 0211 WRITE EXIT |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # PIP /Y OPTION DOES NOT WORK PROPERLY WHEN TRANSFERRING A SYSTEM HEAD FROM A # DEVICE WHICH IS NOT CO-RESIDENT WITH SYS. (ES) # Problem: PIP /Y option always reads absolute block 7 of the input devices # even if the input is from a file. # The following patch: # 1) Fixes /Y problems in PIP # 2) Adds RL01 Disk to PIP device tables # 3) Upgrades patch level to V12B (from V11A - an incorrect revision code) .GET SYS PIP .ODT 13626/0000 17 13631/0000 4027 16012/1373 7001 16051/4764 7410 16112/3400 1600 16134/3243 7200 16151/7400 5600 16152/0016 0007 16153/7774 7770 16167/6254 6210 16210/1377 3032 16211/3020 1766 16212/1376 3024 16213/3344 5763 16622/6161 6162 16623/0100 0200 \c .SAVE SYS PIP |
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | PIP10 V3A Seq 21.24.1 M Supersedes article dated Dec 78/Jan 79 DATE '78 PATCH TO PIP10 (RY) Problem: When PIP10 creates a new file on a PDP-10 DECtape, the file gets the wrong date. Diagnois: PIP10 does not understand about the new OS/8 extended date bits for today's date. Cure: Install the following patch which fixes this problem until 1984. .GET SYS:PIP10 .ODT 2612/1023 4760;1116 2760/nnnn 1554 1555/nnnn 1765;0176;7112;7012;3116;1023;0156;5754;7777 4320/6301 6302 \c .SAVE SYS:PIP10 # This patch corrects the above problem and upgrades PIP10 to # V3B. # This article replaces and supercedes the same sequence number # published in the Dec 78-Jan 79 DSN. |
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # SABR V18A Seq 21.91.1 M # LINE BUFFER PROBLEM IN SABR (DBB) # Problem: When a SABR input line generates code across a page boundary, # SABR puts out an altered version of the line next to the code # at the beginning of the next page in the listing file. # Diagnosis: The routine to enable the buffer to be placed in the listing # file is in error. # Solution: Install the following patch. .GET SYS SABR .ODT 14755/6201 1362;5757;5375;3362;5754 15375/0000 6201;5777;6173; 16173/0000 3777;6211;5776;4760;1646 17033/7001 7002 \c .SAVE SYS SABR # The underlined text is computer generated. This patch # corrects the problem and upgrades SABR to Version 18B. |
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # The commands SET TTY SCOPE and SET SYS INIT # ruin systems which use a 2-page system # handler. # SET modifies block 0 of the system device to # handle these commands. However, in the case # of two-page system handlers, the correct # image is stored in block 66 instead. # Install the following patch which creates # once-only code in SET VlB to check for a # 2-page system handler and modify itself # accordingly. .GET SYS:SET .ODT 0507/6102 6103 0240/5632 5357 0357/xxxx 1765;1366;7650;4767;3362;5632;7612;7775;4400 4401/0000 1207;3460;2202;2210;5201;5600;0066;7774 0060/xxxx 0713;0725;3444;3453 \c .SAVE SYS:SET |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # If SET is run directly ( .R SET) and TTY SCOPE # had previously been SET, then rubouts to a SET # command fail to properly erase characters from # the screen. # The scope rubout code is failing to send the # initial backspace character to the display # terminal. # Install the following patch to SET VIC: # This patch upgrades SET to VlD. .GET SYS:SET .ODT 0507/6103 6104 2337/5274 5370 2370/xxxx 1056;7650;5274;5271 \c .SAVE SYS:SET |
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # SET VlD # Seq 21. 26. 3 M # 1 of 1 # PARSING OF - IN TTY WIDTH OPTION (SR) # Problem: The valid command SET TTY WIDTH=80 results in a syntax error # Diagnosis: The code that checks for an optional equals sign is failing to # advance the character scan pointer. # Solution: Install the following patch: .GET SYS:SET .ODT 5763/5754 4564;7200;5754 0507/6104 6105 \c .SAVE SYS:SET # This patch upgrades SET to Version VIE. In both the commands # SET TTY WIDTH=n # and # SET CDR CODE=02x # the equals sign is optional, and may be replaced by one or more spaces. # If the equals sign is specified, it may also be optionally preceded or # followed by spaces. |
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | # In OS/8 TECO VS, the default value for the EU flag is 0 # (unless .SET TTY SCOPE has been specified to the KBM # in which case the default value is -1). # # Users who wish to permanently change the default value to be -1 # (no case flagging) may install the following patch: .GET SYS TECO .ODT 4576/ 0000 7777 2245/ 7650 7200 \c .SAVE SYS TECO |
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # CHANGING THE DEFAULT EH VALUE for one-line error printouts. # # In OS/8 TECO V5, as on the PDP-10 and PDP-11, the default value of the # EH flag is 0, which is the same as 2. This value causes the one-line # form of an error message to print upon encountering an error. # This could be annoying to experienced users with slow terminals. # Naturally, you can change this at run-time by executing the # 1EH command which causes only the 3-character error message cod # to print thereafter. # # Users who wish to cause the default value of the EH flag # to be permanently set to 1, can install the following patch: .GET SYS TECO .ODT 4572/0000 1 \c .SAVE SYS TECO |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # REMOVING YANK PROTECTION (SR) # # Probably the most common way to lose data in TECO is to accidentally # type 'Y' when you meant to type 'T'. OS/8 TECO VS has included # what is known as Yank protection. Yank protection causes the error message # # ?YCA Y Command Aborted # # to be produced any time that the following 3 conditions are met: # (a) The current command is Y or # (b) There is text in the text buffer # (c) There is an output file open. # # If all these conditions are met, it is presumed that you are about # to lose some important data, and so the command is rejected. # Note that the Yank is always legal if the text buffer is empty # or if no output file is open. If you really want to do the Yank, # you can always type HKY, a command which will always succeed. # # Users who do not wish to have Yank protection can patch it out of TECO # by installiing the following patch: .GET SYS TECO .ODT 2032/ 7640 7610 \c .SAVE SYS TECO |
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # SCOPE SUPPORT FOR VT05 USERS # # Version 5 of TECO supports scope terminals (such as VT50, VT52, VT78, etc.) # by sending appropriate escape sequences to the terminal. # For example, when typing the immediate mode command ^U during a multi-line # command string, TECO will physically erase the current line from the screen. # This support will not work properly on terminals which do not support these # escape sequences. # # For our users with VT05's, we offer the following patch which will # permit TECO to work properly on a VT05 terminal: .GET SYS TECO .ODT 2771/ 4552 7200 1446/ 0101 0032 1437/ 0113 0036 5405/ 0113 0036 \c .SAVE SYS TECO |
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # PROBLEM WITH AY COMMAND (SR) # # Problem: On rare occasions, the Y command will fail, giving the error message # # ?NAY Numeric Argument with Y # # even though no numeric argument was specified. # For example, the AY command (Append then Yank) consistently fails in this manner. # The test for a numeric argument is incorrect. # The following patch corrects this problem and upgrades TECO to 5A: .GET SYS TECO .ODT 2022/ 1024 2024;7610 4573/ 0005 0765 \c .SAVE SYS TECO |
> > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # CONDITIONALS INSIDE ITERATIONS # # Problem: TECO does not properly handle unsatisfied conditionals # if other conditionals are encountered within an inner iteration # while scanning for the terminating single quote. # # While scanning for the matching single quote, TECO keeps an iteration count # for each level of nested iterations which it finds. # TECO then ignores any single quotes which occur at a 'nest' level greater than 0. # (All conditionals must end at the same macro level that they begin.) # The problem is that TECO incorrectly bumps the conditional count # whenever it sees a double quote. # This should not be done for double quotes occurring at a non-zero level. # # The following patch fixes this problem by causing TECO to # ignore double quotes within iterations while scanning for # a terminating single quote. This ?atch upgrades TECO to VSB: .GET SYS TECO .ODT 6077/ 7240 5356 6156/ xxxx 7200;1763;7650;7240;5300;3331 4573/ 0765 0766 \c .SAVE SYS TECO |
> > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # ECHOING OF WARNING BELLS (SR) # # Problem: When typing in command characters to TECO, # if you come within 10 characters of running out of memory, TECO warns you by # ringing the terminal bell after each character input. # (This gives you a small margin in which to clean up your command, # e.g. by typing two altmodes.) # Should you persist in typing after the ten warnings, # upon typing the 11th character, TECO prints the error message # # ?QMO Q-Register Memory Overflow. # # This mechanism works correctly except that the ringing of the bell # is accompanied by the printing of the (unwanted) two-character sequence "^G". # TECO is ringing the bell by calling TYPTCV instead of TPUT. # # The following patch corrects this problem, by causing # only a warning bell to ring. This patch upgrades TECO to V5C. .GET SYS TECO .ODT 0365/ 4521 4552 4573/ 0766 0767 \c .SAVE SYS TECO |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # CTRL/U SOMETIMES FAILS AFTER * (SR) # PROBLEMS: # (I) If a command line contains the character '*', then a subsequent # use of the immediate mode command, ^U, will reprint the entire # command string as well as erasing the current line. (This will # not hurt you - but it is annoying.) # (II) If on a scope terminal, a command line contains the character # '*', then rubbing out a tab, line feed, vertical tab, or form # feed will cause the entire command string to be reprinted. # (III) The bell-space and bell-star (^G<space> and ^G* ) commands were # not documented because they did not work properly. # The immediate mode command, ^G<space> causes the current line of # the commmand string to be retyped. # The immediate mode command, ^G* causes the entire command string # to be retyped. # Note that the ^G (bell) character cannot be entered in up-arrow # mode. # (IV) The ^G* command incorrectly prints out the contents of all your # Q-Pegisters. # (V) When in scope mode, if you rub-out back to the first line of the # command string, and if there is text in some Q-register, the '*' # representing TECO's last prompt vanishes from the screen. # (VI) The ^G<space> command works improperly on 12K machines when # there are more than 2900 characters stored away in Q-registers. # ANALYSIS: # Poltergeists in TECO. # DISPOSITION: # The following patch fixes all these bugs in TECO. It also makes # the ^G<space> and ^G* commands work properly. This patch # upgrades TECO to version 5.04. .GET SYS:TECO .ODT 1341/1435 1464;1464 1431/5235 5264 1435/4265 7510;5313;1072;5304 1500/7240 1072;7040;1050;5235 1463/4265 5266;1175;3331 1524/1175 6032;5775;1175;5253 4570/1454 1526 0255/5772 5004 0004/xxxx 1577;4540;5407;1464 4573/0767 0770 \c .SAVE SYS:TECO |
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # TECO computes the product n*0 incorrectly. # Complementing a 13-bit 0 sets the link. # TECO fails to account for this. # The following patch to TECO V5.04 fixes this bug by # zeroing the link before starting the multiply. # This patch upgrades TECO to V5.05 # Just as in V3C TECO (Version 4), multiplication by # negative numbers is not supported and unpredictable # results will occur if a multiplicand is less than 0 .GET SYS:TECO .ODT 1311/7010 7110 4573/0770 0771 \c .SAVE SYS:TECO |
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # Q-REGISTERS DON'T WORK IN 8K (SR) # TECO doesn't work properly on 8K machines. # The code which changes the handling of Q-register # storage in the 8K case is faulty. # This patch upgrades TECO to Version 5.06. .GET SYS:TECO .ODT 5762/0122 7777 5771/xxxx 122;127;102;107;7777 5710/3362 3371;24 # Correction: Original patch had version change wrong. 4573/0771 772 \c .SAVE SYS:TECO |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # CAN'T SKIP OVER A "W" (SR) # PROBLEM: # If the letter w (as in PW) occurs inside a piece of # TECO code which is being skipped (say because it is # part of an unsatisfied conditional), TECO V5.06 # will blow up. # DIAGNOSIS: # The appropriate skip table does not end with the # required negative number. This table flows into # the skip table for skipping the second letter of an # E command (R, w, B, or G). The corresponding # entries in the dispatch table are all harmless # (positive) except for 'W' which causes SORT to # branch to 'death'. # SOLUTION: # The following patch inserts a -1 indicator to # properly terminate the table: # This patch upgrades TECO to V5.07. .GET SYS:TECO .ODT 5264/7240 1360 5461/7346 7344 6250/7346 7344 # Correction: original patch had version wrong. 4573/0772 0773 5227/1760 1642 5242/6201 7777 5360/7777 7776 5331/5266 5264 \c .SAVE SYS:TECO |
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # UNSPECIFIED ITERATIONS AFTER INSERTS (SR) # Problem: # If an iteration has no iteration count specified, and the # previous command was "on insert, then the iteration is # skipped. For example, the command IA$<L> will not work # properly. # Diagnosis: # The insert code destructively tests the number flag (NFLG) # and if it was 0, sets it to a 1. It is never reset to 0. # The iteration code sees a 1 and thinks a number is # present. Looking for one, it finds 0 and thinks the # iteration count is 0 meaning skip this iteration. # Cure: # The insert code should reset (zero) the number flag. This # was not a problem in TECO V4 because 0<> was the same as # <> then. Apply the following patch (which upgrades TECO # to version 5.08): .GET SYS:TECO .ODT 2616/6032 5776;3167 2674/5565 5617 4573/0773 0774 \c .SAVE SYS:TECO |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # Most of these patches have been verified # by reading the source code. # The patches that remain commented out are not recommended # and the reason why appears in the line above it. # # ABSLDR-21.29.1M is against v6A but we have v4A. # v6A came with OS/8 Devices Extension kit QF026 # Binary DECtape: AL-H525A-BA, Source not on DECtape # DO NOT APPLY THIS PATCH. ## ABSLDR-21.29.1M-v6C.patch8 BASIC.UF-31.5.1M-V5B.patch8 BATCH-31.23.1M-v7B.patch8 BLOAD-31.10.1M-v5B.patch8 BRTS-31.11.1M-v5B.patch8 # BRTS 31.11.2O disables 8th bit parity. Recommended. BRTS-31.11.2-O.patch8 # BRTS 31.11.3O enables 132 column output. Recommended. BRTS-31.11.3-O.patch8 BRTS-31.11.5-x.patch8 CREF-21.15.1M-v5B.patch8 CREF-21.15.2M-v5C.patch8 EDIT-21.17.1M-v12B.patch8 EDIT-21.17.2M-v12C.patch8 EDIT-21.17.3M-v12D.patch8 # EDIT 21.17.4 overwrites patch in 21.17.2. DO NOT APPLY THIS PATCH # EDIT-21.17.4M-V12C.patch8 F4-21.1.2M-v4B.patch8 F4-51.3.1M-v4C.patch8 F4-51.3.2M-v4x.patch8 # FORLIB 51.10.1M is hard-coded into mkos8 to copy a new # FORLIB.RL made with instructions from the patch. # So the patch will not apply but is listed here for completeness. ## FORLIB-51.10.1M.patch8 FOTP-21.19.1M-V9B.patch8 # FRTS-51.3.3-O is to enable FRTS to work with 2-page system # handlers. I've read the code but do not fully understand it. # It is plausable that it generalizes on the code that makes # the 2-page TD8E handler work. But it could also be a # patch tha tONLY works with the OS/8 Devices Extension kit QF026. # We are enabling the patch for not. If further testing shows # that it breaks TD8E support, we will turn it off. FRTS-51.3.3-O.patch8 # The two FUTIL patches only get applied to FUTIL V7 which comes with # OS/8 V3D to bring it up to V7D. MACREL V2 comes with FUTIL V8B, so # these patches are skipped by mkos8 using an RE match on the file name # when the user does not pass --disable-os8-macrel to configure. FUTIL-31.21.1M-v7B.patch8 FUTIL-31.21.2M-v7D.patch8 # FUTIL 31.21.3O switches XS format. Recommend to leave it out. # FUTIL-31.21.3O.patch8 # LQP 21.49.1 consists of commands run in BUILD. # The auto-apply system won't apply it. # It has not been validated. It uses hardware we don't have. ## LQP-21.49.1M-vB.patch8 MCPIP-21.21M-v6B.patch8 MSBAT-31.22.1M-v3B.patch8 PAL8-21.22.1M-v10B.patch8 PAL8-21.22.2M-v10C.patch8 PAL8-21.22.3M-v10D.patch8 # PAL8 21.22.4M is for V12 PAL8. It BREAKS LS output in V10! # DO NOT APPLY THIS PATCH! # PAL8-21.22.4M.patch8 PIP-21.23.1M-v12B.patch8 PIP10-21.24.1M-v3B.patch8 SABR-21.91.1M-v18B.patch8 SET-21.26.1M-v1C.patch8 SET-21.26.2M-v1D.patch8 SET-21.26.3M-v1E.patch8 # TECO 31.20.1 Unconditional no case flagging. Not recommended # TECO-31.20.01O.patch8 # TECO 31.20.2 Turns off verbose errors. Not recommended. # TECO-31.20.02O.patch8 # TECO 31.20.3 Turns off Yank overwrite warning. Not recommended. # TECO-31.20.03O.patch8 # TECO 31.20.4 Special support for VT05. Not recommended. # TECO-31.20.04O.patch8 TECO-31.20.05M-v5A.patch8 TECO-31.20.06M-v5B.patch8 TECO-31.20.07M.v5C.patch8 TECO-31.20.08M-v5.04.patch8 TECO-31.20.10M-5.05.patch8 TECO-31.20.11M-v5.06.patch8 TECO-31.20.12M-v5.07.patch8 TECO-31.20.13M-v5.08.patch8 # # MACREL, LINK, and OVDRV patches have not been validated. # The Version numbers dont all match. Some wont apply. # More work is needed before they are deemed safe. # NOT Recommended. ## MACREL-40.5.1M-v1D.patch8 ## MACREL-40.5.2M-v1E.patch8 ## LINK-40.2.1M-v1D.patch8 ## LINK-40.2.2M-v1E.patch8 ## LINK-40.2.3M-v1F.patch8 # OVRDRV 40.6.1 is a source level patch ## OVRDRV-40.6.1M-v1B-8srccom |
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
|
| < < < < < < < < < < < < < < < < |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
cannot compute difference between binary files
︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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 | > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | dealings in this Software without prior written authorization from those authors. ---------------------------------------------------------------------------- cpu central processor 07-Sep-17 RMS Fixed sim_eval declaration in history routine (COVERITY) 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 |
︙ | ︙ | |||
217 218 219 220 221 222 223 | 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 */ | > | > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | 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 */ #include "pdp8_defs.h" /* ---PiDP add---------------------------------------------------------------------------------------------- */ #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 |
︙ | ︙ | |||
408 409 410 411 412 413 414 | 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; | | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 | 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, 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; |
︙ | ︙ | |||
434 435 436 437 438 439 440 | 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 | | | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | 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, 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: |
︙ | ︙ | |||
1526 1527 1528 1529 1530 1531 1532 | 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 | | < > | 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 | 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, IR, LAC, MQ, IF, DF, SC, int_req, Pause); // 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% } Pause = 0; // it's set outside the "if", so it must be *reset* outside /* ---PiDP end---------------------------------------------------------------------------------------------- */ } /* end while */ /* Simulation halted */ saved_PC = IF | (PC & 07777); /* save copies */ saved_DF = DF & 070000; |
︙ | ︙ | |||
1760 1761 1762 1763 1764 1765 1766 | /* 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; | < | 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 | /* 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; 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)) |
︙ | ︙ | |||
1783 1784 1785 1786 1787 1788 1789 | 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, " "); | | | | 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 | 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[0] = 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; } |
︙ | ︙ | |||
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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: | > > > > | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | authors. */ #include "pidp8i.h" #include "../gpio-common.h" #include "pdp8_defs.h" #include <assert.h> #include <dirent.h> // for USB stick searching #include <errno.h> #include <string.h> //// 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: |
︙ | ︙ | |||
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | // 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; | > > > > | > > | | | | > > > > > | > | 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 | // 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) { extern int suppressILS; 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; case SIM_THROT_SPC: { suppressILS = 1; break; } } if (ips) { suppressILS = 0; 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 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. // // The only non-obvious one is that we use the PDP-8 simulator's IR // register value for the MB lights due to a quirk in the way the // register states are set at the time this function is called; MB // is not passed to us because its value at the call time is bogus. set_pidp8i_row_leds (pd, 0, sPC); set_pidp8i_row_leds (pd, 1, sMA); set_pidp8i_row_leds (pd, 2, sIR); 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]); |
︙ | ︙ | |||
291 292 293 294 295 296 297 | // 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); } | | | > > | | < > > > > > | | > | 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 | // 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 & Execute LEDs are pulsed once per instruction. // On real hardware, the pulses don't happen at exactly the same // time, but we can't simulate that because SIMH handles each CPU // instruction "whole." When running real code, all we care about // is that both LEDs are twiddled so rapidly that they both just // become a 50% blur, mimicking the hardware closely enough. // // The exception is that when the CPU is stopped, both LEDs are off, // because the pulses happen "outside" the STOP state: Fetch before // and Execute after resuming from STOP. 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 |
︙ | ︙ | |||
326 327 328 329 330 331 332 | if (!running || resumeFromInstructionLoopExit) { memcpy(pdis_paint, pdis_update, sizeof(struct display)); } } //// mount_usb_stick_file ////////////////////////////////////////////// | | | | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | if (!running || resumeFromInstructionLoopExit) { memcpy(pdis_paint, pdis_update, sizeof(struct display)); } } //// mount_usb_stick_file ////////////////////////////////////////////// // Search for a PDP-8 media image on a USB device mounted under /media // and attempt to ATTACH it to the simulator. static void mount_usb_stick_file (int devNo, char *devCode) { char sFoundFile[CBUFSIZE] = { '\0' }; char sDirName[CBUFSIZE]; // will be "/media/DIRNAME" 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 |
︙ | ︙ | |||
355 356 357 358 359 360 361 | // 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'; | | > > > > > | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | | > | > > | 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 | // 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'; // Search all directories under /media DIR *pDir1 = opendir ("/media"); if (pDir1) { struct dirent* pDE1; while ((pDE1 = readdir (pDir1)) != 0) { if (pDE1->d_type != DT_DIR) continue; // Found a directory under /media. Search it for plausibly // named files given devCode. snprintf (sDirName, sizeof(sDirName), "/media/%s", pDE1->d_name); DIR *pDir2 = opendir (sDirName); if (pDir2) { struct dirent* pDE2; while ((pDE2 = readdir (pDir2)) != 0) { // search all files in directory if (pDE2->d_name[0] == '.') continue; // dotfiles clutter debug output char* pext = strstr (pDE2->d_name, fileExtension); if (pext && (pext == (pDE2->d_name + strlen (pDE2->d_name) - 3))) { snprintf (sFoundFile, sizeof (sFoundFile), "%s/%s", sDirName, pDE2->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...", pDE2->d_name, sDirName, fileExtension); } #endif } // end while (pDE2...) closedir (pDir2); } // end if (pDir2) else { // USB auto-mounting either doesn't work here or uses // something other than the /media/DIR/FILE.EXT scheme // we expect. printf ("\r\nCannot open %s: %s\r\n", sDirName, strerror (errno)); return; } } // end while (pDE1...) closedir(pDir1); } // end if (pDir1) 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); |
︙ | ︙ |
︙ | ︙ | |||
26 27 28 29 30 31 32 | dealings in this Software without prior written authorization from those authors. */ #if !defined(PIDP8I_H) #define PIDP8I_H | | > | | | | | | | | 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 | dealings in this Software without prior written authorization from those authors. */ #if !defined(PIDP8I_H) #define PIDP8I_H #include <stdint.h> #include <stdlib.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_t 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_t* pM, uint32_t *pPC, uint32_t *pMA, int32_t *pMB, int32_t *pLAC, int32_t *pIF, int32_t *pDF, int32_t* pint_req); extern void set_pidp8i_leds (uint32_t sPC, uint32_t sMA, uint16_t sIR, int32_t sLAC, int32_t sMQ, int32_t sIF, int32_t sDF, int32_t sSC, int32_t int_req, int Pause); #endif // !defined(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 | / 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 $ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 $ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> 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 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 <https://www.gnu.org/licenses/>. Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: <program> Copyright (C) <year> <name of author> This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <https://www.gnu.org/licenses/>. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <https://www.gnu.org/licenses/why-not-lgpl.html>. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 src/cc8/ 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 CC8 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 $@ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # A Minimal Implementation of C for the DEC PDP-8 Processor ## Introduction The C language and its derivatives are now the industry standard for the development of operating systems and utilities. The language has evolved significantly since its initial specification in 1972. At this time, the PDP-7 was used for the initial implementation and the compiler ported to a number of other systems including the PDP-11. Also, the first glimmerings of Unix appeared following a re-write of the assembly language version in C and the rest is of course history. The PDP-8 was introduced by DEC in 1965 at the same time as the PDP-7 with the intention of being a small and cheap processor that could be used in a variety of environments. From this simple machine, the modern desktop device has evolved which I am using to type this document. Nonetheless, far from fading into obscurity, there is a very active group of enthusiasts who have looked to implementing the PDP-8 on modern hardware and the thanks to Oscar Vermuelen and others, we can all have a PDP8/I to play with. With this in mind, I thought it was time to have a modern language compiler running on the PDP-8 which as far as I can tell, the last native compiler developed for the PDP-8 was Pascal in 1979 by Heinz Stegbauer. In more recent times, one cross-compiler has been developed by Vince Slyngstad and updated by Paolo Maffei based on Ron Cain’s Small-C using a VM approach. [This code][sms] is most certainly worth examining, and I am delighted to acknowledge this work as I have used some of the C library code in this project. [sms]: http://so-much-stuff.com/pdp8/C/C.php Finally, I would refer the reader to Fabrice Bellard’s OTCC. It is this bit of remarkable software that suggested that there may be a chance to implement a native PDP-8 compiler. Developing a native compiler for the PDP-8 is not an easy task as this processor has a very limited address space and no hardware stack. And, although the option exists to write the whole thing in assembly language as has been the case for Pascal and Algol, this project has explored the option of writing the compiler itself in C. To this end, 2 compilers have been written. Firstly, a cross-compiler based again on Ron Cain’s Small-C which is used to compile the native OS/8 compiler and library. As yet, the native compiler has rather limited functionality and will not compile itself. The cross-compiler will compile itself but produces an enormous (28K) assembler file which cannot be run on the PDP-8. <a id="cross" name="posix"></a> # The Cross-Compiler The code for this is in the `cross` subdirectory, and is built along with the top-level PiDP-8/I software. When installed, it is in your `PATH` as `cc8`. The CC8 cross-compiler is based upon Ron Cain’s famous Small-C compiler. The reader is directed to the extensive documentation available on the web. The key file is the PDP-8 code generator in `code8.c` which emits SABR — Symbolic Assembler for Binary Relocatable programmes — assembly code. SABR is normally used as the second pass of the OS/8 FORTRAN II system. When you use the cross-compiler on a POSIX type system such as the Raspbian PiDP-8/I environment, the resulting `*.sb` files will have LF-only line endings, but OS/8 expects CR+LF line endings. The `txt2ptp` utility program included with the PiDP-8/I distribution will automatically do that conversion for you when making a SIMH paper tape image file, which you can then read into the OS/8 environment. The cross-compiler has some non-standard features to enable the interface between the main programme and the C library. This constitutes a compile time linkage system to allow for standard and vararg functions to be called in the library. Several of the C programs in this distribution `#include <init.h>` which inserts an assembly language initialization routine into the program at that point using the `#asm` inline assembly feature. This file is symlinked into each directory that has a `*.c` file needing it since CC8 doesn't have an include path feature, and it must be in the current directory in any case when using the OS/8 version of CC8. The `init.h` initialization routine defines some low-level subroutines, initializes the environment for the programs, and calls into the LIBC initialization code. This file was copied to the OS/8 boot disk as `DSK:INIT.H` unless you gave `--disable-os8-cc8` when configuring the PiDP-8/I software. The file `include/libc.h` is likewise copied to `DSK:LIBC.H`. It defines the mappings between the familiar C library routine names and their underlying implementation names. The linking loader determines the core layout for the built programs. Most commonly, it uses this scheme: **Field 0:** FOTRAN library utility functions and OS/8 I/O system **Field 1:** The programme’s runtime stack/globals/literals **Field 2:** The programme's executable code **Field 3:** The LIBC library code Since this memory layout applies to the phases of the CC8 compiler as well, this means that each phase uses approximately 16 kWords of core. <a id="native" name="os8"></a> ## The Native Compiler This compiler is supplied in both source and binary forms as part of the PiDP-8/I software distribution. We ship pre-built binaries to avoid a chicken-and-egg problem: the binaries require a working OS/8 environment to be built, but when the PiDP-8/I build system goes to build the bootable OS/8 media, it expects to have the OS/8 CC8 binaries at hand so it can copy them to the RK05 disk it is building. It's trivial to deal with that on our development systems, since we normally have a working `os8v3d-*.rk05` disk set from the previous build sitting around to bootstrap the process, so we break the cycle at that point rather than do a two-stage RK05 bootstrap build on end-user systems. These pre-built binaries are saved as `media/os8/subsys/cc8.tu56` by the `tools/cc8-tu56-update` script. Basically, that script uses the cross-compiler to produce SABR assembly files for each stage of the OS/8 CC8 compiler, which it then copies into the OS/8 environment, then it assembles, links, and saves the result as `CC*.SV`: 2. `c8.c` → `c8.sb` → `CC.SV`: The compiler driver: accepts the input file name from the user, and calls the first proper compiler stage, `CC1`. Should we add a preprocessor feature, this driver will call it before calling `CC1`. 2. `n8.c` → `n8.sb` → `CC1.SV`: The parser/tokeniser section of the compiler. 3. `p8.c` → `p8.sb` → `CC2.SV`: The token to SABR code converter section of the compiler. 4. `libc.c` → `libc.sb` → `LIBC.RL`: The C library linked to any program built with CC8, including the stages above, but also to your own programs. If you are not changing the OS/8 CC8 source code, you needn't run the `cc8-tu56-update` script or build the OS/8 version of CC8 by hand. The PiDP-8/I build system's OS/8 RK05 media build script copies those files and the other files required for building C programs under OS/8 to the appropriate OS/8 volumes: `CC*.SV` on `SYS:`, and everything else on `DSK:`. Input programs should go on `DSK:`. Compiler outputs are also placed on `DSK:`. To try it out: Boot OS/8 within the PiDP-8/I environment as you normally would. If you're at the Linux command prompt within the PiDP-8/I source tree, you can start it most easily with a `make run` command. With the OS/8 environment running, you can enter a C programme in lower case via the editor, but before doing that, try building a copy of one of the example programs: .R CC ⇠ compiler front end >ps.c ⇠ takes name of C program; creates CC.SB .COMP CC ⇠ compile SABR output of CC8 to CC.RL Link and run it with: .R LOADER *CC,LIBC/G ⇠ CC.RL + pre-built LIBC.RL = runnable program; /G = "go" These steps are wrapped up into the `CC.BI` BATCH file: .EXE CC.BI ⇠ must specify .BI to avoid running CC.SV instead >ps.c ⇠ builds, links, and runs it That demo is particularly interesting. It generates Pascal’s triangle without using factorials, which are a bit out of range for 12 bits! <a id="warning"></a> ## GOVERNMENT HEALTH WARNING **You are hereby warned**: The native OS/8 compiler does not contain any error checking whatsoever. If the source files contain an error or you mistype a build command, you may get: * A runtime crash in the compiler * SABR assembly output that won't assemble * Output that assembles but won't run correctly Rarely will any of these failure modes give any kind of sensible hint as to the cause. OS/8 CC8 cannot afford the hundreds of kilobytes of error checking and text reporting that you get in a modern compiler like GCC or Clang. That would have required a roomful of core memory to achieve on a real PDP-8. Since we're working within the constraints of the old PDP-8 architecture, we only have about 3 kWords to construct the parse result, for example. In addition, the native OS/8 compiler is severely limited in code space, so it does not understand the full C language. It is less functional than K&R C 1978; we do not have a good benchmark for what it compares to in terms of other early C dialects, but we can sum it up in a single word: "primitive." Nonetheless, our highly limited C dialect is Turing complete. It might be better to think of it as a high-level assembly language that resembles C rather than as "C" proper. <a id="cross-fl"></a> ### Features and Limitations of the Cross-Compiler The features of the cross-compiler are basically that of Small-C itself, the primary difference being in the PDP-8 SABR code generator, which doesn't affect its C language support. A good approximation is K&R C (1978) minus: * `struct` and `union` * function pointers * `float` and `long` <a id="features"></a> ### Features of the OS/8 CC8 Compiler The OS/8 version of CC8 is missing many features relative to the cross-compiler, and much more compared to modern C. Before we list those limitations, here is what is known to work: 1. **Local and global variables** 1. **Pointers,** within limitations given in the following section. 1. **Functions:** Parameter lists must be declared in K&R form: int foo (a, b) int a, b; { ... } 1. **Recursion:** See [`FIB.CC`][fib] for an example of this. [fib]: https://tangentsoft.com/pidp8i/doc/src/cc8/examples/fib.c 1. **Simple arithmetic operators:** `+`, `-`, `*`, `/`, etc. 1. **Bitwise operators:** `&`, ¦, `~` and `!` 1. **Simple comparison operators:** False expressions evaluate as 0 and true as -1 in twos complement form, meaning all 1's in binary form. See the list of limitations below for the operators excluded by our "simple" qualifier. 1. **A few 2-character operators:** `++`, `--` (postfix only) and `==`. 1. **Limited library:** See `libc.h` for allowed libc functions, of which there are currently 31, including: 1. **A subset of stdio:** * `fopen` is implemented as void fopen(char *filename, char *mode) The filename must be upper case. Mode is either "w" or "r". * Only 1 input file and 1 output may be open at any one time * `fclose()` only closes the output file. * Call `fopen` to open a new input file. The current file does not need to be closed. * `fprintf`, `fputc`, and `fputs` are as expected. * `fgets` is implemented. It will read and retain CR/LF. It returns a null string on EOF. * `fscanf` is not implemented. Read a line with `fgets()` and then call `sscanf` on it. * `feof` is not implemented; `fgetc` and `fgets` will return a null on EOF. 1. **printf:** See `libc.c` for the allowed format specifiers: `%d`, `%s` etc. Length and width.precision formatting is supported. There are many limitations in this library relative to Standard C or even K&R C, which are documented below. 1. **Limited structuring constructs:** `if`, `while`, `for`, etc. are supported, but they may not work as expected when deeply nested or in long `if/else if/...` chains. <a id="limitations"></a> ### Known Limitations of the OS/8 CC8 Compiler The OS/8 compiler has these known limitations relative to [those of the cross-compiler](#cross-fl): 1. The language is typeless in that everything is a 12 bit integer and any variable/array can interpreted as `int`, `char` or pointer. All variables and arrays must be declared as `int`. The return type may be left off of a function's definition; it is implicitly `int` in all cases, since `void` is not supported. 2. There must be an `int main()` which must be the last function in the single input C file. 3. We do not yet support separate compilation of multiple C modules that get linked together. You can produce relocatable libraries in OS/8 `*.RL` format and link them with the OS/8 LOADER, but because of the previous limitation, only one of these can be written in C. 4. Unlike the CC8 cross-compiler, the OS/8 compiler ignores all C preprocessor directives: `#define`, `#ifdef`, `#include`, etc. This even includes inline assembly via `#asm`! One day, we may add a preprocessor called by the `CC.SV` driver program, but not today. This means you cannot use `#include` directives to string multiple C modules into a single program. If that then makes you wonder how the OS/8 compiler looks up the stock library functions defined in `libc.h` — note that I've resisted using the word "standard" here, for they are anything but that in the Standard C sense — it is that the entry point mappings declared in `libc.h` are hard-coded into the `CC2` compiler stage, implemented in `p8.c`. Similarly, the program initialization code defined in `init.h` is inserted into the program directly by the compiler rather than being pulled in via the preprocessor. Both of these header files must be included when building with the cross-compiler. The examples have these `#include` statements stripped out as they are copied to the OS/8 RK05 disk during the build process. This is done by `bin/cc8-to-os8`, a tool you may find use for yourself if you use both compilers on a single source program. If you have a program that is compiled using both the cross-compiler and the OS/8 compiler, you may wish to use `#include` statements, since the cross-compiler does process them. 5. Variables are implicitly `static`, even when local. 6. Arrays may only be single indexed. See `PS.CC` for an example. 7. The compiler does not yet understand how to assign a variable's initial value as part of its declaration. This: int i = 5; must instead be: int i; i = 5; 8. There is no `&&` nor ¦¦. Neither is there support for complex relational operators like `>=` nor even `!=`. Abandon all hope for complex assignment operators like `+=`. Most of this can be worked around through clever coding. For example, this: if (i != 0 || j == 5) could be rewritten to avoid both missing operators as: if (!(i == 0) | (j == 5)) because a true result in each subexpression yields -1 per the previous point, which when bitwise OR'd together means you get -1 if either subexpression is true, which means the whole expression evaluates to true if either subexpression is true. If the code you were going to write was instead: if (i != 0 || j != 5) then the rewrite is even simpler owing to the rules of [Boolean algebra](https://en.wikipedia.org/wiki/Boolean_algebra): if (!(i == 0 & j == 5)) These rules mean that if we negate the entire expression, we get the same truth table if we flip the operators around and swap the logical test from OR to AND, which in this case converts the expression to a form that is now legal in our limited C dialect. All of this comes from the Laws section of the linked Wikipedia article; if you learn nothing else about Boolean algebra, you would be well served to memorize those rules. 9. `atoi` is non-standard: `int atoi(char *, int *)`, returning the length of the numeric string. 10. `scanf` is not implemented; use `gets` then `sscanf` 11. Dereferencing parenthesized expressions does not work: `*(<expr>)` 12. The stack, which includes all globals and literals, is only 4 kwords. Stack overflow is not detected. Literals are inlcuded in this due to a limitation in the way `COMMN` is implemented in SABR. 13. There is no argument list checking, not even for standard library functions. 14. `do/while` loops are parsed, but the code is not properly generated. Regular `while` loops work fine, however. 15. `switch` doesn't work. <a id="bugs"></a> ### Known Bugs in the OS/8 CC8 Compiler 1. Binary file I/O is not always reliable. You are strongly encouraged to limit I/O to text files. 2. Don’t forget to handle form feed. See `c8.c`. 3. For some obscure reason, always open the input file first, then the output file. I suspect a fault in `libc.c`, which you are welcome to fix, keeping in mind that we're using every trick in the book to fit as much functionality in as we currently do. It may not be possible to make this as reliable as modern C programmers expect. ## Conclusion This is a somewhat limited manual which attempts to give an outline of a very simple compiler for which I apologise as the source code is obscure and badly commented. However, the native OS/8 compiler/tokeniser (`n8.c`) is only 600 lines which is a nothing in the scale of things these days. However, I hope this project gives some insight into compiler design and code generation strategies to target a most remarkable computer. I would also like to give credit to the builders of OS/8 and in particular the FORTRAN II system which was never designed to survive the onslaught of this kind of modern software. Don’t expect too much! This compiler will not build this week’s bleeding edge kernel. But, it may be used to build any number of useful utility programs for OS/8. ## License This document is under the [GNU GPLv3 License][gpl], copyright © May, June, and November 2017 by [Ian Schofield][ian], with assorted updates by [Warren Young][wy] in 2017. [gpl]: https://www.gnu.org/licenses/gpl.html [ian]: mailto:Isysxp@gmail.com [wy]: https://tangentsoft.com/ |
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | This directory contains the sources for the CC8 cross-compiler, which is based on Ron Cain's Small-C system. It is built by the top-level build system as `bin/cc8` and is installed to `$prefix/bin/cc8`. Call it as: cc8 myfile.c The compiler does not have any consequential command line options. The output file is `myfile.s` which is in SABR assembly code, intended to be assembled within the PiDP-8/I OS/8 environment. See the `test` subdirectory and [the top-level README][/doc/trunk/cc8/README.md] for further details. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * This file is part of the CC8 cross-compiler. * * The CC8 cross-compiler 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. * * The CC8 cross-compiler 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 the CC8 cross-compiler as ../GPL3.txt. If not, see * <http://www.gnu.org/licenses/>. */ #define unix #include <stdio.h> #include "defs.h" #include "data.h" #include <string.h> /* Define ASNM and LDNM to the names of the assembler and linker respectively */ /* * Some predefinitions: * * INTSIZE is the size of an integer in the target machine * BYTEOFF is the offset of an byte within an integer on the * target machine. (ie: 8080,pdp11 = 0, 6809 = 1, * 360 = 3) * This compiler assumes that an integer is the SAME length as * a pointer - in fact, the compiler uses INTSIZE for both. */ #define INTSIZE 1 #define BYTEOFF 0 /* * print all assembler info before any code is generated * */ header () { outstr ("/ Small C PDP8 Coder (1.0:27/1/99)"); nl(); FEvers(); nl (); ol ("OPDEF ANDI 0400"); ol ("OPDEF TADI 1400"); ol ("OPDEF ISZI 2400"); ol ("OPDEF DCAI 3400"); ol ("OPDEF JMSI 4400"); ol ("OPDEF JMPI 5400"); ol ("OPDEF MQL 7421"); ol ("OPDEF MQA 7701"); ol ("OPDEF MQO 7501"); ol ("OPDEF SWP 7521"); ol ("OPDEF CDF1 6211"); ol ("OPDEF CDF0 6201"); ol ("OPDEF RIF 6224"); ol ("OPDEF CAF0 6203"); ol ("OPDEF BSW 7002"); ol ("OPDEF CAM 7621"); ol ("/"); return 0; } nl () { outbyte (EOL); /* outbyte (10); */ return 0; } initmac() { defmac("cpm\t1"); defmac("I8080\t1"); defmac("RMAC\t1"); defmac("smallc\t1"); return 0; } galign(t) int t; { return(t); } /* * return size of an integer */ intsize() { return(INTSIZE); } /* * return offset of ls byte within word * (ie: 8080 & pdp11 is 0, 6809 is 1, 360 is 3) */ byteoff() { return(BYTEOFF); } /* * Output internal generated label prefix */ olprfix() { ot("CC"); return 0; } /* * Output a label definition terminator */ col () { outbyte (','); return 0; } /* * begin a comment line for the assembler * */ comment () { outbyte ('/'); return 0; } /* * Emit user label prefix */ prefix () { return 0; } /* Stkbase output stack base->literals =stkp+2 ... ie 202(8) =130(10) + sizeof(globals) */ stkbase() { ot("GBL"); return 0; } /* * print any assembler stuff needed after all code * */ trailer () { // ot("\tENTRY "); // outbyte('M'); // printlabel (litlab); // nl(); outbyte('M'); printlabel (litlab); col(); ot("\t0"); nl(); ol("\tCDF1"); ot("\tTAD L"); printlabel (litlab); nl(); ol ("\tSNA CLA / Any literals to push?"); ot ("\tJMP I M"); printlabel (litlab); nl(); ot("\tTAD X"); printlabel (litlab); nl(); ol ("\tDCA JLC"); outbyte('D'); printlabel (litlab); col(); ol("CDF0"); ot("\tTADI JLC"); nl(); ol ("\tJMSI PSH"); ol ("\tCLA"); ol ("\tISZ JLC"); ot("\tISZ L"); printlabel (litlab); nl(); ot("\tJMP D"); printlabel (litlab); nl(); ot ("\tJMP I M"); printlabel (litlab); nl(); ol("CCEND,\t0"); ol ("END"); return 0; } /* * function prologue */ prologue (sym) char *sym; { return 0; } /* * text (code) segment */ gtext () { /* ol ("cseg"); */ return 0; } /* * data segment */ gdata () { /* ol ("dseg"); */ return 0; } /* * Output the variable symbol at scptr as an extrn or a public */ ppubext(scptr) char *scptr; { if (scptr[STORAGE] == STATIC) return 0; // ot (scptr[STORAGE] == EXTERN ? "extrn\t" : "public\t"); // prefix (); // outstr (scptr); // nl(); return 0; } /* * Output the function symbol at scptr as an extrn or a public */ fpubext(scptr) char *scptr; { /* if (scptr[STORAGE] == STATIC) return; // ot (scptr[OFFSET] == FUNCTION ? "public\t" : "extrn\t"); // prefix (); // outstr (scptr); // nl (); */ return 0; } /* * Output a decimal number to the assembler file */ onum(num) int num; { outdec(num); /* pdp11 needs a "." here */ return 0; } /* * fetch a static memory cell into the primary register getmem (sym) char *sym; { int adr; ol ("\tCLA"); immd3 (); adr=glint(sym)+128; onum(glint(sym)+128); nl(); ol("\tDCA JLC"); ol("\tTADI JLC"); }*/ getmem (sym) char *sym; { int adr; ol ("\tCLA"); immd4 (); adr=glint(sym)+128; onum(glint(sym)+128); nl(); return 0; } /* * fetch a static memory cell into the primary register (pre-increment*/ getincmem (sym) char *sym; { int adr; ol ("\tCLA"); adr=glint(sym)+128; ot ("\tISZI ("); onum(adr); nl(); immd4 (); onum(adr); nl(); return 0; } /* * fetch the address of the specified symbol into the primary register * */ getloc (sym) char *sym; { ol("\tCLA"); ol("\tTAD STKP"); if (sym[STORAGE] == LSTATIC) { immd3 (); printlabel(-1-glint(sym)); nl(); } else { if (stkp-glint(sym)==0) outstr("/"); immd3 (); outdec (stkp-glint(sym)); nl (); } return 0; } /* * store the primary register into the specified static memory cell * putmem (sym) char *sym; { ol("\tMQL"); immd3 (); onum(glint(sym)+128); nl(); ol("\tDCA JLC"); ol("\tMQA"); ol("\tDCAI JLC"); ol("\tTADI JLC"); } */ putmem (sym) char *sym; { ot("\tDCAI ("); onum(glint(sym)+128); nl(); immd4 (); onum(glint(sym)+128); nl(); return 0; } /* * store the specified object type in the primary register * at the address on the top of the stack * */ putstk (typeobj) char typeobj; { ol("\tJMSI PTSK"); stkp = stkp + INTSIZE; return 0; } /* * fetch the specified object type indirect through the primary * register into the primary register * */ indirect (typeobj) char typeobj; { ol("\tDCA JLC"); /* ol("\tCDF1"); */ ol("\tTADI JLC"); return 0; } /* * fetch the specified object type indirect through the primary * register into the primary register (pre-increment) * */ incdirect (typeobj) char typeobj; { ol("\tDCA JLC"); ol("\tISZI JLC"); ol("\tTADI JLC"); return 0; } /* * swap the primary and secondary registers * */ swap () { ol ("\tSWP"); return 0; } /* * Clear primary reg */ cpri() { ol("\tCLA"); return 0; } /* * print partial instruction to get an immediate value into * the primary register * */ immed () { ol ("\tCLA"); ot ("\tTAD ("); return 0; } immd2 () { ol ("\tCLA"); ot ("\tTAD "); return 0; } immd3 () { ot ("\tTAD ("); return 0; } immd4 () { ot("\tTADI ("); return 0; } /* * push the primary register onto the stack * */ gpush () { ol ("\tJMSI PSH"); stkp = stkp - INTSIZE; return 0; } /* * pop the top of the stack into the secondary register * */ gpop () { ol ("\tJMSI POP"); stkp = stkp + INTSIZE; return 0; } /* * swap the primary register and the top of the stack * */ swapstk () { ol ("\tMQL"); gpop(); ol ("\tSWP"); gpush(); ol ("\tSWP"); return 0; } /* * call the specified subroutine name * varag is allowed for libc functions using a v prefix. In this case, the arg count+1 is pushed onto the stack as well. * For the actual routine, the declaration should be a single arg eg printf(int args) in this case, the value of args is the count and &args-args point to the first arg in the caller's list. */ gcall (sname,nargs) char *sname; int *nargs; { char tm[10]; if (strstr(sname,"vlibc")) { immed(); sname++; outdec(*nargs); outstr("\t/ PUSH ARG COUNT"); nl(); ol("\tJMSI PSH"); stkp = stkp - INTSIZE; (*nargs)++; } if (strstr(sname,"libc")) { strcpy(tm,sname); immed(); outstr(tm+4); nl(); ol("\tMQL"); ol("\tCALL 1,LIBC"); ol("\tARG STKP"); ol("\tCDF1"); /* Make sure DF is correct */ return 0; } ol("\tCPAGE 2"); ol("\tJMSI PCAL"); ot ("\t"); outstr (sname); nl (); return 0; } stri() { ol("\tDCAI 10"); return 0; } iinit() { ol("\tCIA;CMA"); ol("\tDCA 10"); return 0; } /* * return from subroutine * */ gret (sym) char *sym; { ol ("\tJMPI POPR"); return 0; } /* * perform subroutine call to value on top of stack * */ callstk () { immed (); outstr ("$+5"); nl (); swapstk (); ol ("pchl"); stkp = stkp + INTSIZE; return 0; } /* * jump to specified internal label number * */ jump (label) int label; { ot ("\tJMP\t"); printlabel (label); nl (); return 0; } /* * test the primary register and jump if false to label * */ testjump (label, ft) int label, ft; { if (ft) ol ("\tSZA"); else ol ("\tSNA"); jump (label); return 0; } casejump() { ol("\tTAD TMP"); ol("\tSNA CLA"); return 0; } /* * print pseudo-op to define a byte * */ defbyte () { ot ("\t"); return 0; } /* * print pseudo-op to define storage * */ defstorage () { ot ("COMMN\t"); return 0; } /* * print pseudo-op to define a word * */ defword () { ot ("\t"); return 0; } /* * modify the stack pointer to the new value indicated * */ modstk (newstkp) int newstkp; { int k; k = galign(stkp-newstkp); if (k == 0) return (newstkp); if (k>0 && k<5) { while (k--) ol ("\tISZ STKP"); return (newstkp); } ol ("\tMQL"); immd3 (); outdec (k); nl (); ol ("\tTAD STKP"); ol ("\tDCA STKP"); swap (); return (newstkp); } /* * multiply the primary register by INTSIZE */ gaslint () { return 0; } /* * divide the primary register by INTSIZE */ gasrint() { return 0; } /* * Case jump instruction */ gjcase() { ol ("\tCIA"); ol ("\tDCA TMP"); return 0; } /* * add the primary and secondary registers * if lval2 is int pointer and lval is not, scale lval */ gadd (lval,lval2) int *lval,*lval2; { /* if (lval==0) ol("\tCIA");*/ ol("\tDCA JLC"); ol("\tJMSI POP"); ol("\tMQA"); ol("\tTAD JLC"); stkp = stkp + INTSIZE; return 0; } /* * subtract the primary register from the secondary * */ gsub () { ol("\tCIA"); ol("\tDCA JLC"); ol("\tJMSI POP"); ol("\tMQA"); ol("\tTAD JLC"); stkp = stkp + INTSIZE; return 0; } /* * multiply the primary and secondary registers * (result in primary) * */ gmult () { ol("\tDCA JLC"); ol("\tJMSI POP"); ol("\tMQA"); ol("\tCALL 1,MPY"); ol("\tARG JLC"); ol("\tCDF1"); stkp = stkp + INTSIZE; return 0; } /* * divide the secondary register by the primary * (quotient in primary, remainder in secondary) * */ gdiv () { ol("\tDCA JLC"); ol("\tJMSI POP"); ol("\tMQA"); ol("\tCALL 1,DIV"); ol("\tARG JLC"); ol("\tCDF1"); stkp = stkp + INTSIZE; return 0; } /* * compute the remainder (mod) of the secondary register * divided by the primary register * (remainder in primary, quotient in secondary) * */ gmod () { ol("\tDCA JLC"); ol("\tJMSI POP"); ol("\tMQA"); ol("\tCALL 1,DIV"); ol("\tARG JLC"); ol("\tCALL 1,IREM"); ol("\tARG 0"); ol("\tCDF1"); stkp = stkp + INTSIZE; return 0; } /* * inclusive 'or' the primary and secondary registers * */ gor () { ol("\tJMSI POP"); ol("\tMQA"); stkp = stkp + INTSIZE; return 0; } /* * exclusive 'or' the primary and secondary registers * */ gxor () { gpop(); gcall ("?xor"); return 0; } /* * 'and' the primary and secondary registers * */ gand () { ol("\tDCA JLC"); ol("\tJMSI POP"); ol("\tMQA"); ol("\tAND JLC"); stkp = stkp + INTSIZE; return 0; } /* * arithmetic shift right the secondary register the number of * times in the primary register * (results in primary register) * */ gasr () { int lbl; lbl=getlabel(); ol("\tCIA"); ol("\tJMSI POP"); gnlabel(lbl); ol("\tSWP"); ol("\tCLL RAR"); ol("\tSWP"); ol("\tIAC"); ol("\tSZA"); jump(lbl); ol("\tSWP"); stkp = stkp + INTSIZE; return 0; } /* * arithmetic shift left the secondary register the number of * times in the primary register * (results in primary register) * */ gasl () { int lbl; lbl=getlabel(); ol("\tCIA"); ol("\tJMSI POP"); gnlabel(lbl); ol("\tSWP"); ol("\tCLL RAL"); ol("\tSWP"); ol("\tIAC"); ol("\tSZA"); jump(lbl); ol("\tSWP"); stkp = stkp + INTSIZE; return 0; } /* * two's complement of primary register * */ gneg () { ol("\tCIA"); return 0; } /* * logical complement of primary register * */ glneg () { ol("\tSNA CLA"); ol("\tCMA"); return 0; } /* * one's complement of primary register * */ gcom () { ol("\tCMA"); return 0; } /* * Convert primary value into logical value (0 if 0, 1 otherwise) * */ gbool () { ol("\tSZA CLA"); ol("\tIAC"); return 0; } /* * increment the primary register by 1 if char, INTSIZE if * int */ ginc (lval) int lval[]; { ol ("\tIAC"); /* if (lval[2] == CINT) // ol ("inx\th"); */ return 0; } /* * Shortened INC */ gisz (lval) int *lval; { int adr; char *sym=lval[0]; if (lval[1]) { ol ("\tISZI JLC"); return 0; } ot ("\tISZI ("); adr=stkp-glint(sym); // if (lval[STORAGE] == PUBLIC) adr=glint(sym)+128; onum(adr); nl(); return 0; } /* * decrement the primary register by one if char, INTSIZE if * int */ gdec (lval) int lval[]; { ol ("\tTAD (-1"); /* if (lval[2] == CINT) // ol("dcx\th"); */ return 0; } /* * following are the conditional operators. * they compare the secondary register against the primary register * and put a literl 1 in the primary if the condition is true, * otherwise they clear the primary register * */ /* * equal * */ geq () { ol("\tCIA"); ol("\tTADI STKP"); gpop(); ol("\tSNA CLA"); ol("\tCMA"); return 0; } /* * not equal * */ gne () { gpop(); ol("\tCIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); return 0; } /* * less than (signed) * */ glt () { gpop(); ol("\tCIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tAND (2048"); return 0; } /* * less than or equal (signed) * */ gle () { gpop(); ol("\tCIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tSNA"); ol("\tCLA CMA"); ol("\tAND (2048"); return 0; } /* * greater than (signed) * */ ggt () { gpop(); ol("\tSWP"); ol("\tCIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tAND (2048"); return 0; } /* * greater than or equal (signed) * */ gge () { gpop(); ol("\tSWP"); ol("\tCIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tSNA"); ol("\tCLA CMA"); ol("\tAND (2048"); return 0; } /* * less than (unsigned) * */ gult () { gpop(); ol("\tCLL CIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tSNL CLA"); ol("\tIAC"); return 0; } /* * less than or equal (unsigned) * */ gule () { gpop(); ol("\tCLL CIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tSNL CLA"); ol("\tIAC"); return 0; } /* * greater than (unsigned) * */ gugt () { gpop(); ol("\tCLL CIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tSNA SZL CLA"); ol("\tIAC"); return 0; } /* * greater than or equal (unsigned) * */ guge () { gpop(); ol("\tSWP"); ol("\tCLL CIA"); ol("\tDCA JLC"); ol("\tMQA"); ol("\tTAD JLC"); ol("\tSNL CLA"); ol("\tIAC"); return 0; } /* Squirrel away argument count in a register that modstk doesn't touch. */ gnargs(d) int d; { /* ot ("mvi\ta,"); // onum(d); // nl (); */ return 0; } assemble(s) char *s; { #ifdef ASNM char buf[100]; strcpy(buf, ASNM); strcat(buf, " "); strcat(buf, s); buf[strlen(buf)-1] = 's'; return(system(buf)); #else return(0); #endif } |
> | 1 | /* Nothing needed in this file */ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File data.c: 2.2 (84/11/27,16:26:13) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" /* storage words */ char symtab[SYMTBSZ]; char *glbptr, *rglbptr, *locptr; int ws[WSTABSZ]; int *wsptr; int swstcase[SWSTSZ]; int swstlab[SWSTSZ]; int swstp; char litq[LITABSZ]; int litptr; char macq[MACQSIZE]; int macptr; char line[LINESIZE]; char mline[LINESIZE]; int lptr, mptr, gsize; /* miscellaneous storage */ int nxtlab, litlab, stkp, argstk, ncmp, errcnt, glbflag, ctext, cmode, lastst, inbreak; FILE *input, *input2, *output; FILE *inclstk[INCLSIZ]; int inclsp; char fname[NAMESIZE]; FILE *bfile; char quote[2]; unsigned char *cptr; int *iptr; int fexitlab; int iflevel, skiplevel; int errfile; int sflag; int cflag; int errs; int aflag; |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File data.h: 2.2 (84/11/27,16:26:11) */ /* storage words */ extern char symtab[]; extern char *glbptr, *rglbptr, *locptr; extern int ws[]; extern int *wsptr; extern int swstcase[]; extern int swstlab[]; extern int swstp; extern char litq[]; extern int litptr; extern char macq[]; extern int macptr; extern char line[]; extern char mline[]; extern int lptr, mptr, gsize; /* miscellaneous storage */ extern int nxtlab, litlab, stkp, argstk, ncmp, errcnt, glbflag, ctext, cmode, lastst, inbreak; extern FILE *input, *input2, *output, *bfile; extern FILE *inclstk[]; extern int inclsp; extern char fname[]; extern char quote[]; extern char *cptr; extern int *iptr; extern int fexitlab; extern int iflevel, skiplevel; extern int errfile; extern int sflag; extern int cflag; extern int errs; extern int aflag; |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File defs.h: 2.1 (83/03/21,02:07:20) */ #define FOREVER for(;;) #define FALSE 0 #define TRUE 1 #define NO 0 #define YES 1 /* miscellaneous */ #define EOS 0 #define EOL 10 #define BKSP 8 #define CR 13 #define FFEED 12 #define TAB 9 /* symbol table parameters */ #define SYMSIZ 14 #define SYMTBSZ 2800 #define NUMGLBS 150 #define STARTGLB symtab #define ENDGLB (STARTGLB+NUMGLBS*SYMSIZ) #define STARTLOC (ENDGLB+SYMSIZ) #define ENDLOC (symtab+SYMTBSZ-SYMSIZ) /* symbol table entry format */ #define NAME 0 #define IDENT 9 #define TYPE 10 #define STORAGE 11 #define OFFSET 12 /* system-wide name size (for symbols) */ #define NAMESIZE 20 #define NAMEMAX 20 /* possible entries for "ident" */ #define VARIABLE 1 #define ARRAY 2 #define POINTER 3 #define FUNCTION 4 /* possible entries for "type" */ #define CCHAR 1 #define CINT 2 /* possible entries for storage */ #define PUBLIC 1 #define AUTO 2 #define EXTERN 3 #define STATIC 4 #define LSTATIC 5 #define DEFAUTO 6 /* "do"/"for"/"while"/"switch" statement stack */ #define WSTABSZ 100 #define WSSIZ 7 #define WSMAX ws+WSTABSZ-WSSIZ /* entry offsets in "do"/"for"/"while"/"switch" stack */ #define WSSYM 0 #define WSSP 1 #define WSTYP 2 #define WSCASEP 3 #define WSTEST 3 #define WSINCR 4 #define WSDEF 4 #define WSBODY 5 #define WSTAB 5 #define WSEXIT 6 /* possible entries for "wstyp" */ #define WSWHILE 0 #define WSFOR 1 #define WSDO 2 #define WSSWITCH 3 /* "switch" label stack */ #define SWSTSZ 100 /* literal pool */ #define LITABSZ 2000 #define LITMAX LITABSZ-1 /* input line */ #define LINESIZE 200 #define LINEMAX (LINESIZE-1) #define MPMAX LINEMAX /* macro (define) pool */ #define MACQSIZE 1000 #define MACMAX (MACQSIZE-1) /* "include" stack */ #define INCLSIZ 3 /* statement types (tokens) */ #define STIF 1 #define STWHILE 2 #define STRETURN 3 #define STBREAK 4 #define STCONT 5 #define STASM 6 #define STEXP 7 #define STDO 8 #define STFOR 9 #define STSWITCH 10 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File error.c: 2.1 (83/03/20,16:02:00) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" error (ptr) char ptr[]; { FILE *tempfile; tempfile = output; output = stdout; doerror(ptr); output = tempfile; doerror(ptr); errcnt++; return 0; } doerror(ptr) char *ptr; { int k; comment (); outstr (line); nl (); comment (); k = 0; while (k < lptr) { if (line[k] == 9) tab (); else outbyte (' '); k++; } outbyte ('^'); nl (); comment (); outstr ("****** "); outstr (ptr); outstr (" ******"); nl (); return 0; } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File expr.c: 2.2 (83/06/21,11:24:26) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* * lval[0] - symbol table address, else 0 for constant * lval[1] - type indirect object to fetch, else 0 for static object * lval[2] - type pointer or array, else 0 */ expression (comma) int comma; { int lval[3]; do { if (heir1 (lval)) rvalue (lval); if (!comma) return 0; } while (match (",")); return 0; } heir1 (lval) int lval[]; { int k, lval2[3]; char fc; k = heir1a (lval); if (match ("=")) { if (k == 0) { needlval (); return (0); } if (lval[1]) gpush (); if (heir1 (lval2)) rvalue (lval2); store (lval); return (0); } else { fc = ch(); if (match ("-=") || match ("+=") || match ("*=") || match ("/=") || match ("%=") || match (">>=") || match ("<<=") || match ("&=") || match ("^=") || match ("|=")) { if (k == 0) { needlval (); return (0); } if (lval[1]) gpush (); rvalue (lval); gpush (); if (heir1 (lval2)) rvalue (lval2); switch (fc) { case '-': { if (dbltest(lval,lval2)) gaslint(); gsub(); result (lval, lval2); break; } case '+': { if (dbltest(lval,lval2)) gaslint(); gadd (lval,lval2); result(lval,lval2); break; } case '*': gmult (); break; case '/': gdiv (); break; case '%': gmod (); break; case '>': gasr (); break; case '<': gasl (); break; case '&': gand (); break; case '^': gxor (); break; case '|': gor (); break; } store (lval); return (0); } else return (k); } } heir1a (lval) int lval[]; { int k, lval2[3], lab1, lab2; k = heir1b (lval); blanks (); if (ch () != '?') return (k); if (k) rvalue (lval); FOREVER if (match ("?")) { testjump (lab1 = getlabel (), FALSE); if (heir1b (lval2)) rvalue (lval2); jump (lab2 = getlabel ()); printlabel (lab1); col (); nl (); blanks (); if (!match (":")) { error ("missing colon"); return (0); } if (heir1b (lval2)) rvalue (lval2); printlabel (lab2); col (); nl (); } else return (0); } heir1b (lval) int lval[]; { int k, lval2[3], lab; k = heir1c (lval); blanks (); if (!sstreq ("||")) return (k); if (k) rvalue (lval); FOREVER if (match ("||")) { testjump (lab = getlabel (), TRUE); if (heir1c (lval2)) rvalue (lval2); printlabel (lab); col (); nl (); gbool(); } else return (0); } heir1c (lval) int lval[]; { int k, lval2[3], lab; k = heir2 (lval); blanks (); if (!sstreq ("&&")) return (k); if (k) rvalue (lval); FOREVER if (match ("&&")) { testjump (lab = getlabel (), FALSE); if (heir2 (lval2)) rvalue (lval2); printlabel (lab); col (); nl (); gbool(); } else return (0); } heir2 (lval) int lval[]; { int k, lval2[3]; k = heir3 (lval); blanks (); if ((ch() != '|') | (nch() == '|') | (nch() == '=')) return (k); if (k) rvalue (lval); FOREVER { if ((ch() == '|') & (nch() != '|') & (nch() != '=')) { inbyte (); gpush (); if (heir3 (lval2)) rvalue (lval2); gor (); blanks(); } else return (0); } } heir3 (lval) int lval[]; { int k, lval2[3]; k = heir4 (lval); blanks (); if ((ch () != '^') | (nch() == '=')) return (k); if (k) rvalue (lval); FOREVER { if ((ch() == '^') & (nch() != '=')){ inbyte (); gpush (); if (heir4 (lval2)) rvalue (lval2); gxor (); blanks(); } else return (0); } } heir4 (lval) int lval[]; { int k, lval2[3]; k = heir5 (lval); blanks (); if ((ch() != '&') | (nch() == '|') | (nch() == '=')) return (k); if (k) rvalue (lval); FOREVER { if ((ch() == '&') & (nch() != '&') & (nch() != '=')) { inbyte (); gpush (); if (heir5 (lval2)) rvalue (lval2); gand (); blanks(); } else return (0); } } heir5 (lval) int lval[]; { int k, lval2[3]; k = heir6 (lval); blanks (); if (!sstreq ("==") & !sstreq ("!=")) return (k); if (k) rvalue (lval); FOREVER { if (match ("==")) { gpush (); if (heir6 (lval2)) rvalue (lval2); geq (); } else if (match ("!=")) { gpush (); if (heir6 (lval2)) rvalue (lval2); gne (); } else return (0); } } heir6 (lval) int lval[]; { int k, lval2[3]; k = heir7 (lval); blanks (); if (!sstreq ("<") && !sstreq ("<=") && !sstreq (">=") && !sstreq (">")) return (k); if (sstreq ("<<") || sstreq (">>")) return (k); if (k) rvalue (lval); FOREVER { if (match ("<=")) { gpush (); if (heir7 (lval2)) rvalue (lval2); if (lval[2] || lval2[2]) { gule (); continue; } gle (); } else if (match (">=")) { gpush (); if (heir7 (lval2)) rvalue (lval2); if (lval[2] || lval2[2]) { guge (); continue; } gge (); } else if ((sstreq ("<")) && !sstreq ("<<")) { inbyte (); gpush (); if (heir7 (lval2)) rvalue (lval2); if (lval[2] || lval2[2]) { gult (); continue; } glt (); } else if ((sstreq (">")) && !sstreq (">>")) { inbyte (); gpush (); if (heir7 (lval2)) rvalue (lval2); if (lval[2] || lval2[2]) { gugt (); continue; } ggt (); } else return (0); blanks (); } } heir7 (lval) int lval[]; { int k, lval2[3]; k = heir8 (lval); blanks (); if (!sstreq (">>") && !sstreq ("<<") || sstreq(">>=") || sstreq("<<=")) return (k); if (k) rvalue (lval); FOREVER { if (sstreq(">>") && ! sstreq(">>=")) { inbyte(); inbyte(); gpush (); if (heir8 (lval2)) rvalue (lval2); gasr (); } else if (sstreq("<<") && ! sstreq("<<=")) { inbyte(); inbyte(); gpush (); if (heir8 (lval2)) rvalue (lval2); gasl (); } else return (0); blanks(); } } heir8 (lval) int lval[]; { int k, lval2[3]; k = heir9 (lval); blanks (); if ((ch () != '+') & (ch () != '-') | nch() == '=') return (k); if (k) rvalue (lval); FOREVER { if (match ("+")) { gpush (); if (heir9 (lval2)) rvalue (lval2); /* if left is pointer and right is int, scale right */ if (dbltest (lval, lval2)) gaslint (); /* will scale left if right int pointer and left int */ gadd (lval,lval2); result (lval, lval2); } else if (match ("-")) { gpush (); if (heir9 (lval2)) rvalue (lval2); /* if dbl, can only be: pointer - int, or pointer - pointer, thus, in first case, int is scaled up, in second, result is scaled down. */ if (dbltest (lval, lval2)) gaslint (); gsub (); /* if both pointers, scale result */ if ((lval[2] == CINT) && (lval2[2] == CINT)) { gasrint(); /* divide by intsize */ } result (lval, lval2); } else return (0); } } heir9 (lval) int lval[]; { int k, lval2[3]; k = heir10 (lval); blanks (); if (((ch () != '*') && (ch () != '/') && (ch () != '%')) || (nch() == '=')) return (k); if (k) rvalue (lval); FOREVER { if (match ("*")) { gpush (); if (heir10 (lval2)) rvalue (lval2); gmult (); } else if (match ("/")) { gpush (); if (heir10 (lval2)) rvalue (lval2); gdiv (); } else if (match ("%")) { gpush (); if (heir10 (lval2)) rvalue (lval2); gmod (); } else return (0); } } heir10 (lval) int lval[]; { int k; unsigned char *ptr; if (match ("++")) { if ((k = heir10 (lval)) == 0) { needlval (); return (0); } // if (lval[1]) // gpush (); rivalue (lval); // ginc (lval); // store (lval); return (0); } else if (match ("--")) { if ((k = heir10 (lval)) == 0) { needlval (); return (0); } if (lval[1]) gpush (); rvalue (lval); gdec (lval); store (lval); return (0); } else if (match ("-")) { k = heir10 (lval); if (k) rvalue (lval); gneg (); return (0); } else if (match ("~")) { k = heir10 (lval); if (k) rvalue (lval); gcom (); return (0); } else if (match ("!")) { k = heir10 (lval); if (k) rvalue (lval); glneg (); return (0); } else if (ch()=='*' && nch() != '=') { inbyte(); k = heir10 (lval); if (k) rvalue (lval); if (ptr = lval[0]) lval[1] = ptr[TYPE]; else lval[1] = CINT; lval[2] = 0; /* flag as not pointer or array */ return (1); } else if (ch()=='&' && nch()!='&' && nch()!='=') { inbyte(); k = heir10 (lval); if (k == 0) { error ("illegal address"); return (0); } ptr = lval[0]; lval[2] = ptr[TYPE]; if (lval[1]) return (0); /* global and non-array */ immed (); k=128+ptr[OFFSET]+ptr[OFFSET+1]*256; onum(k); ot("\t/Offset from stackbase at 128 (200(8))"); nl (); lval[1] = ptr[TYPE]; return (0); } else { k = heir11 (lval); if (match ("++")) { if (k == 0) { needlval (); return (0); } // if (lval[1]) // gpush (); rvalue (lval); gisz (lval); // ginc (lval); // store (lval); // gdec (lval); return (0); } else if (match ("--")) { if (k == 0) { needlval (); return (0); } if (lval[1]) gpush (); rvalue (lval); gdec (lval); store (lval); ginc (lval); return (0); } else return (k); } } heir11 (lval) int *lval; { int k; char *ptr; k = primary (lval); ptr = lval[0]; blanks (); if ((ch () == '[') | (ch () == '(')) FOREVER { if (match ("[")) { if (ptr == 0) { error ("can't subscript"); junk (); needbrack ("]"); return (0); } else if (ptr[IDENT] == POINTER) rvalue (lval); else if (ptr[IDENT] != ARRAY) { error ("can't subscript"); k = 0; } gpush (); expression (YES); needbrack ("]"); if (ptr[TYPE] == CINT) gaslint (); gadd (NULL,NULL); lval[0] = 0; lval[1] = ptr[TYPE]; k = 1; } else if (match ("(")) { if (ptr == 0) callfunction (0); else if (ptr[IDENT] != FUNCTION) { rvalue (lval); callfunction (0); } else callfunction (ptr); k = lval[0] = 0; } else return (k); } if (ptr == 0) return (k); if (ptr[IDENT] == FUNCTION) { immed (); prefix (); outstr (ptr); nl (); return (0); } return (k); } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File function.c: 2.1 (83/03/20,16:02:04) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* * begin a function * * called from "parse", this routine tries to make a function out * of what follows * modified version. p.l. woods * */ int argtop; newfunc () { char n[NAMESIZE], *ptr, rtn[NAMESIZE]; fexitlab = getlabel(); if (!symname (n) ) { error ("illegal function or declaration"); kill_line (); return 0; } if (ptr = findglb (n)) { if (ptr[IDENT] != FUNCTION) multidef (n); else if (ptr[OFFSET] == FUNCTION) multidef (n); else ptr[OFFSET] = FUNCTION; } else addglb (n, FUNCTION, CINT, 0, PUBLIC); // Do not allocate any storage to global functions if (!match ("(")) error ("missing open paren"); prefix (); if (astreq(n,"main",4)) { if (inbreak) { ol("\tEND"); output=bfile; } outstr("xmain"); } else outstr (n); strcpy(rtn,n); col (); // outstr("\t0"); nl (); if (inbreak) { ol("\tCLA CLL"); ol("\tCALL 2,PGINIT"); ol("\tARG STKP"); ol("\tARG GBL"); } prologue (rtn); locptr = STARTLOC; argstk = 0; while (!match (")")) { if (symname (n)) { if (findloc (n)) multidef (n); else { addloc (n, 0, 0, argstk, AUTO); argstk = argstk + intsize(); } } else { error ("illegal argument name"); junk (); } blanks (); if (!streq (line + lptr, ")")) { if (!match (",")) error ("expected comma"); } if (endst ()) break; } stkp = 0; argtop = argstk; while (argstk) { if (amatch ("register", 8)) { if (amatch("char", 4)) getarg(CCHAR); else if (amatch ("int", 3)) getarg(CINT); else getarg(CINT); ns(); } else if (amatch ("char", 4)) { getarg (CCHAR); ns (); } else if (amatch ("int", 3)) { getarg (CINT); ns (); } else { error ("wrong number args"); break; } } statement(YES); printlabel(fexitlab); col(); nl(); if (astreq(n,"main",4)) /* On exit from main pop literal table as well */ modstk(0); else modstk (0); gret (rtn); stkp = 0; locptr = STARTLOC; return 0; } /* * declare argument types * * called from "newfunc", this routine add an entry in the local * symbol table for each named argument * completely rewritten version. p.l. woods * */ getarg (t) int t; { int j, legalname, address; char n[NAMESIZE], c, *argptr; FOREVER { if (argstk == 0) return 0; if (match ("*")) j = POINTER; else j = VARIABLE; if (!(legalname = symname (n))) illname (); if (match ("[")) { while (inbyte () != ']') if (endst ()) break; j = POINTER; } if (legalname) { if (argptr = findloc (n)) { argptr[IDENT] = j; argptr[TYPE] = t; address = argtop - glint(argptr); if (t == CCHAR && j == VARIABLE) address = address + byteoff(); argptr[OFFSET] = (address) & 0xff; argptr[OFFSET + 1] = (address >> 8) & 0xff; } else error ("expecting argument name"); } argstk = argstk - intsize(); if (endst ()) return 0; if (!match (",")) error ("expected comma"); } } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File gen.c: 2.1 (83/03/20,16:02:06) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* ToUpper routine */ ucase(ch) int ch; { if ('a'>ch || ch>'z') return(ch); return(ch-32); } /* * return next available internal label number * */ getlabel () { return (nxtlab++); } /* * print specified number as label */ printlabel (label) int label; { olprfix (); outdec (label); return 0; } /* * glabel - generate label */ glabel (lab) char *lab; { prefix (); outstr (lab); col (); nl (); return 0; } /* * gnlabel - generate numeric label */ gnlabel (nlab) int nlab; { printlabel (nlab); col (); nl (); return 0; } outbyte (c) char c; { if (c == 0) return (0); fputc (c, output); return (c); } outstr (ptr) char ptr[]; { int k; k = 0; while (outbyte (ucase(ptr[k++]))); return 0; } tab () { outbyte (9); return 0; } ol (ptr) char ptr[]; { ot (ptr); nl (); return 0; } ot (ptr) char ptr[]; { outstr (ptr); return 0; } outdec (number) int number; { int k, zs; char c; if (number == -32768) { outstr ("-32768"); return 0; } zs = 0; k = 10000; if (number < 0) { number = (-number); outbyte ('-'); } while (k >= 1) { c = number / k + '0'; if ((c != '0' | (k == 1) | zs)) { zs = 1; outbyte (c); } number = number % k; k = k / 10; } return 0; } store (lval) int *lval; { if (lval[1] == 0) putmem (lval[0]); else putstk (lval[1]); return 0; } rvalue (lval) int *lval; { if ((lval[0] != 0) & (lval[1] == 0)) getmem (lval[0]); else indirect (lval[1]); return 0; } rivalue (lval) int *lval; { if ((lval[0] != 0) & (lval[1] == 0)) getincmem (lval[0]); else incdirect (lval[1]); return 0; } test (label, ft) int label, ft; { needbrack ("("); expression (YES); needbrack (")"); testjump (label, ft); return 0; } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File io.c: 2.1 (83/03/20,16:02:07) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* * open input file */ openin (p) char *p; { strcpy(fname, p); fixname (fname); if (!checkname (fname)) return (NO); if ((input = fopen (fname, "r")) == NULL) { pl ("Open failure\n"); return (NO); } kill_line (); return (YES); } /* * open output file */ openout () { outfname (fname); if ((output = fopen (fname, "w")) == NULL) { pl ("Open failure"); return (NO); } kill_line (); return (YES); } /* * Change input filename to output filename. We already checked that * the input file name matches *.c, so we replace the 'c' with an 's' * and then, space permitting, append a 'b'. * */ outfname (s) char *s; { char *os = s; while (*s) s++; *--s = 's'; if ((s - os) < (NAMESIZE - 2)) { *++s = 'b'; *++s = '\0'; } return 0; } /* * remove NL from filenames * */ fixname (s) char *s; { while (*s && *s++ != EOL); if (!*s) return 0; *(--s) = 0; return 0; } /* * check that filename is "*.c" */ checkname (s) char *s; { while (*s) s++; if (*--s != 'c') return (NO); if (*--s != '.') return (NO); return (YES); } kill_line () { lptr = 0; line[lptr] = 0; return 0; } inln () { int k; FILE *unit; FOREVER { if (feof (input)) return 0; if ((unit = input2) == NULL) unit = input; kill_line (); while ((k = fgetc (unit)) != EOF) { if ((k == EOL) | (lptr >= LINEMAX)) break; if (k != 13) line[lptr++] = k; } line[lptr] = 0; if (output && cmode) { outstr("/\t"); ol(line); } if (k <= 0) if (input2 != NULL) { input2 = inclstk[--inclsp]; fclose (unit); } if (lptr) { if ((ctext) & (cmode)) { comment (); outstr (line); nl (); } lptr = 0; return 0; } } } inbyte () { while (ch () == 0) { if (feof (input)) return (0); preprocess (); } return (gch ()); } inchar () { if (ch () == 0) inln (); if (feof (input)) return (0); return (gch ()); } gch () { if (ch () == 0) return (0); else return (line[lptr++] & 127); } nch () { if (ch () == 0) return (0); else return (line[lptr + 1] & 127); } ch () { return (line[lptr] & 127); } /* * print a carriage return and a string only to console * */ pl (str) char *str; { int k; k = 0; putchar (EOL); while (str[k]) putchar (str[k++]); return 0; } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File lex.c: 2.1 (83/03/20,16:02:09) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* * semicolon enforcer * * called whenever syntax requires a semicolon * */ ns () { if (!match (";")) error ("missing semicolon"); return 0; } junk () { if (an (inbyte ())) while (an (ch ())) gch (); else while (an (ch ())) { if (ch () == 0) break; gch (); } blanks (); return 0; } endst () { blanks (); return ((streq (line + lptr, ";") | (ch () == 0))); } needbrack (str) char *str; { if (!match (str)) { error ("missing bracket"); comment (); outstr (str); nl (); } return 0; } /* * test if given character is alpha * */ alpha (c) char c; { c = c & 127; return (((c >= 'a') & (c <= 'z')) | ((c >= 'A') & (c <= 'Z')) | (c == '_')); } /* * test if given character is numeric * */ numeric (c) char c; { c = c & 127; return ((c >= '0') & (c <= '9')); } /* * test if given character is alphanumeric * */ an (c) char c; { return ((alpha (c)) | (numeric (c))); } sstreq (str1) char *str1; { return (streq(line + lptr, str1)); } streq (str1, str2) char str1[], str2[]; { int k; k = 0; while (str2[k]) { if ((str1[k] != str2[k])) return (0); k++; } return (k); } astreq (str1, str2, len) char str1[], str2[]; int len; { int k; k = 0; while (k < len) { if ((str1[k] != str2[k])) break; if (str1[k] == 0) break; if (str2[k] == 0) break; k++; } if (an (str1[k])) return (0); if (an (str2[k])) return (0); return (k); } match (lit) char *lit; { int k; blanks (); if (k = streq (line + lptr, lit)) { lptr = lptr + k; return (1); } return (0); } amatch (lit, len) char *lit; int len; { int k; blanks (); if (k = astreq (line + lptr, lit, len)) { lptr = lptr + k; while (an (ch ())) inbyte (); return (1); } return (0); } blanks () { FOREVER { while (ch () == 0) { preprocess (); if (feof (input)) break; } if (ch () == ' ') gch (); else if (ch () == 9) gch (); else return 0; } } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File main.c: 2.7 (84/11/28,10:14:56) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" main (argc, argv) int argc; char** argv; /* OS/8 CC8 can't cope, but bootstrapping CC8 doesn't work, either */ { char *p,*bp; int smacptr; macptr = 0; ctext = 0; argc--; argv++; errs = 0; aflag = 1; while (p = *argv++) if (*p == '-') while (*++p) switch(*p) { case 't': case 'T': ctext = 1; break; case 's': case 'S': sflag = 1; break; case 'c': case 'C': cflag = 1; break; case 'a': case 'A': aflag = 0; break; case 'd': case 'D': bp = ++p; if (!*p) usage(); while (*p && *p != '=') p++; if (*p == '=') *p = '\t'; while (*p) p++; p--; defmac(bp); break; default: usage(); } else break; smacptr = macptr; if (!p) usage(); while (p) { errfile = 0; if (typof(p) == 'c' || typof(p) =='C') { glbptr = STARTGLB; locptr = STARTLOC; wsptr = ws; inclsp = iflevel = skiplevel = swstp = litptr = stkp = errcnt = ncmp = lastst = quote[1] = gsize = inbreak = 0; macptr = smacptr; input2 = NULL; quote[0] = '"'; cmode = 1; glbflag = 1; nxtlab = 0; litlab = getlabel (); defmac("end\tmemory"); rglbptr = glbptr; defmac("short\tint"); initmac(); /* * compiler body */ if (!openin (p)) return 0; if (!openout ()) return 0; header (); gtext (); parse (); fclose (input); gdata (); dumplits (); dumpglbs (); errorsummary (); trailer (); fclose (output); pl (""); errs = errs || errfile; #ifndef NOASLD } if (!errfile && !sflag) errs = errs || assemble(p); #else } else { fputs("Don't understand file ", stderr); fputs(p, stderr); errs = 1; } #endif p = *argv++; } exit(errs != 0); return 0; } FEvers() { outstr("/\tFront End (1.0:27/1/99)"); return 0; } usage() { fputs("usage: sccXXXX [-tcsa] [-dSYM[=VALUE]] files\n", stderr); exit(1); } /* * process all input text * * at this level, only static declarations, defines, includes, * and function definitions are legal. * */ parse () { while (!feof (input)) { if (amatch ("extern", 6)) dodcls(EXTERN); else if (amatch ("static",6)) dodcls(STATIC); else if (dodcls(PUBLIC)) ; else if (match ("#asm")) doasm (); else if (match ("#include")) doinclude (); else if (match ("#define")) dodefine(); else if (match ("#undef")) doundef(); else newfunc (); blanks (); } return 0; } /* * parse top level declarations */ dodcls(stclass) int stclass; { blanks(); if (amatch("char", 4)) declglb(CCHAR, stclass); else if (amatch("int", 3)) declglb(CINT, stclass); else if (stclass == PUBLIC) return(0); else declglb(CINT, stclass); ns (); return(1); } /* * dump the literal pool */ dumplits () { int j, k; /* A loc containing the size */ ol("\tLAP"); ot ("\tCPAGE "); onum (2+litptr); nl(); outbyte('L'); printlabel (litlab); col(); ot("\t"); onum (-litptr); nl(); if (litptr == 0) return 0; /* Generate a loc containing the address of the literals */ outbyte('X'); printlabel (litlab); col(); ot("\t"); printlabel (litlab); nl(); printlabel (litlab); col (); k = 0; while (k < litptr) { defbyte (); j = 8; while (j--) { onum (litq[k++] & 127); if ((j == 0) | (k >= litptr)) { nl (); break; } outbyte (';'); } } ol("\tEAP"); return 0; } /* * dump all static variables */ dumpglbs () { int j; if (!glbflag) { ot("GBLS,\t0"); nl(); return 0; } cptr = rglbptr; while (cptr < glbptr) { if (cptr[IDENT] != FUNCTION) { ppubext(cptr); if (cptr[STORAGE] != EXTERN) { //prefix (); //outstr (cptr); //col (); //defstorage (); j = glint(cptr); if ((cptr[TYPE] == CINT) || (cptr[IDENT] == POINTER)) j = j * intsize(); //onum (j); //nl (); } } else { fpubext(cptr); } cptr = cptr + SYMSIZ; } ot("GBLS,\t"); onum(gsize+128); // Beginning of stack after globals nl(); return 0; } /* * report errors */ errorsummary () { if (ncmp) error ("missing closing bracket"); nl (); comment (); outdec (errcnt); if (errcnt) errfile = YES; outstr (" error(s) in compilation"); nl (); comment(); ot("literal pool:"); outdec(litptr); nl(); comment(); ot("global pool:"); outdec(glbptr-rglbptr); nl(); comment(); ot("Macro pool:"); outdec(macptr); nl(); pl (errcnt ? "Error(s)" : "No errors"); return 0; } typof(s) char *s; { s += strlen(s) - 2; if (*s == '.') return(*(s+1)); return(' '); } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File preproc.c: 2.3 (84/11/27,11:47:40) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* * open an include file */ doinclude () { char *p; FILE *inp2; blanks (); if (inp2 = fixiname ()) if (inclsp < INCLSIZ) { inclstk[inclsp++] = input2; input2 = inp2; } else { fclose (inp2); error ("too many nested includes"); } else { error ("Could not open include file"); } kill_line (); return 0; } /* * fixiname - remove "brackets" around include file name */ fixiname () { char c1, c2, *p, *ibp; char buf[20]; ibp = &buf[0]; if ((c1 = gch ()) != '"' && c1 != '<') return (NULL); for (p = line + lptr; *p ;) *ibp++ = *p++; c2 = *(--p); if (c1 == '"' ? (c2 != '"') : (c2 != '>')) { error ("incorrect delimiter"); return (NULL); } *(--ibp) = 0; return c1 == '<' ? fopen(buf, "r") : NULL; } /* * "asm" pseudo-statement * * enters mode where assembly language statements are passed * intact through parser * */ doasm () { cmode = 0; FOREVER { inln (); if (match ("#endasm")) { ol("/\t#ENDASM"); break; } if (feof (input)) break; outstr (line); nl (); } kill_line (); cmode = 1; return 0; } dodefine () { addmac(); return 0; } doundef () { int mp; char sname[NAMESIZE]; if (!symname(sname)) { illname(); kill_line (); return 0; } if (mp = findmac(sname)) delmac(mp); kill_line (); return 0; } preprocess () { if (ifline()) return 0; while (cpp()); return 0; } doifdef (ifdef) int ifdef; { char sname[NAMESIZE]; int k; blanks(); ++iflevel; if (skiplevel) return 0; k = symname(sname) && findmac(sname); if (k != ifdef) skiplevel = iflevel; return 0; } ifline() { FOREVER { inln(); if (feof(input)) return(1); if (match("#ifdef")) { doifdef(YES); continue; } else if (match("#ifndef")) { doifdef(NO); continue; } else if (match("#else")) { if (iflevel) { if (skiplevel == iflevel) skiplevel = 0; else if (skiplevel == 0) skiplevel = iflevel; } else noiferr(); continue; } else if (match("#endif")) { if (iflevel) { if (skiplevel == iflevel) skiplevel = 0; --iflevel; } else noiferr(); continue; } if (!skiplevel) return(0); } } noiferr() { error("no matching #if..."); return 0; } cpp () { int k; char c, sname[NAMESIZE]; int tog; int cpped; /* non-zero if something expanded */ cpped = 0; /* don't expand lines with preprocessor commands in them */ if (!cmode || line[0] == '#') return(0); mptr = lptr = 0; while (ch ()) { if ((ch () == '/') & (nch () == '/')) { inln(); } if ((ch () == ' ') | (ch () == 9)) { keepch (' '); while ((ch () == ' ') | (ch () == 9)) gch (); } else if (ch () == '"') { keepch (ch ()); gch (); while (ch () != '"') { if (ch () == 0) { error ("missing quote"); break; } if (ch() == '\\') keepch(gch()); keepch (gch ()); } gch (); keepch ('"'); } else if (ch () == 39) { keepch (39); gch (); while (ch () != 39) { if (ch () == 0) { error ("missing apostrophe"); break; } if (ch() == '\\') keepch(gch()); keepch (gch ()); } gch (); keepch (39); } else if ((ch () == '/') & (nch () == '*')) { inchar (); inchar (); while ((((c = ch ()) == '*') & (nch () == '/')) == 0) if (c == '$') { inchar (); tog = TRUE; if (ch () == '-') { tog = FALSE; inchar (); } if (alpha (c = ch ())) { inchar (); toggle (c, tog); } } else { if (ch () == 0) inln (); else inchar (); if (feof (input)) break; } inchar (); inchar (); } else if (an (ch ())) { k = 0; while (an (ch ())) { if (k < NAMEMAX) sname[k++] = ch (); gch (); } sname[k] = 0; if (k = findmac (sname)) { cpped = 1; while (c = macq[k++]) keepch (c); } else { k = 0; while (c = sname[k++]) keepch (c); } } else keepch (gch ()); } keepch (0); if (mptr >= MPMAX) error ("line too long"); lptr = mptr = 0; while (line[lptr++] = mline[mptr++]); lptr = 0; return(cpped); } keepch (c) char c; { mline[mptr] = c; if (mptr < MPMAX) mptr++; return (c); } defmac(s) char *s; { kill_line(); strcpy(line, s); addmac(); return 0; } addmac () { char sname[NAMESIZE]; int k; int mp; if (!symname (sname)) { illname (); kill_line (); return 0; } if (mp = findmac(sname)) { error("Duplicate define"); delmac(mp); } k = 0; while (putmac (sname[k++])); while (ch () == ' ' | ch () == 9) gch (); while (putmac (gch ())); if (macptr >= MACMAX) error ("macro table full"); return 0; } delmac(mp) int mp; { --mp; --mp; /* step over previous null */ while (mp >= 0 && macq[mp]) macq[mp--] = '%'; return 0; } putmac (c) char c; { macq[macptr] = c; if (macptr < MACMAX) macptr++; return (c); } findmac (sname) char *sname; { int k; k = 0; while (k < macptr) { if (astreq (sname, macq + k, NAMEMAX)) { while (macq[k++]); return (k); } while (macq[k++]); while (macq[k++]); } return (0); } toggle (name, onoff) char name; int onoff; { switch (name) { case 'C': ctext = onoff; break; } return 0; } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File primary.c: 2.4 (84/11/27,16:26:07) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" primary (lval) int *lval; { unsigned char *ptr, sname[NAMESIZE]; int num[1]; int k; lval[2] = 0; /* clear pointer/array type */ if (match ("(")) { k = heir1 (lval); needbrack (")"); return (k); } if (amatch("sizeof", 6)) { needbrack("("); immed(); if (amatch("int", 3)) onum(intsize()); else if (amatch("char", 4)) onum(1); else if (symname(sname)) { if ((ptr = findloc(sname)) || (ptr = findglb(sname))) { if (ptr[STORAGE] == LSTATIC) error("sizeof local static"); k = glint(ptr); if ((ptr[TYPE] == CINT) || (ptr[IDENT] == POINTER)) k *= intsize(); onum(k); } else { error("sizeof undeclared variable"); onum(0); } } else { error("sizeof only on type or variable"); } needbrack(")"); nl(); return(lval[0] = lval[1] = 0); } if (symname (sname)) { if (ptr = findloc (sname)) { getloc (ptr); lval[0] = ptr; lval[1] = ptr[TYPE]; if (ptr[IDENT] == POINTER) { lval[1] = CINT; lval[2] = ptr[TYPE]; } if (ptr[IDENT] == ARRAY) { lval[2] = ptr[TYPE]; lval[2] = 0; return (0); } else return (1); } if (ptr = findglb (sname)) if (ptr[IDENT] != FUNCTION) { lval[0] = ptr; lval[1] = 0; if (ptr[IDENT] != ARRAY) { if (ptr[IDENT] == POINTER) lval[2] = ptr[TYPE]; return (1); } immed (); onum(128+ptr[OFFSET]+ptr[OFFSET+1]*256); ot("\t/Offset from stackbase at 128 (200(8))"); nl (); lval[1] = lval[2] = ptr[TYPE]; lval[2] = 0; return (0); } blanks (); if (ch() != '(') error("undeclared variable"); ptr = addglb (sname, FUNCTION, CINT, 0, PUBLIC); lval[0] = ptr; lval[1] = 0; return (0); } if (constant (num)) return (lval[0] = lval[1] = 0); else { error ("invalid expression"); immed (); onum (0); nl (); junk (); return (0); } } /* * true if val1 -> int pointer or int array and val2 not pointer or array */ dbltest (val1, val2) int val1[], val2[]; { if (val1 == NULL) return (FALSE); if (val1[2] != CINT) return (FALSE); if (val2[2]) return (FALSE); return (TRUE); } /* * determine type of binary operation */ result (lval, lval2) int lval[], lval2[]; { if (lval[2] && lval2[2]) lval[2] = 0; else if (lval2[2]) { lval[0] = lval2[0]; lval[1] = lval2[1]; lval[2] = lval2[2]; } return 0; } constant (val) int val[]; { if (number (val)) { if (val[0]==0) { ol("\t/ (0)"); cpri(); return (1); } immed (); } else if (pstr (val)) immed (); else if (qstr (val)) { immd2 (); stkbase(); nl(); /* outbyte ('+'); */ immd3 (); } else return (0); onum (val[0]); nl (); return (1); } number (val) int val[]; { int k, minus, base; char c; k = minus = 1; while (k) { k = 0; if (match ("+")) k = 1; if (match ("-")) { minus = (-minus); k = 1; } } if (!numeric (c = ch ())) return (0); if (match ("0x") || match ("0X")) while (numeric (c = ch ()) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { inbyte (); k = k * 16 + (numeric (c) ? (c - '0') : ((c & 07) + 9)); } else { base = (c == '0') ? 8 : 10; while (numeric (ch ())) { c = inbyte (); k = k * base + (c - '0'); } } if (minus < 0) k = (-k); val[0] = k; return (1); } pstr (val) int val[]; { int k; char c; k = 0; if (!match ("'")) return (0); while ((c = gch ()) != 39) { c = (c == '\\') ? spechar(): c; k = (k & 255) * 256 + (c & 255); } val[0] = k; return (1); } qstr (val) int val[]; { char c; if (!match (quote)) return (0); val[0] = litptr; while (ch () != '"') { if (ch () == 0) break; if (litptr >= LITMAX) { error ("string space exhausted"); while (!match (quote)) if (gch () == 0) break; return (1); } c = gch(); litq[litptr++] = (c == '\\') ? spechar(): c; } gch (); litq[litptr++] = 0; return (1); } /* * decode special characters (preceeded by back slashes) */ spechar() { char c; c = ch(); if (c == 'n') c = EOL; else if (c == 't') c = TAB; else if (c == 'r') c = CR; else if (c == 'f') c = FFEED; else if (c == 'b') c = BKSP; else if (c == '0') c = EOS; else if (c == EOS) return 0; gch(); return (c); } /* * perform a function call * * called from "heir11", this routine will either call the named * function, or if the supplied ptr is zero, will call the contents * of HL * NB Added section to load Acc with nargs for vararg calls * NB have addded pseudo functions here as well */ callfunction (ptr) char *ptr; { int nargs; if (strcmp(ptr,"stri")==0) { expression(NO); stri(); needbrack(")"); return 0; } if (strcmp(ptr,"iinit")==0) { expression(NO); iinit(); needbrack(")"); return 0; } nargs = 0; blanks (); if (ptr == 0) gpush (); while (!streq (line + lptr, ")")) { if (endst ()) break; expression (NO); if (ptr == 0) swapstk (); gpush (); nargs = nargs + intsize(); if (!match (",")) break; } needbrack (")"); if (aflag) gnargs(nargs / intsize()); if (ptr) gcall (ptr,&nargs); else callstk (); stkp = modstk (stkp + nargs); return 0; } needlval () { error ("must be lvalue"); return 0; } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File stmt.c: 2.1 (83/03/20,16:02:17) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* * statement parser * * called whenever syntax requires a statement. this routine * performs that statement and returns a number telling which one * * 'func' is true if we require a "function_statement", which * must be compound, and must contain "statement_list" (even if * "declaration_list" is omitted) */ statement (func) int func; { if ((ch () == 0) & feof (input)) return (0); lastst = 0; if (func) if (match ("{")) { compound (YES); return (lastst); } else error ("function requires compound statement"); if (match ("{")) compound (NO); else stst (); return (lastst); } /* * declaration */ stdecl () { if (amatch("register", 8)) doldcls(DEFAUTO); else if (amatch("auto", 4)) doldcls(DEFAUTO); else if (amatch("static", 6)) doldcls(LSTATIC); else if (doldcls(AUTO)) ; else return (NO); return (YES); } doldcls(stclass) int stclass; { blanks(); if (amatch("char", 4)) declloc(CCHAR, stclass); else if (amatch("int", 3)) declloc(CINT, stclass); else if (stclass == LSTATIC || stclass == DEFAUTO) declloc(CINT, stclass); else return(0); ns(); return(1); } /* * non-declaration statement */ stst () { if (amatch ("if", 2)) { doif (); lastst = STIF; } else if (amatch ("while", 5)) { dowhile (); lastst = STWHILE; } else if (amatch ("switch", 6)) { doswitch (); lastst = STSWITCH; } else if (amatch ("do", 2)) { dodo (); ns (); lastst = STDO; } else if (amatch ("for", 3)) { dofor (); lastst = STFOR; } else if (amatch ("return", 6)) { doreturn (); ns (); lastst = STRETURN; } else if (amatch ("break", 5)) { dobreak (); ns (); lastst = STBREAK; } else if (amatch ("continue", 8)) { docont (); ns (); lastst = STCONT; } else if (match (";")) ; else if (amatch ("case", 4)) { docase (); lastst = statement (NO); } else if (amatch ("default", 7)) { dodefault (); lastst = statement (NO); } else if (match ("#asm")) { doasm (); lastst = STASM; } else if (match ("{")) compound (NO); else { expression (YES); /* if (match (":")) { dolabel (); lastst = statement (NO); } else { */ ns (); lastst = STEXP; /* } */ } return 0; } /* * compound statement * * allow any number of statements to fall between "{" and "}" * * 'func' is true if we are in a "function_statement", which * must contain "statement_list" */ compound (func) int func; { int decls; decls = YES; ncmp++; while (!match ("}")) { if (feof (input)) return 0; if (decls) { if (!stdecl ()) decls = NO; } else stst (); } ncmp--; return 0; } /* * "if" statement */ doif () { int fstkp, flab1, flab2; char *flev; flev = locptr; fstkp = stkp; flab1 = getlabel (); test (flab1, FALSE); statement (NO); stkp = modstk (fstkp); locptr = flev; if (!amatch ("else", 4)) { gnlabel (flab1); return 0; } jump (flab2 = getlabel ()); gnlabel (flab1); statement (NO); stkp = modstk (fstkp); locptr = flev; gnlabel (flab2); return 0; } /* * "while" statement */ dowhile () { int ws[7]; ws[WSSYM] = locptr; ws[WSSP] = stkp; ws[WSTYP] = WSWHILE; ws[WSTEST] = getlabel (); ws[WSEXIT] = getlabel (); addwhile (ws); gnlabel (ws[WSTEST]); test (ws[WSEXIT], FALSE); statement (NO); jump (ws[WSTEST]); gnlabel (ws[WSEXIT]); locptr = ws[WSSYM]; stkp = modstk (ws[WSSP]); delwhile (); return 0; } /* * "do" statement */ dodo () { int ws[7]; ws[WSSYM] = locptr; ws[WSSP] = stkp; ws[WSTYP] = WSDO; ws[WSBODY] = getlabel (); ws[WSTEST] = getlabel (); ws[WSEXIT] = getlabel (); addwhile (ws); gnlabel (ws[WSBODY]); statement (NO); if (!match ("while")) { error ("missing while"); return 0; } gnlabel (ws[WSTEST]); test (ws[WSBODY], TRUE); gnlabel (ws[WSEXIT]); locptr = ws[WSSYM]; stkp = modstk (ws[WSSP]); delwhile (); return 0; } /* * "for" statement */ dofor () { int ws[7], *pws; ws[WSSYM] = locptr; ws[WSSP] = stkp; ws[WSTYP] = WSFOR; ws[WSTEST] = getlabel (); ws[WSINCR] = getlabel (); ws[WSBODY] = getlabel (); ws[WSEXIT] = getlabel (); addwhile (ws); pws = readwhile (); needbrack ("("); if (!match (";")) { expression (YES); ns (); } gnlabel (pws[WSTEST]); if (!match (";")) { expression (YES); testjump (pws[WSBODY], TRUE); jump (pws[WSEXIT]); ns (); } else pws[WSTEST] = pws[WSBODY]; gnlabel (pws[WSINCR]); if (!match (")")) { expression (YES); needbrack (")"); jump (pws[WSTEST]); } else pws[WSINCR] = pws[WSTEST]; gnlabel (pws[WSBODY]); statement (NO); jump (pws[WSINCR]); gnlabel (pws[WSEXIT]); locptr = pws[WSSYM]; stkp = modstk (pws[WSSP]); delwhile (); return 0; } /* * "switch" statement */ doswitch () { int ws[7]; int *ptr; ws[WSSYM] = locptr; ws[WSSP] = stkp; ws[WSTYP] = WSSWITCH; ws[WSCASEP] = swstp; ws[WSTAB] = getlabel (); ws[WSDEF] = ws[WSEXIT] = getlabel (); addwhile (ws); // immed (); // printlabel (ws[WSTAB]); // nl (); // gpush (); needbrack ("("); expression (YES); needbrack (")"); // stkp = stkp + intsize(); /* '?case' will adjust the stack */ gjcase (); jump (ws[WSTAB]); statement (NO); ptr = readswitch (); // if (ptr[WSDEF]!=ptr[WSEXIT]) jump (ptr[WSDEF]); jump (ptr[WSEXIT]); dumpsw (ptr); gnlabel (ptr[WSEXIT]); locptr = ptr[WSSYM]; // stkp = modstk (ptr[WSSP]); swstp = ptr[WSCASEP]; delwhile (); return 0; } /* * "case" label */ docase () { int val; val = 0; if (readswitch ()) { if (!number (&val)) if (!pstr (&val)) error ("bad case label"); addcase (val); if (!match (":")) error ("missing colon"); } else error ("no active switch"); return 0; } /* * "default" label */ dodefault () { int *ptr, lab; if (ptr = readswitch ()) { ptr[WSDEF] = lab = getlabel (); gnlabel (lab); if (!match (":")) error ("missing colon"); } else error ("no active switch"); return 0; } /* * "return" statement */ doreturn () { if (endst () == 0) expression (YES); jump(fexitlab); return 0; } /* * "break" statement */ dobreak () { int *ptr; if ((ptr = readwhile ()) == 0) return 0; modstk (ptr[WSSP]); jump (ptr[WSEXIT]); return 0; } /* * "continue" statement */ docont () { int *ptr; if ((ptr = findwhile ()) == 0) return 0; /* modstk (ptr[WSSP]); */ if (ptr[WSTYP] == WSFOR) jump (ptr[WSINCR]); else jump (ptr[WSTEST]); return 0; } /* * dump switch table */ dumpsw (ws) int ws[]; { int i,j; gdata (); gnlabel (ws[WSTAB]); if (ws[WSCASEP] != swstp) { j = ws[WSCASEP]; while (j < swstp) { i = 4; while (i--) { immd3(); onum (swstcase[j]); nl(); casejump(); jump (swstlab[j++]); if ((i == 0) | (j >= swstp)) { nl (); break; } nl(); } } jump(ws[WSDEF]); } gtext (); return 0; } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* File sym.c: 2.1 (83/03/20,16:02:19) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" /* * declare a static variable */ declglb (typ, stor) int typ, stor; { int k, j; char sname[NAMESIZE]; FOREVER { FOREVER { if (endst ()) return 0; k = 1; if (match ("*")) j = POINTER; else j = VARIABLE; if (!symname (sname)) illname (); if (findglb (sname)) multidef (sname); if (match ("[")) { k = needsub (); if (k || stor == EXTERN) j = ARRAY; else j = POINTER; } addglb (sname, j, typ, k, stor); break; } if (!match (",")) return 0; } } /* * declare local variables * * works just like "declglb", but modifies machine stack and adds * symbol table entry with appropriate stack offset to find it again */ declloc (typ, stclass) int typ, stclass; { int k, j; char sname[NAMESIZE]; FOREVER { FOREVER { if (endst ()) return 0; if (match ("*")) j = POINTER; else j = VARIABLE; if (!symname (sname)) illname (); if (findloc (sname)) multidef (sname); if (match ("[")) { k = needsub (); if (k) { j = ARRAY; if (typ == CINT) k = k * intsize(); } else { j = POINTER; k = intsize(); } } else if ((typ == CCHAR) & (j != POINTER)) k = 1; else k = intsize(); if (stclass != LSTATIC) { k = galign(k); stkp = modstk (stkp - k); addloc (sname, j, typ, stkp+k-1, AUTO); /* Reversed stack for PDP8 */ } else addloc( sname, j, typ, k, LSTATIC); break; } if (!match (",")) return 0; } } /* * get required array size */ needsub () { int num[1]; if (match ("]")) return (0); if (!number (num)) { error ("must be constant"); num[0] = 1; } if (num[0] < 0) { error ("negative size illegal"); num[0] = (-num[0]); } needbrack ("]"); return (num[0]); } findglb (sname) char *sname; { char *ptr; ptr = STARTGLB; while (ptr != glbptr) { if (astreq (sname, ptr, NAMEMAX)) return (ptr); ptr = ptr + SYMSIZ; } return (0); } findloc (sname) char *sname; { char *ptr; ptr = locptr; while (ptr != STARTLOC) { ptr = ptr - SYMSIZ; if (astreq (sname, ptr, NAMEMAX)) return (ptr); } return (0); } addglb (sname, id, typ, value, stor) char *sname, id, typ; int value, stor; { char *ptr; if (cptr = findglb (sname)) return (cptr); if (glbptr >= ENDGLB) { error ("global symbol table overflow"); return (0); } cptr = ptr = glbptr; while (an (*ptr++ = *sname++)); cptr[IDENT] = id; cptr[TYPE] = typ; cptr[STORAGE] = stor; cptr[OFFSET] = gsize & 0xff; cptr[OFFSET+1] = (gsize >> 8) & 0xff; gsize = gsize + value; glbptr = glbptr + SYMSIZ; return (cptr); } addloc (sname, id, typ, value, stclass) char *sname, id, typ; int value, stclass; { char *ptr; int k; if (cptr = findloc (sname)) return (cptr); if (locptr >= ENDLOC) { error ("local symbol table overflow"); return (0); } cptr = ptr = locptr; while (an (*ptr++ = *sname++)); cptr[IDENT] = id; cptr[TYPE] = typ; cptr[STORAGE] = stclass; if (stclass == LSTATIC) { gdata(); printlabel(k = getlabel()); col(); defstorage(); onum(value); nl(); gtext(); value = k; } else value = galign(value); cptr[OFFSET] = value & 0xff; cptr[OFFSET+1] = (value >> 8) & 0xff; locptr = locptr + SYMSIZ; return (cptr); } /* * test if next input string is legal symbol name * */ symname (sname) char *sname; { int k; char c; blanks (); if (!alpha (ch ())) return (0); k = 0; while (an (ch ())) sname[k++] = gch (); sname[k] = 0; return (1); } illname () { error ("illegal symbol name"); return 0; } multidef (sname) char *sname; { error ("already defined"); comment (); outstr (sname); nl (); return 0; } glint(syment) char *syment; { short l,u,r; l = syment[OFFSET]; u = syment[OFFSET+1]; r = (l & 0xff) + ((u << 8) & ~0x00ff); return (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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | /* File while.c: 2.1 (83/03/20,16:02:22) */ /*% cc -O -c % * */ #include <stdio.h> #include "defs.h" #include "data.h" addwhile (ptr) int ptr[]; { int k; if (wsptr == WSMAX) { error ("too many active whiles"); return 0; } k = 0; while (k < WSSIZ) *wsptr++ = ptr[k++]; return 0; } delwhile () { if (readwhile ()) wsptr = wsptr - WSSIZ; return 0; } int readwhile () { if (wsptr == ws) { error ("no active do/for/while/switch"); return (0); } else return (wsptr-WSSIZ); } int *findwhile () { int *ptr; for (ptr = wsptr; ptr != ws;) { ptr = ptr - WSSIZ; if (ptr[WSTYP] != WSSWITCH) return (ptr); } error ("no active do/for/while"); return (0); } int *readswitch () { int *ptr; if (ptr = (int *)readwhile ()) if (ptr[WSTYP] == WSSWITCH) return (ptr); return (0); } addcase (val) int val; { int lab; if (swstp == SWSTSZ) error ("too many case labels"); else { swstcase[swstp] = val; swstlab[swstp++] = lab = getlabel (); printlabel (lab); col (); nl (); } return 0; } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # Using the Examples This directory contains several example programs. We will use the `calc.c` example throughout this section. The program may be compiled using the cc8 cross-compiler to SABR sources like so: $ cc8 calc.c You can then use the `txt2ptp` program to turn the resulting `calc.s` file into a paper tape to be loaded into OS/8: $ txt2ptp < calc.s > calc.pt $ pidp8i ⇠ ...start PDP-8 sim somehow, then hit Ctrl-E sim> att -r dt0 calc.pt sim> cont .R PIP *CALC.SB<PTR: ⇠ hit Enter, then Escape twice The <kbd>Enter</kbd> key starts the transfer in the final command. The transfer stops when `PIP` sees the <kbd>Ctrl-Z</kbd> EOF marker added to the end of the paper tape by `txt2ptp`. The first <kbd>Escape</kbd> finalizes the transfer and the second exits PIP, returning you to the OS/8 command prompt. See the [assembly examples' `README.md` file][aerm] or the [U/W FOCAL manual supplement][uwfs] for more ideas on how to get text files like this SABR file into OS/8. However you manage it, you can then assemble, load, and run the programs on the OS/8 side with: .COMP CALC.SB .R LOADER *CALC,LIBC/G ⇠ press Esc to execute command and exit LOADER The `/G` flag causes the loader to run the linked program immediately, but once you're done modifying the program, you probably want to save it as a core image so it can be run directly instead of being linked and loaded again each time. You can give `/M` instead, which finalizes the link and then exits, printing a map file before it does so. You can then save the result where the OS/8 `R` command can find it with: .SAVE SYS:CALC That produces `SYS:CALC.SV`, which an `R CALC` command will load and run. If you wish to compile from C source code on the OS/8 side rather than cross-compile, I recommend using the `CC0` front-end rather than the method shown in the [top level `README.md` file][tlrm] involving the `CC1` stage: .R CC0 >calc.cc .COMP CC.SB .R LOADER *CC,LIBC/M Notice that the front-end processor produces `CC.SB`, not `CALC.SB` as you might be expecting. This is where the `CC` comes from in the `COMP` and `LOADER` commands. Note that `CC0` tolerates lowercase input. [aerm]: /doc/trunk/examples/README.md [tlrm]: /doc/trunk/src/cc8/README.md [uwfs]: /doc/trunk/doc/uwfocal-manual-supp.md # The Examples In order of complexity, they are: ## calc.c This is a simple 4-function calculator. ## ps.c This prints several levels of [Pascal's triangle][pt]. [pt]: https://en.wikipedia.org/wiki/Pascal%27s_triangle ## fib.c This program calculates [Fibonacci humbers][fn], which implicitly demonstrates the C compiler's ability to handle [recursion][rec]. [fn]: https://en.wikipedia.org/wiki/Fibonacci_number [rec]: https://en.wikipedia.org/wiki/Recursion_(computer_science) ## basic.c A very simple BASIC interpreter. This program tests a broad swath of the compiler's functionality. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include <libc.h> #include <init.h> #define SMAX 10 #define CMAX 256 #define BMAX 64 #define LMAX 32 #define DMAX 32 #define CBMX 1024 #define LXMX 999 int E [SMAX]; /* subroutine line number stack */ int L [CMAX]; /* FOR loop beginning line number */ int M [CMAX]; /* FOR loop maximum index value */ int P [CMAX]; /* program variable value */ char Lb[CBMX]; /* Line buffer of CBMX chars */ int l,i,j; int *C; /* subroutine stack pointer */ char B [BMAX]; /* command input buffer */ char F [2]; /* temporary search string */ char *m [LXMX]; /* pointers to lines of program. This is a real waste of space! */ char *p,*q,*x,*y,*z,*s,*d; G( ) { /* get program line from buffer */ atoi(B,&l); y=m[l]; if(y){ if(strstr(B," ")) strcpy(y,B); else y=m[l]=0; return; } y=Lb; while(*y) y=y+DMAX; strcpy(y,B); m [l]=y; } /* end G */ /* recursive descent parser for arithmetic/logical expressions */ S( ) { int o; o=J( ); switch(*p++){ case '=': return o==S( ); break; case '#': return o!=S( ); default: p--; return o; } } /* end S */ J( ) { int o; o=K( ); switch(*p++){ case '<': return o<J( ); break; case '>': return o>J( ); default: p--; return o; } } /* end J */ K( ) { int o; o=V( ); switch(*p++){ case '$': return o<=K( ); break; case '!': return o>=K( ); default: p--; return o; } } /* end K */ V( ) { int o; o=W( ); switch(*p++){ case '+': return o+V( ); break; case '-': return o-V( ); default: p--; return o; } } /* end V */ W( ) { int o; o=Y( ); switch(*p++){ case '*': return o*W( ); break; case '/': return o/W( ); default: p--; return o; } } /* end W */ Y( ) { int o; if(*p=='-'){ p++; return -Y(); } q=p; if(*p>='0'&&*p<='9'){ while(*p>='0'&&*p<='9') p++; atoi(q,&o); return o; } if(*p=='('){ p++; o=S( ); p++; return o; } return P [*p++]; } /* end Y */ bufclear() { memset(m,0,LXMX); memset(Lb,0,CBMX); } main( ) { int tmp; /* temp var to fix bug 07Sep2005 Somos */ bufclear(); while(puts("Ok\r\n"),gets(B)) switch(*B){ case 'R': /* "RUN" command */ C=E; l=1; for(i=0; i<CMAX; i++) /* initialize variables */ P [i]=0; while(l){ while(!(s=m [l])) l++; while(*s!=' ') s++; /* skip line number */ if ( ! strstr ( s , "\"" ) ) { while ( ( p = strstr ( s , "<>" ) ) ) * p ++ = '#' , * p = ' ' ; while ( ( p = strstr ( s , "<=" ) ) ) * p ++ = '$' , * p = ' ' ; while ( ( p = strstr ( s , ">=" ) ) ) * p ++ = '!' , * p = ' ' ; } d=B; j=0; while(*s){ if(*s=='"') j++; if(*s!=' '||(j&1)) *d++=*s; s++; } *d=j=0; d--; /* backup to last char in line */ if(B [1]!='='){ switch(*B){ case 'E': /* "END" */ l=-1; break; case 'R': /* "REM" */ if(B [2]!='M') l=*--C; /* "RETURN" */ break; case 'I': if(B [1]=='N'){ /* "INPUT" */ tmp=*d; /* save for bug fix next line 07Sep2005 Somos */ gets(p=B); P [tmp]=S( ); } else { /* "IF" */ *(tmp=strstr(B,"TH"))=0; /* "THEN" */ p=B+2; if(S( )){ p=tmp+4; l=S( )-1; } } break; case 'P': /* "PRINT" */ tmp=','; p=B+5; while(tmp==','){ if(*p=='"'){ while(*++p!='"') putc(*p); p++; } else { printf("%d",S( )); } tmp=*p++; putc(' '); } puts("\r\n"); break; case 'G': /* "GOTO" */ p=B+4; if(B [2]=='S'){ /* "GOSUB" */ *C++=l; p++; } l=S( )-1; break; case 'F': /* "FOR" */ *(tmp=strstr(B,"TO"))=0; /* "TO" */ p=B+5; P [i=B [3]]=S( ); p=tmp+2; M [i]=S( ); L [i]=l; break; case 'N': /* "NEXT" */ tmp=*d; if(P [tmp]<M [tmp]){ l=L [tmp]; P [tmp]++; } break; } } else { p=B+2; P [*B]=S( ); } l++; } /* end while l */ break; case 'L': /* "LIST" command */ for(j=0; j<LXMX; j++) if(m[j]){ puts(m[j]); puts("\r\n"); } break; case 'N': /* "NEW" command */ bufclear(); break; case 'B': /* "BYE" command */ return 0; break; case 0: default: G( ); }/* end switch *B */ return 0; } /* end main */ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #include <init.h> #include <libc.h> main() { int x, y, ans; int choice; int bfr[10]; /* CC8 doesn't let you initialize variables at declaration time. */ ans = 'Y'; /* This would be clearer as a do/while loop, but CC8 doesn't support * that yet. */ while (1) { /* Force answer from tail end of loop to uppercase since CC8 * doesn't know the || operator yet. CC8's libc doesn't have * toupper(), and I can't seem to get its cupper() alternative * to work. Don't rewrite with the -= operator: that doesn't * work yet, either. */ if (ans > 'Z') ans = ans - 32; /* You might be tempted to write "if (ans != 'Y') break;" and * then do away with one indent level for the main body of code * that follows, but CC8 doesn't know the != operator yet. */ if (ans == 'Y') { printf("\r\nENTER ANY TWO NUMBERS.\r\n"); printf("ENTER THE FIRST NUMBER: "); gets(bfr); sscanf(bfr, "%d", &x); printf("ENTER THE SECOND NUMBER: "); gets(bfr); sscanf(bfr, "%d", &y); printf("SELECT THE OPERATION:\r\n"); printf("1: ADDITION\r\n"); printf("2: SUBTRACTION\r\n"); printf("3: MULTIPLICATION\r\n"); printf("4: DIVISION\r\n"); printf("CHOICE: "); gets(bfr); sscanf(bfr, "%d", &choice); if (choice == 1) printf("Result: %d\r\n", x + y); if (choice == 2) printf("Result: %d\r\n", x - y); if (choice == 3) printf("Result: %d\r\n", x * y); if (choice == 4) printf("Result: %d\r\n", x / y); printf("DO YOU WISH TO CONTINUE (Y/N): "); ans = getc(); } else { break; } } } |
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <init.h> #include <libc.h> fib(n) { if (n < 2) return n; else return fib(n-1)+fib(n-2); } main() { int i; for (i=0;i<10;i++) printf("Fib#:%d = %d\r\n", i, fib(i)); } |
> | 1 | ../include/init.h |
> | 1 | ../include/libc.h |
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <init.h> #include <libc.h> main() { int ar[20],i,j,n; n=14; for (i=1;i<n;i++) { ar[i]=1; for (j=i-1;j>1;j--) ar[j]=ar[j-1]+ar[j]; for (j=0;j<2*(n-i-1);j++) putc(' '); for (j=1;j<i+1;j++) printf("%4d",ar[j]); printf("\r\n"); } } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * This file is part of the CC8 cross-compiler. * * The CC8 cross-compiler 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. * * The CC8 cross-compiler 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 the CC8 cross-compiler as ../GPL3.txt. If not, see * <http://www.gnu.org/licenses/>. */ #asm / / PDP8/E Run time routines for the Small-C compiler. SABR syntax. / ABSYM POP 160 ABSYM PSH 161 ABSYM JLC 162 ABSYM STKP 163 ABSYM PTSK 164 ABSYM POPR 165 ABSYM PCAL 166 ABSYM TMP 167 ABSYM GBL 170 ABSYM ZTMP 171 / DECIM / STK, COMMN 3840 / / / ENTRY MAIN MAIN, BLOCK 2 TAD GBLS DCA STKP TAD GBLS DCA GBL ISZ GBL / LOCAL LITERALS = STKP+1 TAD PVL DCA PSH TAD OVL DCA POP TAD MVL DCA PTSK TAD PVR DCA POPR TAD PVC DCA PCAL RIF TAD (3201 DCA PCL1 TAD PCL1 DCA DCC0 JMS MCC0 CLA CMA MQL CALL 1,LIBC ARG STKP CALL 0,OPEN JMSI PCAL XMAIN CALL 0,EXIT / PUSH, 0 CDF1 ISZ STKP DCAI STKP TADI STKP JMPI PUSH PPOP, 0 CDF1 DCA TMP TADI STKP MQL CMA TAD STKP DCA STKP TAD TMP JMPI PPOP PUTSTK, 0 JMSI POP SWP DCA JLC SWP DCAI JLC TADI JLC JMPI PUTSTK POPRET, JMSI POP SWP DCA ZTMP SWP JMPI ZTMP PCALL, 0 CLA CLL PCL1, 0 TADI PCALL DCA ZTMP TAD PCALL IAC JMSI PSH / PUSH RETURN CLA JMPI ZTMP PVL, PUSH OVL, PPOP MVL, PUTSTK SVL, STK PVR, POPRET PVC, PCALL / #endasm |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * This file is part of the CC8 cross-compiler. * * The CC8 cross-compiler 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. * * The CC8 cross-compiler 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 the CC8 cross-compiler as ../GPL3.txt. If not, see * <http://www.gnu.org/licenses/>. */ /* * Libc header * * Please note: no function declarations are made, so make sure the * arg lists are correct in the calling code. * */ #define itoa libc0 #define puts libc1 #define nl libc2 #define getc libc3 #define gets libc4 #define atoi libc5 #define sscanf vlibc6 #define xinit libc7 #define memcpy libc8 #define kbhit libc9 #define putc libc10 #define strcpy libc11 #define strcat libc12 #define strstr libc13 #define exit libc14 #define isnum libc15 #define isdigit libc15 #define isalpha libc16 #define sprintf vlibc17 #define memset libc18 #define fgetc libc19 #define fopen libc20 #define fputc libc21 #define fclose libc22 #define printf vlibc23 #define isalnum libc24 #define isspace libc25 #define fprintf vlibc26 #define fputs libc27 #define strcmp libc28 #define cupper libc29 #define fgets libc30 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 src/cc8/os8 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 CC8 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 $@ |
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $JOB BUILD C COMPILER AND LIBRARY .COMP C8.SB .COMP P8.SB .COMP N8.SB .COMP LIBC.SB .R LOADER *P8,LIBC/I/O$ .SAVE SYS CC2 .R LOADER *N8,LIBC/I/O$ .SAVE SYS CC1 .R LOADER *C8,LIBC/I/O$ .SAVE SYS CC $END |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * This file is part of the CC8 OS/8 C compiler. * * The CC8 OS/8 C compiler 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. * * The CC8 OS/8 C compiler 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 the CC8 OS/8 C compiler as ../GPL3.txt. If not, see * <http://www.gnu.org/licenses/>. */ #include <libc.h> #include <init.h> /* C compiler driver: asks for input files, copies to CC.C & runs CC1 */ main() { int bfr; int fnm[10]; putc('>'); gets(fnm); cupper(fnm); fopen(fnm,"r"); fopen("CC.C","w"); while (bfr=fgetc()) if (bfr!=12) /* Ignore form feed */ fputc(bfr); fclose(); #asm CALL 1,CHAIN ARG FNM HLT FNM, TEXT "CC1@@@" #endasm } |
> > > > > > | 1 2 3 4 5 6 | $JOB COMPILE AND RUN C PROGRAMME .R CC .COMP CC.SB .R LOADER *CC,LIBC/I/O/G $END |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | // // This file is part of the CC8 OS/8 C compiler. // // The CC8 OS/8 C compiler 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. // // The CC8 OS/8 C compiler 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 the CC8 OS/8 C compiler as ../GPL3.txt. If not, see // <http://www.gnu.org/licenses/>. // / SABR DEFINITIONS / FRONT END (2.0:1/4/2017) OPDEF ANDI 0400 OPDEF TADI 1400 OPDEF ISZI 2400 OPDEF DCAI 3400 OPDEF JMSI 4400 OPDEF JMPI 5400 OPDEF MQL 7421 OPDEF MQA 7701 OPDEF MQO 7501 OPDEF SWP 7521 OPDEF CDF1 6211 OPDEF CDF0 6201 OPDEF RIF 6224 OPDEF CAF0 6203 OPDEF BSW 7002 OPDEF CAM 7621 / / PDP8/E Run time routines for Small c compiler / ABSYM POP 160 ABSYM PSH 161 ABSYM JLC 162 ABSYM STKP 163 ABSYM PTSK 164 ABSYM POPR 165 ABSYM PCAL 166 ABSYM TMP 167 ABSYM GBL 170 ABSYM ZTMP 171 / DECIM / STK, COMMN 3840 / / / ENTRY MAIN MAIN, BLOCK 2 TAD GBLS DCA STKP TAD GBLS DCA GBL ISZ GBL / LOCAL LITERALS = STKP+1 TAD PVL DCA PSH TAD OVL DCA POP TAD MVL DCA PTSK TAD PVR DCA POPR TAD PVC DCA PCAL RIF TAD (3201 DCA PCL1 TAD PCL1 DCA DCC0 JMS MCC0 CLA CMA MQL CALL 1,LIBC ARG STKP CALL 0,OPEN JMSI PCAL XMAIN CALL 0,EXIT / PUSH, 0 CDF1 ISZ STKP DCAI STKP TADI STKP JMPI PUSH PPOP, 0 CDF1 DCA TMP TADI STKP MQL CMA TAD STKP DCA STKP TAD TMP JMPI PPOP PUTSTK, 0 JMSI POP SWP DCA JLC SWP DCAI JLC TADI JLC JMPI PUTSTK POPRET, JMSI POP SWP DCA ZTMP SWP JMPI ZTMP PCALL, 0 CLA CLL PCL1, 0 TADI PCALL DCA ZTMP TAD PCALL IAC JMSI PSH / PUSH RETURN CLA JMPI ZTMP PVL, PUSH OVL, PPOP MVL, PUTSTK SVL, STK PVR, POPRET PVC, PCALL / |
> | 1 | ../include/init.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 | /* * This file is part of the CC8 OS/8 C compiler. * * The CC8 OS/8 C compiler 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. * * The CC8 OS/8 C compiler 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 the CC8 OS/8 C compiler as ../GPL3.txt. If not, see * <http://www.gnu.org/licenses/>. */ /* * PDP8/E LIBC routines for Small-C compiler. * * This is a complex collection of mixed C and SABR assembly routines. * Some functions have been substantially shortened to save space * relative to the original versions. Eventually, most of the C will * need to be rewritten in SABR and hand optimised; e.g. atoi(). */ #asm ABSYM POP 147 ABSYM PSH 150 ABSYM JLC 151 ABSYM STKP 152 ABSYM PTSK 153 ABSYM POPR 154 ABSYM PCAL 155 ABSYM TMP 156 ABSYM GBL 157 ABSYM ZTMP 146 ABSYM ZPTR 145 ABSYM ZCTR 144 ABSYM FPTR 160 / DECIM / / / / DUMMY ARGST DUMMY ARGNM ARGST, BLOCK 2 ARGNM, BLOCK 2 / ENTRY LIBC LIBC, BLOCK 2 CLA CLL TAD I LIBC DCA ARGST INC LIBC# TAD I LIBC DCA ARGST# INC LIBC# TAD I ARGST DCA STKP IAC TAD LCALL / INIT ? LCALL==-1 SZA CLA JMP LB1 TAD STKP DCA GBL / SET LOCAL GBL(LITPTR) ISZ GBL TAD PVL DCA PSH TAD OVL DCA POP TAD MVL DCA PTSK TAD PVR DCA POPR TAD PVC DCA PCAL RIF TAD (3201 DCA PCL1 TAD PCL1 DCA DCC0 JMS MCC0 TAD STKP DCA I ARGST / UPDATE MASTER STKP DCA ZPTR / INIT PRINTF FLAG DCA FPTR / INIT FPRINTF FLAG LB1, MQA / CALL INDEX IN MQ SPA JMP LRET TAD CPNT DCA LCALL TAD I LCALL DCA LCALL JMSI PCAL LCALL, -1 RETRN LIBC LRET, CLA MQL DCA LCALL / INIT OK RETRN LIBC / PUSH, 0 CDF1 ISZ STKP DCAI STKP TADI STKP JMPI PUSH PPOP, 0 CDF1 DCA TMP TADI STKP MQL CMA TAD STKP DCA STKP TAD TMP JMPI PPOP PUTSTK, 0 JMSI POP SWP DCA JLC SWP DCAI JLC TADI JLC JMPI PUTSTK POPRET, JMSI POP SWP DCA ZTMP TAD STKP DCA I ARGST / UPDATE MASTER STKP SWP CDF1 JMPI ZTMP PCALL, 0 CLA CLL PCL1, 0 TADI PCALL DCA ZTMP TAD PCALL IAC JMSI PSH / PUSH RETURN CLA TAD STKP DCA I ARGST / UPDATE MASTER STKP CDF1 JMPI ZTMP PVL, PUSH OVL, PPOP MVL, PUTSTK PVR, POPRET PVC, PCALL / CPNT, CLIST CPAGE 24 / / THIS IS THE DISPATCH LIST FOR THIS LIBRARY / MAKE SURE LIBC.H MATCHES / CLIST, ITOA PUTS DISPXY GETC GETS ATOI SSCANF XINIT MEMCPY KBHIT PUTC STRCPY STRCAT STRSTR EXIT ISNUM ISALPHA SPRINTF MEMSET FGETC FOPEN FPUTC FCLOSE PRINTF ISALNUM ISSPACE FPRINTF FPUTS STRCMP CUPPER FGETS #endasm #define stdout 0 #define NULL 0 #define isdigit isnum fgetc() { #asm CLA CLL CALL 2,CHRIO ARG (-4 ARG FRSL TAD FRSL TAD (-26 /^Z SNA CLA DCA FRSL TAD FRSL CDF1 JMPI POPR FRSL,BLOCK 2 // CHRIO - CHARACTER I/O. / / CALL CHRIO(IDEVN,ICHAR) / / IDEV = FORT II DEVICE NUMBER. / / ICHAR = 7 OR 8 BIT CHARACTER. / / IF IDEV IS POSITIVE, THE CHAR IS OUTPUTTED. / / IF IDEV IS NEGATIVE, THE NEXT CHAR IS / READ FROM THE DEVICE, AND PUT IN ICHAR. / // ENTRY CHRIO CHRIO, BLOCK 2 JMS GETP SPA /WHAT IS DEVICE SIGN? JMP RCHAR /NEG DEV. MEANS READ. JMS SETDEV /POS DEV. MEANS WRITE. 0000 JMS GETP DCA ICHAR JMS CHSUB JMP XIT IDEV, 0 ICHAR, 0 ADDR, 0 RCHAR, CIA /READ A CHAR. JMS SETDEV 1024 /SET BIT FOR READ. (8 UNITS NOW!) JMS GETP CLA TAD CDFB DCA CDFCH JMS CHSUB CDFCH, HLT AND (127 / 7 BIT FOR NOW DCAI ADDR XIT, CLA RETRN CHRIO SETDEV, 0 TAD (-1 AND (7 CLL RAR;RTR;RTR TAD I SETDEV INC SETDEV DCA IDEV JMP I SETDEV CHSUB, 0 TAD ICHAR AND (255 TAD IDEV CALL 0,GENIO JMP I CHSUB GETP, 0 TAD CHRIO DCA CDFA CDFA, HLT TADI CHRIO# DCA CDFB INC CHRIO# TADI CHRIO# DCA ADDR INC CHRIO# CDFB, HLT TADI ADDR JMP I GETP #endasm } fputc(ch) int ch; { ch; #asm DCA FRSL CALL 2,CHRIO ARG (4 ARG FRSL CDF1 TAD FRSL #endasm } sixbit(p) char *p; { *p++; #asm AND (63 BSW MQL #endasm *p; #asm AND (63 MQO #endasm } fputs(p) int *p; { while (*p++) #asm DCA FRSL CALL 2,CHRIO ARG (4 ARG FRSL CDF1 #endasm } fopen (fnm,flg) char *fnm; int flg; { char *p; p=fnm; p=strstr(fnm,"."); if (p==0) return(-1); if (*flg=='w') { #asm CLA TAD FC1# DCA FBSE# JMP FC3 FC1, CALL 0,OOPEN FC2, CALL 0,IOPEN #endasm } if (*flg=='r') { #asm CLA TAD FC2# DCA FBSE# FC3, CDF1 #endasm *p++=0; sixbit(p); #asm PAGE / OFFSET IOPEN+81 = FILEEX DCA ZTMP TAD FC2# / CODE AND (63 TAD (128 DCA FDCT CDF0 TADI FDCT DCA FEX1 TAD FDCT TAD (64 DCA FDCT TADI FDCT TAD (81 / OFFSET OF EXTENSION DCA FDCT FEX1, HLT TAD ZTMP DCAI FDCT CDF1 #endasm fnm; #asm DCA ZTMP / PACK 6 8BIT CHARS INTO FILENAME TAD (-3 DCA FDCT TAD FDCA DCA FP4 FP1, CAM TADI ZTMP SNA JMP FP2 AND (63 BSW MQL ISZ ZTMP FP2, TADI ZTMP / WILL USE STACK FIELD AND (63 SZA ISZ ZTMP MQO FP4, DCA FFNM ISZ FP4 ISZ FDCT JMP FP1 TAD (46 DCAI ZTMP / PUT . BACK INTO FNM CLA CLL CMA TAD STKP DCA STKP FBSE, CALL 2,IOPEN ARG FDEV ARG FFNM JMPI POPR FDCA, DCA FFNM FDCT, 0 FFNM, TEXT /TM@@@@/ FDEV, TEXT /DSK@@@/ #endasm } } fclose() { #asm CALL 0,OCLOS #endasm } puts(p) char *p; { while (*p++) #asm TLS XC1, TSF JMP XC1 #endasm } dispxy(x,y) int x,y; { x; #asm 3115 / DIX #endasm y; #asm 3116 / DIY 3117 / DIL #endasm } getc() { #asm CLA GT1, KSF JMP GT1 KRB TLS AND (127 /* 7 BIT! */ #endasm } gets(p) char *p; { int q,tm; tm=1; q=p; while (tm) { #asm XC2, CLA CLL KSF JMP XC2 KRB TAD (-255 CLA KRB SNL / DO NOT ECHO BS TLS XC3, AND (127 TAD (-13 / CR IS END OF STRING -> 0 SZA TAD (13 DCAI STKP #endasm if (tm!=127) *p++=tm; else if (p-q) { puts("\b \b"); p--; } } putc(10); /* newline */ return 1; } atoi(p,rsl) char *p; int *rsl; { #asm DCA ZTMP DCA ZCTR TAD (3584 / NOP DCA XINV CDF1 / Change DF back to 1 in case SABR changes it! #endasm while (*p==' ') p++; if (*p=='-') { #asm CLA TAD (3617 DCA XINV / CIA CDF1 #endasm p++; } while (*p++) { #asm TAD (-48 / '0' ... SEE CODE DCA JLC TAD JLC SPA CLA JMP XRET TAD (-10 TAD JLC SMA CLA JMP XRET / EXIT IF NOT NUMBER TAD ZTMP CLL RTL / *4 TAD ZTMP / *5 CLL RAL / *10 TAD JLC DCA ZTMP ISZ ZCTR / CHAR COUNTER #endasm } #asm XRET, TAD ZCTR MQL CMA TAD STKP / ->RSL DCA TMP TADI TMP DCA TMP TAD ZTMP XINV, NOP DCAI TMP / WRITE RSL MQA / RETURN LENGTH #endasm } xinit() { puts("PDP-8 C Compiler V1.0:\r\n"); } memcpy(dst,src,cnt) int dst,src,cnt; { #asm CLA TAD STKP TAD (-4 DCA 12 CMA TADI 12 DCA 11 CMA TADI 12 DCA 10 TADI 12 CIA DCA ZTMP CP1, TADI 10 DCAI 11 ISZ ZTMP JMP CP1 #endasm } kbhit() { #asm CLA CMA KSF CLA #endasm } putc(p) char p; { p; #asm TLS MP1, TSF JMP MP1 #endasm } strcmp( dm , sm ) char *dm,*sm; { int rsl; rsl=0; while (*dm) rsl+=(*sm++-*dm++); return rsl; } strcpy( dm , sm ) char *dm,*sm; { while (*dm++=*sm++); } strcat( dm , sm ) char *dm,*sm; { int qm; qm=dm; while(*dm) dm++; strcpy(dm,sm); return qm; } strstr ( s , o ) char *s , *o ; { char *x , *y , *z ; for ( x = s ; * x ; x ++ ) { for ( y = x , z = o ; * z && * y == * z ; y ++ ) z ++ ; if ( z > o && ! * z ) return x ; } return 0 ; } exit(retval) int retval; { #asm CALL 0,EXIT HLT #endasm } isalnum(vl) int vl; { return (isnum(vl) + isalpha(vl)); } isnum(vl) int vl; { vl; #asm TAD (-48 SPA JMP XNO TAD (-10 SMA CLA XNO, CLA SKP IAC #endasm } isspace(vl) int vl; { vl; #asm SNA JMP YNO TAD (-33 SMA CLA YNO, CLA SKP IAC #endasm } isalpha(vl) int vl; { vl; /* Include '?' and '@' as alpha vars */ #asm TAD (-65 SPA JMP ANO TAD (-26 SPA JMP BNO TAD (-6 SPA JMP ANO TAD (-26 BNO, SMA CLA ANO, CLA SKP IAC #endasm } cupper(p) /* In place convert to uppercase */ int p; { p; #asm DCA ZTMP CPP1, CLA TADI ZTMP SNA JMP CPP2 TAD (-97 SPA JMP CPP3 TAD (-26 SMA JMP CPP3 TAD (91 DCAI ZTMP CPP3, ISZ ZTMP JMP CPP1 CPP2, #endasm } /* Arbitrary fgets(). Read until LF, CR/LF are retained*/ /* EOF returns null, else strlen(*p) */ fgets(p) char *p; { char *q; q=p; while(*p=fgetc()) { if (*p++==10) break; } *p=0; return (p-q); } memset(dst, dt, sz) char *dst; int dt,sz; { int i; for (i=0;i<sz;i++) *dst++=dt; } /* ** reverse string in place */ reverse(s) char *s; { char *j; int c; j = s + strlen(s) - 1; while(s < j) { c = *s; *s++ = *j; *j-- = c; } } /* This is somewhat involved in that the vararg system in SmallC is rather limited. For printf and sprintf, a char buffer is required supplied by the user or, as below, located at the end of the stack (7500 .. 64 locs). In addition, another page zero location (ZPTR) is required. This is always risky as the SABR/LOADER system uses a lot of locations here. See how this goes as it is possible to use arbitrary localions on the stack as well. */ fprintf(nxtarg) int nxtarg; { #asm ISZ FPTR JMP PRINTF #endasm } printf(nxtarg) int nxtarg; { #asm TAD (3904 / THIS IS THE PRINT BUFFER AT 7500 ON THE STACK DCA ZPTR JMP SPRINTF #endasm } /* ** sprintf(obfr, ctlstring, arg, arg, ...) ** Called by printf(). */ sprintf(nxtarg) int nxtarg; { int arg, left, pad, cc, len, maxchr, width; char *ctl, *sptr, str[17],*obfr,zptr; #asm TAD ZPTR DCAI STKP / POINTS TO ZPTR #endasm cc = 0; nxtarg = &nxtarg-nxtarg; if (zptr) obfr=zptr; else obfr = *nxtarg++; ctl = *nxtarg++; while(*ctl) { if(*ctl!='%') {*obfr++=*ctl++; ++cc; continue;} else ++ctl; if(*ctl=='%') {*obfr++=*ctl++; ++cc; continue;} if(*ctl=='-') {left = 1; ++ctl;} else left = 0; if(*ctl=='0') pad = '0'; else pad = ' '; width=0; if(isdigit(*ctl)) { ctl+=atoi(ctl, &width); } maxchr=0; if(*ctl=='.') { ctl+=atoi(++ctl,&maxchr)+1; } arg = *nxtarg++; sptr = str; switch(*ctl++) { case 'c': str[0] = arg; str[1] = NULL; break; case 's': sptr = arg; break; case 'd': itoa(arg,str); break; case 'b': itoab(arg,str,2); break; case 'o': itoab(arg,str,8); break; case 'u': itoab(arg,str,10); break; case 'x': itoab(arg,str,16); break; default: return (cc); } len = strlen(sptr); if(maxchr && maxchr<len) len = maxchr; if(width>len) width = width - len; else width = 0; if(!left) while(width--) {*obfr++=pad; ++cc;} while(len--) {*obfr++=*sptr++; ++cc; } if(left) while(width--) {*obfr++=pad; ++cc;} } *obfr=0; zptr; #asm SNA / IF ZPTR, EITHER USE PUTS OR FPUTS JMP PF1 JMSI PSH CLA TAD FPTR SNA CLA JMP PF2 JMSI PCAL FPUTS JMP PF3 PF2, JMSI PCAL PUTS PF3, JMSI POP PF1, CLA DCA ZPTR DCA FPTR #endasm return(cc); } /* ** itoa(n,s) - Convert n to characters in s */ itoa(n, s) char *s; int n; { int sign; char *ptr; ptr = s; if ((sign = n) < 0) n = -n; do { *ptr++ = n % 10 + '0'; } while ((n = n / 10) > 0); if (sign < 0) *ptr++ = '-'; *ptr = '\0'; reverse(s); } /* ** itoab(n,s,b) - Convert "unsigned" n to characters in s using base b. ** NOTE: This is a non-standard function. */ itoab(n, s, b) int n; char *s; int b; { char *ptr; int lowbit; ptr = s; b >>= 1; do { lowbit = n & 1; n = (n >> 1) & 4095; *ptr = ((n % b) << 1) + lowbit; if(*ptr < 10) *ptr += '0'; else *ptr += 55; ++ptr; } while(n /= b); *ptr = 0; reverse (s); } strlen(p) char *p; { int n; n=0; while (*p++) n++; return n; } #define EOF 0 sscanf(nxtarg) int nxtarg; { char *ctl; int u; int *narg, wast, ac, width, ch, cnv, base, ovfl, sign, *ibfr; ac = 0; nxtarg = &nxtarg-nxtarg; ibfr = *nxtarg++; ctl = *nxtarg++; while(*ctl) { if(*ctl++ != '%') continue; narg = *nxtarg++; ctl += atoi(ctl, &width); if (!width) width=-1; if(!(cnv = *ctl++)) break; switch(cnv) { case 'c': *narg = *ibfr++; break; case 's': while(width--) if((*narg++ = *ibfr++) == 0) break; *narg = 0; break; default: switch(cnv) { case 'b': base = 2; break; case 'd': base = 10; break; case 'o': base = 8; break; case 'x': base = 16; break; default: return (ac); } *narg = u = 0; sign = 1; while(width-- && (ch=*ibfr++)>32) { if(ch == '-') {sign = -1; continue;} if(ch < '0') break; if(ch >= 'a') ch -= 87; else if(ch >= 'A') ch -= 55; else ch -= '0'; u = u * base + ch; } *narg = sign * u; } ++ac; } return (ac); } |
> | 1 | ../include/libc.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 | /* * This file is part of the CC8 OS/8 C compiler. * * The CC8 OS/8 C compiler 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. * * The CC8 OS/8 C compiler 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 the CC8 OS/8 C compiler as ../GPL3.txt. If not, see * <http://www.gnu.org/licenses/>. */ #include <libc.h> #include <init.h> #define SMAX 10 #define CMAX 256 #define BMAX 64 #define LMAX 32 #define DMAX 32 #define CBMX 1024 #define LXMX 999 int asm[CBMX]; int ltbf[512]; int xlt[CMAX]; int gm[CMAX]; /* Global symbol table */ int tkbf[LMAX]; int *p,*q,*s,*ltpt; int gsym,lsym,gadr,ladr,stkp,lctr,*fptr,gsz,ctr,tm,ectr,cop; int glim,*n,ccm; int tmp; int tkn[BMAX]; int bfr[BMAX]; int tmbf[LMAX]; int smbf[LMAX]; int Lb[BMAX]; int lm[CMAX]; /* Auto symbol table */ int fstk[BMAX]; /* Push down stack for For etc. */ int inproc,addr,cbrk; int izf,ixf,idf,ssz,icd; skpsp() { while (isspace(*p)) p++; } getsym() { q=tkbf; skpsp(); while (isalnum(*p)) *q++=*p++; *q=0; skpsp(); return *tkbf; } /* recursive descent parser for arithmetic/logical expressions */ S( ) { cop=0; J( ); switch(*p++){ case '=': S(); stri(1); stkp--; break; case ']': case ')': return 1; case ',': break; default: p--; } return 0; } /* end S */ J( ) { K( ); switch(*p++){ case '&': J( ); stri(20); break; case '|': J( ); stri(-20); break; default: p--; return; } stkp--; } /* end J */ K( ) { V( ); switch(*p++){ case '<': K( ); stri(11); break; case '>': K( ); stri(-11); break; case '$': K( ); stri(24); break; default: p--; return; } stkp--; } /* end K */ V( ) { W( ); switch(*p++){ case '+': V(); stri(2); break; case '-': V(); stri(3); break; default: p--; return; } stkp--; } /* end V */ W( ) { Y( ); skpsp(); cop=*p; switch(*p++) { case '*': W( ); stri(13); break; case '/': W( ); stri(14); break; case '%': W( ); stri(14);stri(-14); break; case '=': if (*p=='=') { *p='$';return; } default: p--; return; } stkp--; } /* end W */ Y( ) { int o,ctx; int txbf[10]; skpsp(); if (!*p) return; if (cop) { stri(19); stkp++; } if (*p=='"') { stri(10); stri(ltpt-ltbf); while (*++p-'"') { if (*p=='\\') switch (*++p) { case 'r': *p=13; break; case 'n': *p=10; } *ltpt++=*p; } *ltpt++=0; p++; return; } n=q=p; if (*p=='-') p++; if(isdigit(*p)) { while(isdigit(*p)) p++; stri(4); atoi(q,&tmp); stri(tmp); return; } if (*p==39) { stri(4); stri(*++p); p+=2; return; } ixf=izf=idf=icd=0; if (!getsym()) { switch (*p++) { case '&': getsym(); stri(21); stri(fndlcl(tkbf)); return; case '*': getsym(); ixf++; break; case '!': Y(); stri(26); return; case '~': Y(); stri(-26); return; case '(': S(); return; case ')': icd=1; return; } } if(*p=='('){ strcpy(txbf,tkbf); ctx=o=0;p++; while (*p && !o) { o=S( ); if (icd) break; stkp++; stri(19); ctx++; /* arg count */ } stri(9); stri(ctx); stkp-=ctx; if ((o=strstr(gm,txbf))){ stri(o-gm); } else { stri(gsz); strpad(txbf); strcat(gm,smbf); gsz+=9; } return; } /* Digraphs */ q=p+1; if (tmp=*q==*p) switch (*p) { case '+': izf=-tmp; p+=2; break; case '-': idf=-tmp; p+=2; break; } o=fndlcl(tkbf); tmp=-17; if (ssz>1) { if (*p=='[') { stri(21); stri(o); stri(19); stkp++; p++;S(); stri(2); if (*p=='=') stri(19); else { stri(22); stkp--; } return; } tmp=21; } switch (*p) { case '=': if (*q=='=') break; tmp=8; if (ixf) tmp=-8; ixf=0; stkp++; break; } stri(tmp); stri(o); if (*n=='-') stri(27); if (izf) stri(15); if (idf) stri(25); if (ixf) stri(22); return; } /* end Y */ procst(trm) char trm; { ccm=ctr=1; p=q=Lb; while(1) { tm=fgetc(); ctr-=tm=='('; ctr+=tm==')'; ccm-=tm==','; if (!ctr || tm==trm) break; *q++=tm; } *q=0; if (inproc) while (*p) S(); } strpad(sym) char *sym; { char *a,*b; strcpy(a=smbf," "); /* 9 spaces */ while (*sym) *a++=*sym++; } addsym(sym,sz) char *sym; int sz; { strpad(sym); smbf[8]=sz; if (inproc+(sz<0)) { smbf[7]=stkp+1; stkp+=sz; strcat(lm,smbf); stri(6); stri(sz); return; } smbf[7]=gadr; gadr+=sz; strcat(gm,smbf); gsz+=9; } fndlcl(sym) char *sym; { strpad(sym); smbf[7]=0; if (s=strstr(lm,smbf)) { ssz=s[8]; s=s+7; return *s-stkp; } if (s=strstr(gm,smbf)) { ssz=s[8]; s=s+7; return *s; } return 0; } gettk() { char xtm; q=tkbf; while (isspace(xtm=fgetc())); while (isalnum(xtm)) { *q++=xtm; xtm=fgetc(); } *q=0; return xtm; } popfr() { while (*fptr==inproc) { cbrk=*--fptr; stri(23); stri(*--fptr); stri(5); stri(*fptr+2); fptr--; } } dostt() { p=tmbf; while (tm!=';') { *p++=tm; tm=fgetc(); } *p=0; strcpy(Lb,tkbf); strcat(Lb,tmbf); p=Lb; S(); tm=1; } fnbrk() { while (tm!='(') tm=fgetc(); } next() { char *lp; int fflg; lp=0; if (*tkbf) { strcat(tkbf," "); lp=strstr(tkn,tkbf); } fflg=lctr; if (lp) { switch(lp-tkn) { case 0: while (tm!=';' && tm!='{') { tm=gettk(); strcpy(bfr,tkbf); while (isspace(tm)) tm=fgetc(); switch (tm) { case '[': tm=gettk(); atoi(tkbf,&fflg); addsym(bfr,fflg); tm=fgetc(); break; case '(': stri(7); stri(gsz); if (strstr("main",tkbf)) strcpy(tkbf,"XMAIN"); addsym(tkbf,1); procst(')'); stkp=-(ccm+1); while (*p) { getsym(); addsym(tkbf,-1); p++; stkp+=2; } stkp=0; tm=gettk(); cbrk=100; break; case ',': case ';': addsym(tkbf,1); break; } /* end whie */ } /* end case 0: */ break; case 4: fflg=fflg+100; case 12: fnbrk(); stri(5); *++fptr=fflg; stri(fflg); procst(0); stri(12); stri(tm=*fptr+2); *++fptr=cbrk; if (fflg<100) cbrk=tm; *++fptr=inproc; lctr+=3; tm=0; stri(99); break; case 7: tm=0; break; case 18: stri(23); stri(cbrk); break; case 24: procst(';'); stri(23); stri(ectr); tm=1; break; case 31: fnbrk(); procst(';'); stri(5); stri(lctr++); *++fptr=lctr; procst(';'); stri(12); stri(lctr+2); stri(23); stri(lctr+1); stri(5); stri(lctr++); procst(')'); *++fptr=cbrk; *++fptr=inproc; stri(23); stri(lctr-2); stri(5); stri(lctr++); cbrk=lctr++; tm=0; break; default: dostt(); } /* End switch */ } else switch (tm) { case '{': tm=1; inproc++; break; case '}': break; case -1: case 0: stri(0); #asm CALL 1,CHAIN ARG FNM HLT FNM, TEXT "CC2@@@" #endasm case '/': while (fgetc()!='/'); /* Skip comment */ tm=1; break; default: dostt(); } return tm; } main() { char trm; memset(ltbf,0,&ssz-ltbf); fopen("CC.C","r"); strcpy(tkn,"int if else while break return for "); lctr = 10; ectr = 900; ltpt = ltbf; fptr = fstk; *fptr = -1; gadr = 128; /* Start of globals */ iinit(asm); tm=gettk(); while (1) { trm=next(); tm=gettk(); switch (trm) { case '{': inproc++; break; case '}': inproc--; if (!inproc) { stri(5); stri(ectr++); stri(16); stri(-stkp); stkp = *lm = 0; break; } case ';': case 1: stri(99); if (!strcmp("else",tkbf)) { stri(-23); stri(100+lctr+2); popfr(); *++fptr=100+lctr++; *++fptr=cbrk; *++fptr=inproc; } else popfr(); case 0: break; default: procst(';'); } } } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * This file is part of the CC8 OS/8 C compiler. * * The CC8 OS/8 C compiler 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. * * The CC8 OS/8 C compiler 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 the CC8 OS/8 C compiler as ../GPL3.txt. If not, see * <http://www.gnu.org/licenses/>. */ #include <libc.h> #include <init.h> #define SMAX 10 #define CMAX 256 #define BMAX 64 #define LMAX 32 #define DMAX 32 #define CBMX 1024 #define LXMX 999 int asm[CBMX]; int ltbf[512]; int xlt[CMAX]; int gm[CMAX]; /* Global symbol table */ int tkbf[LMAX]; int *p,*q,*s,*ltpt; int gsym,lsym,gadr,ladr,stkp,*as,lctr,*fptr,gsz,ctr,tm,ectr; int glim; int ltsz,pflg,t; int tmstr[32]; main() { as=asm; fopen("HEADER.SB","r"); fopen("CC.SB","w"); strcpy(xlt,"ITOA PUTS DISPXY GETC GETS ATOI SSCANF XINIT MEMCPY KBHIT PUTC STRCPY STRCAT STRSTR EXIT ISNUM "); strcat(xlt,"ISALPH SPRINTF MEMSET FGETC FOPEN FPUTC FCLOSE PRINTF ISALNUM ISSPACE FPRINTF FPUTS STRCMP CUPPER FGETS "); while (t=fgetc()) if (t!=12) /* Ignore form feed */ fputc(t); cupper(gm); while (*as) { pflg=0; *tmstr=0; switch (*as++) { case 99: fprintf("/\r"); break; case 1: fprintf("\tJMSI PTSK\r"); break; case 3: strcpy(tmstr,"\tCIA\r"); case 2: fprintf("%s\tTADI STKP\r\tJMSI POP\r",tmstr); break; case 4: fprintf("\tCLA\r\tTAD (%d\r",*as++); break; case 5: if (*as<0) *as=100-*as; fprintf("CC%d,\r",*as++); break; case 6: if (*as>1) fprintf("\tTAD STKP\r\tTAD (%d\r\tDCA STKP\r",*as); else if (*as>0) fputs("\tISZ STKP\r"); as++; break; case 7: p=gm+*as++; while (*p-' ') fputc(*p++); fputs(",\r"); break; case -8: strcpy(tmstr,"\tDCA JLC\r\tTADI JLC\r"); case 8: if (*as>0) fprintf("\tCLA\r\tTAD (%d\r%s\tJMSI PSH\r",*as++,tmstr); else fprintf("\tCLA\r\tTAD STKP\r\tTAD (%d\r%s\tJMSI PSH\r",*as++,tmstr); break; case 9: tm=*as++; p=gm+*as++; strcpy(tkbf," "); memcpy(tkbf,p,7); if (p=strstr(xlt,tkbf)) { t=(p-xlt)>>3; if ((t==6) + (t==17) + (t==23)) fprintf("\tCLA\r\tTAD (%d\r\tJMSI PSH\r",tm++); fprintf("\tCLA\r\tTAD (%d\r\tMQL\r\tCALL 1,LIBC\r\tARG STKP\r\tCDF1\r",t); } else fprintf("\tJMSI PCAL\r\t%s\r",tkbf); if (tm) fprintf("\tMQL\r\tTAD (%d\r\tTAD STKP\r\tDCA STKP\r\tSWP\r",-tm); break; case 10: fprintf("\tCLA\r\tTAD GBL\r\tTAD (%d\r",*as++); break; case -11: fprintf("\tCIA\r\tTADI STKP\r\tJMSI POP\r\tSMA SZA CLA\r\tCMA\r"); break; case 11: fprintf("\tCIA\r\tTADI STKP\r\tJMSI POP\r\tSPA CLA\r\tCMA\r"); break; case 12: fprintf("\tSNA\r\tJMP CC%d\r",*as++); break; case 13: fprintf("\tJMSI POP\r\tDCA JLC\r\tSWP\r\tCALL 1,MPY\r\tARG JLC\r\tCDF1\r"); break; case -14: fprintf("\tCALL 1,IREM\r\tARG 0\r\tCDF1\r"); break; case 14: fprintf("\tJMSI POP\r\tDCA JLC\r\tSWP\r\tCALL 1,DIV\r\tARG JLC\r\tCDF1\r"); break; case 15: fprintf("\tISZI JLC\r\tNOP\r"); break; case 16: fprintf("\tMQL\r\tTAD STKP\r\tTAD (%d\r\tDCA STKP\r\tSWP\r\tJMPI POPR\r/\r",*as++); break; case 17: pflg++; case -17: if (*as>0) fprintf("\tCLA\r\tTAD (%d\r\tDCA JLC\r\tTADI JLC\r",*as++); else fprintf("\tCLA\r\tTAD STKP\r\tTAD (%d\r\tDCA JLC\r\tTADI JLC\r",*as++); if (pflg==0) break; case 19: fprintf("\tJMSI PSH\r"); break; case 20: fprintf("\tANDI STKP\r\tJMSI POP\r"); break; case -20: fprintf("\tJMSI POP\r\tMQO\r"); break; case 21: if (*as>0) fprintf("\tCLA\r\tTAD (%d\r",*as++); else fprintf("\tCLA\r\tTAD STKP\r\tTAD (%d\r",*as++); break; case 22: fprintf("\tDCA JLC\r\tTADI JLC\r"); break; case 23: if (*as<100) fprintf("\tJMP CC%d\r",*as); as++; break; case -23: fprintf("\tJMP CC%d\r",*as++); break; case 24: fprintf("\tCIA\r\tTADI STKP\r\tJMSI POP\r\tSNA CLA\r\tCMA\r"); break; case 25: fprintf("\tMQL\r\tCMA\r\tTADI JLC\r\tDCAI JLC\r\tSWP\r"); break; case 26: fprintf("\tSNA CLA\r"); case -26: fprintf("\tCMA\r"); break; case 27: fputs("\tCIA\r"); } } ltsz=ltpt-ltbf; fprintf("\tLAP\r\tCPAGE %d\rLCC0,\t%d\rXCC0,\tCC0\rCC0,\t\r",ltsz+2,-ltsz); p=ltbf; while (ltsz) { fprintf("%d",*p++); if (ltsz>1) fputs("; "); if ((ltsz&7)==0) fputc(13); ltsz--; } fprintf("\r\tEAP\rGBLS,\t%d\r",gadr); fprintf("\rMCC0,\t0\r\tCDF1\r\tTAD LCC0\r\tSNA CLA\r\tJMP I MCC0\r\tTAD XCC0\r\tDCA JLC\rDCC0,\tCDF0\r\tTADI JLC\r"); fprintf("\tJMSI PSH\r\tCLA\r\tISZ JLC\r\tISZ LCC0\r\tJMP DCC0\r\tJMP I MCC0\rCCEND,\t0\r\t\END\r"); fclose(); } |
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | I received the following license grant via private email, which supercedes the LICENSE file text distributed with d8tape in 2002: --------- On Fri, Nov 10, 2017 at 6:38 PM, Rob Krten <rob@krten.com> wrote: As far as d8tape goes: I, Robert Krten, hereby provide a royalty free, perpetual, worldwide license to use the source code and information provided in my PDP-8 disassembler, called "d8tape" for any purpose whatsoever. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * d8tape.h * * (C) Copyright 2007 by Robert Krten, all rights reserved. * Please see the LICENSE file for more information. * * This module contains the manifest constants and other header * information. * * 2007 10 25 R. Krten created * 2007 10 28 R. Krten added TAG_INDIRECTFC */ // constants #define CORE_SIZE 4096 // size of core memory #define TAG_DATA 0x0001 // memory region is tagged as data, #define TAG_SUB 0x0002 // subroutine target, or, #define TAG_LABEL 0x0004 // label #define TAG_RETURN 0x0008 // return from subroutine #define TAG_TYPE_MASK 0x00ff // mask of above types #define TAG_WRITABLE 0x0100 // set if anyone writes to this data location (else constant) #define TAG_KONSTANT 0x0200 // can be changed from Caaaa -> Kvvvv #define TAG_INDIRECTFC 0x0400 // target of an indirect flow control (JMS I / JMP I) (only meaningful if not writable) #include <stdint.h> // segment info typedef struct { uint16_t saddr; // starting address uint16_t nwords; // number of contiguous words } segment_t; // prototypes // flow.c extern void flow (void); // dasm.c extern int ea (int addr, int opcode, int *indirect, int *curpage); extern void disassemble (void); extern int is_data (int v); extern int fetch_iot (int code, char *dis, char *com); |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * dasm.c * * (C) Copyright 2003 by Robert Krten, all rights reserved. * Please see the LICENSE file for more information. * * This module contains the PDP-8 disassembler. * Note that the 8/I and 8/L are featured at this point; other models * should be added (particularly the 8/E's EAE instructions, as well * as new IOT decodings, etc) * * 2003 12 16 R. Krten created * 2007 10 29 R. Krten added better output formatting * 2007 11 02 R. Krten added xrefs * 2009 02 08 D. North fixups for missing 7002 BSW and removal of * 7600 CLA case (conflicts with 7200 on reassembly) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <time.h> #include "d8tape.h" #include "iot.h" // decode table for IOTs extern char *progname; // main.c extern char *version; // version.c extern int optv; // main.c extern char *tapename; // main.c, name of tape image extern short int core []; // main.c, in-core image (-1 means location never used) extern uint16_t tags []; // main.c, analysis tags extern segment_t *segments; // main.c, used to accumulate runs of data (from origin for nwords) extern int nsegments; // main.c, indicates how many segments we have static void header (void); static void disassemble_range (int start, int end); static void pad (char *buf, int off, int pos); static void xrefs (int addr); /* * dasm8 * * This takes the current address and the instruction value * and prints the decoded instruction. A static variable * is used to kludge up 2-word instructions (e.g., MUY <const>). * * The IOTs are coded in a table; in some cases, conflicts exist, you'll * need to select the appropriate #defines to make them go away :-) * As shipped, the #defines match my preferences. * * Formatting rules: * - the following types of output exist: * - labels * - banners * - code * - data * * For each type, the following format is used (all tabs, as shown by the single backtick * character, are assumed to be at 4 character tabstops. If you don't like this, pipe * the output through "expand -4"). * * Labels: * 1111111111222222222233333333334444444444555555555566666666667777777777 * 01234567890123456789012345678901234567890123456789012345678901234567890123456789 * t t t t t t t t t t t t t t t t t t t t * TAAAA, * * where "T" is the label type, one of "D" for data, "L" for executable label, * and "S" for subroutine entry, and "AAAA" is the four digit octal address. * (See "Data" below for additional details of the "D" type). * * Banners: * 1111111111222222222233333333334444444444555555555566666666667777777777 * 01234567890123456789012345678901234567890123456789012345678901234567890123456789 * t t t t t t t t t t t t t t t t t t t t * //////////////////////////////////////////////////////////////////////////////// * / * /```CONTENT * / * //////////////////////////////////////////////////////////////////////////////// * * Where "CONTENT" is the content of the banner, e.g., "SUBROUTINE S1234". * * Code: * 1111111111222222222233333333334444444444555555555566666666667777777777 * 01234567890123456789012345678901234567890123456789012345678901234567890123456789 * t t t t t t t t t t t t t t t t t t t t * op1`````````````````````/ COMMENTS..............................@@=AAAA,OOOO * opc1````````````````````/ COMMENTS..............................@@=AAAA,OOOO * op1 TAAAA```````````````/ COMMENTS..............................@@=AAAA,OOOO * op1 I TAAAA`````````````/ COMMENTS..............................@@=AAAA,OOOO * op1 op2 op3 op4 op5 op6`/ COMMENTS..............................@@=AAAA,OOOO * 12345678911234567892123 1234567891123456789212345678931234567 (DISLEN and COMLEN, resp.) * 01234567891123456789212345678 234567891123456789212345678931234567890 (COMSTART and DATASTART, resp.) * * Where "op1", "opc1", "op2" through "op6" are 3 or 4 character mnemonic * opcodes. "T" is the label type (as above), and "AAAA" is the address. * Tabs are used to fill whitespace to the "/" comment delimiter, and from the * end of the comment to the @@. The area at the "@@" indicates the address * and the contents. * * This is where the COMLEN and DISLEN buffer sizes are derived from, and the * COMSTART position (28, the start of the "/") * * Data: * 1111111111222222222233333333334444444444555555555566666666667777777777 * 01234567890123456789012345678901234567890123456789012345678901234567890123456789 * t t t t t t t t t t t t t t t t t t t t * CAAAA,``VVVV````````````````/ op1 op2 op3 op4 op5 op6 COMMENTS.................. * DAAAA,``VVVV````````````````/ op1 op2 op3 op4 op5 op6 COMMENTS.................. * KVVVV,``VVVV````````````````/ op1 op2 op3 op4 op5 op6 COMMENTS.................. * * Where "C" is used for constants whose values are not unique, "D" is used * for writable data, and "K" is used for constants that can be added in the * symbol table. The distinction between "C" and "K" is that if two different * memory locations both define the same constant value, we need to use "C" * because it's tagged based on the address, whereas "K" is tagged based on * the value. * * Other types to consider are comment blocks imported from a control file. */ static const char *codes [6] = {"AND", "TAD", "ISZ", "DCA", "JMS", "JMP"}; // IOT and OPR are decoded elsewhere static unsigned short int two_word = 0; // set to hold two-word instruction (e.g., EAE ops), else zero (instruction 0, AND, is not a two-word instruction) #define COMLEN 37 // length of comment, see "Code", above (both the number of bytes and the max number of characters; tabs will only make the number of bytes less) #define DISLEN 23 // length of disassembly area, see "Code" above (ditto) #define COMSTART 28 // 0-based column number where the comments start #define DATASTART 40 // 0-based column number where the data (@@=AAAA,OOOO) starts static char disbuf [DISLEN + 1]; static char combuf [COMLEN + 1]; void dasm8 (int addr, unsigned short int buf) { int ind, cur; int eff_addr; int primary; // is primary disassembly 'c'ode or 'd'ata? if (optv > 1) { printf ("dasm8 (addr 0%04o word 0%04o tag 0x%04x)\n", addr, buf, tags [addr]); } eff_addr = ea (addr, buf, &ind, &cur); if (two_word) { printf ("\t%04o /\t\t\t\t\t / (operand)\n", buf); two_word = 0; return; } // prepare buffer areas for disassembly and comments. memset (disbuf, 0, sizeof (disbuf)); memset (combuf, 0, sizeof (combuf)); primary = 'c'; // default to code disassembly if (tags [addr] & TAG_LABEL) { printf ("L%04o,\n", addr); } if (tags [addr] & TAG_SUB) { printf ("\n"); printf ("////////////////////////////////////////////////////////////////////////////////\n"); printf ("/\n"); printf ("/\tSUBROUTINE: S%04o\n", addr); printf ("/\n"); xrefs (addr); printf ("////////////////////////////////////////////////////////////////////////////////\n"); printf ("S%04o,\n", addr); printf ("\t0\t\t\t\t\t\t/ return area\n"); // done; can't be SUB and anything else (except label, perhaps) return; } if (tags [addr] & TAG_DATA) { // if it's data, set primary as data primary = 'd'; if ((addr & 07770) == 00010) { // addresses 0010 -> 0017 are autoindex printf ("AI%o,\t%04o\t\t\t\t/ AUTO-INDEX REGISTER", addr & 7, core [addr]); } else { if (tags [addr] & TAG_INDIRECTFC) { printf ("C%04o,\n", addr); } printf ("%c%04o,\t", tags [addr] & TAG_KONSTANT ? 'K' : tags [addr] & TAG_WRITABLE ? 'D' : 'C', tags [addr] & TAG_KONSTANT ? core [addr] : addr); printf ("%04o\t\t\t\t/", core [addr]); } } switch (buf & 07000) { case 00000: // AND case 01000: // TAD case 02000: // ISZ case 03000: // DCA case 04000: // JMS case 05000: // JMP sprintf (disbuf, "%s ", codes [buf >> 9]); if (ind) { strcat (disbuf, "I "); } else { strcat (disbuf, " "); } if (tags [eff_addr] & TAG_SUB) { strcat (disbuf, "S"); } else if (tags [eff_addr] & TAG_LABEL) { strcat (disbuf, "L"); } else { if ((eff_addr & 07770) == 00010) { // addresses 0010 -> 0017 strcat (disbuf, "AI"); strcat (combuf, "AUTO INDEX REGISTER"); } else { strcat (disbuf, (tags [eff_addr] & TAG_KONSTANT) ? "K" : tags [eff_addr] & TAG_WRITABLE ? "D" : "C"); } } if (tags [addr] & TAG_RETURN) { strcat (combuf, "return "); } else { // comment indirect flow control change to reflect ultimate target switch (buf & 07400) { case 04400: sprintf (combuf + strlen (combuf), "long call to S%04o ", core [eff_addr]); break; case 05400: sprintf (combuf + strlen (combuf), "long jump to L%04o ", core [eff_addr]); break; } } if ((eff_addr & 07770) == 00010) { // address 0010 -> 0017 sprintf (disbuf + strlen (disbuf), "%o ", eff_addr & 7); } else { sprintf (disbuf + strlen (disbuf), "%04o ", (tags [eff_addr] & TAG_KONSTANT) ? core [eff_addr] : eff_addr); } break; case 06000: // IOT fetch_iot (buf, disbuf, combuf); break; case 07000: // OPR // perform "short form" OPRs here first... switch (buf) { case 07000: sprintf (disbuf, "NOP"); break; case 07002: sprintf (disbuf, "BSW"); break; case 07041: sprintf (disbuf, "CIA"); break; case 07120: sprintf (disbuf, "STL"); break; case 07204: sprintf (disbuf, "GLK"); break; case 07240: sprintf (disbuf, "STA"); strcat (combuf, "AC = 7777 (-0001)"); break; case 07300: sprintf (disbuf, "CLA CLL"); strcat (combuf, "AC = 0000"); break; case 07301: sprintf (disbuf, "CLA CLL IAC"); strcat (combuf, "AC = 0001"); break; case 07302: sprintf (disbuf, "CLA IAC BSW"); strcat (combuf, "AC = 0100 (64)"); break; case 07305: sprintf (disbuf, "CLA CLL IAC RAL"); strcat (combuf, "AC = 0002"); break; case 07325: sprintf (disbuf, "CLA CLL CML IAC RAL"); strcat (combuf, "AC = 0003"); break; case 07326: sprintf (disbuf, "CLA CLL CML RTL"); strcat (combuf, "AC = 0002"); break; case 07307: sprintf (disbuf, "CLA CLL IAC RTL"); strcat (combuf, "AC = 0004"); break; case 07327: sprintf (disbuf, "CLA CLL CML IAC RTL"); strcat (combuf, "AC = 0006"); break; case 07330: sprintf (disbuf, "CLA CLL CML RAR"); strcat (combuf, "AC = 4000 (-4000 = -2048 dec)"); break; case 07332: sprintf (disbuf, "CLA CLL CML RTR"); strcat (combuf, "AC = 2000 (1024)"); break; case 07333: sprintf (disbuf, "CLA CLL CML IAC RTL"); strcat (combuf, "AC = 6000 (-2000 = -1024 dec)"); break; case 07340: sprintf (disbuf, "CLA CLL CMA"); strcat (combuf, "AC = 7777 (-0001)"); break; case 07344: sprintf (disbuf, "CLA CLL CMA RAL"); strcat (combuf, "AC = 7776 (-0002)"); break; case 07346: sprintf (disbuf, "CLA CLL CMA RTL"); strcat (combuf, "AC = 7775 (-0003)"); break; case 07350: sprintf (disbuf, "CLA CLL CMA RAR"); strcat (combuf, "AC = 3777 (2047)"); break; case 07352: sprintf (disbuf, "CLA CLL CMA RTR"); strcat (combuf, "AC = 5777 (-2001 = -1025 dec)"); break; case 07401: sprintf (disbuf, "NOP"); break; case 07410: sprintf (disbuf, "SKP"); break; case 07600: sprintf (disbuf, "7600"); strcat (combuf, "AKA \"CLA\""); break; case 07610: sprintf (disbuf, "SKP CLA"); break; case 07604: sprintf (disbuf, "LAS"); break; case 07621: sprintf (disbuf, "CAM"); break; default: // determine group (0401 is 0000/0001 for group 1, 0400 for group 2, 0401 for EAE) switch (buf & 00401) { case 00000: // group 1 case 00001: // group 1 // sequence 1 if (buf & 00200) { strcat (disbuf, "CLA "); } if (buf & 00100) { strcat (disbuf, "CLL "); } // sequence 2 if (buf & 00040) { strcat (disbuf, "CMA "); } if (buf & 00020) { strcat (disbuf, "CML "); } // sequence 3 if (buf & 00001) { strcat (disbuf, "IAC "); } // sequence 4 if (buf & 00010) { if (buf & 00002) { strcat (disbuf, "RTR "); } else { strcat (disbuf, "RAR "); } } if (buf & 00004) { if (buf & 00002) { strcat (disbuf, "RTL "); } else { strcat (disbuf, "RAL "); } } break; case 00400: // group 2 // sequence 1 if (buf & 00100) { if (buf & 00010) { strcat (disbuf, "SPA "); } else { strcat (disbuf, "SMA "); } } if (buf & 00040) { if (buf & 00010) { strcat (disbuf, "SNA "); } else { strcat (disbuf, "SZA "); } } if (buf & 00020) { if (buf & 00010) { strcat (disbuf, "SZL "); } else { strcat (disbuf, "SNL "); } } // sequence 2 if (buf & 00200) { strcat (disbuf, "CLA "); } // sequence 3 if (buf & 00004) { strcat (disbuf, "OSR "); } if (buf & 00002) { strcat (disbuf, "HLT "); } break; case 00401: // EAE // sequence 1 if (buf & 00200) { strcat (disbuf, "CLA "); } // sequence 2 if (buf & 00100) { strcat (disbuf, "MQA "); } if (buf & 00040) { strcat (disbuf, "SCA "); } if (buf & 00020) { strcat (disbuf, "MQL "); } // sequence 3 switch (buf & 00016) { case 0: // no further ops, done break; case 002: strcat (disbuf, "SCL "); two_word = buf; break; case 004: strcat (disbuf, "MUY "); two_word = buf; break; case 006: strcat (disbuf, "DVI "); two_word = buf; break; case 010: strcat (disbuf, "NMI"); break; case 012: strcat (disbuf, "SHL "); two_word = buf; break; case 014: strcat (disbuf, "ASR "); two_word = buf; break; case 016: strcat (disbuf, "LSR "); two_word = buf; break; } break; } break; } break; } if (two_word) { strcat (disbuf, "+"); } // trim any trailing spaces while (*disbuf && disbuf [strlen (disbuf) - 1] == ' ') { disbuf [strlen (disbuf) - 1] = 0; } if (primary == 'c') { // if primary is code, then spill data too pad (disbuf, 0, COMSTART - 4); // add tabs to get disassembly to comment start (one tab less because we print it next) printf ("\t%s", disbuf); // print disassembly so far printf ("/ "); // print comment start pad (combuf, 2, DATASTART); // pad comment buffer to get to data area printf ("%s@@%04o=%04o\n", combuf, addr, buf); // print comment, address and opcode } else { // else we've already spilled both, just terminate the line pad (disbuf, 2, DATASTART); printf (" %s", disbuf); printf ("\n"); two_word = 0; // we don't care that it's a two-word when we're printing it as data } } /* * ea * * Calculate the effective address given the * address and opcode. Opcodes that don't have * an effective address (e.g., IOTs), return -1. * * The indirect pointer is optional, and, if specified, * will cause the location to be returned with a zero * or one indicating indirection. The indirect pointer * is not modified in case of a non-EA opcode. * * Similarly for the curpage pointer. */ int ea (int addr, int opcode, int *indirect, int *curpage) { int eff_addr; int c; int i; if (opcode >= 06000) { // IOTs and OPRs don't have an EA return (-1); } i = opcode & 00400; c = opcode & 00200; eff_addr = c ? (addr & 07600) + (opcode & 00177) : opcode & 00177; if (indirect) { *indirect = i; } if (curpage) { *curpage = c; } return (eff_addr); } /* * disassemble * * This drives disassembly once the flow analysis has been done. * * We disassemle in segment order. */ void disassemble (void) { int snum; header (); for (snum = 0; snum < nsegments; snum++) { printf ("\n*%04o\n", segments [snum].saddr); disassemble_range (segments [snum].saddr, segments [snum].saddr + segments [snum].nwords); } } static void header (void) { struct tm *tm; time_t now; int nused, ndata, ncode; int i; time (&now); tm = localtime (&now); nused = ndata = ncode = 0; for (i = 0; i < CORE_SIZE; i++) { if (core [i] >= 0) { nused++; if (tags [i] & TAG_DATA) { ndata++; } else { ncode++; } } } printf ("TITLE \"AUTOMATIC DISASSEMBLY OF %s BY D8TAPE\"\n", tapename); printf ("////////////////////////////////////////////////////////////////////////////////\n"); printf ("/\n"); printf ("/\tAutomatic Disassembly of %s\n", tapename); printf ("/\tGenerated %04d %02d %02d %02d:%02d:%02d\n", tm -> tm_year + 1900, tm -> tm_mon + 1, tm -> tm_mday, tm -> tm_hour, tm -> tm_min, tm -> tm_sec); printf ("/\tGenerated by d8tape version %s\n", version); printf ("/\tVisit http://www.pdp12.org/pdp8/software/index.html for updates\n"); printf ("/\n"); printf ("/\tSymbol format:\n"); printf ("/\t\tAIx -- Auto-index variables (address range 001x)\n"); printf ("/\t\tCaaaa -- Constants (non-unique)\n"); printf ("/\t\tDaaaa -- Data (read/write variables)\n"); printf ("/\t\tKvvvv -- Program-wide unique constants\n"); printf ("/\t\tLaaaa -- Labels for control flow targets\n"); printf ("/\t\tSaaaa -- Subroutines\n"); printf ("/\n"); printf ("/\tWhere:\n"); printf ("/\t\taaaa is the definition address\n"); printf ("/\t\tvvvv is the value of the constant\n"); printf ("/\t\tx is the last digit of the address 001x for auto-index variables\n"); printf ("/\n"); printf ("/\t%04o locations used, %04o code and %04o data\n", nused, ncode, ndata); printf ("////////////////////////////////////////////////////////////////////////////////\n"); } static void disassemble_range (int start, int end) { int addr; for (addr = start; addr < end; addr++) { dasm8 (addr, core [addr]); } } /* * fetch_iot * * This function looks up in the iot table (iot.h) to find * the opcode passed in "code" and updates the disassembled * output "dis" and the comment "com". * * More work needs to be done here for conflicting IOTs. * * Current, I assume that there are no conflicts (actually, I * return the first match, regardless of conflicts). A command * line / control file option needs to be created to allow * the selection of devices. Something like "-i vc8i", for example * to allow the VC8/I IOTs to be enabled. */ int fetch_iot (int code, char *dis, char *com) { int i; for (i = 0; i < sizeof (iots) / sizeof (iots [0]); i++) { if (code == iots [i].code) { if (dis) { strcpy (dis, iots [i].mnemonic); } if (com) { strncpy (com, iots [i].comment, COMLEN - 1); } return (1); } } if (dis) { sprintf (dis, "%04o", code); } if (com) { sprintf (com, "unknown IOT"); } return (0); } /* * pad * * Figures out where the current print position is based on expanding * the current tabs in "buf" and adds more tabs to get to "pos". */ static void pad (char *buf, int loc, int pos) { for (; *buf; buf++) { if (*buf == '\t') { if ((loc & 3) == 0) { loc += 4; } else { loc += 4 - (loc & ~3); } } else { loc++; } } loc = pos / 4 - loc / 4; while (loc--) { *buf++ = '\t'; } *buf = 0; } int is_data (int v) { return ((v & TAG_TYPE_MASK) == TAG_DATA); } static void xrefs (int addr) { int i; int eff; int count; count = 0; for (i = 0; i < CORE_SIZE; i++) { if (core [i] < 0) { continue; } if (tags [i] & TAG_DATA) { //printf ("+XREF ADDR %04o CHECK %04o IS DATA\n", addr, i); continue; } if ((core [i] & 07400) == 04000) { // direct JMS eff = ea (i, core [i], NULL, NULL); //printf ("+XREF ADDR %04o CHECK %04o %04o JMS EA %04o\n", addr, i, core [i], eff); if (eff == addr) { if (!count) { printf ("/\tCalled from:\n/\t"); } printf ("%04o ", i); count++; if ((count % 15) == 0) { printf ("\n/\t"); } } } else if ((core [i] & 07400) == 04400) { // indirect JMS eff = ea (i, core [i], NULL, NULL); //printf ("+XREF ADDR %04o CHECK %04o %04o JMS I EA %04o\n", addr, i, core [i], eff); if (tags [eff] & TAG_WRITABLE) { continue; } //printf ("+XREF ADDR %04o CHECK %04o %04o JMS I is not writable\n", addr, i, core [i]); if (core [eff] < 0) { continue; } //printf ("+XREF ADDR %04o CHECK %04o %04o JMS I has valid indirect value\n", addr, i, core [i]); if (core [eff] == addr) { if (!count) { printf ("/\tCalled from:\n/\t"); } printf ("%04o ", i); count++; if ((count % 15) == 0) { printf ("\n/\t"); } } } } if (count) { printf ("\n"); printf ("/\tTotal %04o (%d) calls\n", count, count); } else { printf ("/\tNever called\n"); } } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * flow.c * * (C) Copyright 2007 by Robert Krten, all rights reserved. * Please see the LICENSE file for more information. * * This module contains the PDP-8 flow analyzer. * * 2007 10 25 R. Krten created * 2007 10 28 R. Krten added TAG_INDIRECTFC */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include "d8tape.h" extern char *progname; // main.c extern char *version; // version.c extern int optv; // main.c extern short int core []; // main.c, in-core image (-1 means location never used) extern uint16_t tags []; // main.c, analysis tags char konstmap [4096]; // 12 bits gives us 0..4095, so 4096 different constants (0 == not used, 1 == unique, 2 == used but not unique) static void pass1 (void); static void pass2 (void); static void pass3 (void); static void pass4 (void); static void verify_subroutines (void); static int valid_opr (int opr); /* * Main flow analysis * * See individual functions for more details * * Basic idea is that there is a shadow array called "tags", which indicates * information about the given memory location (e.g., tags [0017] gives * information about core [0017]). * * The various passes affect the tags[] array with whatever they can detect. */ void flow (void) { pass1 (); pass2 (); pass3 (); // pass4 (); // this pass is fundamentally broken (well, maybe not the pass, but the interpretation of the results in dasm.c) verify_subroutines (); } /* * pass1 * * On pass 1, we can say with certainty only the following statements: * - if it's an invalid IOT or OPR, then it's data. * - if the instruction must have a valid EA, and it's invalid, * then it's data. * - if the JMS (direct only) target is not zero or the same as the * address, then it's data */ static void pass1 (void) { int addr, eff; for (addr = 0; addr < CORE_SIZE; addr++) { // skip unused if (core [addr] == -1) { continue; } // handle IOTs if ((core [addr] & 07000) == 06000) { // if we can't decode it, it's not valid if (!fetch_iot (core [addr], NULL, NULL)) { tags [addr] |= TAG_DATA; } continue; } // check OPRs; if they're invalid, tag as DATA, else skip if ((core [addr] & 07000) == 07000) { if (!valid_opr (core [addr])) { tags [addr] |= TAG_DATA; if (optv > 1) { printf ("+FLOW1 %04o %04o has invalid OPR -> DATA\n", addr, core [addr]); } } // done OPRs, skip continue; // @@@ NOTE: this does not work with EAE OPRs that take the next location as their parameter... } // ea() is always valid for opcodes < 06000 eff = ea (addr, core [addr], NULL, NULL); // if the instruction should have a valid EA and doesn't... if (core [eff] == -1) { // then it's not an instruction tags [addr] |= TAG_DATA; if (optv > 1) { printf ("+FLOW1 %04o %04o has EA %04o (invalid or not in core) and OP < 6000 -> DATA\n", addr, core [addr], eff); } continue; } // if it's a plain JMS if ((core [addr] & 07400) == 04000) { // and the target isn't zero or it's not the same as the address if (core [eff] && core [eff] != eff) { tags [addr] |= TAG_DATA; if (optv > 1) { printf ("+FLOW1 %04o %04o JMS target not 0000 or ADDR (EA %04o is %04o)\n", addr, core [addr], eff, core [eff]); } continue; } // else, if it's ok, then the target is writable, after all (JMS drops the return address there) tags [eff] |= TAG_WRITABLE; if (optv > 1) { printf ("+FLOW1 %04o %04o JMS target is 0000 or ADDR, marking EA %04o as WRITABLE\n", addr, core [addr], eff); } } } } /* * pass2 * * In this pass, we operate on the direct targets (no indirection) * and mark the targets as data, variable, label, or subroutine * target. */ static void pass2 (void) { int addr; int eff; for (addr = 0; addr < CORE_SIZE; addr++) { // skip unused or data locations if (core [addr] == -1 || (tags [addr] & TAG_DATA)) { continue; } eff = ea (addr, core [addr], NULL, NULL); switch (core [addr] & 07400) { // check opcode case 00000: // AND case 00400: // AND I case 01000: // TAD case 01400: // TAD I case 02000: // ISZ case 02400: // ISZ I case 03000: // DCA case 03400: // DCA I tags [eff] |= TAG_DATA; // the referenced EA is data if (optv > 1) { printf ("+FLOW2 %04o %04o is AND/TAD/ISZ/DCA's EA %04o tagged as DATA\n", addr, core [addr], eff); } // mark as writable if someone writes to it directly (ISZ and DCA only) if ((core [addr] & 07400) == 02000 || (core [addr] & 07400) == 03000) { tags [eff] |= TAG_WRITABLE; if (optv > 1) { printf ("+FLOW2 %04o %04o is ISZ/DCA so EA %04o is WRITABLE\n", addr, core [addr], eff); } } break; case 04000: // JMS if (core [eff] == 0 || core [eff] == eff) { // first word of JMS target must be zero or the address itself tags [eff] |= TAG_SUB; // otherwise, it's a valid subroutine target if (optv > 1) { printf ("+FLOW2 %04o %04o is JMS with good target %04o content (%04o) so tagged as SUB\n", addr, core [addr], eff, core [eff]); } } else { tags [addr] |= TAG_DATA; // then invalidate this "instruction", it's bogus if (optv > 1) { printf ("+FLOW2 %04o %04o is JMS with bad target %04o content (%04o) so tagged as DATA\n", addr, core [addr], eff, core [eff]); } } break; case 05000: // JMP tags [eff] |= TAG_LABEL; if (optv > 1) { printf ("+FLOW2 %04o %04o is JMP so EA %04o is LABEL\n", addr, core [addr], eff); } break; break; // JMS I, JMP I, IOTs, and OPRs are not handled in this pass } } } /* * pass3 * * In this pass, we verify and mark the indirects */ static void pass3 (void) { int addr; int eff; for (addr = 0; addr < CORE_SIZE; addr++) { // skip unused, data, or non-indirect opcodes if (core [addr] == -1 || (tags [addr] & TAG_DATA) || core [addr] >= 06000 || !(core [addr] & 00400)) { if (optv > 2 && core [addr] != -1) { printf ("+FLOW3 %04o %04o tags 0x%04x skipped\n", addr, core [addr], tags [addr]); } continue; } eff = ea (addr, core [addr], NULL, NULL); switch (core [addr] & 07000) { // check opcode (indirectness assured above) case 00000: // AND I case 01000: // TAD I case 02000: // ISZ I case 03000: // DCA I if (core [eff] != -1 && !(tags [eff] & TAG_WRITABLE)) { // if it's valid and constant tags [core [eff]] |= TAG_DATA; // then the target is data if (optv > 1) { printf ("+FLOW3 %04o %04o is AND/TAD/ISZ/DCA I through constant EA %04o so target %04o is DATA\n", addr, core [addr], eff, core [eff]); } // mark as writable if someone writes to it (ISZ and DCA only) if ((core [addr] & 07000) == 02000 || (core [addr] & 07000) == 03000) { tags [core [eff]] |= TAG_WRITABLE; if (optv > 1) { printf ("+FLOW3 %04o %04o is ISZ/DCA I thorugh constant EA %04o so target %04o is WRITABLE\n", addr, core [addr], eff, core [eff]); } } } break; case 04000: // JMS I if (core [eff] != -1 && !(tags [eff] & TAG_WRITABLE)) { // if it's valid and constant if (core [core [eff]] == 0 || core [core [eff]] == core [eff]) { // valid first word of JMS I target tags [core [eff]] |= TAG_SUB; // ultimate target is a valid subroutine target tags [eff] |= TAG_DATA; // and the pointer is a valid data type tags [eff] |= TAG_INDIRECTFC; // and the pointer is used in an indirect flow control target if (optv > 1) { printf ("+FLOW3 %04o %04o is JMS I through constant EA %04o so target %04o (content %04o) is ok, so tagged as SUB\n", addr, core [addr], eff, core [eff], core [core [eff]]); } } else { tags [addr] |= TAG_DATA; // then this isn't a valid instruction if (optv > 1) { printf ("+FLOW3 %04o %04o is JMS I through constant EA %04o with target %04o (invalid content %04o), so tagged as DATA\n", addr, core [addr], eff, core [eff], core [core [eff]]); } } } break; case 05000: // JMP I if (core [eff] != -1) { // if it's valid if (!(tags [eff] & TAG_WRITABLE)) { // and constant tags [eff] |= TAG_DATA; // pointer is a valid data type tags [eff] |= TAG_INDIRECTFC; // and the pointer is used in an indirect flow control target tags [core [eff]] |= TAG_LABEL; // ultimate target is a valid JMP target if (optv > 1) { printf ("+FLOW3 %04o %04o is JMP I through constant EA %04o with valid target %04o, so EA tagged as DATA | INDIRECTFC and target data %04o tagged as LABEL\n", addr, core [addr], eff, core [eff], core [core [eff]]); } } } else { tags [addr] |= TAG_DATA; // else, it's not really a valid constant expression if (optv > 1) { printf ("+FLOW3 %04o %04o is JMP I through constant EA %04o with invalid target %04o, so tagged as DATA\n", addr, core [addr], eff, core [eff]); } } break; } } } /* * pass4 * * In this pass, we update the constant map (konstmap). * * This effectively converts Cxxxx to Kxxxx, and results in more human- * friendly code. So, instead of: * * C1234, 0777 * * you'd see: * * K0777, 0777 * * The only trick to this is that since symbols must be unique in 6 * characters (for PAL compatibility), we need to ensure that the * items that convert from Cxxxx to Kxxxx are unique. That's why * konstmap[] has the values 0, 1, and 2: * * 0 == constant is not used anywhere in the code * 1 == constant is defined exactly once (can be converted) * 2 == constant has been defined more than once (cannot be converted) * * Any constant that's used in an indirect flow control manner, however, * is not a candidate, because technically it's not used as a K-style * constant. */ static void pass4 (void) { int i; memset (konstmap, 0, sizeof (konstmap)); // populate konstant[] map for (i = 0; i < CORE_SIZE; i++) { if (core [i] == -1) { continue; } if (tags [i] & TAG_WRITABLE) { if (optv > 1) { printf ("+FLOW4 %04o %04o TAG %02X is writable, therefore, not a constant\n", i, core [i], tags [i]); } continue; } if (optv > 1) { printf ("+FLOW4 %04o %04o TAG %02X\n", i, core [i], tags [i]); } if ((tags [i] & TAG_DATA) && !(tags [i] & TAG_INDIRECTFC)) { switch (konstmap [core [i]]) { case 0: if (optv > 1) { printf ("+FLOW4 %04o %04o FRESH KONSTANT\n", i, core [i]); } konstmap [core [i]]++; // this is our first one, bump the counter break; case 1: if (optv > 1) { printf ("+FLOW4 %04o %04o NO LONGER UNIQUE KONSTANT\n", i, core [i]); } konstmap [core [i]]++; // this is our second one, go to "2" break; case 2: if (optv > 1) { printf ("+FLOW4 %04o %04o PROMISCUOUS CONSTANT\n", i, core [i]); } // do nothing, we're at "2" indicating "non-unique" break; } } } // analyze konstant[] map for (i = 0; i < CORE_SIZE; i++) { if (core [i] == -1) { continue; } if (tags [i] & TAG_WRITABLE) { if (optv > 1) { printf ("+FLOW4 %04o %04o TAG %02X is writable, therefore, not a constant\n", i, core [i], tags [i]); } continue; } if (optv > 1) { printf ("+FLOW4 %04o %04o TESTING (%02X)\n", i, core [i], tags [i]); } if (tags [i] & TAG_DATA) { if (optv > 1) { printf ("+FLOW4 %04o %04o TESTING...DATA\n", i, core [i]); } if (konstmap [core [i]] == 1) { // if it's unique tags [i] |= TAG_KONSTANT; // then go ahead and tag it if (optv > 1) { printf ("+FLOW4 %04o %04o TAGGED AS KONSTANT\n", i, core [i]); } } } } } /* * verify_subroutines * * This is used to verify that a target really is a subroutine. * Verification consists of ensuring that somewhere within the * same page is a JMP I through the return address. If not, * then the subroutine is bogus, because you can't return from * it, so we knock down the "TAG_SUB" flag. * * BUG: This misses the following case: * * *0 * 0 /return area * *4000 * jmp i 0 / return through zero page * * because we only search for returns within the page that the * subroutine definition is in. I don't think this is a major * problem, just something to be aware of. Plus, the TAG_RETURN * is *really* only used as a comment field indicator anyway. */ static void verify_subroutines (void) { int addr; int page; int found; for (addr = 0; addr < CORE_SIZE; addr++) { if (!(tags [addr] & TAG_SUB)) { continue; } // try and find returns within page found = 0; for (page = addr; page <= (addr | 00177); page++) { if ((core [page] & 07400) == 05400) { if (ea (page, core [page], NULL, NULL) == addr) { // JMP I <start of subroutine> found! tags [page] |= TAG_RETURN; // mark the returns found++; } } } if (!found) { tags [addr] &= ~TAG_SUB; // not a subroutine, no return } } } static int valid_opr (int opr) { // a valid OPR must be 07xxx if ((opr & 07000) != 07000) { return (0); } if ((opr & 07400) == 07000) { // group 1 if ((opr & 00014) == 00014) { // with both L and R rotate bits on return (0); } } else if ((opr & 07401) == 07400) { // group 2 // all ok } else if ((opr & 07401) == 07401) { // EAE // if bits 6, 8, 9, or 10 are set... if (opr & 00056) { return (0); // @@@ we're disabling EAE for now } // otherwise it's an "MQ microinstruction", which is ok } return (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 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 | /* * iot.h * * (C) Copyright 2003 by Robert Krten, all rights reserved. * Please see the LICENSE file for more information. * * This module contains the IOT decode table. * * 2003 12 16 R. Krten created */ /* * Conflicting decodes for IOTs * * 6050 - 6077 VC8I or KV8I; one only * 6440 - 6457 PT08 uses some of the data areas from the Data Communications System 680/I -- definition of PT08 is optional * 6530 - 6547 AF01A or AF04A; one only * 6551 used by AA01A, AA05, or not used. Define zero or one only. * 6571 used by AF04A, AC01A, or not used. Define zero or one only. * 6600 - 6667 used by DP01AA, overrides DF32/RF08 selection. If defining DP01AA, don't bother with DF32/RF08 * 6600 - 6627 used by DF32 and RF08, define one only. * 6640 - 6647 used by RF08 or not used, define RF08 or not. * 6700 - 6727 used by TC58, TR02, and TA8A, define one only */ // Select one of the following: #define VC8I //#define KV8I // Select PT08 if required; it will override some of the IOTs from the Data Communications System 680/I //#define PT08 // Select one of the following: #define AF01A //#define AF04A // Select one of the following: #define AA01A //#define AA05 // If selecting DP01AA, don't bother with DF32/RF08 //#define DP01AA #ifndef DP01AA // Select one of the following: #define DF32 // #define RF08 #endif // DP01AA // Select one of the following: #define TA8A //#define TC58 //#define TR02 typedef struct { int code; // code number, e.g. 06001 char *option; // hardware option, e.g., vc8i char *mnemonic; // decoded value, e.g., "ION" char *comment; // code description of IOT, e.g., "clear x coordinate buffer" } one_iot_t; #define OP_ALL "" one_iot_t iots [] = { // 6000 Interrupts { 06001, OP_ALL, "ION", "Enable Interrupts"}, { 06002, OP_ALL, "IOF", "Disable Interrupts"}, // 6010 High Speed Perforated Tape Reader and Control { 06011, OP_ALL, "RSF", "Skip if reader flag is a 1."}, { 06012, OP_ALL, "RFB", "Read the content of the reader buffer and clear the reader flag. This instructions does not clear the AC. RB v AC4-11 -> AC4-11"}, { 06014, OP_ALL, "RFC", "Clear reader flag and reader buffer, fetch one character from tape and load it into the reader buffer, and set the reader flag when done."}, // 6020 High Speed Perforated Tape Punch and Control { 06021, OP_ALL, "PSF", "Skip if punch flag is a 1"}, { 06022, OP_ALL, "PCF", "Clear punch flag and punch buffer."}, { 06024, OP_ALL, "PPC", "Load the punch buffer from bits 4 through 11 of the AC and punch the character. This instructions does not clear the punch flag or punch buffer. AC4-11 v PB -> PB"}, { 06026, OP_ALL, "PLS", "Clear the punch flag, clear the bunch buffer, load the punch buffer from the content of bits 4 through 11 of the accumulator, punch the character, and set the punch flag to 1 when done."}, // 6030 Teletype Keyboard / Reader { 06031, OP_ALL, "KSF", "Skip if keyboard flag is a 1."}, { 06032, OP_ALL, "KCC", "Clear AC and clear keyboard flag."}, { 06034, OP_ALL, "KRS", "Read keyboard buffer static. This is a static command in that neither the AC nor the keyboard flag is cleared. TTI v AC4-11 -> AC4-11"}, { 06036, OP_ALL, "KRB", "Clear AC, clear keyboard flag, and read the content of the keyboard buffer into the content of AC4-11."}, // 6040 Teletype Teleprinter / Punch { 06041, OP_ALL, "TSF", "Skip if teleprinter flag is a 1."}, { 06042, OP_ALL, "TCF", "Clear teleprinter flag."}, { 06044, OP_ALL, "TPC", "Load the TTO from the content of AC4-11 and print and/or punch the character."}, { 06046, OP_ALL, "TLS", "Load the TTO from the content of AC4-11, clear the teleprinter flag, and print and/or punch the character."}, #ifdef VC8I // 6050 Oscilloscope Display Type VC8/I [VC8/L] { 06051, OP_ALL, "DCX", "Clear X coordinate buffer"}, { 06053, OP_ALL, "DXL", "Clear and load X coordinate buffer. AC2-11 -> YB"}, { 06054, OP_ALL, "DIX", "Intensify the point defined by the content of the X and Y coordinate buffers."}, { 06057, OP_ALL, "DXS", "Executes the combined functions of DXL followed by DIX"}, // 6060 (continued) { 06061, OP_ALL, "DCY", "Clear Y coordinate buffer"}, { 06063, OP_ALL, "DYL", "Clear and load Y coordinate buffer. AC2-11 -> YB"}, { 06064, OP_ALL, "DIY", "Intensify the point defined by the content of the X and Y coordinate buffers."}, { 06067, OP_ALL, "DYS", "Executes the combined functions of DYL followed by DIY"}, // 6070 (continued) { 06071, OP_ALL, "DSF", "(Light Pen Type 370) Skip if display flag is a 1."}, { 06072, OP_ALL, "DCF", "(Light Pen Type 370) Clear the display flag."}, { 06074, OP_ALL, "DSB", "Zero brightness"}, { 06075, OP_ALL, "DSB", "Set minimum brightness"}, { 06076, OP_ALL, "DSB", "Set medium brightness"}, { 06077, OP_ALL, "DSB", "Set maximum brightness"}, #endif #ifdef KV8I // 6050 Storage Tube Display Control, Type KV8/I [KV8/L] { 06051, OP_ALL, "SNC", "Senses the condition of the cursor interrupt flag. The flag produces an interrupt request when set by operation of the interrupt pushbutton on the joystick. The flag is initially cleared when the computer is started. As with all flag-sent instructions, SNC can be used under interrupt conditions to detect the source of the interrupt, or it can be used under interrupt on (ION) when the interrupt request has been caused by the operation of thecursor interrupt button. In a program running with the interrupt off, SNC can be used to ignore the cursor successive approximation subroutine in the program if a request for service has not been made from the joystick controller."}, { 06052, OP_ALL, "CCF", "This instruction is used to clear the cursor flag after a request for service has been acknowledged by the program."}, // 6060 (continued) { 06062, OP_ALL, "SAC", "The analog comparator is set to compare the analog content of any one of six analog sources with the content of the digital-to-analog converter. The analog sources are chosen according to a 3-bit binary code. This code establishes the parameter for choosing the wanted register according to the content of AC2, AC3, and AC6."}, { 06063, OP_ALL, "LDF", "This instruction is used to establish the mode in which a wanted graphic is to be produced according to a 2-bit binary code. This code determines whether the wanted vector will be linear absolute relative, whether the point plot mode will be used, or whether the cursor will be displayed. This code establishes the paramteres for these formats according to the content of AC2 and AC3. The LDF instruction must precede the LDX and LDY instructions."}, { 06064, OP_ALL, "LDX", "The X-axis sample and hold register is loaded with the binary equivalent of the X-axis coordinate according to the contents of AC2-11. This data appears at the output of the digital-to-analog converter as the analog equivalent of the X-axis value of the binary word stored in the AC. The LDX instruction clears an existing ready flag and sets the ready flag after 100 +/- 20 us."}, { 06065, OP_ALL, "LDY", "The Y-axis sample and hold register is loaded with the binary equivalent of the Y-axis coordinate according to the contents of AC2-11. This data appears at the output of the digital-to-analog converter as the analog equivalent of the binary word in the AC. The LDY instruction clears an existing ready flag and sets the ready flag after 100 +/- 20 us."}, { 06066, OP_ALL, "EXC", "Used to execute the wanted vector according to the contents of AC2-4 and AC6-11. The parameter word establishes long or short formats, circular vectors, display erasure, reset of the integrators, and intensification of the vector. The EXC instruction clears an existing ready flag and sets the ready flag as follows: a) after 20 +/- 5 us for a point or vector continue; b) after 250 us for short vectors; c) after 4.05 ms for long vectors; d) after 500 ms for an erase."}, // 6070 (continued) { 06071, OP_ALL, "SRF", "Used to determine when the controller is ready to perform the next execute instruction. The ready flag produces an interrupt condition when set. The flag can be set by pressing the erase pushbutton on the VT01 unit. Normally, however, the state of this flag is determined by the controller. This flag is initially cleared when the computer is started and prior to an LDX, LDY, or EXC instruction."}, { 06072, OP_ALL, "CRF", "This instruction clears the ready flag after a skip instruction has been acknowledged."}, { 06073, OP_ALL, "SDA", "Used in the successive approximation subroutine to determine the digital equivalent of the selected analog holding register. This instruction is used with the SAC (6062) instruction."}, { 06074, OP_ALL, "LDA", "This instruction is used to load the content of AC2-11. This instruction is used with DSA (6073) in the successive approximation subroutine to determine the digital value of the content of the selected analog holding register. Does not change flag states."}, #endif // 6100 Memory Parity Type MP8/I [MP8/L] // 6100 Automatic Restart Type KP8/I [KP8/L] { 06101, OP_ALL, "SMP", "(MP8/I) Skip if memory parity error flag = 0."}, { 06102, OP_ALL, "SPL", "(KP8/I) Skip if power low"}, { 06104, OP_ALL, "CMP", "(MP8/I) Clear memory parity error flag."}, // 6110 Multiple Asynchronous Serial Line Interface Unit, Type DC02D { 06111, OP_ALL, "MKSF", "Skip the next instruction if the keyboard flag is set."}, { 06112, OP_ALL, "MKCC", "Clear the keyboard and reader flags; clear the AC."}, { 06113, OP_ALL, "MTPF", "(DC02A) Transfer status of teleprinter flags to AC 0-3."}, { 06114, OP_ALL, "MKRS", "Transfer the shift register contents to AC 4-11."}, { 06115, OP_ALL, "MINT", "(DC02A) Interrupt on if AC 11 is set (interrupt request, if any flags)."}, { 06116, OP_ALL, "MKRB", "Clear the keyboard and reader flags, clear the AC, trasnfer the shift register contents to AC 4-11 (MKCC and MKRS combined)."}, { 06117, OP_ALL, "MTON", "Transfer AC0-3 to selection register (SELF) (select stations when bit is set)."}, // 6120 Multiple Asynchronous Line Unit, Type DC02A { 06121, OP_ALL, "MTSF", "Skip the next instruction if the teleprinter flag is set."}, { 06122, OP_ALL, "MTCF", "Clear the teleprinter flag."}, { 06123, OP_ALL, "MTKF", "Transfer status of keyboard flags to AC 0-3."}, { 06124, OP_ALL, "MTPC", "Load AC4-11 into the shift register (begin print/punch)."}, { 06125, OP_ALL, "MINS", "Skip if the interrupt request is active (if interrupt is on and any flag is raised)."}, { 06126, OP_ALL, "MTLS", "Clear the teleprinter flag and load AC4-11 into the shift register (MTCF and MTPC combined)"}, { 06127, OP_ALL, "MTRS", "Trasnfer the status of the selection register to AC 0-3."}, // 6130 Real Time Clock, Type KW8/I [KW8/L] { 06132, OP_ALL, "CCFF", "The flag, flag buffer, clock enable, and interrupt enable flip-flops are cleared. This disables the real-time clock."}, { 06133, OP_ALL, "CSCF", "When the flag flip-flop has been set by a clock pulse, the flag buffer flip-flop is set to a 1. Upon execution of this instruction, an IO BUS IN SKIP is generated if the flag is set. The content of the PC is incremented by 1, so that the next sequential instruction is skipped. The flag flip-flop is then cleared. If the flag flip-flop has not been set, no skip is generated nor is the flag flip-flop cleared."}, { 06134, OP_ALL, "CRCA", "The output buffer is gated to the I/O BUS during IOP4, and a CLK AC CLR signal generated. This register contains the last count in the count register. The transfer from the count register is synchronized with this instruction so that a transfer that would occur during this instruction is not made."}, { 06136, OP_ALL, "CCEC", "All clock control flip-flops are first cleared, then the clock enable flip-flop is set. For the variable frequency clock, the frequency source is enabled synchronously with program operation. With all clocks, the data input to the flag is enabled after IOP2 time. This represents an 800-ns mask, after the clock is enabled."}, { 06137, OP_ALL, "CECI", "All clock control flip-flops are cleared, then the clock enable, and interrupt enable flip-flops are set. The clock enable flip-flop is described with the CCEC instruction. The interrupt enable flip-flop allows an IO BUS IN INT signal when the flag is set."}, // 6140 // 6150 // 6160 // 6170 // 6200 through 6277 Memory Extension Control Type MC8/I [MC8/L] { 06201, OP_ALL, "CDF0", "Change to data field 0. The data field register is loaded with the selected field number (0). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06202, OP_ALL, "CIF0", "Prepare to change to instruction field N (0). The instruction buffer register is loaded with the selected field number (0). The next JMP or JMS instruction causes the new field to be entered."}, { 06204, OP_ALL, "CINT", "(KT8/I) Clear user interrupt. Resets the user interrupt (UINT) flip-flop to the 0 state."}, // 6210 { 06211, OP_ALL, "CDF0", "Change to data field 1. The data field register is loaded with the selected field number (1). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06212, OP_ALL, "CIF0", "Prepare to change to instruction field N (1). The instruction buffer register is loaded with the selected field number (1). The next JMP or JMS instruction causes the new field to be entered."}, { 06214, OP_ALL, "RDF", "Read data field into AC6-8. Bit 0-5 and 9-11 of the AC are not affected."}, // 6220 { 06221, OP_ALL, "CDF0", "Change to data field 2. The data field register is loaded with the selected field number (2). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06222, OP_ALL, "CIF0", "Prepare to change to instruction field N (2). The instruction buffer register is loaded with the selected field number (2). The next JMP or JMS instruction causes the new field to be entered."}, { 06224, OP_ALL, "RIF", "Same as RDF except reads the instruction field"}, // 6230 { 06231, OP_ALL, "CDF0", "Change to data field 3. The data field register is loaded with the selected field number (3). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06232, OP_ALL, "CIF0", "Prepare to change to instruction field N (3). The instruction buffer register is loaded with the selected field number (3). The next JMP or JMS instruction causes the new field to be entered."}, { 06234, OP_ALL, "RIB", "Read interrupt buffer. The instruction field and data field stored during an interrupt are read into AC6-8 and AC9-11, respectively."}, // 6240 { 06241, OP_ALL, "CDF0", "Change to data field 4. The data field register is loaded with the selected field number (4). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06242, OP_ALL, "CIF0", "Prepare to change to instruction field N (4). The instruction buffer register is loaded with the selected field number (4). The next JMP or JMS instruction causes the new field to be entered."}, { 06244, OP_ALL, "RMF", "Restore memory field. Used to exit from a program interrupt."}, // 6250 { 06251, OP_ALL, "CDF0", "Change to data field 5. The data field register is loaded with the selected field number (5). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06252, OP_ALL, "CIF0", "Prepare to change to instruction field N (5). The instruction buffer register is loaded with the selected field number (5). The next JMP or JMS instruction causes the new field to be entered."}, { 06254, OP_ALL, "SINT", "(KT8/I) Skip on user interrupt. When the user interrupt (UINT) flip-flop is in the 1 state, sets the user skip flip-flop (USF) to the 1 state and causes the program to skip the next instruction."}, // 6260 { 06261, OP_ALL, "CDF0", "Change to data field 6. The data field register is loaded with the selected field number (6). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06262, OP_ALL, "CIF0", "Prepare to change to instruction field N (6). The instruction buffer register is loaded with the selected field number (6). The next JMP or JMS instruction causes the new field to be entered."}, { 06264, OP_ALL, "CUF", "(KT8/I) Clears the user flag. Clears the user buffer (UB) flip-flop."}, // 6270 { 06271, OP_ALL, "CDF0", "Change to data field 7. The data field register is loaded with the selected field number (7). All subsequent memory requests for operands are automatically switched to that data field until the data field number is changed by a new CDF command."}, { 06272, OP_ALL, "CIF0", "Prepare to change to instruction field N (7). The instruction buffer register is loaded with the selected field number (7). The next JMP or JMS instruction causes the new field to be entered."}, { 06274, OP_ALL, "SUF", "(KT8/I) Sets the user flag. Sets user buffer (UB) and inhibits processor interrupts until the next JMP or JMS instruction. Generation of IB -> IF during the next JMP or JMS instruction transfers the state of UB to the user field (UF) flip-flop."}, // 6400 Data Communications System 680/I { 06401, OP_ALL, "TTINCR", "This instruction causes the contents of the line register to be incremented by 1. This command, when microprogrammed with a TTO command is executed."}, { 06402, OP_ALL, "TTI", "Causes a JMS to be executed (N+3) if the R register does not equal 0 and either the line hold bit of the selected line (specified by bits 2-8 of the LSW) is in the 1 state, or as a result of jamming the line state into and shifting the CAW; bit 11 of the CAW is a 1."}, { 06404, OP_ALL, "TTO", "Clears the link and shifts the link and accumulator one bit position to the right. Bit 11 of the accumulator is shifted into the line unit specified by the line register. The previuos contents (1 bit) of the selected line unit is lost."}, // 6410 { 06411, OP_ALL, "TTCL", "The command sets the contents of the line register to 0."}, { 06412, OP_ALL, "TTSL", "The contents of AC5-11 are ORed into the line register."}, { 06413, OP_ALL, "TTLL", "The contents of AC5-11 are trasnferred into the line register. This is a microprogram of TTCL and TTSL."}, { 06414, OP_ALL, "TTRL", "The contents of the line register are ORed into AC5-11. The AC must be 0 for a true transfer."}, // 6420 { 06421, OP_ALL, "T1skip", "(Data Communications System 680/I) Clock Control Instruction: Causes the program to skip the next instruction if clock flag 1 is in the 1 state. To clear the flag, either T1on or T1off can be used."}, { 06422, OP_ALL, "T1off", "(Data Communications System 680/I) Clock Control Instruction: Inhibits clock 1 from setting its flag. This instruction also sets the flag to the 0 state."}, { 06424, OP_ALL, "T1on", "(Data Communications System 680/I) Clock Control Instruction: Enables clock 1 to set its flag at the predetermined lcock rate. The flag in the 1 state causes a program interrupt when the interrupt is enabled. This instruction also sets the flag to the 0 state."}, // 6430 { 06431, OP_ALL, "T2skip", "(Data Communications System 680/I) same as T1skip except for clock 2"}, { 06432, OP_ALL, "T2off", "(Data Communications System 680/I) same as T1off except for clock 2"}, { 06434, OP_ALL, "T2on", "(Data Communications System 680/I) same as T1on except for clock 2"}, #ifdef PT08 // 6440 Asynchronous Serial Line Interface, Type PT08 { 06441, OP_ALL, "TSFXXX", "Skip if teleprinter/punch 3 flag is a 1."}, { 06442, OP_ALL, "TCFXXX", "Clear teleprinter/punch 3 flag."}, { 06444, OP_ALL, "TPCXXX", "Load teleprinter 3 buffer (TTOX) with AC4-11 and print/punch the character."}, { 06446, OP_ALL, "TLSXXX", "Load TTOX with AC4-11, 3 flag, print/punch the character and clear teleprinter/punch."}, { "6450"}, { 06451, OP_ALL, "KSFXXX", "Skip if keyboard/reader 3 flag is a 1."}, { 06452, OP_ALL, "KCCXXX", "Clear AC and keyboard/reader 3 flag."}, { 06454, OP_ALL, "KRSXXX", "Read keyboard/reader 3 buffer (TTI3) static. TTI3 is loaded into AC4-11 by an OR transfer."}, { 06456, OP_ALL, "KRBXXX", "Clear the AC, read TTI3 into AC4-11, and clear keyboard 3 flag."}, {#else "PT08"}, { 06441, OP_ALL, "T3skip", "(Data Communications System 680/I) same as T1skip except for clock 3"}, { 06442, OP_ALL, "T3off", "(Data Communications System 680/I) same as T1off except for clock 3"}, { 06444, OP_ALL, "T3on", "(Data Communications System 680/I) same as T1on except for clock 3"}, { 06451, OP_ALL, "T4skip", "(Data Communications System 680/I) same as T1skip except for clock 4"}, { 06452, OP_ALL, "T4off", "(Data Communications System 680/I) same as T1off except for clock 4"}, { 06454, OP_ALL, "T4on", "(Data Communications System 680/I) same as T1on except for clock 4"}, #endif { 06461, OP_ALL, "TTRINC", "(Data Communications System 680/I) This command causes the contents of the R register to be incremented by 1. Because it is loaded with a 2's complement number, the result is a subtract. This instruction can be microprogrammed with TTRR."}, { 06464, OP_ALL, "TTRR", "(Data Communications System 680/I) This command reads the contents of the R register into AC7-11. The contents of the AC must be 0s before issuing this instruction. This instruction, when microprogrammed with TTINCR, causes the incremented results to be read into the AC."}, // 6470 { 06471, OP_ALL, "TTCR", "(Data Communications System 680/I) This command causes the R register to be set to 0"}, { 06472, OP_ALL, "TTLR", "(Data Communications System 680/I) This command causes the contents of AC7-11 to be trasnferred into the R register."}, // 6500 Incremental Plotter and Control Type VP8/I { 06501, OP_ALL, "PLSF", "Skip if plotter flag is a 1."}, { 06502, OP_ALL, "PLCF", "Clear plotter flag."}, { 06504, OP_ALL, "PLPU", "Plotter pen up. Raise pen off of paper."}, // 6510 { 06511, OP_ALL, "PLPR", "Plotter pen right."}, { 06512, OP_ALL, "PLDU", "Plotter drum (paper) upward"}, { 06514, OP_ALL, "PLDD", "Plotter drum (paper) downward."}, // 6520 { 06521, OP_ALL, "PLPL", "Plotter pen left."}, { 06522, OP_ALL, "PLUD", "Plotter drum (paper) upward. Same as 6512"}, { 06524, OP_ALL, "PLPD", "Plotter pen down. Lower pen on to paper."}, #ifdef AF01A // 6530 General Purpose Converter and Multiplexer Control Type AF01A (this option is mutually exclusive with AF04A) { 06531, OP_ALL, "ADSE", "Skip if A/D converter flag is a 1."}, { 06532, OP_ALL, "ADCV", "Clear A/D converter flag and convert input voltage to a digital number, flag will set to 1 at end of conversion. Number of bits in converted number determined by switch setting, 11 bits maximum."}, { 06534, OP_ALL, "ADRB", "Read A/D converter buffer into AC, left justified, and clear flag."}, // 6540 { 06541, OP_ALL, "ADCC", "Clear multiplexer channel address register."}, { 06542, OP_ALL, "ADSC", "Set up multiplexer channel as per AC6-11. Maximum of 64 single ended or 32 differntial input channels."}, { 06544, OP_ALL, "ADIC", "Index multiplexer channel address (present address + 1). Upon reaching address limit, increment will cause channel 00 to be selected."}, #endif // AF01A #ifdef AF04A // 6530 Guarded Scanning Digital Voltmeter Type AF04A (this option is mutually exclusive with AF01A) { 06531, OP_ALL, "VSDR", "Skip if data ready flag is a 1."}, { 06532, OP_ALL, "VRD", "Selected byte of voltmeter is transferred to the accumulator and the data ready flag is cleared."}, { 06534, OP_ALL, "VBA", "BYTE ADVANCE command requests next twelve bits, data ready flag is set."}, // 6540 { 06541, OP_ALL, "VCNV", "The contents of the accumulator are transferred to the AF04A channel address register. Analog signal on selected channel is automatically digitized."}, { 06542, OP_ALL, "VSEL", "The contents of the accumulator are transferred to the AF04A control register."}, { 06544, OP_ALL, "VINX", "The last channel address is incremented by one and the analog signal on the selected channel is automatically digitized."}, #endif // AF04A // 6550 #ifdef AA01A { 06551, OP_ALL, "DAL1", "(AA01A) The character in the accumulator is loaded into the channel 1 buffer. The DAC then converts the buffered value to the analog equivalent. NOTE: Similar instructions for DAL2 and DAL3 load respective DACs."}, #else // AA01A #ifdef AA05 { 06551, OP_ALL, "CLDA", "The address register in the AA05/AA07 is cleared."}, #else // AA05 #endif // AA05 #endif // AA01A { 06552, OP_ALL, "LDAD", "(AA05/AA07) The address register in the AA05/AA07 is loaded with the contents of AC0-5."}, // 6560 { 06562, OP_ALL, "LDAR", "(AA05/AA07) The buffer (input buffer, if the channel is double-buffered) of the DAC is loaded from AC0-9."}, { 06564, OP_ALL, "UPDT", "(AA05/AA07) The contents of the input buffers of all double-buffered channels are trasnferred to their respective output buffers. The input buffer is not affected by this instruction."}, // 6570 #ifdef AF04A { 06571, OP_ALL, "VSCC", "SAMPLE CURRENT CHANNEL when required to digitize analog signal on current channel repeatedly (AF04A)"}, #else // AF04A #ifdef AC01A { 06571, OP_ALL, "HRAN", "The contents of AC3-5 are trasnferred to the channel address register (CHAR). The 3-bit code is decoded to address any of the 8 channels."}, #else // AC01A #endif // AC01A #endif // AF04A #ifdef AC01A { 06572, OP_ALL, "HSIM", "Simultaneously places all 8 channels into the hold mode."}, #else // AC01A #endif // AC01A { 06574, OP_ALL, "SAMP", "(AA01A) Places all 8 channels into the sample (or track) mode."}, #ifdef DP01AA // 6600 Synchronous Modem Interface, Type DP01AA { 06601, OP_ALL, "TAC", "Causes the contents of the AC (6, 7, 8, or 9 bits right-justified) to be transferred into the TB."}, { 06602, OP_ALL, "CTF", "Resets the trasnmit flag. If trasnmit active flag is set, CTF also causes the program to skip the next instruction."}, { 06604, OP_ALL, "CIM", "Resets the transmit logic idle mode (IM) flip-flop."}, { 06611, OP_ALL, "STF", "Causes the program to skip the next instruction if the transmit flag is in the 0 state. When the transmit flag is in the 1 state, the trasnmit buffer register (TB) is ready to accept another character."}, { 06612, OP_ALL, "RRB", "Transfers the contents of the receiver buffer (RB) (6, 7, 8, or 9 bits, right-justified) to the computer AC. RRB also resets the receive flag."}, { 06614, OP_ALL, "SIM", "Sets the transmit idle mode (IM) flip-flop."}, { 06621, OP_ALL, "SEF", "Causes the program to skip the next instruction if the receive end flag is 0. The receive end flag slip-flop is set when the receive logic has stopped receiving serial data from the communications equipment due to termination of th SERIAL CLOCK RECEIVE pulse train."}, { 06622, OP_ALL, "CEF", "Clears the receive end flag"}, { 06624, OP_ALL, "SRE", "Sets the ring enable (RE) flip-flop to a 1, which permits the ring flag to request a program interrupt."}, { 06631, OP_ALL, "SRI", "Causes the program to skip the next instruction if the ring flag is 0. The ring flag is set when a ring input is received."}, { 06632, OP_ALL, "CRF", "Clears the ring flag."}, { 06634, OP_ALL, "STR", "Sets the terminal read (TR) flip-flop to the 1 state. This causes the terminal ready lead to the modem to be set on the ON state. The state changes to OFF for CTR"}, { 06641, OP_ALL, "SSR", "Causes the program to skip the next instruction if the data-set-ready lead from the modem is in the ON state."}, { 06642, OP_ALL, "CTR", "Clears the terminal ready (TR) flip-flop (see STR)"}, { 06644, OP_ALL, "CRE", "Clears the ring enable (RE) flip-flop."}, { 06651, OP_ALL, "SRF", "Causes the program to skip the next instruction if the receive flag is 0. The flag is set when a received character is ready for trasnfer to the AC and the flag is cleared when an RRB instruction is issued."}, { 06652, OP_ALL, "CRA", "Clears the receive active (RA) flip-flop, taking the receive logic out of the active state. This inhibits any more receive flags until a new sync character is received."}, { 06654, OP_ALL, "XOB", "Causes an exclusive OR of the AC with the buffer register (BR)."}, { 06661, OP_ALL, "COB", "Clears the XOR buffer."}, { 06662, OP_ALL, "ROB", "Transfers the buffer register (BR) content to the AC."}, { 06664, OP_ALL, "IOB", "Transfers 1s from the AC to the buffer register (BR)."}, #else // DP01AA #ifdef DF32 // 6600 Random Access Disc File (type DF32) { 06601, OP_ALL, "DCMA", "Clears memory address register, parity erorr and completion flags. This instruction clears the disk memory request flag and interrupt flags."}, { 06603, OP_ALL, "DMAR", "The contents of the AC are loaded into the disk memory address register and the AC is cleared. Begin to read information from the disk into the specified core location. Clears parity error and completion flags. Clears interrupt flags."}, { 06605, OP_ALL, "DMAW", "The contents of the AC are loaded into the disk memory address register and the AC is cleared. Begin to write information into the disk from the specified core location. Clears parity error and completion flags."}, // 6610 { 06611, OP_ALL, "DCEA", "Clears the disk extended address and memory address extension register."}, { 06612, OP_ALL, "DSAC", "Skips next instruction if address confirmed flag is a 1. AC is cleared."}, { 06615, OP_ALL, "DEAL", "The disk extended-address extension registers are cleared and loaded with the track data held in the AC."}, { 06616, OP_ALL, "DEAC", "Clear the AC then loads the contents of the disk extended-address register into the AC to allow program evaluation. Skip next instruction if address confirmed flag is a 1."}, // 6620 { 06621, OP_ALL, "DFSE", "Skip next instruction if the completion flag is a 1. Indicates data transfer is complete."}, { 06626, OP_ALL, "DMAC", "Clear the AC then loads contents of disk memory address register into the AC to allow program evaluation."}, #endif // DF32 #ifdef RF08 // 6600 Disk File and Control, Type RF08/Expander Disk File, Type RS08 // 6610 { 06611, OP_ALL, "DCIM", "Clear the disk interrupt enable and core memory address extension register."}, { 06615, OP_ALL, "DIML", "Clear the interrupt enable and memory address extension register, then load the interrupt enable and memory address extension registers with data held in the AC. Then clear the AC. NOTE: Transfers cannot occur across memory fields. Attempts to do so will cause the transfer to "wrap around" within the specified memory field."}, { 06616, OP_ALL, "DIMA", "Clear the AC. Then load the contents of the status register (STR) into the AC to allow program evaluation."}, // 6620 { 06621, OP_ALL, "DFSE", "Skip next instruction if there is a parity error, data request late, write lock status, or nonexistent disk flag set."}, { 06623, OP_ALL, "DISK", "If either the error or data completion flag (or both) is set, the next instruction is skipped."}, #endif // RF08 // 6630 Card Reader and Control Type CR8/I [CR8/L] (see also 6670) { 06631, OP_ALL, "RCSF", "Generates an IOP pulse (IOP 1) to test the data-ready flag output. If the data ready flag is 1, the next sequential program instruction is skipped."}, { 06632, OP_ALL, "RCRA", "Generates an IOP pulse (IOP 2) to read the alphanumeric data at the control-logic buffer register and clear the data ready flag."}, { 06634, OP_ALL, "RCRB", "Generates an IOP pulse (IOP 4) to read the BCD data at the control logic buffer register and clear the data ready flag."}, #ifdef RF08 // 6640 { 06641, OP_ALL, "DCXA", "Clear the high order 8-bits of the disk address register (DAR)."}, { 06643, OP_ALL, "DXAL", "Clear the high order 8 bits of the DAR. Then load the DAR from data stored in the AC. Then clear the AC."}, { 06645, OP_ALL, "DXAC", "Clear the AC; then load the contents of the high order 8-bit DAR into the AC."}, { 06646, OP_ALL, "DMMT", "For maintenance purposes only with the appropriate maintenance cable connections and the disk disconnected from the RS08 logic, the (given) standard signals may be generated by IOT 6646 and associated AC bits. The AC is cleared and the maintenance register is initiated by issuing an IOT 6601 command."}, #else // RF08 // 6640 #endif // RF08 // 6650 Automatic Line Printer and Control Type 645 { 06651, OP_ALL, "LSE", "Skip if line printer error flag is a 1."}, { 06652, OP_ALL, "LCB", "Clear both sections of the printing buffer."}, { 06654, OP_ALL, "LLB", "Load printing buffer from the content of AC6-11 and clear the AC"}, // 6660 Automatic Line Printer and Control Type 645 (continued) { 06661, OP_ALL, "LSD", "Skip if the printer done flag is a 1."}, { 06662, OP_ALL, "LCF", "Clear line printer done and error flags."}, { 06664, OP_ALL, "LPR", "Clear the format register, load the format register from the content of AC9-11, print the line contained in the section of the printer buffer loaded last, clear the AC, and advance the paper in accordance with the selected channel of the format tape if the content of AC8=1. If the content of AC8=0, the line is printed and paper advance is inhibited."}, #endif // DP01AA // 6670 Card Reader and Control Type CR8/I [CR8/L] (see also 6630) { 06671, OP_ALL, "RCSD", "Generates an IOP pulse (IOP 1) to test the card-done flag output. If the card done flag is 1, the next sequential program instruction is skipped."}, { 06672, OP_ALL, "RCSE", "Generates an IOP pulse (IOP 2) to advance the card, clear the card done flag, and produce a skip flag is reader is ready. If skip flag is generated, the next sequential program instruction is skipped."}, { 06674, OP_ALL, "RCRD", "Generates an IOP pulse (IOP 4) to clear the card done flag."}, #ifdef TA8A // 6700 -> 6707 TU60 DECassette Controller TA8A { 06700, OP_ALL, "KCLR", "Clear All; clear the status A and B register"}, { 06701, OP_ALL, "KSDR", "Skip the next instruction if the data flag is set during read or write operations"}, { 06702, OP_ALL, "KSEN", "Skip the next instruction if any of the following are true: a) tape is at EOT/BOT, b) the TU60 is not ready or the selected drive is empty"}, { 06703, OP_ALL, "KSBF", "Skip the next instruction if the ready flag is set"}, { 06704, OP_ALL, "KLSA", "Load status A from AC4-AC11, clear the AC, and load the complement of status A back into the AC"}, { 06705, OP_ALL, "KSAF", "Skip on any flag or error condition"}, { 06706, OP_ALL, "KGOA", "Assert the contents of the status A register and transfer data into the AC during a read operation or out of the AC to the Read/Write buffer during a write operation. This instruction has three functions: a) enables the command in the status A register to be executed by the TU60, b) for read operations, the first KGOA instruction causes the tape to start moving, and when the data flag sets, a second KGOA transfers the first byte from the read/write buffer to the AC. The data flag sets after each 8-bit byte is read from the TU60. c) for write operations, the status A register is set up for a write, and the AC contains the first byte to be written on tape. When the KGOA instruction is executed, the tape starts to move and the first byte is transferred to the TU60."}, { 06707, OP_ALL, "KRSB", "Transfer the contents of the status B register into AC4-AC11."}, #endif #ifdef TC58 // 6700 Automatic Magnetic Tape Control Type TC58 { 06701, OP_ALL, "MTSF", "Skip on error flag or magnetic tape flag. The status of the error flag (EF) and the magnetic tape flag (MTF) are sampled. If either or both are set to 1, the content of the PC is incremented by one to skip the next sequential instruction."}, { 06702, OP_ALL, "6702", "(no mnemonic assigned) Clear the accumulator."}, { 06704, OP_ALL, "6704", "(no mnemonic assigned) Inclusively OR the contents of the status register into AC0-11"}, { 06706, OP_ALL, "MTRS", "Read the contents of the status register into AC0-11."}, // 6710 { 06711, OP_ALL, "MTCR", "Skip on tape control ready (TCR). If the tape control is ready to receive a command, the PC is incremented by one to skip the next sequential instruction."}, { 06712, OP_ALL, "MTAF", "Clear the status and command registers, and the EF and MTF if tape control ready. If tape control not ready, clears MTF and EF flags only."}, { 06714, OP_ALL, "MTCM", "Inclusively OR the contents of AC0-5, AC9-11 into the command register; JAM transfer bits 6, 7, 8 (command function)"}, { 06716, OP_ALL, "MTLC", "Load the contents of AC0-1j1 into the command register."}, // 6720 { 06721, OP_ALL, "MTTR", "Skip on tape transport ready (TTR). The next sequential instruction is skipped if the tape transport is ready."}, { 06722, OP_ALL, "MTGO", "Set "go" bit to execute command in the command register if command is legal."}, { 06724, OP_ALL, "MTRC", "Inclusively OR the contents of the contents of the command register into AC0-11."}, #endif // TC58 #ifdef TR02 // 6700 Incremental Magnetic Tape Controller, Type TR02 { 06701, OP_ALL, "IRS", "When data is ready to be strobed into the AC from the read buffer (RB), the PC is incremented by one to skip the next sequential instruction. The read done flag is cleared only if the skip occurs."}, { 06702, OP_ALL, "ISR", "The content of the status register (STR) is read into AC0-8. The AC should be cleared before it is read by this instruction."}, { 06703, OP_ALL, "IWS", "If the write done flag is set, the next instruction is skipped and the write done flag is cleared."}, { 06704, OP_ALL, "IMC", "The move command decoded from AC0-2 is generated. This instruction also clears the read done, write done, and gap detect flags. The indicated flag is set when the command has been executed."}, { 06705, OP_ALL, "IGS", "If the gap detect flag is set, the next instruction is skipped and the gap detect flag is cleared."}, { 06706, OP_ALL, "IWR", "The contents of the AC are loaded into the tape input data buffer (WB) and a write step command is generated. The write done flag is set when writing is completed."}, { 06707, OP_ALL, "IRD", "The AC is cleared and the content of the read buffer (RB) is loaded into the AC. Data bits are transferred into AC6-11 (7-track) or AC4-11 (9-track). Parity error is transferred into AC0 which is 0 if there is no parity error."}, // 6710 { 06711, OP_ALL, "IRSA", "When data is ready to be strobed into the AC from the read buffer (RB), the PC is incremented by one to skip the next sequential instruction. The read done flag is cleared only if the skip occurs."}, { 06712, OP_ALL, "ISRA", "The content of the status register (STR) is read into AC0-8. The AC should be cleared before it is read by this instruction."}, { 06713, OP_ALL, "IWSA", "If the write done flag is set, the next instruction is skipped and the write done flag is cleared."}, { 06714, OP_ALL, "IMCA", "The move command decoded from AC0-2 is generated. This instruction also clears the read done, write done, and gap detect flags. The indicated flag is set when the command has been executed."}, { 06715, OP_ALL, "IGSA", "If the gap detect flag is set, the next instruction is skipped and the gap detect flag is cleared."}, { 06716, OP_ALL, "IWRA", "The contents of the AC are loaded into the tape input data buffer (WB) and a write step command is generated. The write done flag is set when writing is completed."}, { 06717, OP_ALL, "IRDA", "The AC is cleared and the content of the read buffer (RB) is loaded into the AC. Data bits are transferred into AC6-11 (7-track) or AC4-11 (9-track). Parity error is transferred into AC0 which is 0 if there is no parity error."}, // 6720 #endif // TC58 // 6730 // 6740 // 6750 // 6760 DECtape Transport Type TU55 and DECtape Control Type TC01 { 06761, OP_ALL, "DTRA", "The content of status register A is read into AC0-9 by an OR transfer. The bit assignments are: AC0-2 = Transport unit select numnber; AC3-4 = Motion; AC5 = Mode; AC6-8 = Function; AC9 = Enable/disable DECtape control flag."}, { 06762, OP_ALL, "DCTA", "Clear status register A. All flags undisturbed."}, { 06764, OP_ALL, "DTXA", "Status register A is loaded by an exclusive OR transfer from the content of the AC, and AC10 and AC11 are sampled. If AC10 = 0, the error flags are cleared. If AC11 = 0, the DECtape control flag is cleared."}, // 6770 { 06771, OP_ALL, "DTSF", "Skip if error flag is a 1 or if DECtape control flag is a 1."}, { 06772, OP_ALL, "DTRB", "The content of status register B is read into the AC by an OR transfer. The bit assignments are: AC0 = Error flag; AC1 = Mark track error; AC2 = End of tape ; AC3 = Select error ; AC4 = Parity error; AC5 = Timing error; AC6-8 = Memory field; AC9-10 = Unused; AC11 = DECtape flag."}, { 06774, OP_ALL, "DTLB", "The memory field portion of status register B is loaded from the content of AC6-8."}, }; |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * main.c * * (C) Copyright 2000 by Robert Krten, all rights reserved. * Please see the LICENSE file for more information. * * This module represents the main module for the RIM/BIN * dumper/disassembler/converter/reverse engineering tool. * * This program will dump a RIM/BIN-formatted image to stdout, or * convert a tape from one format to another, or clean up a tape, * or disassemble a tape with reverse-engineering aids. * * 2001 01 07 R. Krten created * 2003 12 16 R. Krten added disassembler * 2003 12 17 R. Krten made it RIM/BIN aware. * 2007 10 25 R. Krten added reverse-engineering features * 2007 11 04 R. Krten fixed header skip logic (see dumptape()) */ #ifdef __USAGE %C [options] papertapefile [papertapefile...] where [options] are optional parameters chosen from: -b generate a BIN-formatted output (adds ".bin") -d suppress disassembly (useful for conversion-only mode) -r generate a RIM-formatted output (adds ".rim") -T generate test pattern 0000=0000..7756=7756 -v verbose operation Dumps the RIM- or BIN-formatted input file(s) specified on the command line. If the "-r" and/or "-b" options are present, also creates a RIM and/or BIN version of the output by adding ".rim" and/or ".bin" (respectively) to the input filename (can be used to "clean up" BIN and RIM images by deleting excess data before and after the leader/trailer). #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #include "d8tape.h" static void seg_add (uint16_t addr, int len); static void seg_more (int len); static void optproc (int, char **); static int dumptape (unsigned char *t, int n); static int dumprim (unsigned char *t, int n); static int dumpbin (unsigned char *t, int n); static int checkrim (unsigned char *t, int n); static int checkbin (unsigned char *t, int n); static void writebin (void); static void writerim (void); static int blank (short int *core, int size); const char *progname = "d8tape"; const char *blankname= " "; extern char *version; // version.c int optb; int optd; int optr; int optT; int optv; unsigned char *tape; // paper tape image short int core [CORE_SIZE]; // in-core image (-1 means location never used) uint16_t tags [CORE_SIZE]; // analysis tags segment_t *segments; // used to accumulate runs of data (from origin for nwords) int nsegments; // indicates how many segments we have char *tapename; /* * main * * Main simply calls the option processor, from which everything happens. */ int main (int argc, char **argv) { optproc (argc, argv); exit (EXIT_SUCCESS); } /* * usageError * * This is the usage message */ static void usageError () { fprintf (stderr, "\nUsage: %s [options] papertapefile [papertapefile...]\n\n", progname); fprintf (stderr, "where [options] are optional parameters chosen from:\n"); fprintf (stderr, " -b generate a BIN-formatted output (adds \".bin\")\n"); fprintf (stderr, " -d suppress disassembly (useful for conversion-only mode)\n"); fprintf (stderr, " -r generate a RIM-formatted output (adds \".rim\")\n"); fprintf (stderr, " -v verbose operation\n"); fprintf (stderr, "\n"); fprintf (stderr, "Dumps the RIM- or BIN-formatted input file(s) specified on\n"); fprintf (stderr, "the command line. If the \"-r\" and/or \"-b\" options are\n"); fprintf (stderr, "present, also creates a RIM and/or BIN version of the output\n"); fprintf (stderr, "by adding \".rim\" and/or \".bin\" (respectively) to the input\n"); fprintf (stderr, "filename (can be used to \"clean up\" BIN and RIM images by\n"); fprintf (stderr, "deleting excess data before and after the leader/trailer).\n"); fprintf (stderr, "\n"); fprintf (stderr, "Disassembly conforms to PAL III input requirements\n"); fprintf (stderr, "\n"); exit (EXIT_FAILURE); } /* * optproc * * This is the option processor. It detects the command line options, and * then processes the individual files. */ static void optproc (int argc, char **argv) { int opt; int got_any; int fd; int i; struct stat statbuf; int sts; if (!argc) { usageError (); } // clear out option values to defaults optb = optr = optT = 0; // handle command line options got_any = 0; while ((opt = getopt (argc, argv, "bdrTv")) != -1) { switch (opt) { case 'b': optb++; break; case 'd': optd++; break; case 'r': optr++; break; case 'T': optT++; break; case 'v': optv++; if (optv > 1) { fprintf (stderr, "Verbosity is %d\n", optv); } break; default: usageError (); break; } } // handle command line arguments for (; optind < argc; optind++) { got_any++; tapename = argv [optind]; // snap tapename to global // open the tape fd = open (tapename, O_RDONLY); if (fd == -1) { fprintf (stderr, "%s: couldn't open %s for O_RDONLY, errno %d\n", progname, tapename, errno); perror (NULL); exit (EXIT_FAILURE); } fstat (fd, &statbuf); // get the size, so we can read it into memory tape = calloc (1, statbuf.st_size); if (tape == NULL) { fprintf (stderr, "%s: can't allocate %zu bytes during processing of %s, errno %d (%s)\n", progname, statbuf.st_size, tapename, errno, strerror (errno)); exit (EXIT_FAILURE); } // initialize data areas memset (core, 0xff, sizeof (core)); // set to -1 -- since we are only using 12 bits of each 16 bit word, -1 isn't a valid PDP-8 core value memset (tags, 0, sizeof (tags)); // reset tags nsegments = 0; segments = NULL; read (fd, tape, statbuf.st_size); close (fd); // dump the tape (this also reads the tape into "core" and disassembles) sts = dumptape (tape, statbuf.st_size); free (tape); if (!sts) { continue; // skip tape } // convert to RIM/BIN if required (-b and/or -r) if (optb || optr) { // see if there is any data there at all.. if (blank (core, CORE_SIZE)) { fprintf (stderr, "%s: tape image from %s is empty, not creating a BIN version\n", progname, tapename); return; } if (optb) { writebin (); } if (optr) { writerim (); } } } // if no arguments given, dump usage message if (optT) { memset (core, 0xff, sizeof (core)); // set to -1 (assumption; all 0xff's in an int is -1; pretty safe) for (i = 0; i < 07600; i++) { core [i] = ((i & 07700) >> 6) + ((i & 00077) << 6); } tapename = "test"; if (optb) { writebin (); } if (optr) { writerim (); } } else { if (!got_any) { usageError (); } } } /* * dumptape * * This function does some basic processing (detecting and skipping the * header, killing off data past the trailer) and then determines via * checkrim() and ckeckbin() the format of the tape. Depending on the * type of tape, dumprim() or dumpbin() is called to read the tape into * the "core" array and disassemble it. * * 20071104: Changed the 'skip header' logic to look for a character * less than 0x80, not just not equal to, because a tape I received * had the following: * 0000000 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 * * * 0000100 300 100 000 000 000 050 001 000 002 000 003 000 000 000 000 054 * * Notice the "300" (0xc0) at location 0100. * * Returns 0 on error. */ static int dumptape (unsigned char *t, int n) { int i; // basic preprocessing; find header for (i = 0; i < n; i++) { if (t [i] == 0x80) { // got a header break; } } if (i == n) { fprintf (stderr, "%s: couldn't find a 0x80 leader on tape %s; tape ignored\n", progname, tapename); return (0); } // skip header for (; i < n; i++) { if (t [i] < 0x80) { // RK 20071104 was "!= 0x80"; break; } } if (i == n) { fprintf (stderr, "%s: no data content found after 0x80 leader on tape %s; tape ignored\n", progname, tapename); return (0); } // at this point, we're positioned on the first-non-leader byte of the tape if (n - i < 4) { fprintf (stderr, "%s: tape %s is too short; tape ignored\n", progname, tapename); return (0); } // skip leader (t now points to start of tape; n indicates remaining # bytes) if (optv) { fprintf (stderr, "%s: tape %s skipped %d (0x%0X, 0%0o) bytes of header, original size %d new size %d\n", progname, tapename, i, i, i, n, n - i); } t += i; n -= i; // find first 0x80 -- trailer for (i = 0; i < n; i++) { if (t [i] == 0x80) { break; } } if (i == n) { fprintf (stderr, "%s: warning -- tape %s does not have a trailer\n", progname, tapename); // find first data >= 0x80, then for (i = 0; i < n; i++) { if (t [i] >= 0x80) { // at least stop on the first invalid character, then break; } } } // reset end-of-tape to last character if (optv > 2) { printf ("%s: tape %s skipped %d bytes of trailer, new size is %d bytes\n", progname, tapename, n - i, i); } n = i; // determine type of tape and dump it if (checkrim (t, n)) { if (!dumprim (t, n)) { return (0); } } else if (checkbin (t, n)) { if (!dumpbin (t, n)) { return (0); } } else { fprintf (stderr, "%s: tape %s is neither RIM nor BIN (first four bytes are 0%03o 0%03o 0%03o 0%03o)\n", progname, tapename, t [0], t [1], t [2], t [3]); return (0); } if (!optd) { flow (); // perform flow analysis disassemble (); // disassemble printf ("\n$\n"); } return (1); } /* * checkrim * checkbin * * These two functions try to determine what format the tape is in. * A zero return indicates the tape is not in the given format; a one * indicates it is. The heuristics used here are fairly simple. */ static int checkrim (unsigned char *t, int n) { int i; if (n % 4) { if (optv > 2) { printf ("%s: tape %s size (%d bytes) is not divisible by four; not a RIM tape\n", progname, tapename, n); } return (0); } // see if it's a RIM-formatted tape; we're looking for 01xxxxxx 00xxxxxx 00xxxxxx 00xxxxxx for (i = 0; i < n; i += 4) { if ((t [i] & 0xC0) != 0x40 || (t [i + 1] & 0xC0) || (t [i + 2] & 0xC0) || (t [i + 3] & 0xC0)) { if (optv > 2) { printf ("%s: tape %s does not have the RIM signature at offset 0%04o; expected 01xxxxxx 00xxxxxx 00xxxxxx 00xxxxxx, got 0%04o 0%04o 0%04o 0%04o\n", progname, tapename, i, t [i], t [i + 1], t [i + 2], t [i + 3]); } return (0); } } return (1); } static int checkbin (unsigned char *t, int n) { if (n % 2) { if (optv > 2) { printf ("%s: tape %s size (%d bytes) is not divisible by two; not a BIN tape\n", progname, tapename, n); } return (0); } // see if it's a BIN-formatted tape; 01xxxxxx 00xxxxxx (i.e., we at least expect an origin) if ((t [0] & 0xC0) != 0x40 || (t [1] & 0xC0)) { if (optv > 2) { printf ("%s: tape %s does not have the BIN origin signature; expected header of 01xxxxxx 00xxxxxx, got 0%04o 0%04o\n", progname, tapename, t [0], t [1]); } return (0); } return (1); } /* * From the PDP-8/I & PDP-8/L Small Computer Handbook (099-00272-A1983 / J-09-5) * Appendix D, "Perforated-Tape Loader Sequences", page 383 * * READIN MODE LOADER * The readin mode (RIM) loader is a minimum length, basic perforated-tape * reader program for the ASR33, it is initially stored in memory by manual use * of the operator console keys and switches. The loader is permanently stored in * 18 locations of page 37. * * A perforated tape to be read by the RIM loader must be in RIM format: * * Tape Channel * 8 7 6 5 4 3 2 1 OCTAL Format * --------------- ----- ------------------------ * 1 0 0 0 0 0 0 0 200 Leader-trailer code * 0 1 -A1- -A2- 1AA Absolute address to * 0 0 -A3- -A4- 0AA contain next 4 digits * 0 0 -X1- -X2- 0XX Content of previous * 0 0 -X3- -X4- 0XX 4-digit address * 0 1 -A1- -A2- 1AA Address * 0 0 -A3- -A4- 0AA * 0 0 -X1- -X2- 0XX Content * 0 0 -X3- -X4- 0XX * (etc) (etc) * 1 0 0 0 0 0 0 0 200 Leader-trailer code * * The RIM loader can only be used in conjunction with the ASR33 reader (not * the high-speed perforated-tape reader). Because a tape in RIM format is, in * effect, twice as long as it need be, it is suggested that the RIM loader be used * only to read the binary loader when using the ASR33. (Note that PDP-8 diag- * nostic program tapes are in RIM format.) * * The complete PDP-8/I RIM loader (SA=7756) is as follows: * * Absolute Octal * Address Content Tag Instruction I Z Comments * 7756, 6032 BEG, KCC /CLEAR AC AND FLAG * 7757, 6031 KSF /SKIP IF FLAG = 1 * 7760, 5357 JMP .-1 /LOOKING FOR CHARACTER * 7761, 6036 KRB /READ BUFFER * 7762, 7106 CLL RTL * 7763, 7006 RTL /CHANNEL 8 IN AC0 * 7764, 7510 SPA /CHECKING FOR LEADER * 7765, 5357 JMP BEG+1 /FOUND LEADER * 7766, 7006 RTL /OK, CHANNEL 7 IN LINK * 7767, 6031 KSF * 7770, 5367 JMP .-1 * 7771, 6034 KRS /READ, DO NOT CLEAR * 7772, 7420 SNL /CHECKING FOR ADDRESS * 7773, 3776 DCA I TEMP /STORE CONTENT * 7774, 3376 DCA TEMP /STORE ADDRESS * 7775, 5356 JMP BEG /NEXT WORD * 7776, 0 TEMP, 0 /TEMP STORAGE * 7777, 5XXX JMP X /JMP START OF BIN LOADER */ /* * dumprim * * This is a finite-state-machine that runs through the tape reading the address * and data records, stuffs them into core[], and disassembles the opcodes unless * "-d" is specified. * * Note that disassembly is done after the complete tape has been read in, this * allows us to do some flow analysis. */ #define RIM_Initial 1 // waiting for address #define RIM_Addr 2 // got top part of address, process bottom part #define RIM_Data1 3 // got address, process top part of data #define RIM_Data2 4 // got top part of data, process bottom part static int dumprim (unsigned char *t, int n) { int state; int i; uint16_t addr, data; uint16_t cur_addr; state = RIM_Initial; cur_addr = 0xffff; // impossible address for PDP-8 for (i = 0; i < n; i++) { if (optv > 2) { printf ("[%03o] ", t [i]); fflush (stdout); if ((i % 13) == 12) { printf ("\n"); } } switch (state) { case RIM_Initial: if (t [i] & 0100) { // indicates 1st part of address addr = (t [i] & 0077) << 6; // store top part state = RIM_Addr; } break; case RIM_Addr: addr |= (t [i] & 0077); state = RIM_Data1; break; case RIM_Data1: data = (t [i] & 0077) << 6; // store top part state = RIM_Data2; break; case RIM_Data2: // final decode complete, store data data |= (t [i] & 0077); core [addr] = data; // stash data into core image // segment management -- if it's the next byte, add, else create new if (addr == cur_addr) { cur_addr++; seg_more (1); } else { seg_add (addr, 1); cur_addr = addr + 1; } state = RIM_Initial; break; } } if (optv > 2) { printf ("\n"); } return (1); } /* * BIN format, from the same doc as above, page 384: * * BINARY LOADER * The binary loader (BIN) is used to read machine language tapes (in binary * format) produced by the program assembly language (PAL). A tape in binary * format is about one-half the length of the comparable RIM format tape. It can, * therefore, be read about twice as fast as a RIM tape and is, for this reason, * the more desirable format to use with the 10 cps ASR33 reader or the Type * PR8/I High-Speed Perforated-Tape Reader. * * The format of a binary tape is as follows: * * LEADER: about 2 feet of leader-trailer codes. * * BODY: characters representing the absolute, machine language program * in easy-to-read binary (or octal) form. The section of tape may contain * characters representing instructions (channel 8 and 7 not punched) or * origin resettings (channel 8 not punched, channel 7 punched) and is * concluded by 2 characters (channel 8 and 7 not punched) that represent * a check sum for the entire section. * * TRAILER: same as leader. * * I.e., * * Tape Channel * 8 7 6 5 4 3 2 1 OCTAL Format * --------------- ----- ------------------------ * 1 0 0 0 0 0 0 0 200 Leader * 0 1 A A A A A A 1AA Address (top) * 0 1 B B B B B B 1BB Address (bottom) * 0 0 C C C C C C 0CC Data (top) * 0 0 D D D D D D 0DD Data (bottom) * 0 0 C C C C C C 0CC Data (top) * 0 0 D D D D D D 0DD Data (bottom) * . . . ... next data (2 bytes) * 0 1 A A A A A A 1AA New address (top) * 0 1 B B B B B B 1BB New address (bottom) * . . . ... next data (2 bytes) * 0 0 X X X X X X 0XX Checksum (top) * 0 0 Y Y Y Y Y Y 0YY Checksum (bottom) * */ /* * dumpbin * * This is a finite-state-machine that runs through the tape looking for the * origin and subsequent data fields, stuffs them into the core[] array, and * optionally disassembles the opcodes. * * Every time we hit an origin change, we create a new segment and accumulate * bytes into it. */ #define BIN_Initial 1 // initial state; we require an origin to get out of it #define BIN_Origin 2 // we got the top part of the origin, now need to get the bottom part #define BIN_DataHW 3 // we have an address, so we are looking for another origin or the top part of the data #define BIN_DataLW 4 // we have the top part of the data, now fetching the low part static int dumpbin (unsigned char *t, int n) { int tape_checksum; // checksum stored on tape int calc_checksum; // calculated checksum int i; int state; unsigned short int addr, data; if (n < 4) { fprintf (stderr, "%s: tape %s is too short; tape skipped\n", progname, tapename); return (0); } tape_checksum = ((t [n - 2] & 0x3f) << 6) + (t [n - 1] & 0x3f); if (optv > 1) { printf ("%s: tape %s expected checksum 0%04o\n", progname, tapename, tape_checksum); } n -= 2; // tape is now shorter by the two bytes // now calculate checksum calc_checksum = 0; for (i = 0; i < n; i++) { calc_checksum += t [i]; } calc_checksum &= 07777; // mask to 12 bits if (optv > 1) { printf ("%s: tape %s calculated checksum 0%04o\n", progname, tapename, calc_checksum); } if (tape_checksum != calc_checksum) { fprintf (stderr, "%s: tape %s calculated checksum [0%04o] != stored checksum [0%04o]; tape skipped\n", progname, tapename, calc_checksum, tape_checksum); return (0); } // now we can dump the binary data via the state machine state = BIN_Initial; for (i = 0; i < n; i++) { if (optv > 2) { printf ("[%03o] ", t [i]); fflush (stdout); if ((i % 13) == 12) { printf ("\n"); } } switch (state) { case BIN_Initial: if (t [i] & 0100) { // indicates origin setting code addr = (t [i] & 0077) << 6; // store top part state = BIN_Origin; } break; case BIN_Origin: addr += (t [i] & 0077); // store bottom part state = BIN_DataHW; seg_add (addr, 0); break; case BIN_DataHW: if (t [i] & 0100) { // another origin; skip loading data and load address instead addr = (t [i] & 0077) << 6; state = BIN_Origin; } else { data = (t [i] & 0077) << 6; // store top part of data state = BIN_DataLW; } break; case BIN_DataLW: data += (t [i] & 0077); core [addr] = data; seg_more (1); addr++; // the magic of BIN-format is the autoincrement of the address state = BIN_DataHW; } } if (optv > 2) { printf ("\n"); } return (1); } /* * writebin * writerim * * These two functions write the BIN and RIM format tapes to a file. * The filename is constructed by appending ".bin" or ".rim" to the * input filename. * * The header and trailer written are short, LEADER_LENGTH bytes. * * The writebin() uses a finit-state-machine to generate the origin. */ #define LEADER_LENGTH 16 // 16 chars of leader/trailer should be plenty #define WBIN_Initial 1 // looking for first/next in-use core[] element #define WBIN_Writing 2 // origin written, dumping consecutive words static void writebin (void) { char fname [PATH_MAX]; char leader [LEADER_LENGTH]; FILE *fp; int i; int cksum; int state; // create filename and open it sprintf (fname, "%s.bin", tapename); if ((fp = fopen (fname, "w")) == NULL) { fprintf (stderr, "%s: unable to open BIN output file %s for w, errno %d (%s); creation of output file skipped\n", progname, fname, errno, strerror (errno)); return; } // write leader memset (leader, 0x80, sizeof (leader)); fwrite (leader, 1, sizeof (leader), fp); // now scan through "core" and write the data out... cksum = 0; state = WBIN_Initial; for (i = 0; i < CORE_SIZE; i++) { switch (state) { case WBIN_Initial: // transit out of WBIN_Initial on a "used" core position if (core [i] != -1) { state = WBIN_Writing; fprintf (fp, "%c%c", 0x40 | ((i & 07700) >> 6), i & 00077); // write origin directive fprintf (fp, "%c%c", (core [i] & 07700) >> 6, core [i] & 00077); // write data cksum += (0x40 | ((i & 07700) >> 6)) + (i & 00077) + ((core [i] & 07700) >> 6) + (core [i] & 00077); } break; case WBIN_Writing: if (core [i] == -1) { state = WBIN_Initial; // waiting again for a used core position } else { fprintf (fp, "%c%c", (core [i] & 07700) >> 6, core [i] & 00077); cksum += ((core [i] & 07700) >> 6) + (core [i] & 00077); } break; } } // now write the checksum fprintf (fp, "%c%c", (cksum & 07700) >> 6, cksum & 00077); // write trailer fwrite (leader, 1, sizeof (leader), fp); fclose (fp); } static void writerim (void) { char fname [PATH_MAX]; char leader [LEADER_LENGTH]; FILE *fp; int i; // create the filename and open it sprintf (fname, "%s.rim", tapename); if ((fp = fopen (fname, "w")) == NULL) { fprintf (stderr, "%s: unable to open RIM output file %s for w, errno %d (%s); creation of output file skipped\n", progname, fname, errno, strerror (errno)); return; } // write leader memset (leader, 0x80, sizeof (leader)); fwrite (leader, 1, sizeof (leader), fp); for (i = 0; i < CORE_SIZE; i++) { if (core [i] != -1) { fprintf (fp, "%c%c%c%c", 0x40 + ((i & 07700) >> 6), i & 00077, (core [i] & 07700) >> 6, core [i] & 00077); } } // write trailer fwrite (leader, 1, sizeof (leader), fp); fclose (fp); } /* * blank * * A utility routine to see if core[] is blank (returns 1). * Used to avoid writing an empty tape. */ static int blank (short int *c, int size) { int i; for (i = 0; i < size; i++) { if (c [i] != -1) { return (0); } } return (1); } /* * seg_add (addr, len) * seg_more (more) * * These functions manipulate the segment data stored * in "segments[]" and "nsegments". * * seg_add creates a new segment with the given address * and length. * * seg_more lengthens the current segment by "more" * words. */ static void seg_add (uint16_t addr, int len) { if (optv > 3) { printf ("seg_add (0%04o, %d (0%04o))\n", addr, len, len); } segments = realloc (segments, (nsegments + 1) * sizeof (segments [0])); if (segments == NULL) { fprintf (stderr, "%s: couldn't realloc segments array to be %d elements (%ld bytes) long, errno %d (%s)\n", progname, nsegments + 1, (nsegments + 1) * sizeof (segments [0]), errno, strerror (errno)); exit (EXIT_FAILURE); } segments [nsegments].saddr = addr; segments [nsegments].nwords = len; nsegments++; } static void seg_more (int len) { if (optv > 3) { printf ("seg_more (+%d (0%04o))\n", len, len); } if (nsegments) { segments [nsegments - 1].nwords += len; } else { fprintf (stderr, "%s: seg_more called with no segments in existence\n", progname); exit (EXIT_FAILURE); } } |
> | 1 | const char *version="0.352"; |
︙ | ︙ | |||
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | // 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 | > > > > > > > > | | 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 | // 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 to override ILS mode, forcing fallback to NLS mode. Set when // the PDP-8 instruction decoding loop detects that we're using the // ratio form of SET THROTTLE, which prevents the use of ILS due to the // way instructions are executed in that mode. Defined here rather than // in gpio-ils.c because we don't want to make code that sets this // conditional based on whether ILS is in fact actually enabled. int suppressILS = 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 static 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; |
︙ | ︙ | |||
220 221 222 223 224 225 226 | } } //// bcm_host_get_peripheral_address /////////////////////////////////// // Find Pi's GPIO base address | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | } } //// bcm_host_get_peripheral_address /////////////////////////////////// // Find Pi's GPIO base address static 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) |
︙ | ︙ | |||
561 562 563 564 565 566 567 | } for (size_t row = 0; row < NLEDROWS; ++row) { INP_GPIO (ledrows[row]); } } | < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < | < < < | | | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | } for (size_t row = 0; row < NLEDROWS; ++row) { INP_GPIO (ledrows[row]); } } //// init_pidp8i_gpio ////////////////////////////////////////////////// // Initialize the GPIO pins to the initial states required by // gpio_thread(). It's a separate exported function so that scanswitch // can also use it. void init_pidp8i_gpio (void) { // 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 |
︙ | ︙ | |||
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | 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; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < | < | < > | > > > > > > > > > > > > > > > > > | 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 | 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 } //// 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; // Set GPIO pins to initial states init_pidp8i_gpio (); // 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; } //// map_gpio_for_pidp8i /////////////////////////////////////////////// // Wrapper around map_peripheral() taking care of some higher level // details. This is the interface we expose to outsiders. int map_gpio_for_pidp8i (int must_map) { // 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 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]; if (map_gpio_for_pidp8i (must_map != 0) != 0) { return EFAULT; } // 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)); |
︙ | ︙ |
︙ | ︙ | |||
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 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); | > > > > > > > | | | 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 | 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; // Simplified interface for single-threaded programs that don't use our // GPIO thread, but do want to share some our implementation. extern void init_pidp8i_gpio (void); extern int map_gpio_for_pidp8i (int must_map); 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); // Alternative to start_pidp8i_gpio_thread() for programs that run // single-threaded and do their own GPIO scanning, like scanswitch. extern void init_pidp8i_gpio (void); 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); |
︙ | ︙ |
︙ | ︙ | |||
138 139 140 141 142 143 144 | else { *p -= *p * FALLING_FACTOR; } } } // Light up LEDs | | | > | | > > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | else { *p -= *p * FALLING_FACTOR; } } } // Light up LEDs extern int swStop, swSingInst, suppressILS; if (swStop || swSingInst || suppressILS) { // The CPU is in STOP mode or someone has suppressed the ILS, // so show the current LED states full-brightness using the // same mechanism NLS uses. Force a display swap if the next // loop iteration won't do it in case this isn't STOP mode. update_led_states (intervl * 60); if (step != (MAX_BRIGHTNESS - 1)) swap_displays(); } 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) { |
︙ | ︙ |
> > > > > > > > > > > > > > > > | 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 |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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). |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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( ¬_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( ¬_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( <_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( <_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 */ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* * Program to convert between POSIX ASCII text files * and the output of OS/8 PIP to the Paper Tape Punch. * The OS/8 paper tape punch format is: * * leader: a bunch of ASCII NUL chars to be ignored. * ASCII with the 8th bit set, CR+LF line endings. * trailer: a bunch of ASCII NUL chars to be ignored. * This program can be used as a filter from stdin to stdout or * it will create a new file with name ending in .txt if going to * POSIX text or .ptp if going to OS/8 PIP Paper Tape format. * If the program is called with the name "txt2ptp" then * LTCOUNT (default 100) bytes of leader is prepended to the * output file and LTCOUNT bytes of leader are appended. * The 8th bit of every output character is set, and LF-only * input is turned into CR+LF output. CR+LF input is passed * as-is. * If called by any other name, the ASCII NUL character is * ignored anywhere in the file, and the 8th bit is cleared. * Line endings are untouched in this case. * This program helps work around the issue that the * OS/8 Paper Tape reader handler assumes the last * character in the buffer is junk, so that when you send * a plain text file into PDP-8 SIMH OS/8 with the * ptr device, the last character is lost. */ /* * Author: Bill Cattey * License: The SIMH License: * Copyright © 2015-2017 * by Bill Cattey et. ux. William Cattey et. ux. Poetnerd * 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 include * 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 <errno.h> #include <fcntl.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libgen.h> #define BLOCK_SIZE 256 #define TO_PTP 1 #define TO_TXT 2 #define LTCHAR '\0' #define LTCOUNT 100 /* global variable: ltbuf */ int global_ltbuf[LTCOUNT]; void make_txt (FILE *fpin, FILE *fpout) { int inchar, outchar; int read_ct, n; char *obuffp; char ibuff[BLOCK_SIZE], obuff[BLOCK_SIZE]; while ((read_ct = fread (ibuff, sizeof(char), BLOCK_SIZE, fpin))) { obuffp = obuff; for (n = 0; n < read_ct; n++) { inchar = *(ibuff + n); if (inchar == LTCHAR) continue; *obuffp++ = inchar & 0177; } fwrite (obuff, sizeof(char), obuffp - obuff, fpout); } } /* We could just create an empty buffer and output it, but this is better if for some reason LTCHAR changes. */ void init_ltbuf () { int n; for (n = 0; n < LTCOUNT; n++) { global_ltbuf[n] = LTCHAR; } } void make_lt (FILE *fpout) { fwrite (global_ltbuf, sizeof(char), LTCOUNT, fpout); } void make_ptp (FILE *fpin, FILE *fpout) { int inchar, outchar, prior = '\0'; int read_ct, n; char *obuffp; char ibuff[BLOCK_SIZE]; /* Every \n might add a \r to the output. Worst case is obuff doubles in size. */ char obuff[2*BLOCK_SIZE]; make_lt (fpout); while ((read_ct = fread (ibuff, sizeof(char), BLOCK_SIZE, fpin))) { obuffp = obuff; for (n = 0; n < read_ct; n++) { inchar = *(ibuff + n); if (inchar == '\n' && prior != '\r') { *obuffp++ = (char)('\r' | 0200); } *obuffp++ = inchar | 0200; prior = inchar; } fwrite (obuff, sizeof(char), obuffp - obuff, fpout); } /* If we don't already have an EOF, add one. */ if (inchar != '\032') { fwrite ("\232", sizeof(char), 1, fpout); } make_lt (fpout); } void process_file (char *fname, int flag) { FILE *fpin, *fpout; char *ofname; char *fend; if (flag == TO_PTP) fend = ".ptp"; else fend = ".txt"; ofname = malloc (((strlen (fname) + strlen(fend)) * sizeof (char)) + 1); strcpy (ofname, fname); strcat (ofname, fend); /* printf ("Filename is: %s.\n", ofname); */ if ((fpin = fopen (fname, "r")) == NULL) { printf ("Open of input file %s failed with status %d. Skipping.\n", fname, errno); return; } if ((fpout = fopen (ofname, "w")) == NULL) { printf ("Open of output file %s failed with status %d. Skipping.\n", ofname, errno); return; } if (flag == TO_PTP) make_ptp (fpin, fpout); else make_txt (fpin, fpout); fclose (fpin); fclose (fpout); free (ofname); } int main (int argc, char *argv[]) { int i, flag; char *ltbuf; if (strcmp (basename (argv[0]), "txt2ptp") == 0) { /* printf ("Flag is TO_PTP"); */ flag = TO_PTP; init_ltbuf (); } else { flag = TO_TXT; } if (argc == 1) { if (flag == TO_PTP) make_ptp (stdin, stdout); else make_txt (stdin, stdout); } else { for (i = 1; i < argc; i++) { process_file (argv[i], flag); } } } |
︙ | ︙ | |||
36 37 38 39 40 41 42 | #define pgpio (&gpio) int main() { int i,j,k,switchscan[2], tmp; | < | < | < | < < < < | | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #define pgpio (&gpio) int main() { int i,j,k,switchscan[2], tmp; extern struct bcm2835_peripheral gpio; if (map_gpio_for_pidp8i (1) != 0) { printf("Failed to map the GPIO SoC peripheral into our VM space.\n"); return -1; } init_pidp8i_gpio(); // Read the 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? |
︙ | ︙ |
︙ | ︙ | |||
239 240 241 242 243 244 245 | 11-Dec-95 RMS Fixed ordering bug in save/restore 22-May-95 RMS Added symbolic input 13-Apr-95 RMS Added symbolic printouts */ /* Macros and data structures */ | | < < < | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | 11-Dec-95 RMS Fixed ordering bug in save/restore 22-May-95 RMS Added symbolic input 13-Apr-95 RMS Added symbolic printouts */ /* Macros and data structures */ #define NOT_MUX_USING_CODE /* sim_tmxr library provider or agnostic */ #define IN_SCP_C 1 /* Include from scp.c */ #include "sim_defs.h" #include "sim_rev.h" #include "sim_disk.h" #include "sim_tape.h" #include "sim_ether.h" #include "sim_serial.h" |
︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 | #endif #include <sys/stat.h> #include <setjmp.h> #if defined(HAVE_DLOPEN) /* Dynamic Readline support */ #include <dlfcn.h> #endif #ifndef MAX #define MAX(a,b) (((a) >= (b)) ? (a) : (b)) #endif /* search logical and boolean ops */ | > > > > > | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | #endif #include <sys/stat.h> #include <setjmp.h> #if defined(HAVE_DLOPEN) /* Dynamic Readline support */ #include <dlfcn.h> #endif #ifdef PIDP8I #include "gpio-common.h" // for start/stop_pidp8i_gpio_thread() #include "PDP8/pidp8i.h" // for build_pidp8i_scp_cmd() #endif #ifndef MAX #define MAX(a,b) (((a) >= (b)) ? (a) : (b)) #endif /* search logical and boolean ops */ |
︙ | ︙ | |||
344 345 346 347 348 349 350 351 352 353 354 355 356 357 | #endif #define GET_SWITCHES(cp) \ if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW #define GET_RADIX(val,dft) \ if (sim_switches & SWMASK ('O')) val = 8; \ else if (sim_switches & SWMASK ('D')) val = 10; \ else if (sim_switches & SWMASK ('H')) val = 16; \ else val = dft; /* Asynch I/O support */ #if defined (SIM_ASYNCH_IO) pthread_mutex_t sim_asynch_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t sim_asynch_wake = PTHREAD_COND_INITIALIZER; | > | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | #endif #define GET_SWITCHES(cp) \ if ((cp = get_sim_sw (cp)) == NULL) return SCPE_INVSW #define GET_RADIX(val,dft) \ if (sim_switches & SWMASK ('O')) val = 8; \ else if (sim_switches & SWMASK ('D')) val = 10; \ else if (sim_switches & SWMASK ('H')) val = 16; \ else if ((sim_switch_number >= 2) && (sim_switch_number <= 36)) val = sim_switch_number; \ else val = dft; /* Asynch I/O support */ #if defined (SIM_ASYNCH_IO) pthread_mutex_t sim_asynch_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t sim_asynch_wake = PTHREAD_COND_INITIALIZER; |
︙ | ︙ | |||
495 496 497 498 499 500 501 | /* Command support routines */ SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr); SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr); int32 test_search (t_value *val, SCHTAB *schptr); static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char); | > > > > > | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | /* Command support routines */ SCHTAB *get_rsearch (CONST char *cptr, int32 radix, SCHTAB *schptr); SCHTAB *get_asearch (CONST char *cptr, int32 radix, SCHTAB *schptr); int32 test_search (t_value *val, SCHTAB *schptr); static const char *get_glyph_gen (const char *iptr, char *optr, char mchar, t_bool uc, t_bool quote, char escape_char); typedef enum { SW_ERROR, /* Parse Error */ SW_BITMASK, /* Bitmask Value or Not a switch */ SW_NUMBER /* Numeric Value */ } SWITCH_PARSE; SWITCH_PARSE get_switches (const char *cptr, int32 *sw_val, int32 *sw_number); CONST char *get_sim_sw (CONST char *cptr); t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); t_value get_rval (REG *rptr, uint32 idx); void put_rval (REG *rptr, uint32 idx, t_value val); void fprint_help (FILE *st); void fprint_stopped (FILE *st, t_stat r); void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr); |
︙ | ︙ | |||
552 553 554 555 556 557 558 559 560 561 562 563 564 565 | /* Global data */ DEVICE *sim_dflt_dev = NULL; UNIT *sim_clock_queue = QUEUE_LIST_END; int32 sim_interval = 0; int32 sim_switches = 0; FILE *sim_ofile = NULL; TMLN *sim_oline = NULL; MEMFILE *sim_mfile = NULL; SCHTAB *sim_schrptr = FALSE; SCHTAB *sim_schaptr = FALSE; DEVICE *sim_dfdev = NULL; UNIT *sim_dfunit = NULL; | > | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | /* Global data */ DEVICE *sim_dflt_dev = NULL; UNIT *sim_clock_queue = QUEUE_LIST_END; int32 sim_interval = 0; int32 sim_switches = 0; int32 sim_switch_number = 0; FILE *sim_ofile = NULL; TMLN *sim_oline = NULL; MEMFILE *sim_mfile = NULL; SCHTAB *sim_schrptr = FALSE; SCHTAB *sim_schaptr = FALSE; DEVICE *sim_dfdev = NULL; UNIT *sim_dfunit = NULL; |
︙ | ︙ | |||
578 579 580 581 582 583 584 585 586 587 588 589 590 591 | char *sim_brk_act_buf[MAX_DO_NEST_LVL]; BRKTAB **sim_brk_tab = NULL; int32 sim_brk_ent = 0; int32 sim_brk_lnt = 0; int32 sim_brk_ins = 0; int32 sim_quiet = 0; int32 sim_step = 0; static double sim_time; static uint32 sim_rtime; static int32 noqueue_time; volatile int32 stop_cpu = 0; static char **sim_argv; t_value *sim_eval = NULL; static t_value sim_last_val; | > > > > | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | char *sim_brk_act_buf[MAX_DO_NEST_LVL]; BRKTAB **sim_brk_tab = NULL; int32 sim_brk_ent = 0; int32 sim_brk_lnt = 0; int32 sim_brk_ins = 0; int32 sim_quiet = 0; int32 sim_step = 0; char *sim_sub_instr = NULL; char *sim_sub_instr_buf = NULL; size_t sim_sub_instr_size = 0; size_t *sim_sub_instr_off = NULL; static double sim_time; static uint32 sim_rtime; static int32 noqueue_time; volatile int32 stop_cpu = 0; static char **sim_argv; t_value *sim_eval = NULL; static t_value sim_last_val; |
︙ | ︙ | |||
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 | char *sim_prompt = NULL; /* prompt string */ static FILE *sim_gotofile; /* the currently open do file */ static int32 sim_goto_line[MAX_DO_NEST_LVL+1]; /* the current line number in the currently open do file */ static int32 sim_do_echo = 0; /* the echo status of the currently open do file */ static int32 sim_show_message = 1; /* the message display status of the currently open do file */ static int32 sim_on_inherit = 0; /* the inherit status of on state and conditions when executing do files */ static int32 sim_do_depth = 0; static int32 sim_on_check[MAX_DO_NEST_LVL+1]; static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1]; static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE]; static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1]; static const char *sim_do_label[MAX_DO_NEST_LVL+1]; t_stat sim_last_cmd_stat; /* Command Status */ static SCHTAB sim_stabr; /* Register search specifier */ static SCHTAB sim_staba; /* Memory search specifier */ static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) }; static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) }; #if defined USE_INT64 static const char *sim_si64 = "64b data"; #else static const char *sim_si64 = "32b data"; | > > > > > > > > | 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 | char *sim_prompt = NULL; /* prompt string */ static FILE *sim_gotofile; /* the currently open do file */ static int32 sim_goto_line[MAX_DO_NEST_LVL+1]; /* the current line number in the currently open do file */ static int32 sim_do_echo = 0; /* the echo status of the currently open do file */ static int32 sim_show_message = 1; /* the message display status of the currently open do file */ static int32 sim_on_inherit = 0; /* the inherit status of on state and conditions when executing do files */ static int32 sim_do_depth = 0; static t_bool sim_cmd_echoed = FALSE; /* Command was emitted already prior to message output */ static int32 sim_on_check[MAX_DO_NEST_LVL+1]; static char *sim_on_actions[MAX_DO_NEST_LVL+1][SCPE_MAX_ERR+1]; static char sim_do_filename[MAX_DO_NEST_LVL+1][CBUFSIZE]; static const char *sim_do_ocptr[MAX_DO_NEST_LVL+1]; static const char *sim_do_label[MAX_DO_NEST_LVL+1]; t_stat sim_last_cmd_stat; /* Command Status */ static SCHTAB sim_stabr; /* Register search specifier */ static SCHTAB sim_staba; /* Memory search specifier */ static DEBTAB sim_dflt_debug[] = { {"EVENT", SIM_DBG_EVENT, "Event Dispatching"}, {"ACTIVATE", SIM_DBG_ACTIVATE, "Event Scheduling"}, {"AIO_QUEUE", SIM_DBG_AIO_QUEUE, "Asynchronous Event Queueing"}, {0} }; static UNIT sim_step_unit = { UDATA (&step_svc, 0, 0) }; static UNIT sim_expect_unit = { UDATA (&expect_svc, 0, 0) }; #if defined USE_INT64 static const char *sim_si64 = "64b data"; #else static const char *sim_si64 = "32b data"; |
︙ | ︙ | |||
802 803 804 805 806 807 808 | " interpreted as an address\n" "3Switches\n" " Switches can be used to control the format of display information:\n\n" /***************** 80 character line width template *************************/ "++-a display as ASCII\n" "++-c display as character string\n" "++-m display as instruction mnemonics\n" | | | > | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | " interpreted as an address\n" "3Switches\n" " Switches can be used to control the format of display information:\n\n" /***************** 80 character line width template *************************/ "++-a display as ASCII\n" "++-c display as character string\n" "++-m display as instruction mnemonics\n" "++-o or -8 display as octal\n" "++-d or -10 display as decimal\n" "++-h or -16 display as hexadecimal\n" "++-2 display as binary\n\n" " The simulators typically accept symbolic input (see documentation with each\n" " simulator).\n\n" "3Examples\n" " Examples:\n\n" "++ex 1000-1100 examine 1000 to 1100\n" "++de PC 1040 set PC to 1040\n" "++ie 40-50 interactively examine 40:50\n" |
︙ | ︙ | |||
994 995 996 997 998 999 1000 | " to open the file read only. If the file does not exist, or the unit does\n" " not support read only operation, an error occurs. Input-only devices, such\n" " as paper-tape readers, and devices with write lock switches, such as disks\n" " and tapes, support read only operation; other devices do not. If a file is\n" " attached read only, its contents can be examined but not modified.\n" "5-q\n" " If the -q switch is specified when creating a new file (-n) or opening one\n" | | | 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 | " to open the file read only. If the file does not exist, or the unit does\n" " not support read only operation, an error occurs. Input-only devices, such\n" " as paper-tape readers, and devices with write lock switches, such as disks\n" " and tapes, support read only operation; other devices do not. If a file is\n" " attached read only, its contents can be examined but not modified.\n" "5-q\n" " If the -q switch is specified when creating a new file (-n) or opening one\n" " read only (-r), any messages announcing these facts will be suppressed.\n" "5-f\n" " For simulated magnetic tapes, the ATTACH command can specify the format of\n" " the attached tape image file:\n\n" "++ATTACH -f <tape_unit> <format> <filename>\n\n" " The currently supported tape image file formats are:\n\n" "++SIMH SIMH simulator format\n" "++E11 E11 simulator format\n" |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 | "++DIR {path} list directory files\n" #define HLP_LS "*Commands Listing_Files LS" "3LS\n" "++LS {path} list directory files\n" "2Displaying Files\n" #define HLP_TYPE "*Commands Displaying_Files TYPE" "3TYPE\n" | | | > | | > > > > > > > | | | | > | 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 | "++DIR {path} list directory files\n" #define HLP_LS "*Commands Listing_Files LS" "3LS\n" "++LS {path} list directory files\n" "2Displaying Files\n" #define HLP_TYPE "*Commands Displaying_Files TYPE" "3TYPE\n" "++TYPE file display a file contents\n" #define HLP_CAT "*Commands Displaying_Files CAT" "3CAT\n" "++CAT file display a file contents\n" "2Removing Files\n" #define HLP_DELETE "*Commands Removing_Files DEL" "3DELETE\n" "++DEL{ete} file deletes a file\n" #define HLP_RM "*Commands Removing_Files RM" "3RM\n" "++RM file deletes a file\n" "2Copying Files\n" #define HLP_COPY "*Commands Copying_Files COPY" "3COPY\n" "++COPY sfile dfile copies a file\n" #define HLP_CP "*Commands Copying_Files CP" "3CP\n" "++CP sfile dfile copies a file\n" #define HLP_SET "*Commands SET" "2SET\n" /***************** 80 character line width template *************************/ #define HLP_SET_CONSOLE "*Commands SET CONSOLE" "3Console\n" "+set console arg{,arg...} set console options\n" "+set console WRU=value specify console drop to simh character\n" "+set console BRK=value specify console Break character\n" "+set console DEL=value specify console delete character\n" "+set console PCHAR=bitmask bit mask of printable characters in\n" "++++++++ range [31,0]\n" "+set console SPEED=speed{*factor}\n" "++++++++ specify console input data rate\n" "+set console TELNET=port specify console telnet port\n" "+set console TELNET=LOG=log_file\n" "++++++++ specify console telnet logging to the\n" "++++++++ specified destination {LOG,STDOUT,STDERR,\n" "++++++++ DEBUG or filename)\n" |
︙ | ︙ | |||
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 | #if defined (SIM_ASYNCH_CLOCKS) "+set clock asynch enable asynchronous clocks\n" "+set clock noasynch disable asynchronous clocks\n" #endif "+set clock nocatchup disable catchup clock ticks\n" "+set clock catchup enable catchup clock ticks\n" "+set clock calib=n%% specify idle calibration skip %%\n" #define HLP_SET_ASYNCH "*Commands SET Asynch" "3Asynch\n" "+set asynch enable asynchronous I/O\n" "+set noasynch disable asynchronous I/O\n" | > > > | > > > > > > > > > | 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 | #if defined (SIM_ASYNCH_CLOCKS) "+set clock asynch enable asynchronous clocks\n" "+set clock noasynch disable asynchronous clocks\n" #endif "+set clock nocatchup disable catchup clock ticks\n" "+set clock catchup enable catchup clock ticks\n" "+set clock calib=n%% specify idle calibration skip %%\n" "+set clock stop=n stop execution after n instructions\n\n" " The set clock stop command allows execution to have a bound when\n" " execution starts with a BOOT, NEXT or CONTINUE command.\n" #define HLP_SET_ASYNCH "*Commands SET Asynch" "3Asynch\n" "+set asynch enable asynchronous I/O\n" "+set noasynch disable asynchronous I/O\n" #define HLP_SET_ENVIRON "*Commands SET Environment" "3Environment\n" "4Explicitily Changing A Variable\n" "+set environment name=val set environment variable\n" "+set environment name clear environment variable\n" "4Gathering Input From A User\n" " Input from a user can be obtained by:\n\n" "+set environment -p \"Prompt String\" name=default\n\n" " The -p switch indicates that the user should be prompted\n" " with the indicated prompt string and the input provided\n" " will be saved in the environment variable 'name'. If no\n" " input is provided, the value specified as 'default' will be\n" " used.\n" #define HLP_SET_ON "*Commands SET Command_Status_Trap_Dispatching" "3Command Status Trap Dispatching\n" "+set on enables error checking after command\n" "++++++++ execution\n" "+set noon disables error checking after command\n" "++++++++ execution\n" "+set on inherit enables inheritance of ON state and\n" |
︙ | ︙ | |||
1224 1225 1226 1227 1228 1229 1230 | "++++++++ messages\n" "+set noquiet re-enables suppression of some output and\n" "++++++++ messages\n" #define HLP_SET_PROMPT "*Commands SET Command_Prompt" "3Command Prompt\n" "+set prompt \"string\" sets an alternate simulator prompt string\n" "3Device and Unit\n" | | | 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 | "++++++++ messages\n" "+set noquiet re-enables suppression of some output and\n" "++++++++ messages\n" #define HLP_SET_PROMPT "*Commands SET Command_Prompt" "3Command Prompt\n" "+set prompt \"string\" sets an alternate simulator prompt string\n" "3Device and Unit\n" "+set <dev> OCT|DEC|HEX|BIN set device display radix\n" "+set <dev> ENABLED enable device\n" "+set <dev> DISABLED disable device\n" "+set <dev> DEBUG{=arg} set device debug flags\n" "+set <dev> NODEBUG={arg} clear device debug flags\n" "+set <dev> arg{,arg...} set device parameters (see show modifiers)\n" "+set <unit> ENABLED enable unit\n" "+set <unit> DISABLED disable unit\n" |
︙ | ︙ | |||
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 | #define HLP_DO "*Commands Executing_Command_Files" "2Executing Command Files\n" " The simulator can execute command files with the DO command:\n\n" "++DO <filename> {arguments...} execute commands in file\n\n" " The DO command allows command files to contain substitutable arguments.\n" " The string %%n, where n is between 1 and 9, is replaced with argument n\n" " from the DO command line. The string %%0 is replaced with <filename>.\n" " The sequences \\%% and \\\\ are replaced with the literal characters %% and \\,\n" " respectively. Arguments with spaces can be enclosed in matching single\n" " or double quotation marks.\n\n" " DO commands may be nested up to ten invocations deep.\n\n" "3Switches\n" " If the switch -v is specified, the commands in the file are echoed before\n" " they are executed.\n\n" " If the switch -e is specified, command processing (including nested command\n" " invocations) will be aborted if a command error is encountered.\n" " (Simulation stop never abort processing; use ASSERT to catch unexpected\n" " stops.) Without the switch, all errors except ASSERT failures will be\n" " ignored, and command processing will continue.\n\n" " If the switch -o is specified, the on conditions and actions from the\n" " calling command file will be inherited in the command file being invoked.\n" " If the switch -q is specified, the quiet mode will be explicitly enabled\n" " for the called command file, otherwise quiet mode is inherited from the\n" " calling context.\n" /***************** 80 character line width template *************************/ #define HLP_GOTO "*Commands Executing_Command_Files GOTO" "3GOTO\n" " Commands in a command file execute in sequence until either an error\n" " trap occurs (when a command completes with an error status), or when an\n" " explict request is made to start command execution elsewhere with the\n" " GOTO command:\n\n" "++GOTO <label>\n\n" | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #define HLP_DO "*Commands Executing_Command_Files" "2Executing Command Files\n" " The simulator can execute command files with the DO command:\n\n" "++DO <filename> {arguments...} execute commands in file\n\n" " The DO command allows command files to contain substitutable arguments.\n" " The string %%n, where n is between 1 and 9, is replaced with argument n\n" " from the DO command line. The string %%0 is replaced with <filename>.\n" " The string %%* is replaced by the whole set of arguments (%%1 ... %%9).\n" " The sequences \\%% and \\\\ are replaced with the literal characters %% and \\,\n" " respectively. Arguments with spaces can be enclosed in matching single\n" " or double quotation marks.\n\n" " DO commands may be nested up to ten invocations deep.\n\n" "3Switches\n" " If the switch -v is specified, the commands in the file are echoed before\n" " they are executed.\n\n" " If the switch -e is specified, command processing (including nested command\n" " invocations) will be aborted if a command error is encountered.\n" " (Simulation stop never abort processing; use ASSERT to catch unexpected\n" " stops.) Without the switch, all errors except ASSERT failures will be\n" " ignored, and command processing will continue.\n\n" " If the switch -o is specified, the on conditions and actions from the\n" " calling command file will be inherited in the command file being invoked.\n" " If the switch -q is specified, the quiet mode will be explicitly enabled\n" " for the called command file, otherwise quiet mode is inherited from the\n" " calling context.\n" /***************** 80 character line width template *************************/ "3Variable_Insertion\n" " Built In variables %%DATE%%, %%TIME%%, %%DATETIME%%, %%LDATE%%, %%LTIME%%,\n" " %%CTIME%%, %%DATE_YYYY%%, %%DATE_YY%%, %%DATE_YC%%, %%DATE_MM%%, %%DATE_MMM%%,\n" " %%DATE_MONTH%%, %%DATE_DD%%, %%DATE_D%%, %%DATE_WYYYY%%, %%DATE_WW%%,\n" " %%TIME_HH%%, %%TIME_MM%%, %%TIME_SS%%, %%STATUS%%, %%TSTATUS%%, %%SIM_VERIFY%%,\n" " %%SIM_QUIET%%, %%SIM_MESSAGE%% %%SIM_MESSAGE%%\n" " %%SIM_NAME%%, %%SIM_BIN_NAME%%, %%SIM_BIN_PATH%%m %%SIM_OSTYPE%%\n\n" "+Token %%0 expands to the command file name.\n" "+Token %%n (n being a single digit) expands to the n'th argument\n" "+Token %%* expands to the whole set of arguments (%%1 ... %%9)\n\n" "+The input sequence \"%%%%\" represents a literal \"%%\". All other\n" "+character combinations are rendered literally.\n\n" "+Omitted parameters result in null-string substitutions.\n\n" "+Tokens preceeded and followed by %% characters are expanded as environment\n" "+variables, and if an environment variable isn't found then it can be one of\n" "+several special variables:\n\n" "++%%DATE%% yyyy-mm-dd\n" "++%%TIME%% hh:mm:ss\n" "++%%DATETIME%% yyyy-mm-ddThh:mm:ss\n" "++%%LDATE%% mm/dd/yy (Locale Formatted)\n" "++%%LTIME%% hh:mm:ss am/pm (Locale Formatted)\n" "++%%CTIME%% Www Mmm dd hh:mm:ss yyyy (Locale Formatted)\n" "++%%UTIME%% nnnn (Unix time - seconds since 1/1/1970)\n" "++%%DATE_YYYY%% yyyy (0000-9999)\n" "++%%DATE_YY%% yy (00-99)\n" "++%%DATE_MM%% mm (01-12)\n" "++%%DATE_MMM%% mmm (JAN-DEC)\n" "++%%DATE_MONTH%% month (January-December)\n" "++%%DATE_DD%% dd (01-31)\n" "++%%DATE_WW%% ww (01-53) ISO 8601 week number\n" "++%%DATE_WYYYY%% yyyy (0000-9999) ISO 8601 week year number\n" "++%%DATE_D%% d (1-7) ISO 8601 day of week\n" "++%%DATE_JJJ%% jjj (001-366) day of year\n" "++%%DATE_19XX_YY%% yy A year prior to 2000 with the same\n" "++++++++++ calendar days as the current year\n" "++%%DATE_19XX_YYYY%% yyyy A year prior to 2000 with the same\n" "++++++++++ calendar days as the current year\n" "++%%TIME_HH%% hh (00-23)\n" "++%%TIME_MM%% mm (00-59)\n" "++%%TIME_SS%% ss (00-59)\n" "++%%STATUS%% Status value from the last command executed\n" "++%%TSTATUS%% The text form of the last status value\n" "++%%SIM_VERIFY%% The Verify/Verbose mode of the current Do command file\n" "++%%SIM_VERBOSE%% The Verify/Verbose mode of the current Do command file\n" "++%%SIM_QUIET%% The Quiet mode of the current Do command file\n" "++%%SIM_MESSAGE%% The message display status of the current Do command file\n" "++%%SIM_NAME%% The name of the current simulator\n" "++%%SIM_BIN_NAME%% The program name of the current simulator\n" "++%%SIM_BIN_PATH%% The program path that invoked the current simulator\n" "++%%SIM_OSTYPE%% The Operating System running the current simulator\n\n" "+Environment variable lookups are done first with the precise name between\n" "+the %% characters and if that fails, then the name between the %% characters\n" "+is upcased and a lookup of that valus is attempted.\n\n" "+The first Space delimited token on the line is extracted in uppercase and\n" "+then looked up as an environment variable. If found it the value is\n" "+supstituted for the original string before expanding everything else. If\n" "+it is not found, then the original beginning token on the line is left\n" "+untouched.\n" #define HLP_GOTO "*Commands Executing_Command_Files GOTO" "3GOTO\n" " Commands in a command file execute in sequence until either an error\n" " trap occurs (when a command completes with an error status), or when an\n" " explict request is made to start command execution elsewhere with the\n" " GOTO command:\n\n" "++GOTO <label>\n\n" |
︙ | ︙ | |||
1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 | /***************** 80 character line width template *************************/ #define HLP_SEND "*Commands Executing_Command_Files Injecting_Console_Input" /***************** 80 character line width template *************************/ "3Injecting Console Input\n" " The SEND command provides a way to insert input into the console device of\n" " a simulated system as if it was entered by a user.\n\n" "++SEND {-t} {after=nn,}{delay=nn,}\"<string>\"\n\n" " The string argument must be delimited by quote characters. Quotes may\n" " be either single or double but the opening and closing quote characters\n" " must match. Data in the string may contain escaped character strings.\n\n" " The SEND command can also insert input into any serial device on a\n" " simulated system as if it was entered by a user.\n\n" | > > | > > > > > > | | < | > > > | | < < | > | > | | 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 | /***************** 80 character line width template *************************/ #define HLP_SEND "*Commands Executing_Command_Files Injecting_Console_Input" /***************** 80 character line width template *************************/ "3Injecting Console Input\n" " The SEND command provides a way to insert input into the console device of\n" " a simulated system as if it was entered by a user.\n\n" "++SEND {-t} {after=nn,}{delay=nn,}\"<string>\"\n\n" "++NOSEND\n\n" "++SHOW SEND\n\n" " The string argument must be delimited by quote characters. Quotes may\n" " be either single or double but the opening and closing quote characters\n" " must match. Data in the string may contain escaped character strings.\n\n" " The SEND command can also insert input into any serial device on a\n" " simulated system as if it was entered by a user.\n\n" "++SEND {-t} {<dev>:line} {after=nn,}{delay=nn,}\"<string>\"\n\n" "++NOSEND {<dev>:line}\n\n" "++SHOW SEND {<dev>:line}\n\n" " The NOSEND command removes any undelivered input data which may be\n" " pending on the CONSOLE or a specific multiplexer line.\n\n" " The SHOW SEND command displays any pending SEND activity for the\n" " CONSOLE or a specific multiplexer line.\n" "4Delay\n" " Specifies an integer (>=0) representing a minimal instruction delay\n" " between characters being sent. The delay parameter can be set by\n" " itself with:\n\n" "++SEND DELAY=n\n\n" " which will set the default delay value for subsequent SEND commands\n" " which don't specify an explicit DELAY parameter along with a string\n" " If a SEND command is processed and no DELAY value has been specified,\n" " the default value of the delay parameter is 1000.\n" /***************** 80 character line width template *************************/ "4After\n" " Specifies an integer (>=0) representing a minimal number of instructions\n" " which must execute before the first character in the string is sent.\n" " The after parameter value can be set by itself with:\n\n" "++SEND AFTER=n\n\n" " which will set the default after value for subsequent SEND commands\n" " which don't specify an explicit AFTER parameter along with a string\n" " If a SEND command is processed and no AFTER value has been specified,\n" " the default value of the delay parameter is the DELAY parameter value.\n" "4Escaping String Data\n" " The following character escapes are explicitly supported:\n" "++\\r Sends the ASCII Carriage Return character (Decimal value 13)\n" "++\\n Sends the ASCII Linefeed character (Decimal value 10)\n" "++\\f Sends the ASCII Formfeed character (Decimal value 12)\n" "++\\t Sends the ASCII Horizontal Tab character (Decimal value 9)\n" "++\\v Sends the ASCII Vertical Tab character (Decimal value 11)\n" |
︙ | ︙ | |||
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 | #define HLP_EXPECT "*Commands Executing_Command_Files Reacting_To_Console_Output" /***************** 80 character line width template *************************/ "3Reacting To Console Output\n" " The EXPECT command provides a way to stop execution and take actions\n" " when specific output has been generated by the simulated system.\n\n" "++EXPECT {dev:line} {[count]} {HALTAFTER=n,}\"<string>\" {actioncommand {; actioncommand}...}\n\n" "++NOEXPECT {dev:line} \"<string>\"\n\n" " The string argument must be delimited by quote characters. Quotes may\n" " be either single or double but the opening and closing quote characters\n" " must match. Data in the string may contain escaped character strings.\n" " If a [count] is specified, the rule will match after the match string\n" " has matched count times.\n\n" " When multiple expect rules are defined with the same match string, they\n" " will match in the same order they were defined in.\n\n" " When expect rules are defined, they are evaluated agains recently\n" " produced output as each character is output to the device. Since this\n" " evaluation processing is done on each output character, rule matching\n" " is not specifically line oriented. If line oriented matching is desired\n" " then rules should be defined which contain the simulated system's line\n" " ending character sequence (i.e. \"\\r\\n\").\n" " Once data has matched any expect rule, that data is no longer eligible\n" " to match other expect rules which may already be defined.\n" " Data which is output prior to the definition of an expect rule is not\n" " eligible to be matched against.\n\n" | > | > > > | 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 | #define HLP_EXPECT "*Commands Executing_Command_Files Reacting_To_Console_Output" /***************** 80 character line width template *************************/ "3Reacting To Console Output\n" " The EXPECT command provides a way to stop execution and take actions\n" " when specific output has been generated by the simulated system.\n\n" "++EXPECT {dev:line} {[count]} {HALTAFTER=n,}\"<string>\" {actioncommand {; actioncommand}...}\n\n" "++NOEXPECT {dev:line} \"<string>\"\n\n" "++SHOW EXPECT {dev:line}\n\n" " The string argument must be delimited by quote characters. Quotes may\n" " be either single or double but the opening and closing quote characters\n" " must match. Data in the string may contain escaped character strings.\n" " If a [count] is specified, the rule will match after the match string\n" " has matched count times.\n\n" " When multiple expect rules are defined with the same match string, they\n" " will match in the same order they were defined in.\n\n" " When expect rules are defined, they are evaluated agains recently\n" " produced output as each character is output to the device. Since this\n" " evaluation processing is done on each output character, rule matching\n" " is not specifically line oriented. If line oriented matching is desired\n" " then rules should be defined which contain the simulated system's line\n" " ending character sequence (i.e. \"\\r\\n\").\n" " Once data has matched any expect rule, that data is no longer eligible\n" " to match other expect rules which may already be defined.\n" " Data which is output prior to the definition of an expect rule is not\n" " eligible to be matched against.\n\n" " The NOEXPECT command removes a previously defined EXPECT command for the\n" " console or a specific multiplexer line.\n\n" " The SHOW EXPECT command displays all of the pending EXPECT state for\n" " the console or a specific multiplexer line.\n" /***************** 80 character line width template *************************/ "4Switches\n" " Switches can be used to influence the behavior of EXPECT rules\n\n" "5-p\n" " EXPECT rules default to be one shot activities. That is a rule is\n" " automatically removed when it matches unless it is designated as a\n" " persistent rule by using a -p switch when the rule is defined.\n" |
︙ | ︙ | |||
1695 1696 1697 1698 1699 1700 1701 | "++\\n{n{n}} where each n is an octal digit (0-7)\n" " and hext character values of the form:\n" "++\\xh{h} where each h is a hex digit (0-9A-Fa-f)\n" "4HaltAfter\n" " Specifies the number of instructions which should be executed before\n" " simulator instruction execution should stop. The default is to stop\n" " executing instructions immediately (i.e. HALTAFTER=0).\n" | | | | > > > > > > > > > > > > | 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 | "++\\n{n{n}} where each n is an octal digit (0-7)\n" " and hext character values of the form:\n" "++\\xh{h} where each h is a hex digit (0-9A-Fa-f)\n" "4HaltAfter\n" " Specifies the number of instructions which should be executed before\n" " simulator instruction execution should stop. The default is to stop\n" " executing instructions immediately (i.e. HALTAFTER=0).\n" " The default HaltAfter delay, once set, persists for all expect behaviors\n" " for that device.\n" " The default HaltAfter parameter value can be set by itself with:\n\n" "++EXPECT HALTAFTER=n\n\n" " A unique HaltAfter value can be specified with each expect matching rule\n" " which if it is not specified then the default value will be used.\n" " To avoid potentially unpredictable system hehavior that will happen\n" " if multiple expect rules are in effect and a haltafter value is large\n" " enough for more than one expect rule to match before an earlier haltafter\n" " delay has expired, only a single EXPECT rule can be defined if a non-zero\n" " HaltAfter parameter has been set.\n" /***************** 80 character line width template *************************/ #define HLP_SLEEP "*Commands Executing_Command_Files Pausing_Command_Execution" "3Pausing Command Execution\n" " A simulator command file may wait for a specific period of time with the\n\n" "++SLEEP NUMBER[SUFFIX]...\n\n" " Pause for NUMBER seconds. SUFFIX may be 's' for seconds (the default),\n" " 'm' for minutes, 'h' for hours or 'd' for days. NUMBER may be an\n" " arbitrary floating point number. Given two or more arguments, pause\n" " for the amount of time specified by the sum of their values.\n" " NOTE: A SLEEP command is interruptable with SIGINT (^C).\n\n" /***************** 80 character line width template *************************/ #define HLP_ASSERT "*Commands Executing_Command_Files Testing_Simulator_State" #define HLP_IF "*Commands Executing_Command_Files Testing_Simulator_State" "3Testing Simulator State\n" " There are two ways for a command file to examine simulator state and\n" " then take action based on that state:\n" "4ASSERT\n" |
︙ | ︙ | |||
1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 | "5Examples:\n" " A command file might be used to bootstrap an operating system that\n" " halts after the initial load from disk. The ASSERT command is then\n" " used to confirm that the load completed successfully by examining the\n" " CPU's \"A\" register for the expected value:\n\n" "++; OS bootstrap command file\n" "++;\n" "++ATTACH DS0 os.disk\n" "++BOOT DS\n" "++; A register contains error code; 0 = good boot\n" "++ASSERT A=0\n" "++ATTACH MT0 sys.tape\n" "++ATTACH MT1 user.tape\n" "++RUN\n\n" /***************** 80 character line width template *************************/ " In the example, if the A register is not 0, the \"ASSERT A=0\" command will\n" " be echoed, the command file will be aborted with an \"Assertion failed\"\n" " message. Otherwise, the command file will continue to bring up the\n" " operating system.\n" "4IF\n" " The IF command tests a simulator state condition and executes additional\n" " commands if the condition is true:\n\n" | > > | > > | | 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 | "5Examples:\n" " A command file might be used to bootstrap an operating system that\n" " halts after the initial load from disk. The ASSERT command is then\n" " used to confirm that the load completed successfully by examining the\n" " CPU's \"A\" register for the expected value:\n\n" "++; OS bootstrap command file\n" "++;\n" "++IF EXIST \"os.disk\" echo os.disk exists\n" "++IF NOT EXIST os.disk echo os.disk not existing\n" "++ATTACH DS0 os.disk\n" "++BOOT DS\n" "++; A register contains error code; 0 = good boot\n" "++ASSERT A=0\n" "++ATTACH MT0 sys.tape\n" "++ATTACH MT1 user.tape\n" "++RUN\n\n" /***************** 80 character line width template *************************/ " In the example, if the A register is not 0, the \"ASSERT A=0\" command will\n" " be echoed, the command file will be aborted with an \"Assertion failed\"\n" " message. Otherwise, the command file will continue to bring up the\n" " operating system.\n" "4IF\n" " The IF command tests a simulator state condition and executes additional\n" " commands if the condition is true:\n\n" "++IF <Conditional Expressions> commandtoprocess{; additionalcommandtoprocess}...\n\n" "5Examples:\n" " A command file might be used to bootstrap an operating system that\n" " halts after the initial load from disk. The ASSERT command is then\n" " used to confirm that the load completed successfully by examining the\n" " CPU's \"A\" register for the expected value:\n\n" "++; OS bootstrap command file\n" "++;\n" "++IF EXIST \"os.disk\" echo os.disk exists\n" "++IF NOT EXIST os.disk echo os.disk not existing\n" "++ATTACH DS0 os.disk\n" "++BOOT DS\n" "++; A register contains error code; 0 = good boot\n" "++IF NOT A=0 echo Boot failed - Failure Code; EX A; exit AFAIL\n" "++ATTACH MT0 sys.tape\n" "++ATTACH MT1 user.tape\n" "++RUN\n\n" /***************** 80 character line width template *************************/ " In the example, if the A register is not 0, the message \"Boot failed -\n" " Failure Code:\" command will be displayed, the contents of the A register\n" " will be displayed and the command file will be aborted with an \"Assertion\n" " failed\" message. Otherwise, the command file will continue to bring up\n" " the operating system.\n" "4Conditional Expressions\n" " The IF and ASSERT commands evaluate three different forms of conditional\n" " expressions.:\n\n" "5Simulator State Expressions\n" " The values of simulator registers can be evaluated with:\n\n" "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n" " If <dev> is not specified, CPU is assumed. <reg> is a register (scalar\n" " or subscripted) belonging to the indicated device. <addr> is an address\n" " in the address space of the indicated device. The <conditional-op>\n" |
︙ | ︙ | |||
1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 | "++GTR - greater than\n" "++>= - greater than or equal\n" "++GEQ - greater than or equal\n\n" " Comparisons are generic. This means that if both string1 and string2 are\n" " comprised of all numeric digits, then the strings are converted to numbers\n" " and a numeric comparison is performed. For example: \"+1\" EQU \"1\" will be\n" " true.\n" /***************** 80 character line width template *************************/ #define HLP_EXIT "*Commands Exiting_The_Simulator" "2Exiting The Simulator\n" " EXIT (synonyms QUIT and BYE) returns control to the operating system.\n" /***************** 80 character line width template *************************/ #define HLP_SCREENSHOT "*Commands Screenshot_Video_Window" "2Screenshot Video Window\n" | > > > > > | 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 | "++GTR - greater than\n" "++>= - greater than or equal\n" "++GEQ - greater than or equal\n\n" " Comparisons are generic. This means that if both string1 and string2 are\n" " comprised of all numeric digits, then the strings are converted to numbers\n" " and a numeric comparison is performed. For example: \"+1\" EQU \"1\" will be\n" " true.\n" "5File Existence Expressions\n" " File existence can be determined with:\n" "++{NOT} EXIST \"<filespec>\"\n\n" "++{NOT} EXIST <filespec>\n\n" " Specifies a true (false {NOT}) condition if the file exists.\n" /***************** 80 character line width template *************************/ #define HLP_EXIT "*Commands Exiting_The_Simulator" "2Exiting The Simulator\n" " EXIT (synonyms QUIT and BYE) returns control to the operating system.\n" /***************** 80 character line width template *************************/ #define HLP_SCREENSHOT "*Commands Screenshot_Video_Window" "2Screenshot Video Window\n" |
︙ | ︙ | |||
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 | { "PWD", &pwd_cmd, 0, HLP_PWD }, { "DIR", &dir_cmd, 0, HLP_DIR }, { "LS", &dir_cmd, 0, HLP_LS }, { "TYPE", &type_cmd, 0, HLP_TYPE }, { "CAT", &type_cmd, 0, HLP_CAT }, { "DELETE", &delete_cmd, 0, HLP_DELETE }, { "RM", &delete_cmd, 0, HLP_RM }, { "SET", &set_cmd, 0, HLP_SET }, { "SHOW", &show_cmd, 0, HLP_SHOW }, { "DO", &do_cmd, 1, HLP_DO }, { "GOTO", &goto_cmd, 1, HLP_GOTO }, { "RETURN", &return_cmd, 0, HLP_RETURN }, { "SHIFT", &shift_cmd, 0, HLP_SHIFT }, { "CALL", &call_cmd, 0, HLP_CALL }, { "ON", &on_cmd, 0, HLP_ON }, { "IF", &assert_cmd, 0, HLP_IF }, { "PROCEED", &noop_cmd, 0, HLP_PROCEED }, { "IGNORE", &noop_cmd, 0, HLP_IGNORE }, { "ECHO", &echo_cmd, 0, HLP_ECHO }, { "ASSERT", &assert_cmd, 1, HLP_ASSERT }, | > > | > > | 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 | { "PWD", &pwd_cmd, 0, HLP_PWD }, { "DIR", &dir_cmd, 0, HLP_DIR }, { "LS", &dir_cmd, 0, HLP_LS }, { "TYPE", &type_cmd, 0, HLP_TYPE }, { "CAT", &type_cmd, 0, HLP_CAT }, { "DELETE", &delete_cmd, 0, HLP_DELETE }, { "RM", &delete_cmd, 0, HLP_RM }, { "COPY", ©_cmd, 0, HLP_COPY }, { "CP", ©_cmd, 0, HLP_CP }, { "SET", &set_cmd, 0, HLP_SET }, { "SHOW", &show_cmd, 0, HLP_SHOW }, { "DO", &do_cmd, 1, HLP_DO }, { "GOTO", &goto_cmd, 1, HLP_GOTO }, { "RETURN", &return_cmd, 0, HLP_RETURN }, { "SHIFT", &shift_cmd, 0, HLP_SHIFT }, { "CALL", &call_cmd, 0, HLP_CALL }, { "ON", &on_cmd, 0, HLP_ON }, { "IF", &assert_cmd, 0, HLP_IF }, { "PROCEED", &noop_cmd, 0, HLP_PROCEED }, { "IGNORE", &noop_cmd, 0, HLP_IGNORE }, { "ECHO", &echo_cmd, 0, HLP_ECHO }, { "ASSERT", &assert_cmd, 1, HLP_ASSERT }, { "SEND", &send_cmd, 1, HLP_SEND }, { "NOSEND", &send_cmd, 0, HLP_SEND }, { "EXPECT", &expect_cmd, 1, HLP_EXPECT }, { "NOEXPECT", &expect_cmd, 0, HLP_EXPECT }, { "SLEEP", &sleep_cmd, 0, HLP_SLEEP }, { "!", &spawn_cmd, 0, HLP_SPAWN }, { "HELP", &help_cmd, 0, HLP_HELP }, #if defined(USE_SIM_VIDEO) { "SCREENSHOT", &screenshot_cmd,0, HLP_SCREENSHOT }, #endif { NULL, NULL, 0 } }; |
︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 | { NULL, NULL, 0 } }; static C1TAB set_dev_tab[] = { { "OCTAL", &set_dev_radix, 8 }, { "DECIMAL", &set_dev_radix, 10 }, { "HEX", &set_dev_radix, 16 }, { "ENABLED", &set_dev_enbdis, 1 }, { "DISABLED", &set_dev_enbdis, 0 }, { "DEBUG", &set_dev_debug, 1 }, { "NODEBUG", &set_dev_debug, 0 }, { NULL, NULL, 0 } }; | > | 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 | { NULL, NULL, 0 } }; static C1TAB set_dev_tab[] = { { "OCTAL", &set_dev_radix, 8 }, { "DECIMAL", &set_dev_radix, 10 }, { "HEX", &set_dev_radix, 16 }, { "BINARY", &set_dev_radix, 2 }, { "ENABLED", &set_dev_enbdis, 1 }, { "DISABLED", &set_dev_enbdis, 0 }, { "DEBUG", &set_dev_debug, 1 }, { "NODEBUG", &set_dev_debug, 0 }, { NULL, NULL, 0 } }; |
︙ | ︙ | |||
2049 2050 2051 2052 2053 2054 2055 | sim_switches = 0; /* init switches */ lookswitch = TRUE; stdnul = fopen(NULL_DEVICE,"wb"); for (i = 1; i < argc; i++) { /* loop thru args */ if (argv[i] == NULL) /* paranoia */ continue; if ((*argv[i] == '-') && lookswitch) { /* switch? */ | | | > | 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 | sim_switches = 0; /* init switches */ lookswitch = TRUE; stdnul = fopen(NULL_DEVICE,"wb"); for (i = 1; i < argc; i++) { /* loop thru args */ if (argv[i] == NULL) /* paranoia */ continue; if ((*argv[i] == '-') && lookswitch) { /* switch? */ if (get_switches (argv[i], &sw, NULL) == SW_ERROR) { fprintf (stderr, "Invalid switch %s\n", argv[i]); return 0; } sim_switches = sim_switches | sw; } else { if ((strlen (argv[i]) + strlen (cbuf) + 3) >= sizeof(cbuf)) { fprintf (stderr, "Argument string too long\n"); return 0; } if (*cbuf) /* concat args */ strlcat (cbuf, " ", sizeof (cbuf)); sprintf(&cbuf[strlen(cbuf)], "%s%s%s", strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); lookswitch = FALSE; /* no more switches */ } } /* end for */ sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ sim_on_inherit = sim_switches & SWMASK ('O'); /* -o means inherit on state */ sim_init_sock (); /* init socket capabilities */ AIO_INIT; /* init Asynch I/O */ if (sim_vm_init != NULL) /* call once only */ (*sim_vm_init)(); sim_finit (); /* init fio package */ setenv ("SIM_NAME", sim_name, 1); /* Publish simulator name */ |
︙ | ︙ | |||
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 | sim_error_text (stat)); return 0; } if (!sim_quiet) { printf ("\n"); show_version (stdout, NULL, NULL, 0, NULL); } if (sim_dflt_dev == NULL) /* if no default */ sim_dflt_dev = sim_devices[0]; if (*argv[0]) { /* sim name arg? */ char *np; /* "path.ini" */ strncpy (nbuf, argv[0], PATH_MAX + 1); /* copy sim name */ if ((np = (char *)match_ext (nbuf, "EXE"))) /* remove .exe */ *np = 0; np = strrchr (nbuf, '/'); /* stript path and try again in cwd */ if (np == NULL) np = strrchr (nbuf, '\\'); /* windows path separator */ if (np == NULL) np = strrchr (nbuf, ']'); /* VMS path separator */ if (np != NULL) setenv ("SIM_BIN_NAME", np+1, 1); /* Publish simulator binary name */ } sim_argv = argv; cptr = getenv("HOME"); if (cptr == NULL) { cptr = getenv("HOMEPATH"); cptr2 = getenv("HOMEDRIVE"); } | > > > > > > > | 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 | sim_error_text (stat)); return 0; } if (!sim_quiet) { printf ("\n"); show_version (stdout, NULL, NULL, 0, NULL); } show_version (stdnul, NULL, NULL, 1, NULL); /* Quietly set SIM_OSTYPE */ if (sim_dflt_dev == NULL) /* if no default */ sim_dflt_dev = sim_devices[0]; if (((sim_dflt_dev->flags & DEV_DEBUG) == 0) && /* default device without debug? */ (sim_dflt_dev->debflags == NULL)) { sim_dflt_dev->flags |= DEV_DEBUG; /* connect default event debugging */ sim_dflt_dev->debflags = sim_dflt_debug; } if (*argv[0]) { /* sim name arg? */ char *np; /* "path.ini" */ strncpy (nbuf, argv[0], PATH_MAX + 1); /* copy sim name */ if ((np = (char *)match_ext (nbuf, "EXE"))) /* remove .exe */ *np = 0; np = strrchr (nbuf, '/'); /* stript path and try again in cwd */ if (np == NULL) np = strrchr (nbuf, '\\'); /* windows path separator */ if (np == NULL) np = strrchr (nbuf, ']'); /* VMS path separator */ if (np != NULL) setenv ("SIM_BIN_NAME", np+1, 1); /* Publish simulator binary name */ setenv ("SIM_BIN_PATH", argv[0], 1); } sim_argv = argv; cptr = getenv("HOME"); if (cptr == NULL) { cptr = getenv("HOMEPATH"); cptr2 = getenv("HOMEDRIVE"); } |
︙ | ︙ | |||
2147 2148 2149 2150 2151 2152 2153 | stat = do_cmd (0, cbuf); /* proc cmd file */ else if (*argv[0]) { /* sim name arg? */ char *np; /* "path.ini" */ nbuf[0] = '"'; /* starting " */ strncpy (nbuf + 1, argv[0], PATH_MAX + 1); /* copy sim name */ if ((np = (char *)match_ext (nbuf, "EXE"))) /* remove .exe */ *np = 0; | | | 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 | stat = do_cmd (0, cbuf); /* proc cmd file */ else if (*argv[0]) { /* sim name arg? */ char *np; /* "path.ini" */ nbuf[0] = '"'; /* starting " */ strncpy (nbuf + 1, argv[0], PATH_MAX + 1); /* copy sim name */ if ((np = (char *)match_ext (nbuf, "EXE"))) /* remove .exe */ *np = 0; strlcat (nbuf, ".ini\"", sizeof (nbuf)); /* add .ini" */ stat = do_cmd (-1, nbuf) & ~SCPE_NOMESSAGE; /* proc default cmd file */ if (stat == SCPE_OPENERR) { /* didn't exist/can't open? */ np = strrchr (nbuf, '/'); /* stript path and try again in cwd */ if (np == NULL) np = strrchr (nbuf, '\\'); /* windows path separator */ if (np == NULL) np = strrchr (nbuf, ']'); /* VMS path separator */ |
︙ | ︙ | |||
2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 | else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prmopt*/ if (cptr == NULL) { /* EOF? */ if (sim_ttisatty()) continue; /* ignore tty EOF */ else break; /* otherwise exit */ } if (*cptr == 0) /* ignore blank */ continue; sim_sub_args (cbuf, sizeof(cbuf), argv); if (sim_log) /* log cmd */ fprintf (sim_log, "%s%s\n", sim_prompt, cptr); if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout)) fprintf (sim_deb, "%s%s\n", sim_prompt, cptr); cptr = get_glyph_cmd (cptr, gbuf); /* get command glyph */ sim_switches = 0; /* init switches */ | > | 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 | else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prmopt*/ if (cptr == NULL) { /* EOF? */ if (sim_ttisatty()) continue; /* ignore tty EOF */ else break; /* otherwise exit */ } if (*cptr == 0) /* ignore blank */ continue; sim_cmd_echoed = TRUE; sim_sub_args (cbuf, sizeof(cbuf), argv); if (sim_log) /* log cmd */ fprintf (sim_log, "%s%s\n", sim_prompt, cptr); if (sim_deb && (sim_deb != sim_log) && (sim_deb != stdout)) fprintf (sim_deb, "%s%s\n", sim_prompt, cptr); cptr = get_glyph_cmd (cptr, gbuf); /* get command glyph */ sim_switches = 0; /* init switches */ |
︙ | ︙ | |||
2249 2250 2251 2252 2253 2254 2255 | if ((!cptr) || (*cptr == '\0')) return SCPE_ARG; cptr = get_glyph_nc (cptr, gbuf, '"'); /* get quote delimited token */ if (gbuf[0] == '\0') { /* Token started with quote */ gbuf[sizeof (gbuf)-1] = '\0'; | | | 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 | if ((!cptr) || (*cptr == '\0')) return SCPE_ARG; cptr = get_glyph_nc (cptr, gbuf, '"'); /* get quote delimited token */ if (gbuf[0] == '\0') { /* Token started with quote */ gbuf[sizeof (gbuf)-1] = '\0'; strlcpy (gbuf, cptr, sizeof (gbuf)); gptr = strchr (gbuf, '"'); if (gptr) *gptr = '\0'; } sim_prompt = (char *)realloc (sim_prompt, strlen (gbuf) + 2); /* nul terminator and trailing blank */ sprintf (sim_prompt, "%s ", gbuf); return SCPE_OK; |
︙ | ︙ | |||
2475 2476 2477 2478 2479 2480 2481 | if (dptr->flags & DEV_DISABLE) { fprint_header (st, &found, header); sprintf (buf, "set %s ENABLE", sim_dname (dptr)); fprintf (st, "%-30s\tEnables device %s\n", buf, sim_dname (dptr)); sprintf (buf, "set %s DISABLE", sim_dname (dptr)); fprintf (st, "%-30s\tDisables device %s\n", buf, sim_dname (dptr)); } | | | 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 | if (dptr->flags & DEV_DISABLE) { fprint_header (st, &found, header); sprintf (buf, "set %s ENABLE", sim_dname (dptr)); fprintf (st, "%-30s\tEnables device %s\n", buf, sim_dname (dptr)); sprintf (buf, "set %s DISABLE", sim_dname (dptr)); fprintf (st, "%-30s\tDisables device %s\n", buf, sim_dname (dptr)); } if ((dptr->flags & DEV_DEBUG) || (dptr->debflags)) { fprint_header (st, &found, header); sprintf (buf, "set %s DEBUG", sim_dname (dptr)); fprintf (st, "%-30s\tEnables debugging for device %s\n", buf, sim_dname (dptr)); sprintf (buf, "set %s NODEBUG", sim_dname (dptr)); fprintf (st, "%-30s\tDisables debugging for device %s\n", buf, sim_dname (dptr)); if (dptr->debflags) { t_bool desc_available = FALSE; |
︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 | if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring)) continue; fprint_header (st, &found, header); sprintf (buf, "show %s %s%s", sim_dname (dptr), mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "=arg" : ""); fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : ""); } } | | | 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 | if ((!mptr->disp) || (!mptr->pstring) || !(*mptr->pstring)) continue; fprint_header (st, &found, header); sprintf (buf, "show %s %s%s", sim_dname (dptr), mptr->pstring, MODMASK(mptr,MTAB_SHP) ? "=arg" : ""); fprintf (st, "%-30s\t%s\n", buf, mptr->help ? mptr->help : ""); } } if ((dptr->flags & DEV_DEBUG) || (dptr->debflags)) { fprint_header (st, &found, header); sprintf (buf, "show %s DEBUG", sim_dname (dptr)); fprintf (st, "%-30s\tDisplays debugging status for device %s\n", buf, sim_dname (dptr)); } if ((dptr->modifiers) && (dptr->units) && (dptr->numunits != 1)) { for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { if ((!MODMASK(mptr,MTAB_VUN)) && MODMASK(mptr,MTAB_XTD)) |
︙ | ︙ | |||
2927 2928 2929 2930 2931 2932 2933 | echo = (sim_switches & SWMASK ('V')) || sim_do_echo; /* -v means echo */ sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet; /* -q means quiet */ sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit; /* -o means inherit ON condition actions */ errabort = sim_switches & SWMASK ('E'); /* -e means abort on error */ abuf[sizeof(abuf)-1] = '\0'; | | | 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 | echo = (sim_switches & SWMASK ('V')) || sim_do_echo; /* -v means echo */ sim_quiet = (sim_switches & SWMASK ('Q')) || sim_quiet; /* -q means quiet */ sim_on_inherit =(sim_switches & SWMASK ('O')) || sim_on_inherit; /* -o means inherit ON condition actions */ errabort = sim_switches & SWMASK ('E'); /* -e means abort on error */ abuf[sizeof(abuf)-1] = '\0'; strlcpy (abuf, fcptr, sizeof(abuf)); c = abuf; do_arg[10] = NULL; /* make sure the argument list always ends with a NULL */ for (nargs = 0; nargs < 10; ) { /* extract arguments */ while (sim_isspace (*c)) /* skip blanks */ c++; if (*c == 0) /* all done? */ do_arg [nargs++] = NULL; /* null argument */ |
︙ | ︙ | |||
2950 2951 2952 2953 2954 2955 2956 | *c++ = 0; } } /* end for */ if (do_arg [0] == NULL) /* need at least 1 */ return SCPE_2FARG; if ((fpin = fopen (do_arg[0], "r")) == NULL) { /* file failed to open? */ | | | | 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 | *c++ = 0; } } /* end for */ if (do_arg [0] == NULL) /* need at least 1 */ return SCPE_2FARG; if ((fpin = fopen (do_arg[0], "r")) == NULL) { /* file failed to open? */ strlcpy (cbuf, do_arg[0], sizeof (cbuf)); /* try again with .sim extension */ strlcat (cbuf, ".sim", sizeof (cbuf)); if ((fpin = fopen (cbuf, "r")) == NULL) { /* failed a second time? */ if (flag == 0) /* cmd line file? */ fprintf (stderr, "Can't open file %s\n", do_arg[0]); return SCPE_OPENERR; /* return failure */ } } if (flag >= 0) { /* Only bump nesting from command or nested */ |
︙ | ︙ | |||
2982 2983 2984 2985 2986 2987 2988 | } strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]); } } } } | | | | 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 | } strcpy(sim_on_actions[sim_do_depth][i], sim_on_actions[sim_do_depth-1][i]); } } } } strlcpy( sim_do_filename[sim_do_depth], do_arg[0], sizeof (sim_do_filename[sim_do_depth])); /* stash away do file name for possible use by 'call' command */ sim_do_label[sim_do_depth] = label; /* stash away do label for possible use in messages */ sim_goto_line[sim_do_depth] = 0; if (label) { sim_gotofile = fpin; sim_do_echo = echo; stat = goto_cmd (0, label); if (stat != SCPE_OK) { |
︙ | ︙ | |||
3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 | stat = SCPE_OK; /* set good return */ break; } if (*cptr == 0) /* ignore blank */ continue; if (echo) /* echo if -v */ sim_printf("%s> %s\n", do_position(), cptr); if (*cptr == ':') /* ignore label */ continue; cptr = get_glyph_cmd (cptr, gbuf); /* get command glyph */ sim_switches = 0; /* init switches */ sim_gotofile = fpin; sim_do_echo = echo; if ((cmdp = find_cmd (gbuf))) { /* lookup command */ | > | 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 | stat = SCPE_OK; /* set good return */ break; } if (*cptr == 0) /* ignore blank */ continue; if (echo) /* echo if -v */ sim_printf("%s> %s\n", do_position(), cptr); sim_cmd_echoed = echo; if (*cptr == ':') /* ignore label */ continue; cptr = get_glyph_cmd (cptr, gbuf); /* get command glyph */ sim_switches = 0; /* init switches */ sim_gotofile = fpin; sim_do_echo = echo; if ((cmdp = find_cmd (gbuf))) { /* lookup command */ |
︙ | ︙ | |||
3063 3064 3065 3066 3067 3068 3069 | case SCPE_STEP: break; default: break; } if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) && /* error from cmd? */ (stat != SCPE_STEP)) { | | | 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 | case SCPE_STEP: break; default: break; } if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) && /* error from cmd? */ (stat != SCPE_STEP)) { if (!echo && /* report if not echoing */ !stat_nomessage && /* and not suppressing messages */ !(cmdp && cmdp->message)) { /* and not handling them specially */ sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]); } } if (!stat_nomessage) { /* report error if not suppressed */ if (cmdp && cmdp->message) /* special message handler */ |
︙ | ︙ | |||
3097 3098 3099 3100 3101 3102 3103 3104 | Cleanup_Return: fclose (fpin); /* close file */ sim_gotofile = NULL; if (flag >= 0) { sim_do_echo = saved_sim_do_echo; /* restore echo state we entered with */ sim_show_message = saved_sim_show_message; /* restore message display state we entered with */ sim_on_inherit = saved_sim_on_inherit; /* restore ON inheritance state we entered with */ } | > < | 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 | Cleanup_Return: fclose (fpin); /* close file */ sim_gotofile = NULL; if (flag >= 0) { sim_do_echo = saved_sim_do_echo; /* restore echo state we entered with */ sim_show_message = saved_sim_show_message; /* restore message display state we entered with */ sim_on_inherit = saved_sim_on_inherit; /* restore ON inheritance state we entered with */ sim_quiet = saved_sim_quiet; /* restore quiet mode we entered with */ } if ((flag >= 0) || (!sim_on_inherit)) { for (i=0; i<SCPE_MAX_ERR; i++) { /* release any on commands */ free (sim_on_actions[sim_do_depth][i]); sim_on_actions[sim_do_depth][i] = NULL; } sim_on_check[sim_do_depth] = 0; /* clear on mode */ } |
︙ | ︙ | |||
3127 3128 3129 3130 3131 3132 3133 | and other enviroment variables Calling sequence instr = input string instr_size = sizeof input string buffer do_arg[10] = arguments | | | | | > > | 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 | and other enviroment variables Calling sequence instr = input string instr_size = sizeof input string buffer do_arg[10] = arguments Token %0 expands to the command file name. Token %n (n being a single digit) expands to the n'th argument Tonen %* expands to the whole set of arguments (%1 ... %9) The input sequence "%%" represents a literal "%". All other character combinations are rendered literally. Omitted parameters result in null-string substitutions. Tokens preceeded and followed by % characters are expanded as environment variables, and if one isn't found then can be one of several special variables: %DATE% yyyy-mm-dd %TIME% hh:mm:ss %DATETIME% yyyy-mm-ddThh:mm:ss %STIME% hh_mm_ss %CTIME% Www Mmm dd hh:mm:ss yyyy %UTIME% nnn (Unix time - seconds since 1/1/1970) %STATUS% Status value from the last command executed %TSTATUS% The text form of the last status value %SIM_VERIFY% The Verify/Verbose mode of the current Do command file %SIM_VERBOSE% The Verify/Verbose mode of the current Do command file %SIM_QUIET% The Quiet mode of the current Do command file %SIM_MESSAGE% The message display status of the current Do command file Environment variable lookups are done first with the precise name between |
︙ | ︙ | |||
3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 | void sim_sub_args (char *instr, size_t instr_size, char *do_arg[]) { char gbuf[CBUFSIZE]; char *ip = instr, *op, *oend, *istart, *tmpbuf; const char *ap; char rbuf[CBUFSIZE]; int i; time_t now; struct tm *tmnow; time(&now); tmnow = localtime(&now); tmpbuf = (char *)malloc(instr_size); op = tmpbuf; oend = tmpbuf + instr_size - 2; | > > > > > > > > > | > > | < > | | | 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 | void sim_sub_args (char *instr, size_t instr_size, char *do_arg[]) { char gbuf[CBUFSIZE]; char *ip = instr, *op, *oend, *istart, *tmpbuf; const char *ap; char rbuf[CBUFSIZE]; int i; size_t instr_off = 0; size_t outstr_off = 0; time_t now; struct tm *tmnow; time(&now); tmnow = localtime(&now); tmpbuf = (char *)malloc(instr_size); op = tmpbuf; oend = tmpbuf + instr_size - 2; if (instr_size > sim_sub_instr_size) { sim_sub_instr = (char *)realloc (sim_sub_instr, instr_size*sizeof(*sim_sub_instr)); sim_sub_instr_off = (size_t *)realloc (sim_sub_instr_off, instr_size*sizeof(*sim_sub_instr_off)); sim_sub_instr_size = instr_size; } sim_sub_instr_buf = instr; strlcpy (sim_sub_instr, instr, instr_size*sizeof(*sim_sub_instr)); while (sim_isspace (*ip)) { /* skip leading spaces */ sim_sub_instr_off[outstr_off++] = ip - instr; *op++ = *ip++; } istart = ip; for (; *ip && (op < oend); ) { if ((ip [0] == '%') && (ip [1] == '%')) { /* literal % insert? */ sim_sub_instr_off[outstr_off++] = ip - instr; ip++; /* skip one */ *op++ = *ip++; /* copy insert % */ } else if ((*ip == '%') && (sim_isalnum(ip[1]) || (ip[1] == '*') || (ip[1] == '_'))) {/* sub? */ if ((ip[1] >= '0') && (ip[1] <= ('9'))) { /* %n = sub */ ap = do_arg[ip[1] - '0']; for (i=0; i<ip[1] - '0'; ++i) /* make sure we're not past the list end */ |
︙ | ︙ | |||
3242 3243 3244 3245 3246 3247 3248 | ap = rbuf; } else if (!strcmp ("DATETIME", gbuf)) { sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d", tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday, tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec); ap = rbuf; } /* Locale oriented formatted date/time info */ | | | 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 | ap = rbuf; } else if (!strcmp ("DATETIME", gbuf)) { sprintf (rbuf, "%04d-%02d-%02dT%02d:%02d:%02d", tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday, tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec); ap = rbuf; } /* Locale oriented formatted date/time info */ else if (!strcmp ("LDATE", gbuf)) { strftime (rbuf, sizeof(rbuf), "%x", tmnow); ap = rbuf; } else if (!strcmp ("LTIME", gbuf)) { #if defined(HAVE_C99_STRFTIME) strftime (rbuf, sizeof(rbuf), "%r", tmnow); #else |
︙ | ︙ | |||
3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 | #if defined(HAVE_C99_STRFTIME) strftime (rbuf, sizeof(rbuf), "%c", tmnow); #else strcpy (rbuf, ctime(&now)); rbuf[strlen (rbuf)-1] = '\0'; /* remove trailing \n */ #endif ap = rbuf; } /* Separate Date/Time info */ else if (!strcmp ("DATE_YYYY", gbuf)) {/* Year (0000-9999) */ strftime (rbuf, sizeof(rbuf), "%Y", tmnow); ap = rbuf; } else if (!strcmp ("DATE_YY", gbuf)) {/* Year (00-99) */ | > > > > | 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 | #if defined(HAVE_C99_STRFTIME) strftime (rbuf, sizeof(rbuf), "%c", tmnow); #else strcpy (rbuf, ctime(&now)); rbuf[strlen (rbuf)-1] = '\0'; /* remove trailing \n */ #endif ap = rbuf; } else if (!strcmp ("UTIME", gbuf)) { sprintf (rbuf, "%" LL_FMT "d", (LL_TYPE)now); ap = rbuf; } /* Separate Date/Time info */ else if (!strcmp ("DATE_YYYY", gbuf)) {/* Year (0000-9999) */ strftime (rbuf, sizeof(rbuf), "%Y", tmnow); ap = rbuf; } else if (!strcmp ("DATE_YY", gbuf)) {/* Year (00-99) */ |
︙ | ︙ | |||
3381 3382 3383 3384 3385 3386 3387 | else if (!strcmp ("SIM_MESSAGE", gbuf)) { sprintf (rbuf, "%s", sim_show_message ? "" : "-Q"); ap = rbuf; } } } if (ap) { /* non-null arg? */ | | > > > | > > | > | > > | 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 | else if (!strcmp ("SIM_MESSAGE", gbuf)) { sprintf (rbuf, "%s", sim_show_message ? "" : "-Q"); ap = rbuf; } } } if (ap) { /* non-null arg? */ while (*ap && (op < oend)) { /* copy the argument */ sim_sub_instr_off[outstr_off++] = ip - instr; *op++ = *ap++; } } } else if (ip == istart) { /* at beginning of input? */ get_glyph (istart, gbuf, 0); /* substitute initial token */ ap = getenv(gbuf); /* if it is an environment variable name */ if (!ap) { /* nope? */ sim_sub_instr_off[outstr_off++] = ip - instr; *op++ = *ip++; /* press on with literal character */ continue; } while (*ap && (op < oend)) { /* copy the translation */ sim_sub_instr_off[outstr_off++] = ip - instr; *op++ = *ap++; } ip += strlen(gbuf); } else { sim_sub_instr_off[outstr_off++] = ip - instr; *op++ = *ip++; /* literal character */ } } *op = 0; /* term buffer */ sim_sub_instr_off[outstr_off] = 0; strcpy (instr, tmpbuf); free (tmpbuf); return; } t_stat shift_args (char *do_arg[], size_t arg_count) { |
︙ | ︙ | |||
3472 3473 3474 3475 3476 3477 3478 | */ t_stat assert_cmd (int32 flag, CONST char *cptr) { char gbuf[CBUFSIZE], gbuf2[CBUFSIZE]; CONST char *tptr, *gptr; REG *rptr; uint32 idx; | < > > > > > > | | 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 | */ t_stat assert_cmd (int32 flag, CONST char *cptr) { char gbuf[CBUFSIZE], gbuf2[CBUFSIZE]; CONST char *tptr, *gptr; REG *rptr; uint32 idx; t_stat r; t_bool Not = FALSE; t_bool Exist = FALSE; t_bool result; t_addr addr; t_stat reason; cptr = (CONST char *)get_sim_opt (CMD_OPT_SW|CMD_OPT_DFT, (CONST char *)cptr, &r); /* get sw, default */ sim_stabr.boolop = sim_staba.boolop = -1; /* no relational op dflt */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; tptr = get_glyph (cptr, gbuf, 0); /* get token */ if (!strcmp (gbuf, "NOT")) { /* Conditional Inversion? */ Not = TRUE; /* remember that, and */ cptr = (CONST char *)tptr; tptr = get_glyph (cptr, gbuf, 0); /* get next token */ } if (!strcmp (gbuf, "EXIST")) { /* File Exist Test? */ Exist = TRUE; /* remember that, and */ cptr = (CONST char *)tptr; } if (Exist || (*cptr == '"')) { /* quoted string comparison? */ char op[CBUFSIZE]; static struct { const char *op; int aval; int bval; t_bool invert; } *optr, compare_ops[] = |
︙ | ︙ | |||
3519 3520 3521 3522 3523 3524 3525 | tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\'); /* get first string */ if (!*tptr) return SCPE_2FARG; cptr += strlen (gbuf); while (sim_isspace (*cptr)) /* skip spaces */ ++cptr; | > | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > | 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 | tptr = (CONST char *)get_glyph_gen (cptr, gbuf, '=', (sim_switches & SWMASK ('I')), TRUE, '\\'); /* get first string */ if (!*tptr) return SCPE_2FARG; cptr += strlen (gbuf); while (sim_isspace (*cptr)) /* skip spaces */ ++cptr; if (!Exist) { get_glyph (cptr, op, '"'); for (optr = compare_ops; optr->op; optr++) if (0 == strcmp (op, optr->op)) break; if (!optr->op) return sim_messagef (SCPE_ARG, "Invalid operator: %s\n", op); cptr += strlen (op); while (sim_isspace (*cptr)) /* skip spaces */ ++cptr; cptr = (CONST char *)get_glyph_gen (cptr, gbuf2, 0, (sim_switches & SWMASK ('I')), TRUE, '\\'); /* get second string */ if (*cptr) { /* more? */ if (flag) /* ASSERT has no more args */ return SCPE_2MARG; } else { if (!flag) return SCPE_2FARG; /* IF needs actions! */ } result = sim_cmp_string (gbuf, gbuf2); result = ((result == optr->aval) || (result == optr->bval)); if (optr->invert) result = !result; } else { FILE *f = fopen (gbuf, "r"); if (f) fclose (f); result = (f != NULL); } } else { cptr = get_glyph (cptr, gbuf, 0); /* get register */ rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */ if (rptr) { /* got register? */ if (*gptr == '[') { /* subscript? */ if (rptr->depth <= 1) /* array register? */ |
︙ | ︙ | |||
3586 3587 3588 3589 3590 3591 3592 | if (!flag) return SCPE_2FARG; /* IF needs actions! */ } if (rptr) { /* Handle register case */ if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) || /* parse condition */ (sim_stabr.boolop == -1)) /* relational op reqd */ return SCPE_MISVAL; | | | | 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 | if (!flag) return SCPE_2FARG; /* IF needs actions! */ } if (rptr) { /* Handle register case */ if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) || /* parse condition */ (sim_stabr.boolop == -1)) /* relational op reqd */ return SCPE_MISVAL; sim_eval[0] = get_rval (rptr, idx); /* get register value */ result = test_search (sim_eval, &sim_stabr); /* test condition */ } else { /* Handle memory case */ if (!get_asearch (gbuf, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix, &sim_staba) || /* parse condition */ (sim_staba.boolop == -1)) /* relational op reqd */ return SCPE_MISVAL; reason = get_aval (addr, sim_dfdev, sim_dfunit);/* get data */ if (reason != SCPE_OK) /* return if error */ |
︙ | ︙ | |||
3613 3614 3615 3616 3617 3618 3619 | return SCPE_OK; } /* Send command Syntax: SEND {After=m},{Delay=n},"string-to-send" | | | > | > | > | | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | > > > > > > > > | > > > > > > | | | | | | | < < < | 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 | return SCPE_OK; } /* Send command Syntax: SEND {After=m},{Delay=n},"string-to-send" After - is an integer (>= 0) representing a number of instruction delay before the initial characters is sent. The after parameter can is set by itself (with SEND AFTER=n). The value specified then persists across SEND commands, and is the default value used in subsequent SEND commands which don't specify an explicit AFTER parameter. This default value is visible externally via an environment variable. Delay - is an integer (>= 0) representing a number of instruction delay before and between characters being sent. The delay parameter can is set by itself (with SEND DELAY=n) The value specified persists across SEND commands, and is the default value used in subsequent SEND commands which don't specify an explicit DELAY parameter. This default value is visible externally via an environment variable. String - must be quoted. Quotes may be either single or double but the opening anc closing quote characters must match. Within quotes C style character escapes are allowed. The following character escapes are explicitly supported: \r Sends the ASCII Carriage Return character (Decimal value 13) \n Sends the ASCII Linefeed character (Decimal value 10) \f Sends the ASCII Formfeed character (Decimal value 12) \t Sends the ASCII Horizontal Tab character (Decimal value 9) \v Sends the ASCII Vertical Tab character (Decimal value 11) \b Sends the ASCII Backspace character (Decimal value 8) \\ Sends the ASCII Backslash character (Decimal value 92) \' Sends the ASCII Single Quote character (Decimal value 39) \" Sends the ASCII Double Quote character (Decimal value 34) \? Sends the ASCII Question Mark character (Decimal value 63) \e Sends the ASCII Escape character (Decimal value 27) as well as octal character values of the form: \n{n{n}} where each n is an octal digit (0-7) and hext character values of the form: \xh{h} where each h is a hex digit (0-9A-Fa-f) */ static uint32 get_default_env_parameter (const char *dev_name, const char *param_name, uint32 default_value) { char varname[CBUFSIZE]; uint32 val; char *endptr; const char *colon = strchr (dev_name, ':'); if (colon) snprintf (varname, sizeof(varname), "%s_%*.*s_%s", param_name, (int)(colon-dev_name), (int)(colon-dev_name), dev_name, colon + 1); else snprintf (varname, sizeof(varname), "%s_%s", param_name, dev_name); if (!getenv (varname)) val = default_value; else { val = strtoul (getenv (varname), &endptr, 0); if (*endptr) val = default_value; } return val; } static void set_default_env_parameter (const char *dev_name, const char *param_name, uint32 value) { char varname[CBUFSIZE]; char valbuf[CBUFSIZE]; const char *colon = strchr (dev_name, ':'); if (colon) snprintf (varname, sizeof(varname), "%s_%*.*s_%s", param_name, (int)(colon-dev_name), (int)(colon-dev_name), dev_name, colon + 1); else snprintf (varname, sizeof(varname), "%s_%s", param_name, dev_name); snprintf (valbuf, sizeof(valbuf), "%u", value); setenv(varname, valbuf, 1); } t_stat send_cmd (int32 flag, CONST char *cptr) { char gbuf[CBUFSIZE]; CONST char *tptr; uint8 dbuf[CBUFSIZE]; uint32 dsize = 0; const char *dev_name; uint32 delay; t_bool delay_set = FALSE; uint32 after; t_bool after_set = FALSE; t_stat r; SEND *snd; GET_SWITCHES (cptr); /* get switches */ tptr = get_glyph (cptr, gbuf, ','); if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { r = tmxr_locate_line_send (gbuf, &snd); if (r != SCPE_OK) return r; cptr = tptr; tptr = get_glyph (tptr, gbuf, ','); } else snd = sim_cons_get_send (); dev_name = tmxr_send_line_name (snd); if (!flag) return sim_send_clear (snd); delay = get_default_env_parameter (dev_name, "SIM_SEND_DELAY", SEND_DEFAULT_DELAY); after = get_default_env_parameter (dev_name, "SIM_SEND_AFTER", delay); while (*cptr) { if ((!strncmp(gbuf, "DELAY=", 6)) && (gbuf[6])) { delay = (uint32)get_uint (&gbuf[6], 10, 10000000, &r); if (r != SCPE_OK) return sim_messagef (SCPE_ARG, "Invalid Delay Value\n"); cptr = tptr; tptr = get_glyph (cptr, gbuf, ','); delay_set = TRUE; if (!after_set) after = delay; continue; } if ((!strncmp(gbuf, "AFTER=", 6)) && (gbuf[6])) { after = (uint32)get_uint (&gbuf[6], 10, 10000000, &r); if (r != SCPE_OK) return sim_messagef (SCPE_ARG, "Invalid After Value\n"); cptr = tptr; tptr = get_glyph (cptr, gbuf, ','); after_set = TRUE; continue; } if ((*cptr == '"') || (*cptr == '\'')) break; return SCPE_ARG; } if (!*cptr) { if ((!delay_set) && (!after_set)) return SCPE_2FARG; set_default_env_parameter (dev_name, "SIM_SEND_DELAY", delay); set_default_env_parameter (dev_name, "SIM_SEND_AFTER", after); return SCPE_OK; } if ((*cptr != '"') && (*cptr != '\'')) return sim_messagef (SCPE_ARG, "String must be quote delimited\n"); cptr = get_glyph_quoted (cptr, gbuf, 0); if (*cptr != '\0') return SCPE_2MARG; /* No more arguments */ if (SCPE_OK != sim_decode_quoted_string (gbuf, dbuf, &dsize)) return sim_messagef (SCPE_ARG, "Invalid String\n"); return sim_send_input (snd, dbuf, dsize, after, delay); } t_stat sim_show_send (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr) { char gbuf[CBUFSIZE]; CONST char *tptr; |
︙ | ︙ | |||
3734 3735 3736 3737 3738 3739 3740 | EXPECT *exp; GET_SWITCHES (cptr); /* get switches */ tptr = get_glyph (cptr, gbuf, ','); if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { r = tmxr_locate_line_expect (gbuf, &exp); if (r != SCPE_OK) | | | 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 | EXPECT *exp; GET_SWITCHES (cptr); /* get switches */ tptr = get_glyph (cptr, gbuf, ','); if (sim_isalpha(gbuf[0]) && (strchr (gbuf, ':'))) { r = tmxr_locate_line_expect (gbuf, &exp); if (r != SCPE_OK) return sim_messagef (r, "No such active line: %s\n", gbuf); cptr = tptr; } else exp = sim_cons_get_expect (); if (flag) return sim_set_expect (exp, cptr); else |
︙ | ︙ | |||
3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 | if (*tptr != '\0') return SCPE_2MARG; /* No more arguments */ if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\'')) return SCPE_ARG; /* String must be quote delimited */ return sim_exp_show (st, exp, gbuf); } /* Goto command */ t_stat goto_cmd (int32 flag, CONST char *fcptr) { char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE]; const char *cptr; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | if (*tptr != '\0') return SCPE_2MARG; /* No more arguments */ if (*cptr && (cptr[strlen(cptr)-1] != '"') && (cptr[strlen(cptr)-1] != '\'')) return SCPE_ARG; /* String must be quote delimited */ return sim_exp_show (st, exp, gbuf); } /* Sleep command */ t_stat sleep_cmd (int32 flag, CONST char *cptr) { char *tptr; double wait; stop_cpu = 0; signal (SIGINT, int_handler); while (*cptr) { wait = strtod (cptr, &tptr); switch (*tptr) { case ' ': case '\t': case '\0': break; case 's': case 'S': ++tptr; break; case 'm': case 'M': ++tptr; wait *= 60.0; break; case 'h': case 'H': ++tptr; wait *= (60.0*60.0); break; case 'd': case 'D': ++tptr; wait *= (24.0*60.0*60.0); break; default: signal (SIGINT, SIG_DFL); /* cancel WRU */ return sim_messagef (SCPE_ARG, "Invalid Sleep unit '%c'\n", *cptr); } wait *= 1000.0; /* Convert to Milliseconds */ cptr = tptr; while ((wait > 1000.0) && (!stop_cpu)) wait -= sim_os_ms_sleep (1000); if ((wait > 0.0) && (!stop_cpu)) sim_os_ms_sleep ((unsigned)wait); } signal (SIGINT, SIG_DFL); /* cancel WRU */ stop_cpu = 0; return SCPE_OK; } /* Goto command */ t_stat goto_cmd (int32 flag, CONST char *fcptr) { char cbuf[CBUFSIZE], gbuf[CBUFSIZE], gbuf1[CBUFSIZE]; const char *cptr; |
︙ | ︙ | |||
4030 4031 4032 4033 4034 4035 4036 | return SCPE_OK; } /* Set environment routine */ t_stat sim_set_environment (int32 flag, CONST char *cptr) { | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | return SCPE_OK; } /* Set environment routine */ t_stat sim_set_environment (int32 flag, CONST char *cptr) { char varname[CBUFSIZE], prompt[CBUFSIZE], cbuf[CBUFSIZE]; if ((!cptr) || (*cptr == 0)) /* now eol? */ return SCPE_2FARG; if (sim_switches & SWMASK ('P')) { CONST char *deflt = NULL; cptr = get_glyph_quoted (cptr, prompt, 0); /* get prompt */ if (prompt[0] == '\0') return sim_messagef (SCPE_2FARG, "Missing Prompt and Environment Variable Name\n"); if ((prompt[0] == '"') || (prompt[0] == '\'')) { prompt[strlen (prompt) - 1] = '\0'; memmove (prompt, prompt + 1, strlen (prompt)); } deflt = get_glyph (cptr, varname, '='); /* get environment variable name */ if (deflt == NULL) deflt = ""; if (*deflt) { strlcat (prompt, " [", sizeof (prompt)); strlcat (prompt, deflt, sizeof (prompt)); strlcat (prompt, "] ", sizeof (prompt)); } else strlcat (prompt, " ", sizeof (prompt)); if (sim_rem_cmd_active_line == -1) { cptr = read_line_p (prompt, cbuf, sizeof(cbuf), stdin); if ((cptr == NULL) || (*cptr == 0)) cptr = deflt; else cptr = cbuf; } else cptr = deflt; } else cptr = get_glyph (cptr, varname, '='); /* get environment variable name */ setenv(varname, cptr, 1); return SCPE_OK; } /* Set command */ t_stat set_cmd (int32 flag, CONST char *cptr) |
︙ | ︙ | |||
4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 | fprintf (st, " delta %d", vdelt); #if defined (SIM_VERSION_MODE) fprintf (st, " %s", SIM_VERSION_MODE); #endif if (flag) { t_bool idle_capable; uint32 os_ms_sleep_1, os_tick_size; fprintf (st, "\n Simulator Framework Capabilities:"); fprintf (st, "\n %s", sim_si64); fprintf (st, "\n %s", sim_sa64); fprintf (st, "\n %s", eth_capabilities()); idle_capable = sim_timer_idle_capable (&os_ms_sleep_1, &os_tick_size); fprintf (st, "\n Idle/Throttling support is %savailable", idle_capable ? "" : "NOT "); | > | 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 | fprintf (st, " delta %d", vdelt); #if defined (SIM_VERSION_MODE) fprintf (st, " %s", SIM_VERSION_MODE); #endif if (flag) { t_bool idle_capable; uint32 os_ms_sleep_1, os_tick_size; char os_type[128] = "Unknown"; fprintf (st, "\n Simulator Framework Capabilities:"); fprintf (st, "\n %s", sim_si64); fprintf (st, "\n %s", sim_sa64); fprintf (st, "\n %s", eth_capabilities()); idle_capable = sim_timer_idle_capable (&os_ms_sleep_1, &os_tick_size); fprintf (st, "\n Idle/Throttling support is %savailable", idle_capable ? "" : "NOT "); |
︙ | ︙ | |||
4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 | #if defined(__ia64) "I64"; #elif defined(__ALPHA) "Alpha"; #else "VAX"; #endif fprintf (st, "\n OS: OpenVMS %s %s", arch, __VMS_VERSION); } #elif defined(_WIN32) if (1) { char *proc_id = getenv ("PROCESSOR_IDENTIFIER"); char *arch = getenv ("PROCESSOR_ARCHITECTURE"); char *procs = getenv ("NUMBER_OF_PROCESSORS"); | > > | 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 | #if defined(__ia64) "I64"; #elif defined(__ALPHA) "Alpha"; #else "VAX"; #endif strlcpy (os_type, "OpenVMS ", sizeof (os_type)); strlcat (os_type, arch, sizeof (os_type)); fprintf (st, "\n OS: OpenVMS %s %s", arch, __VMS_VERSION); } #elif defined(_WIN32) if (1) { char *proc_id = getenv ("PROCESSOR_IDENTIFIER"); char *arch = getenv ("PROCESSOR_ARCHITECTURE"); char *procs = getenv ("NUMBER_OF_PROCESSORS"); |
︙ | ︙ | |||
4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 | sim_trim_endspc (osversion); } while (osversion[0] == '\0'); _pclose (f); } fprintf (st, "\n OS: %s", osversion); fprintf (st, "\n Architecture: %s%s%s, Processors: %s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "", procs); fprintf (st, "\n Processor Id: %s, Level: %s, Revision: %s", proc_id ? proc_id : "", proc_level ? proc_level : "", proc_rev ? proc_rev : ""); } #else if (1) { char osversion[2*PATH_MAX+1] = ""; FILE *f; if ((f = popen ("uname -a", "r"))) { | > | | > > > > > > > > | > > > > | 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 | sim_trim_endspc (osversion); } while (osversion[0] == '\0'); _pclose (f); } fprintf (st, "\n OS: %s", osversion); fprintf (st, "\n Architecture: %s%s%s, Processors: %s", arch, proc_arch3264 ? " on " : "", proc_arch3264 ? proc_arch3264 : "", procs); fprintf (st, "\n Processor Id: %s, Level: %s, Revision: %s", proc_id ? proc_id : "", proc_level ? proc_level : "", proc_rev ? proc_rev : ""); strlcpy (os_type, "Windows", sizeof (os_type)); } #else if (1) { char osversion[2*PATH_MAX+1] = ""; FILE *f; if ((f = popen ("uname -a", "r"))) { memset (osversion, 0, sizeof (osversion)); do { if (NULL == fgets (osversion, sizeof (osversion)-1, f)) break; sim_trim_endspc (osversion); } while (osversion[0] == '\0'); pclose (f); } fprintf (st, "\n OS: %s", osversion); if ((f = popen ("uname", "r"))) { memset (os_type, 0, sizeof (os_type)); do { if (NULL == fgets (os_type, sizeof (os_type)-1, f)) break; sim_trim_endspc (os_type); } while (os_type[0] == '\0'); pclose (f); } } #endif if ((!strcmp (os_type, "Unknown")) && (getenv ("OSTYPE"))) strlcpy (os_type, getenv ("OSTYPE"), sizeof (os_type)); setenv ("SIM_OSTYPE", os_type, 1); } #if defined(SIM_GIT_COMMIT_ID) #define S_xstr(a) S_str(a) #define S_str(a) #a fprintf (st, "%sgit commit id: %8.8s", flag ? "\n " : " ", S_xstr(SIM_GIT_COMMIT_ID)); #undef S_str #undef S_xstr |
︙ | ︙ | |||
4875 4876 4877 4878 4879 4880 4881 | } t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr) { int32 any = 0; DEBTAB *dep; | | | 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 | } t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr) { int32 any = 0; DEBTAB *dep; if ((dptr->flags & DEV_DEBUG) || (dptr->debflags)) { if (dptr->dctrl == 0) fputs ("Debugging disabled", st); else if (dptr->debflags == NULL) fputs ("Debugging enabled", st); else { uint32 dctrl = dptr->dctrl; |
︙ | ︙ | |||
5036 5037 5038 5039 5040 5041 5042 | char gbuf[4*CBUFSIZE]; if (sim_is_running) return SCPE_INVREM; if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; gbuf[sizeof(gbuf)-1] = '\0'; | | | 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 | char gbuf[4*CBUFSIZE]; if (sim_is_running) return SCPE_INVREM; if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; gbuf[sizeof(gbuf)-1] = '\0'; strlcpy (gbuf, cptr, sizeof(gbuf)); sim_trim_endspc(gbuf); if (chdir(gbuf) != 0) return sim_messagef(SCPE_IOERR, "Unable to directory change to: %s\n", gbuf); return SCPE_OK; } t_stat pwd_cmd (int32 flg, CONST char *cptr) |
︙ | ︙ | |||
5124 5125 5126 5127 5128 5129 5130 | #endif struct stat filestat; char *c; char DirName[PATH_MAX + 1], WholeName[PATH_MAX + 1], WildName[PATH_MAX + 1]; memset (DirName, 0, sizeof(DirName)); memset (WholeName, 0, sizeof(WholeName)); | | | | | | | | | | | | 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 | #endif struct stat filestat; char *c; char DirName[PATH_MAX + 1], WholeName[PATH_MAX + 1], WildName[PATH_MAX + 1]; memset (DirName, 0, sizeof(DirName)); memset (WholeName, 0, sizeof(WholeName)); strlcpy (WildName, cptr, sizeof(WildName)); cptr = WildName; sim_trim_endspc (WildName); if ((!stat (WildName, &filestat)) && (filestat.st_mode & S_IFDIR)) strlcat (WildName, "/*", sizeof (WildName)); if ((*cptr != '/') || (0 == memcmp (cptr, "./", 2)) || (0 == memcmp (cptr, "../", 3))) { #if defined (VMS) getcwd (WholeName, sizeof (WholeName)-1, 0); #else getcwd (WholeName, sizeof (WholeName)-1); #endif strlcat (WholeName, "/", sizeof (WholeName)); strlcat (WholeName, cptr, sizeof (WholeName)); sim_trim_endspc (WholeName); } else strlcpy (WholeName, cptr, sizeof (WholeName)); while ((c = strstr (WholeName, "/./"))) memmove (c + 1, c + 3, 1 + strlen (c + 3)); while ((c = strstr (WholeName, "//"))) memmove (c + 1, c + 2, 1 + strlen (c + 2)); while ((c = strstr (WholeName, "/../"))) { char *c1; c1 = c - 1; while ((c1 >= WholeName) && (*c1 != '/')) c1 = c1 - 1; memmove (c1, c + 3, 1 + strlen (c + 3)); while (0 == memcmp (WholeName, "/../", 4)) memmove (WholeName, WholeName+3, 1 + strlen (WholeName+3)); } c = strrchr (WholeName, '/'); if (c) { memmove (DirName, WholeName, 1+c-WholeName); DirName[1+c-WholeName] = '\0'; } else { #if defined (VMS) getcwd (WholeName, sizeof (WholeName)-1, 0); #else getcwd (WholeName, sizeof (WholeName)-1); #endif } cptr = WholeName; #if defined (HAVE_GLOB) memset (&paths, 0, sizeof (paths)); if (0 == glob (cptr, 0, NULL, &paths)) { #else dir = opendir(DirName[0] ? DirName : "/."); if (dir) { struct dirent *ent; #endif t_offset FileSize; |
︙ | ︙ | |||
5332 5333 5334 5335 5336 5337 5338 | { FILE *file; char lbuf[4*CBUFSIZE]; if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; lbuf[sizeof(lbuf)-1] = '\0'; | | | 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 | { FILE *file; char lbuf[4*CBUFSIZE]; if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; lbuf[sizeof(lbuf)-1] = '\0'; strlcpy (lbuf, cptr, sizeof(lbuf)); sim_trim_endspc(lbuf); file = sim_fopen (lbuf, "r"); if (file == NULL) { /* open failed? */ TYPE_CTX type_state; t_stat stat; memset (&type_state, 0, sizeof (type_state)); |
︙ | ︙ | |||
5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 | return SCPE_2FARG; memset (&del_state, 0, sizeof (del_state)); stat = sim_dir_scan (cptr, sim_delete_entry, &del_state); if (stat == SCPE_OK) return del_state.stat; return sim_messagef (SCPE_ARG, "No such file or directory: %s\n", cptr); } /* Breakpoint commands */ t_stat brk_cmd (int32 flg, CONST char *cptr) { GET_SWITCHES (cptr); /* get switches */ return ssh_break (NULL, cptr, flg); /* call common code */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | return SCPE_2FARG; memset (&del_state, 0, sizeof (del_state)); stat = sim_dir_scan (cptr, sim_delete_entry, &del_state); if (stat == SCPE_OK) return del_state.stat; return sim_messagef (SCPE_ARG, "No such file or directory: %s\n", cptr); } typedef struct { t_stat stat; int count; char destname[CBUFSIZE]; } COPY_CTX; static void sim_copy_entry (const char *directory, const char *filename, t_offset FileSize, const struct stat *filestat, void *context) { COPY_CTX *ctx = (COPY_CTX *)context; struct stat deststat; char FullPath[PATH_MAX + 1]; char dname[CBUFSIZE];\ t_stat st; strlcpy (dname, ctx->destname, sizeof (dname)); sprintf (FullPath, "%s%s", directory, filename); if ((dname[strlen (dname) - 1] == '/') || (dname[strlen (dname) - 1] == '\\')) dname[strlen (dname) - 1] = '\0'; if ((!stat (dname, &deststat)) && (deststat.st_mode & S_IFDIR)) { const char *dslash = (strrchr (dname, '/') ? "/" : (strrchr (dname, '\\') ? "\\" : "/")); dname[sizeof (dname) - 1] = '\0'; snprintf (&dname[strlen (dname)], sizeof (dname) - strlen (dname), "%s%s", dslash, filename); } st = sim_copyfile (FullPath, dname, TRUE); if (SCPE_OK == st) ++ctx->count; else ctx->stat = st; } t_stat copy_cmd (int32 flg, CONST char *cptr) { char sname[CBUFSIZE]; COPY_CTX copy_state; t_stat stat; memset (©_state, 0, sizeof (copy_state)); if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; cptr = get_glyph_quoted (cptr, sname, 0); if ((!cptr) || (*cptr == 0)) return SCPE_2FARG; cptr = get_glyph_quoted (cptr, copy_state.destname, 0); stat = sim_dir_scan (sname, sim_copy_entry, ©_state); if ((stat == SCPE_OK) && (copy_state.count)) return sim_messagef (SCPE_OK, " %3d file(s) copied\n", copy_state.count); return copy_state.stat; } /* Breakpoint commands */ t_stat brk_cmd (int32 flg, CONST char *cptr) { GET_SWITCHES (cptr); /* get switches */ return ssh_break (NULL, cptr, flg); /* call common code */ |
︙ | ︙ | |||
5413 5414 5415 5416 5417 5418 5419 | if (dptr == NULL) return SCPE_IERR; uptr = dptr->units; if (uptr == NULL) return SCPE_IERR; max = uptr->capac - 1; abuf[sizeof(abuf)-1] = '\0'; | | < > | > > > | 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 | if (dptr == NULL) return SCPE_IERR; uptr = dptr->units; if (uptr == NULL) return SCPE_IERR; max = uptr->capac - 1; abuf[sizeof(abuf)-1] = '\0'; strlcpy (abuf, cptr, sizeof(abuf)); if ((aptr = strchr (abuf, ';'))) { /* ;action? */ cptr += aptr - abuf + 1; if (flg != SSH_ST) /* only on SET */ return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", cptr); *aptr++ = 0; /* separate strings */ if ((cptr > sim_sub_instr_buf) && ((size_t)(cptr - sim_sub_instr_buf) < sim_sub_instr_size)) aptr = &sim_sub_instr[sim_sub_instr_off[cptr - sim_sub_instr_buf]]; /* get un-substituted string */ } cptr = abuf; if (*cptr == 0) { /* no argument? */ lo = (t_addr) get_rval (sim_PC, 0); /* use PC */ return ssh_break_one (st, flg, lo, 0, aptr); } while (*cptr) { cptr = get_glyph (cptr, gbuf, ','); tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0); |
︙ | ︙ | |||
5661 5662 5663 5664 5665 5666 5667 | } else { if (!(uptr->dynflags & UNIT_ATTMULT)) return SCPE_ALATT; /* Already attached */ } } gbuf[sizeof(gbuf)-1] = '\0'; | | > > < < | < | < < | < < | < < | < < | < | 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 | } else { if (!(uptr->dynflags & UNIT_ATTMULT)) return SCPE_ALATT; /* Already attached */ } } gbuf[sizeof(gbuf)-1] = '\0'; strlcpy (gbuf, cptr, sizeof(gbuf)); sim_trim_endspc (gbuf); /* trim trailing spc */ return scp_attach_unit (dptr, uptr, gbuf); /* attach */ } /* Call device-specific or file-oriented attach unit routine */ t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, const char *cptr) { if (uptr->flags & UNIT_DIS) /* disabled? */ return SCPE_UDIS; if (dptr->attach != NULL) /* device routine? */ return dptr->attach (uptr, (CONST char *)cptr); /* call it */ return attach_unit (uptr, (CONST char *)cptr); /* no, std routine */ } /* Attach unit to file */ t_stat attach_unit (UNIT *uptr, CONST char *cptr) { DEVICE *dptr; if (!(uptr->flags & UNIT_ATTABLE)) /* not attachable? */ return SCPE_NOATT; if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char)); /* alloc name buf */ if (uptr->filename == NULL) return SCPE_MEM; strlcpy (uptr->filename, cptr, CBUFSIZE); /* save name */ 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 attach_err (uptr, SCPE_NORO); /* no, error */ uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */ if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ sim_messagef (SCPE_OK, "%s: unit is read only\n", sim_dname (dptr)); } else { if (sim_switches & SWMASK ('N')) { /* new file only? */ uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */ if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ sim_messagef (SCPE_OK, "%s: creating new file\n", sim_dname (dptr)); } else { /* normal */ uptr->fileref = sim_fopen (cptr, "rb+"); /* open r/w */ if (uptr->fileref == NULL) { /* open fail? */ #if defined(EPERM) if ((errno == EROFS) || (errno == EACCES) || (errno == EPERM)) {/* read only? */ #else if ((errno == EROFS) || (errno == EACCES)) {/* read only? */ #endif if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ return attach_err (uptr, SCPE_NORO);/* no error */ uptr->fileref = sim_fopen (cptr, "rb"); /* open rd only */ if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ sim_messagef (SCPE_OK, "%s: unit is read only\n", sim_dname (dptr)); } else { /* doesn't exist */ if (sim_switches & SWMASK ('E')) /* must exist? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ uptr->fileref = sim_fopen (cptr, "wb+");/* open new file */ if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ sim_messagef (SCPE_OK, "%s: creating new file\n", sim_dname (dptr)); } } /* end if null */ } /* end else */ } if (uptr->flags & UNIT_BUFABLE) { /* buffer? */ uint32 cap = ((uint32) uptr->capac) / dptr->aincr; /* effective size */ if (uptr->flags & UNIT_MUSTBUF) /* dyn alloc? */ uptr->filebuf = calloc (cap, SZ_D (dptr)); /* allocate */ if (uptr->filebuf == NULL) /* no buffer? */ return attach_err (uptr, SCPE_MEM); /* error */ sim_messagef (SCPE_OK, "%s: buffering file in memory\n", sim_dname (dptr)); uptr->hwmark = (uint32)sim_fread (uptr->filebuf, /* read file */ SZ_D (dptr), cap, uptr->fileref); uptr->flags = uptr->flags | UNIT_BUF; /* set buffered */ } uptr->flags = uptr->flags | UNIT_ATT; uptr->pos = 0; return SCPE_OK; |
︙ | ︙ | |||
5868 5869 5870 5871 5872 5873 5874 | return SCPE_NOTATT; /* complain */ } if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; if ((uptr->flags & UNIT_BUF) && (uptr->filebuf)) { uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr; if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { | < | < | 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 | return SCPE_NOTATT; /* complain */ } if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; if ((uptr->flags & UNIT_BUF) && (uptr->filebuf)) { uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr; if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { sim_messagef (SCPE_OK, "%s: writing buffer to file\n", sim_dname (dptr)); rewind (uptr->fileref); sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref); if (ferror (uptr->fileref)) sim_printf ("%s: I/O error - %s", sim_dname (dptr), strerror (errno)); } if (uptr->flags & UNIT_MUSTBUF) { /* dyn alloc? */ free (uptr->filebuf); /* free buf */ |
︙ | ︙ | |||
6005 6006 6007 6008 6009 6010 6011 | t_stat r; char gbuf[4*CBUFSIZE]; GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; gbuf[sizeof(gbuf)-1] = '\0'; | | | 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 | t_stat r; char gbuf[4*CBUFSIZE]; GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; gbuf[sizeof(gbuf)-1] = '\0'; strlcpy (gbuf, cptr, sizeof(gbuf)); sim_trim_endspc (gbuf); if ((sfile = sim_fopen (gbuf, "wb")) == NULL) return SCPE_OPENERR; r = sim_save (sfile); fclose (sfile); return r; } |
︙ | ︙ | |||
6160 6161 6162 6163 6164 6165 6166 | t_stat r; char gbuf[4*CBUFSIZE]; GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; gbuf[sizeof(gbuf)-1] = '\0'; | | | 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 | t_stat r; char gbuf[4*CBUFSIZE]; GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; gbuf[sizeof(gbuf)-1] = '\0'; strlcpy (gbuf, cptr, sizeof(gbuf)); sim_trim_endspc (gbuf); if ((rfile = sim_fopen (gbuf, "rb")) == NULL) return SCPE_OPENERR; r = sim_rest (rfile); fclose (rfile); return r; } |
︙ | ︙ | |||
6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 | sim_printf (", now attached to '%s'\n", attunits[j]->filename); else sim_printf (", now unattached\n"); } } } free (attnames[j]); } Cleanup_Return: for (j=0; j < attcnt; j++) free (attnames[j]); free (attnames); free (attunits); free (attswitches); | > | 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 | sim_printf (", now attached to '%s'\n", attunits[j]->filename); else sim_printf (", now unattached\n"); } } } free (attnames[j]); attnames[j] = NULL; } Cleanup_Return: for (j=0; j < attcnt; j++) free (attnames[j]); free (attnames); free (attunits); free (attswitches); |
︙ | ︙ | |||
6560 6561 6562 6563 6564 6565 6566 | if (MATCH_CMD (gbuf, "UNTIL") != 0) cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ if (MATCH_CMD (gbuf, "UNTIL") != 0) return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\n", (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr); sim_switches = 0; GET_SWITCHES (cptr); | | > | 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 | if (MATCH_CMD (gbuf, "UNTIL") != 0) cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ if (MATCH_CMD (gbuf, "UNTIL") != 0) return sim_messagef (SCPE_2MARG, "Unexpected %s command argument: %s %s\n", (flag == RU_RUN) ? "RUN" : "GO", gbuf, cptr); sim_switches = 0; GET_SWITCHES (cptr); if (((*cptr == '\'') || (*cptr == '"')) || /* Expect UNTIL condition */ (!sim_strncasecmp(cptr, "HALTAFTER=", 10))) { r = expect_cmd (1, cptr); if (r != SCPE_OK) return r; } else { /* BREAK UNTIL condition */ if (sim_switches == 0) sim_switches = sim_brk_dflt; |
︙ | ︙ | |||
6665 6666 6667 6668 6669 6670 6671 | if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ)) if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) return sim_messagef (SCPE_IERR, "Can't seek to %u in %s for %s\n", (unsigned)uptr->pos, uptr->filename, sim_uname (uptr)); } } stop_cpu = 0; sim_is_running = 1; /* flag running */ | | | | | | | | 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 | if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ)) if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) return sim_messagef (SCPE_IERR, "Can't seek to %u in %s for %s\n", (unsigned)uptr->pos, uptr->filename, sim_uname (uptr)); } } stop_cpu = 0; sim_is_running = 1; /* flag running */ if ((r = sim_ttrun ()) != SCPE_OK) { /* set console mode */ sim_is_running = 0; /* flag idle */ sim_ttcmd (); return sim_messagef (SCPE_TTYERR, "sim_ttrun() returned: %s\n", sim_error_text (r)); } if ((r = sim_check_console (30)) != SCPE_OK) { /* check console, error? */ sim_is_running = 0; /* flag idle */ sim_ttcmd (); sim_messagef (r, "sim_check_console () returned: %s\n", sim_error_text (r)); } if (signal (SIGINT, int_handler) == SIG_ERR) { /* set WRU */ sim_is_running = 0; /* flag idle */ sim_ttcmd (); return sim_messagef (SCPE_SIGERR, "Can't establish SIGINT"); } #ifdef SIGHUP if (signal (SIGHUP, int_handler) == SIG_ERR) { /* set WRU */ sim_is_running = 0; /* flag idle */ sim_ttcmd (); return sim_messagef (SCPE_SIGERR, "Can't establish SIGHUP"); } #endif if (signal (SIGTERM, int_handler) == SIG_ERR) { /* set WRU */ sim_is_running = 0; /* flag idle */ sim_ttcmd (); return sim_messagef (SCPE_SIGERR, "Can't establish SIGTERM"); } if (sim_step) /* set step timer */ sim_activate (&sim_step_unit, sim_step); fflush(stdout); /* flush stdout */ if (sim_log) /* flush log if enabled */ fflush (sim_log); sim_throt_sched (); /* set throttle */ |
︙ | ︙ | |||
7009 7010 7011 7012 7013 7014 7015 | return SCPE_ARG; } } if (*tptr && (*tptr++ != ',')) return SCPE_ARG; reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr, lowr, highr, (uint32) low, (uint32) high); | | | | 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 | return SCPE_ARG; } } if (*tptr && (*tptr++ != ',')) return SCPE_ARG; reason = exdep_reg_loop (ofile, sim_schrptr, flag, cptr, lowr, highr, (uint32) low, (uint32) high); if ((flag & EX_E) && (!sim_oline) && (sim_log && (ofile == stdout))) exdep_reg_loop (sim_log, sim_schrptr, EX_E, cptr, lowr, highr, (uint32) low, (uint32) high); continue; } tptr = get_range (sim_dfdev, gptr, &low, &high, sim_dfdev->aradix, (((sim_dfunit->capac == 0) || (flag == EX_E))? 0: sim_dfunit->capac - sim_dfdev->aincr), 0); if (tptr == NULL) return (tstat ? tstat : SCPE_ARG); if (*tptr && (*tptr++ != ',')) return SCPE_ARG; reason = exdep_addr_loop (ofile, sim_schaptr, flag, cptr, low, high, sim_dfdev, sim_dfunit); if ((flag & EX_E) && (!sim_oline) && (sim_log && (ofile == stdout))) exdep_addr_loop (sim_log, sim_schaptr, EX_E, cptr, low, high, sim_dfdev, sim_dfunit); } /* end for */ if (sim_ofile) /* close output file */ fclose (sim_ofile); return reason; } |
︙ | ︙ | |||
7060 7061 7062 7063 7064 7065 7066 | if ((sim_switches & SIM_SW_HIDE) && (rptr->flags & REG_HIDDEN)) continue; val = last_val = 0; for (idx = lows; idx <= highs; idx++) { if (idx >= rptr->depth) return SCPE_SUB; | | | | 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 | if ((sim_switches & SIM_SW_HIDE) && (rptr->flags & REG_HIDDEN)) continue; val = last_val = 0; for (idx = lows; idx <= highs; idx++) { if (idx >= rptr->depth) return SCPE_SUB; sim_eval[0] = val = get_rval (rptr, idx); sim_switches = saved_switches; if (schptr && !test_search (sim_eval, schptr)) continue; if (flag == EX_E) { if ((idx > lows) && (val == last_val)) continue; if (idx > val_start+1) { if (idx-1 == val_start+1) { reason = ex_reg (ofile, val, flag, rptr, idx-1); |
︙ | ︙ | |||
7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 | return SCPE_IERR; if (rptr->depth > 1) fprintf (ofile, "%s[%d]:\t", rptr->name, idx); else fprintf (ofile, "%s:\t", rptr->name); if (!(flag & EX_E)) return SCPE_OK; GET_RADIX (rdx, rptr->radix); if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr) sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val); else if (!(rptr->flags & REG_VMFLAGS) || | > | | 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 | return SCPE_IERR; if (rptr->depth > 1) fprintf (ofile, "%s[%d]:\t", rptr->name, idx); else fprintf (ofile, "%s:\t", rptr->name); if (!(flag & EX_E)) return SCPE_OK; sim_eval[0] = val; GET_RADIX (rdx, rptr->radix); if ((rptr->flags & REG_VMAD) && sim_vm_fprint_addr) sim_vm_fprint_addr (ofile, sim_dflt_dev, (t_addr) val); else if (!(rptr->flags & REG_VMFLAGS) || (fprint_sym (ofile, (rptr->flags & REG_UFMASK) | rdx, sim_eval, NULL, sim_switches | SIM_SW_REG) > 0)) { fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT); if (rptr->fields) { fprintf (ofile, "\t"); fprint_fields (ofile, val, val, rptr->fields); } } |
︙ | ︙ | |||
7380 7381 7382 7383 7384 7385 7386 | #if defined (USE_INT64) else if (sz <= sizeof (uint32)) PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask); else PUT_RVAL (t_uint64, rptr, idx, val, mask); #else else PUT_RVAL (uint32, rptr, idx, val, mask); #endif | < | 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 | #if defined (USE_INT64) else if (sz <= sizeof (uint32)) PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask); else PUT_RVAL (t_uint64, rptr, idx, val, mask); #else else PUT_RVAL (uint32, rptr, idx, val, mask); #endif } /* Examine address routine Inputs: (sim_eval is an implicit argument) ofile = output stream flag = type of ex/mod command (ex, iex, idep) |
︙ | ︙ | |||
7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 | #define S__STR_QUOTE(tok) #tok #define S__STR(tok) S__STR_QUOTE(tok) handle = dlopen("libncurses." S__STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); handle = dlopen("libcurses." S__STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); handle = dlopen("libreadline." S__STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); if (!handle) handle = dlopen("libreadline." S__STR(HAVE_DLOPEN) ".6", RTLD_NOW|RTLD_GLOBAL); if (!handle) handle = dlopen("libreadline." S__STR(HAVE_DLOPEN) ".5", RTLD_NOW|RTLD_GLOBAL); if (handle) { p_readline = (readline_func)((size_t)dlsym(handle, "readline")); p_add_history = (add_history_func)((size_t)dlsym(handle, "add_history")); } } if (prompt) { /* interactive? */ if (p_readline) { char *tmpc = p_readline (prompt); /* get cmd line */ if (tmpc == NULL) /* bad result? */ cptr = NULL; else { | > > | | 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 | #define S__STR_QUOTE(tok) #tok #define S__STR(tok) S__STR_QUOTE(tok) handle = dlopen("libncurses." S__STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); handle = dlopen("libcurses." S__STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); handle = dlopen("libreadline." S__STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); if (!handle) handle = dlopen("libreadline." S__STR(HAVE_DLOPEN) ".7", RTLD_NOW|RTLD_GLOBAL); if (!handle) handle = dlopen("libreadline." S__STR(HAVE_DLOPEN) ".6", RTLD_NOW|RTLD_GLOBAL); if (!handle) handle = dlopen("libreadline." S__STR(HAVE_DLOPEN) ".5", RTLD_NOW|RTLD_GLOBAL); if (handle) { p_readline = (readline_func)((size_t)dlsym(handle, "readline")); p_add_history = (add_history_func)((size_t)dlsym(handle, "add_history")); } } if (prompt) { /* interactive? */ if (p_readline) { char *tmpc = p_readline (prompt); /* get cmd line */ if (tmpc == NULL) /* bad result? */ cptr = NULL; else { strlcpy (cptr, tmpc, size); /* copy result */ free (tmpc) ; /* free temp */ } } else { printf ("%s", prompt); /* display prompt */ cptr = fgets (cptr, size, stream); /* get cmd line */ } |
︙ | ︙ | |||
7767 7768 7769 7770 7771 7772 7773 | if ((*iptr == '"') || (*iptr == '\'')) { quoting = TRUE; quote_char = *iptr; } } } if (sim_islower (*iptr) && uc) | | | 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 | if ((*iptr == '"') || (*iptr == '\'')) { quoting = TRUE; quote_char = *iptr; } } } if (sim_islower (*iptr) && uc) *optr = (char)sim_toupper (*iptr); else *optr = *iptr; iptr++; optr++; } *optr = 0; if (mchar && (*iptr == mchar)) /* skip terminator */ iptr++; while (sim_isspace (*iptr)) /* absorb spaces */ |
︙ | ︙ | |||
7822 7823 7824 7825 7826 7827 7828 | tptr = cptr + strlen (cptr); while ((--tptr >= cptr) && sim_isspace (*tptr)) *tptr = 0; return cptr; } | | | | | | > > | > > > | > > > | > > > > > > > | | | | | | | < | < | < | < | | 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 | tptr = cptr + strlen (cptr); while ((--tptr >= cptr) && sim_isspace (*tptr)) *tptr = 0; return cptr; } int sim_isspace (int c) { return ((c < 0) || (c >= 128)) ? 0 : isspace (c); } int sim_islower (int c) { return (c >= 'a') && (c <= 'z'); } int sim_isupper (int c) { return (c >= 'A') && (c <= 'Z'); } int sim_toupper (int c) { return ((c >= 'a') && (c <= 'z')) ? ((c - 'a') + 'A') : c; } int sim_tolower (int c) { return ((c >= 'A') && (c <= 'Z')) ? ((c - 'A') + 'a') : c; } int sim_isalpha (int c) { return ((c < 0) || (c >= 128)) ? 0 : isalpha (c); } int sim_isprint (int c) { return ((c < 0) || (c >= 128)) ? 0 : isprint (c); } int sim_isdigit (int c) { return ((c < 0) || (c >= 128)) ? 0 : isdigit (c); } int sim_isgraph (int c) { return ((c < 0) || (c >= 128)) ? 0 : isgraph (c); } int sim_isalnum (int c) { return ((c < 0) || (c >= 128)) ? 0 : isalnum (c); } /* strncasecmp() is not available on all platforms */ int sim_strncasecmp (const char* string1, const char* string2, size_t len) { size_t i; unsigned char s1, s2; for (i=0; i<len; i++) { s1 = (unsigned char)string1[i]; s2 = (unsigned char)string2[i]; s1 = (unsigned char)sim_toupper (s1); s2 = (unsigned char)sim_toupper (s2); if (s1 < s2) return -1; if (s1 > s2) return 1; if (s1 == 0) return 0; } return 0; } /* strcasecmp() is not available on all platforms */ int sim_strcasecmp (const char *string1, const char *string2) { size_t i = 0; unsigned char s1, s2; while (1) { s1 = (unsigned char)string1[i]; s2 = (unsigned char)string2[i]; s1 = (unsigned char)sim_toupper (s1); s2 = (unsigned char)sim_toupper (s2); if (s1 == s2) { if (s1 == 0) return 0; i++; continue; } if (s1 < s2) |
︙ | ︙ | |||
8205 8206 8207 8208 8209 8210 8211 | case 'x': if (1) { static const char *hex_digits = "0123456789ABCDEF"; const char *c; ++iptr; *optr = 0; | | | | 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 | case 'x': if (1) { static const char *hex_digits = "0123456789ABCDEF"; const char *c; ++iptr; *optr = 0; c = strchr (hex_digits, sim_toupper(*iptr)); if (c) { *optr = ((*optr)<<4) + (uint8)(c-hex_digits); ++iptr; } c = strchr (hex_digits, sim_toupper(*iptr)); if (c) { *optr = ((*optr)<<4) + (uint8)(c-hex_digits); ++iptr; } ++optr; } break; |
︙ | ︙ | |||
8568 8569 8570 8571 8572 8573 8574 | } /* get_switches get switches from input string Inputs: cptr = pointer to input string Outputs: | | > | > > | < | | > | > > > > > > > > > | | | | | | | > | > > > > > | > | 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 | } /* get_switches get switches from input string Inputs: cptr = pointer to input string Outputs: *sw = switch bit mask *mumber = numeric value Return value: SW_ERROR if error SW_BITMASK if switch bitmask or not a switch SW_NUMBER if numeric */ SWITCH_PARSE get_switches (const char *cptr, int32 *sw, int32 *number) { *sw = 0; if (*cptr != '-') return SW_BITMASK; if (number) *number = 0; if (sim_isdigit(cptr[1])) { char *end; long val = strtol (1+cptr, &end, 10); if ((*end != 0) || (number == NULL)) return SW_ERROR; *number = (int32)val; return SW_NUMBER; } for (cptr++; (sim_isspace (*cptr) == 0) && (*cptr != 0); cptr++) { if (sim_isalpha (*cptr) == 0) return SW_ERROR; *sw = *sw | SWMASK (sim_toupper (*cptr)); } return SW_BITMASK; } /* get_sim_sw accumulate sim_switches Inputs: cptr = pointer to input string Outputs: ptr = pointer to first non-string glyph NULL if error */ CONST char *get_sim_sw (CONST char *cptr) { int32 lsw, lnum; char gbuf[CBUFSIZE]; while (*cptr == '-') { /* while switches */ cptr = get_glyph (cptr, gbuf, 0); /* get switch glyph */ switch (get_switches (gbuf, &lsw, &lnum)) { /* parse */ case SW_ERROR: return NULL; case SW_BITMASK: sim_switches = sim_switches | lsw; /* accumulate */ break; case SW_NUMBER: sim_switch_number = lnum; /* set number */ break; } } return cptr; } /* get_sim_opt get simulator command options Inputs: opt = command options cptr = pointer to input string Outputs: ptr = pointer to next glypsh, NULL if error *stat = error status */ CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st) { int32 t, n; char gbuf[CBUFSIZE]; CONST char *svptr; DEVICE *tdptr; UNIT *tuptr; sim_switches = 0; /* no switches */ sim_switch_number = 0; /* no numberuc switch */ sim_ofile = NULL; /* no output file */ sim_schrptr = NULL; /* no search */ sim_schaptr = NULL; /* no search */ sim_stabr.logic = sim_staba.logic = SCH_OR; /* default search params */ sim_stabr.boolop = sim_staba.boolop = SCH_GE; sim_stabr.count = 1; sim_stabr.mask = (t_value *)realloc (sim_stabr.mask, sim_emax * sizeof(*sim_stabr.mask)); |
︙ | ︙ | |||
8667 8668 8669 8670 8671 8672 8673 | *st = SCPE_OPENERR; return NULL; } sim_opt_out |= CMD_OPT_OF; /* got output file */ continue; } cptr = get_glyph (cptr, gbuf, 0); | | | > > > > > > > | < > | | 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 | *st = SCPE_OPENERR; return NULL; } sim_opt_out |= CMD_OPT_OF; /* got output file */ continue; } cptr = get_glyph (cptr, gbuf, 0); switch (get_switches (gbuf, &t, &n)) { /* try for switches */ case SW_ERROR: /* err if bad switch */ *st = SCPE_INVSW; return NULL; case SW_NUMBER: sim_switch_number = n; /* set number */ continue; case SW_BITMASK: if (t != 0) { sim_switches = sim_switches | t;/* or in new switches */ continue; } break; } if ((opt & CMD_OPT_SCH) && /* if allowed, */ get_rsearch (gbuf, sim_dfdev->dradix, &sim_stabr)) { /* try for search */ sim_schrptr = &sim_stabr; /* set search */ sim_schaptr = get_asearch (gbuf, sim_dfdev->dradix, &sim_staba);/* populate memory version of the same expression */ sim_opt_out |= CMD_OPT_SCH; /* got search */ } else if ((opt & CMD_OPT_DFT) && /* default allowed? */ ((sim_opt_out & CMD_OPT_DFT) == 0) && /* none yet? */ |
︙ | ︙ | |||
8746 8747 8748 8749 8750 8751 8752 | for (fptr = pptr + 1, eptr = ext; /* match characters */ #if defined (VMS) /* VMS: stop at ; or null */ (*fptr != 0) && (*fptr != ';'); #else *fptr != 0; /* others: stop at null */ #endif fptr++, eptr++) { | | | 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 | for (fptr = pptr + 1, eptr = ext; /* match characters */ #if defined (VMS) /* VMS: stop at ; or null */ (*fptr != 0) && (*fptr != ';'); #else *fptr != 0; /* others: stop at null */ #endif fptr++, eptr++) { if (sim_toupper (*fptr) != sim_toupper (*eptr)) return NULL; } if (*eptr != 0) /* ext exhausted? */ return NULL; } return pptr; } |
︙ | ︙ | |||
9011 9012 9013 9014 9015 9016 9017 | if ((radix < 2) || (radix > 36)) return 0; while (sim_isspace (*inptr)) /* bypass white space */ inptr++; val = 0; nodigit = 1; for (c = *inptr; sim_isalnum(c); c = *++inptr) { /* loop through char */ | < | | 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 | if ((radix < 2) || (radix > 36)) return 0; while (sim_isspace (*inptr)) /* bypass white space */ inptr++; val = 0; nodigit = 1; for (c = *inptr; sim_isalnum(c); c = *++inptr) { /* loop through char */ c = sim_toupper (c); if (sim_isdigit (c)) /* digit? */ digit = c - (uint32) '0'; else if (radix <= 10) /* stop if not expected */ break; else digit = c + 10 - (uint32) 'A'; /* convert letter */ if (digit >= radix) /* valid in radix? */ return 0; |
︙ | ︙ | |||
9815 9816 9817 9818 9819 9820 9821 | free (bp->act); /* deallocate */ bp->act = NULL; /* now no action */ } if ((act != NULL) && (*act != 0)) { /* new action? */ char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */ if (newp == NULL) /* mem err? */ return SCPE_MEM; | | | 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 | free (bp->act); /* deallocate */ bp->act = NULL; /* now no action */ } if ((act != NULL) && (*act != 0)) { /* new action? */ char *newp = (char *) calloc (CBUFSIZE+1, sizeof (char)); /* alloc buf */ if (newp == NULL) /* mem err? */ return SCPE_MEM; strlcpy (newp, act, CBUFSIZE); /* copy action */ bp->act = newp; /* set pointer */ } sim_brk_summ = sim_brk_summ | (sw & ~BRK_TYP_TEMP); return SCPE_OK; } /* Clear a breakpoint */ |
︙ | ︙ | |||
10043 10044 10045 10046 10047 10048 10049 | if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) { /* cmd delimiter? */ lnt = ep - sim_brk_act[sim_do_depth]; /* cmd length */ memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1); /* copy with ; */ buf[lnt] = 0; /* erase ; */ sim_brk_act[sim_do_depth] += lnt + 1; /* adv ptr */ } else { | | | 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 | if ((ep = strchr (sim_brk_act[sim_do_depth], ';'))) { /* cmd delimiter? */ lnt = ep - sim_brk_act[sim_do_depth]; /* cmd length */ memcpy (buf, sim_brk_act[sim_do_depth], lnt + 1); /* copy with ; */ buf[lnt] = 0; /* erase ; */ sim_brk_act[sim_do_depth] += lnt + 1; /* adv ptr */ } else { strlcpy (buf, sim_brk_act[sim_do_depth], size); /* copy action */ sim_brk_clract (); /* no more */ } return buf; } /* Clear pending actions */ |
︙ | ︙ | |||
10180 10181 10182 10183 10184 10185 10186 10187 | /* Set expect */ t_stat sim_set_expect (EXPECT *exp, CONST char *cptr) { char gbuf[CBUFSIZE]; CONST char *tptr; CONST char *c1ptr; t_bool after_set = FALSE; | > > < > > < > | > > > > > > | | 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 | /* Set expect */ t_stat sim_set_expect (EXPECT *exp, CONST char *cptr) { char gbuf[CBUFSIZE]; CONST char *tptr; CONST char *c1ptr; const char *dev_name; uint32 after; t_bool after_set = FALSE; int32 cnt = 0; t_stat r; if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; dev_name = tmxr_expect_line_name (exp); after = get_default_env_parameter (dev_name, "SIM_EXPECT_HALTAFTER", 0); if (*cptr == '[') { cnt = (int32) strtotv (cptr + 1, &c1ptr, 10); if ((cptr == c1ptr) || (*c1ptr != ']')) return sim_messagef (SCPE_ARG, "Invalid Repeat count specification\n"); cptr = c1ptr + 1; while (sim_isspace(*cptr)) ++cptr; } tptr = get_glyph (cptr, gbuf, ','); if ((!strncmp(gbuf, "HALTAFTER=", 10)) && (gbuf[10])) { after = (uint32)get_uint (&gbuf[10], 10, 100000000, &r); if (r != SCPE_OK) return sim_messagef (SCPE_ARG, "Invalid Halt After Value\n"); cptr = tptr; after_set = TRUE; } if ((*cptr != '\0') && (*cptr != '"') && (*cptr != '\'')) return sim_messagef (SCPE_ARG, "String must be quote delimited\n"); cptr = get_glyph_quoted (cptr, gbuf, 0); /* Hsndle a bare HALTAFTER=nnn command */ if ((gbuf[0] == '\0') && (*cptr == '\0') && after_set) { set_default_env_parameter (dev_name, "SIM_EXPECT_HALTAFTER", after); return SCPE_OK; } return sim_exp_set (exp, gbuf, cnt, after, sim_switches, cptr); } /* Clear expect */ t_stat sim_set_noexpect (EXPECT *exp, const char *cptr) { char gbuf[CBUFSIZE]; |
︙ | ︙ | |||
10293 10294 10295 10296 10297 10298 10299 | } free (exp->rules); exp->rules = NULL; exp->size = 0; free (exp->buf); exp->buf = NULL; exp->buf_size = 0; | | | 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 | } free (exp->rules); exp->rules = NULL; exp->size = 0; free (exp->buf); exp->buf = NULL; exp->buf_size = 0; exp->buf_data = exp->buf_ins = 0; return SCPE_OK; } /* Set/Add an expect rule */ t_stat sim_exp_set (EXPECT *exp, const char *match, int32 cnt, uint32 after, int32 switches, const char *act) { |
︙ | ︙ | |||
10359 10360 10361 10362 10363 10364 10365 | return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\n"); } if (after && exp->size) return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n"); exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1)); ep = &exp->rules[exp->size]; exp->size += 1; | < > | 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 | return sim_messagef (SCPE_ARG, "Persistent Expect rule with identical match string already exists\n"); } if (after && exp->size) return sim_messagef (SCPE_ARG, "Multiple concurrent EXPECT rules aren't valid when a HALTAFTER parameter is non-zero\n"); exp->rules = (EXPTAB *) realloc (exp->rules, sizeof (*exp->rules)*(exp->size + 1)); ep = &exp->rules[exp->size]; exp->size += 1; memset (ep, 0, sizeof(*ep)); ep->after = after; /* set halt after value */ ep->match_pattern = (char *)malloc (strlen (match) + 1); if (ep->match_pattern) strcpy (ep->match_pattern, match); ep->cnt = cnt; /* set proceed count */ ep->switches = switches; /* set switches */ match_buf = (uint8 *)calloc (strlen (match) + 1, 1); if ((match_buf == NULL) || (ep->match_pattern == NULL)) { |
︙ | ︙ | |||
10396 10397 10398 10399 10400 10401 10402 | if (ep->act) { /* replace old action? */ free (ep->act); /* deallocate */ ep->act = NULL; /* now no action */ } if (act) while (sim_isspace(*act)) ++act; /* skip leading spaces in action string */ if ((act != NULL) && (*act != 0)) { /* new action? */ | > > > > | > > > | > > > > | | | > > < < | | | | | 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 | if (ep->act) { /* replace old action? */ free (ep->act); /* deallocate */ ep->act = NULL; /* now no action */ } if (act) while (sim_isspace(*act)) ++act; /* skip leading spaces in action string */ if ((act != NULL) && (*act != 0)) { /* new action? */ char *newp; if ((act > sim_sub_instr_buf) && ((size_t)(act - sim_sub_instr_buf) < sim_sub_instr_size)) act = &sim_sub_instr[sim_sub_instr_off[act - sim_sub_instr_buf]]; /* get un-substituted string */ newp = (char *) calloc (strlen (act)+1, sizeof (*act)); /* alloc buf */ if (newp == NULL) /* mem err? */ return SCPE_MEM; strcpy (newp, act); /* copy action */ ep->act = newp; /* set pointer */ } /* Make sure that the production buffer is large enough to detect a match for all rules including a NUL termination byte */ for (i=0; i<exp->size; i++) { uint32 compare_size = (exp->rules[i].switches & EXP_TYP_REGEX) ? MAX(10 * strlen(ep->match_pattern), 1024) : exp->rules[i].size; if (compare_size >= exp->buf_size) { exp->buf = (uint8 *)realloc (exp->buf, compare_size + 2); /* Extra byte to null terminate regex compares */ exp->buf_size = compare_size + 1; } } return SCPE_OK; } /* Show an expect rule */ t_stat sim_exp_show_tab (FILE *st, const EXPECT *exp, const EXPTAB *ep) { const char *dev_name = tmxr_expect_line_name (exp); uint32 default_haltafter = get_default_env_parameter (dev_name, "SIM_EXPECT_HALTAFTER", 0); if (!ep) return SCPE_OK; fprintf (st, " EXPECT"); if (ep->switches & EXP_TYP_PERSIST) fprintf (st, " -p"); if (ep->switches & EXP_TYP_CLEARALL) fprintf (st, " -c"); if (ep->switches & EXP_TYP_REGEX) fprintf (st, " -r"); if (ep->switches & EXP_TYP_REGEX_I) fprintf (st, " -i"); if (ep->after != default_haltafter) fprintf (st, " HALTAFTER=%d", (int)ep->after); fprintf (st, " %s", ep->match_pattern); if (ep->cnt > 0) fprintf (st, " [%d]", ep->cnt); if (ep->act) fprintf (st, " %s", ep->act); fprintf (st, "\n"); return SCPE_OK; } t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match) { CONST EXPTAB *ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 0); const char *dev_name = tmxr_expect_line_name (exp); uint32 default_haltafter = get_default_env_parameter (dev_name, "SIM_EXPECT_HALTAFTER", 0); if (exp->buf_size) { char *bstr = sim_encode_quoted_string (exp->buf, exp->buf_ins); fprintf (st, " Match Buffer Size: %d\n", exp->buf_size); fprintf (st, " Buffer Insert Offset: %d\n", exp->buf_ins); fprintf (st, " Buffer Contents: %s\n", bstr); if (default_haltafter) fprintf (st, " Default HaltAfter: %u instructions\n", (unsigned)default_haltafter); free (bstr); } if (exp->dptr && (exp->dbit & exp->dptr->dctrl)) fprintf (st, " Expect Debugging via: SET %s DEBUG%s%s\n", sim_dname(exp->dptr), exp->dptr->debflags ? "=" : "", exp->dptr->debflags ? get_dbg_verb (exp->dbit, exp->dptr) : ""); fprintf (st, " Match Rules:\n"); if (!*match) return sim_exp_showall (st, exp); if (!ep) { fprintf (st, " No Rules match '%s'\n", match); return SCPE_ARG; } do { sim_exp_show_tab (st, exp, ep); ep = (CONST EXPTAB *)sim_exp_fnd (exp, match, 1 + (ep - exp->rules)); } while (ep); return SCPE_OK; |
︙ | ︙ | |||
10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 | char *tstr = NULL; if ((!exp) || (!exp->rules)) /* Anying to check? */ return SCPE_OK; exp->buf[exp->buf_ins++] = data; /* Save new data */ exp->buf[exp->buf_ins] = '\0'; /* Nul terminate for RegEx match */ for (i=0; i < exp->size; i++) { ep = &exp->rules[i]; if (ep->switches & EXP_TYP_REGEX) { #if defined (USE_REGEX) regmatch_t *matches; char *cbuf = (char *)exp->buf; static size_t sim_exp_match_sub_count = 0; if (tstr) cbuf = tstr; else { if (strlen ((char *)exp->buf) != exp->buf_ins) { /* Nul characters in buffer? */ size_t off; | > > < > | 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 | char *tstr = NULL; if ((!exp) || (!exp->rules)) /* Anying to check? */ return SCPE_OK; exp->buf[exp->buf_ins++] = data; /* Save new data */ exp->buf[exp->buf_ins] = '\0'; /* Nul terminate for RegEx match */ if (exp->buf_data < exp->buf_size) ++exp->buf_data; /* Record amount of data in buffer */ for (i=0; i < exp->size; i++) { ep = &exp->rules[i]; if (ep->switches & EXP_TYP_REGEX) { #if defined (USE_REGEX) regmatch_t *matches; char *cbuf = (char *)exp->buf; static size_t sim_exp_match_sub_count = 0; if (tstr) cbuf = tstr; else { if (strlen ((char *)exp->buf) != exp->buf_ins) { /* Nul characters in buffer? */ size_t off; tstr = (char *)malloc (exp->buf_ins + 1); tstr[0] = '\0'; for (off=0; off < exp->buf_ins; off += 1 + strlen ((char *)&exp->buf[off])) strcpy (&tstr[strlen (tstr)], (char *)&exp->buf[off]); cbuf = tstr; } } ++regex_checks; |
︙ | ︙ | |||
10550 10551 10552 10553 10554 10555 10556 | free (buf); break; } free (matches); #endif } else { | > > | | | | | | | > | 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 | free (buf); break; } free (matches); #endif } else { if (exp->buf_data < ep->size) /* Too little data to match yet? */ continue; /* Yes, Try next one. */ if (exp->buf_ins < ep->size) { /* Match might stradle end of buffer */ /* * First compare the newly deposited data at the beginning * of buffer with the end of the match string */ if (exp->buf_ins) { if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (exp->buf, exp->buf_ins); char *mstr = sim_encode_quoted_string (&ep->match[ep->size-exp->buf_ins], exp->buf_ins); sim_debug (exp->dbit, exp->dptr, "Checking String[0:%d]: %s\n", exp->buf_ins, estr); sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr); free (estr); free (mstr); } if (memcmp (exp->buf, &ep->match[ep->size-exp->buf_ins], exp->buf_ins)) /* Tail Match? */ continue; /* Nope, Try next one. */ } if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->size-exp->buf_ins); char *mstr = sim_encode_quoted_string (ep->match, ep->size-exp->buf_ins); sim_debug (exp->dbit, exp->dptr, "Checking String[%d:%d]: %s\n", exp->buf_size-(ep->size-exp->buf_ins), ep->size-exp->buf_ins, estr); sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr); free (estr); free (mstr); } if (memcmp (&exp->buf[exp->buf_size-(ep->size-exp->buf_ins)], ep->match, ep->size-exp->buf_ins)) /* Front Match? */ continue; /* Nope, Try next one. */ break; } else { if (sim_deb && exp->dptr && (exp->dptr->dctrl & exp->dbit)) { char *estr = sim_encode_quoted_string (&exp->buf[exp->buf_ins-ep->size], ep->size); char *mstr = sim_encode_quoted_string (ep->match, ep->size); sim_debug (exp->dbit, exp->dptr, "Checking String[%d:%d]: %s\n", exp->buf_ins-ep->size, ep->size, estr); sim_debug (exp->dbit, exp->dptr, "Against Match Data: %s\n", mstr); free (estr); free (mstr); } if (memcmp (&exp->buf[exp->buf_ins-ep->size], ep->match, ep->size)) /* Whole string match? */ continue; /* Nope, Try next one. */ break; } } } if (exp->buf_ins == exp->buf_size) { /* At end of match buffer? */ if (regex_checks) { /* When processing regular expressions, let the match buffer fill up and then shuffle the buffer contents down by half the buffer size so that the regular expression has a single contiguous buffer to match against instead of the wrapping buffer paradigm which is used when no regular expression rules are in effect */ memmove (exp->buf, &exp->buf[exp->buf_size/2], exp->buf_size-(exp->buf_size/2)); exp->buf_ins -= exp->buf_size/2; exp->buf_data = exp->buf_ins; sim_debug (exp->dbit, exp->dptr, "Buffer Full - sliding the last %d bytes to start of buffer new insert at: %d\n", (exp->buf_size/2), exp->buf_ins); } else { exp->buf_ins = 0; /* wrap around to beginning */ sim_debug (exp->dbit, exp->dptr, "Buffer wrapping\n"); } } |
︙ | ︙ | |||
10637 10638 10639 10640 10641 10642 10643 | sim_exp_clrall (exp); /* delete all rules */ else { if (!(ep->switches & EXP_TYP_PERSIST)) /* One shot expect rule? */ sim_exp_clr_tab (exp, ep); /* delete it */ } sim_activate (&sim_expect_unit, /* schedule simulation stop when indicated */ (ep->switches & EXP_TYP_TIME) ? | | | | | 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 | sim_exp_clrall (exp); /* delete all rules */ else { if (!(ep->switches & EXP_TYP_PERSIST)) /* One shot expect rule? */ sim_exp_clr_tab (exp, ep); /* delete it */ } sim_activate (&sim_expect_unit, /* schedule simulation stop when indicated */ (ep->switches & EXP_TYP_TIME) ? (int32)((sim_timer_inst_per_sec ()*ep->after)/1000000.0) : ep->after); } /* Matched data is no longer available for future matching */ exp->buf_data = exp->buf_ins = 0; } free (tstr); return SCPE_OK; } /* Queue input data for sending */ |
︙ | ︙ | |||
10663 10664 10665 10666 10667 10668 10669 | } if (snd->insoff+size > snd->bufsize) { snd->bufsize = snd->insoff+size; snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize); } memcpy(snd->buffer+snd->insoff, data, size); snd->insoff += size; | < | < | < < > | | | | | | | | | | | 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 | } if (snd->insoff+size > snd->bufsize) { snd->bufsize = snd->insoff+size; snd->buffer = (uint8 *)realloc(snd->buffer, snd->bufsize); } memcpy(snd->buffer+snd->insoff, data, size); snd->insoff += size; snd->delay = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*delay)/1000000.0) : delay; snd->after = (sim_switches & SWMASK ('T')) ? (uint32)((sim_timer_inst_per_sec()*after)/1000000.0) : after; snd->next_time = sim_gtime() + snd->after; return SCPE_OK; } /* Cancel Queued input data */ t_stat sim_send_clear (SEND *snd) { snd->insoff = 0; snd->extoff = 0; return SCPE_OK; } /* Display console Queued input data status */ t_stat sim_show_send_input (FILE *st, const SEND *snd) { fprintf (st, "%s\n", tmxr_send_line_name (snd)); if (snd->extoff < snd->insoff) { fprintf (st, " %d bytes of pending input Data:\n ", snd->insoff-snd->extoff); fprint_buffer_string (st, snd->buffer+snd->extoff, snd->insoff-snd->extoff); fprintf (st, "\n"); } else fprintf (st, " No Pending Input Data\n"); if ((snd->next_time - sim_gtime()) > 0) { if (((snd->next_time - sim_gtime()) > (sim_timer_inst_per_sec()/1000000.0)) && ((sim_timer_inst_per_sec()/1000000.0) > 0.0)) fprintf (st, " Minimum of %d instructions (%d microseconds) before sending first character\n", (int)(snd->next_time - sim_gtime()), (int)((snd->next_time - sim_gtime())/(sim_timer_inst_per_sec()/1000000.0))); else fprintf (st, " Minimum of %d instructions before sending first character\n", (int)(snd->next_time - sim_gtime())); } if ((snd->delay > (sim_timer_inst_per_sec()/1000000.0)) && ((sim_timer_inst_per_sec()/1000000.0) > 0.0)) fprintf (st, " Minimum of %d instructions (%d microseconds) between characters\n", (int)snd->delay, (int)(snd->delay/(sim_timer_inst_per_sec()/1000000.0))); else fprintf (st, " Minimum of %d instructions between characters\n", (int)snd->delay); if (snd->dptr && (snd->dbit & snd->dptr->dctrl)) fprintf (st, " Send Debugging via: SET %s DEBUG%s%s\n", sim_dname(snd->dptr), snd->dptr->debflags ? "=" : "", snd->dptr->debflags ? get_dbg_verb (snd->dbit, snd->dptr) : ""); return SCPE_OK; } /* Poll for Queued input data */ t_bool sim_send_poll_data (SEND *snd, t_stat *stat) { |
︙ | ︙ | |||
10791 10792 10793 10794 10795 10796 10797 | static const char *debtab_nomatch = "DEBTAB_NOMATCH"; const char *some_match = NULL; int32 offset = 0; if (dptr->debflags == 0) return debtab_none; | | | 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 | static const char *debtab_nomatch = "DEBTAB_NOMATCH"; const char *some_match = NULL; int32 offset = 0; if (dptr->debflags == 0) return debtab_none; dbits &= dptr->dctrl; /* Look for just the bits that matched */ /* Find matching words for bitmask */ while (dptr->debflags[offset].name && (offset < 32)) { if (dptr->debflags[offset].mask == dbits) /* All Bits Match */ return dptr->debflags[offset].name; if (dptr->debflags[offset].mask & dbits) |
︙ | ︙ | |||
10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 | char stackbuf[STACKBUFSIZE]; int32 bufsize = sizeof(stackbuf); char *buf = stackbuf; int32 len; va_list arglist; t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE)); while (1) { /* format passed string, args */ va_start (arglist, fmt); #if defined(NO_vsnprintf) len = vsprintf (buf, fmt, arglist); #else /* !defined(NO_vsnprintf) */ len = vsnprintf (buf, bufsize-1, fmt, arglist); #endif /* NO_vsnprintf */ | > > | 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 | char stackbuf[STACKBUFSIZE]; int32 bufsize = sizeof(stackbuf); char *buf = stackbuf; int32 len; va_list arglist; t_bool inhibit_message = (!sim_show_message || (stat & SCPE_NOMESSAGE)); if ((stat == SCPE_OK) && (sim_quiet || (sim_switches & SWMASK ('Q')))) return stat; while (1) { /* format passed string, args */ va_start (arglist, fmt); #if defined(NO_vsnprintf) len = vsprintf (buf, fmt, arglist); #else /* !defined(NO_vsnprintf) */ len = vsnprintf (buf, bufsize-1, fmt, arglist); #endif /* NO_vsnprintf */ |
︙ | ︙ | |||
11021 11022 11023 11024 11025 11026 11027 | buf[bufsize-1] = '\0'; continue; } break; } if (sim_do_ocptr[sim_do_depth]) { | | > > | 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 | buf[bufsize-1] = '\0'; continue; } break; } if (sim_do_ocptr[sim_do_depth]) { if (!sim_do_echo && !inhibit_message && !sim_cmd_echoed) { sim_printf("%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]); sim_cmd_echoed = TRUE; } else { if (sim_deb) { /* Always put context in debug output */ TMLN *saved_oline = sim_oline; sim_oline = NULL; /* avoid potential debug to active socket */ fprintf (sim_deb, "%s> %s\n", do_position(), sim_do_ocptr[sim_do_depth]); sim_oline = saved_oline; /* restore original socket */ |
︙ | ︙ | |||
11073 11074 11075 11076 11077 11078 11079 | set and the bitmask matches the current device debug options. Extra returns are added for un*x systems, since the output device is set into 'raw' mode when the cpu is booted, and the extra returns don't hurt any other systems. Callers should be calling sim_debug() which is a macro defined in scp.h which evaluates the action condition before incurring call overhead. */ | < < < < | 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 | set and the bitmask matches the current device debug options. Extra returns are added for un*x systems, since the output device is set into 'raw' mode when the cpu is booted, and the extra returns don't hurt any other systems. Callers should be calling sim_debug() which is a macro defined in scp.h which evaluates the action condition before incurring call overhead. */ void _sim_debug (uint32 dbits, DEVICE* vdptr, const char* fmt, ...) { DEVICE *dptr = (DEVICE *)vdptr; if (sim_deb && dptr && (dptr->dctrl & dbits)) { TMLN *saved_oline = sim_oline; char stackbuf[STACKBUFSIZE]; int32 bufsize = sizeof(stackbuf); char *buf = stackbuf; |
︙ | ︙ | |||
11575 11576 11577 11578 11579 11580 11581 | while (sim_isdigit (*start)) /* Get param # */ n += (n * 10) + (*start++ - '0'); if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) FAIL (SCPE_ARG, Invalid parameter number, start); while (n > vsnum) /* Get arg pointer if not cached */ vstrings[vsnum++] = va_arg (ap, char *); end = vstrings[n-1]; /* Check for True */ | | | 12028 12029 12030 12031 12032 12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 | while (sim_isdigit (*start)) /* Get param # */ n += (n * 10) + (*start++ - '0'); if (!*start || *start == '\n'|| n == 0 || n >= VSMAX) FAIL (SCPE_ARG, Invalid parameter number, start); while (n > vsnum) /* Get arg pointer if not cached */ vstrings[vsnum++] = va_arg (ap, char *); end = vstrings[n-1]; /* Check for True */ if (!end || !(sim_toupper (*end) == 'T' || *end == '1')) { excluded = TRUE; /* False, skip topic this time */ if (*htext) htext++; continue; } } newt = (TOPIC *) calloc (sizeof (TOPIC), 1); |
︙ | ︙ | |||
11804 11805 11806 11807 11808 11809 11810 | ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0)); cptr = cbuf; while (*cptr) { if (blankch (*cptr)) { *cptr++ = '_'; } else { | | | 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 | ((topic->children[i]->flags & HLP_MAGIC_TOPIC)? 1 : 0)); cptr = cbuf; while (*cptr) { if (blankch (*cptr)) { *cptr++ = '_'; } else { *cptr = (char)sim_toupper (*cptr); cptr++; } } if (!strncmp (cbuf, token, strlen (token))) { if (match) return HLP_MATCH_AMBIGUOUS; match = i+1; |
︙ | ︙ | |||
11876 11877 11878 11879 11880 11881 11882 | p = dptr->name; flat_help = (dptr->flags & DEV_FLATHELP) != 0; } else p = sim_name; top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1); for (i = 0; p[i]; i++ ) | | | 12329 12330 12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 | p = dptr->name; flat_help = (dptr->flags & DEV_FLATHELP) != 0; } else p = sim_name; top.title = (char *) malloc (strlen (p) + ((flag & SCP_HELP_ATTACH)? sizeof (attach_help)-1: 0) +1); for (i = 0; p[i]; i++ ) top.title[i] = (char)sim_toupper (p[i]); top.title[i] = '\0'; if (flag & SCP_HELP_ATTACH) strcpy (top.title+i, attach_help); top.label = (char *) malloc (sizeof ("1")); strcpy (top.label, "1"); |
︙ | ︙ | |||
12101 12102 12103 12104 12105 12106 12107 | * work (one reason files are probably not a good idea), * but we might as well try. Some OSs won't include a * path. Having failed in the CWD, try to find the location * of the executable. Failing that, try the 'help' subdirectory * of the executable. Failing that, we're out of luck. */ fbuf[sizeof(fbuf)-1] = '\0'; | | | 12554 12555 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 | * work (one reason files are probably not a good idea), * but we might as well try. Some OSs won't include a * path. Having failed in the CWD, try to find the location * of the executable. Failing that, try the 'help' subdirectory * of the executable. Failing that, we're out of luck. */ fbuf[sizeof(fbuf)-1] = '\0'; strlcpy (fbuf, sim_argv[0], sizeof (fbuf)); if ((p = (char *)match_ext (fbuf, "EXE"))) *p = '\0'; if ((p = strrchr (fbuf, '\\'))) { p[1] = '\0'; d = "%s\\"; } else { |
︙ | ︙ |
︙ | ︙ | |||
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 | 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__ | > > | 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 | 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 copy_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 sleep_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__ |
︙ | ︙ | |||
144 145 146 147 148 149 150 | 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); | | > > > > > > | > > > > > > | > > > > > > | > > > > > > | > > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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 (int c); #ifdef isspace #undef isspace #endif #ifndef IN_SCP_C #define isspace(chr) sim_isspace (chr) #endif int sim_islower (int c); #ifdef islower #undef islower #endif #ifndef IN_SCP_C #define islower(chr) sim_islower (chr) #endif int sim_isalpha (int c); #ifdef isalpha #undef isalpha #endif #ifndef IN_SCP_C #define isalpha(chr) sim_isalpha (chr) #endif int sim_isprint (int c); #ifdef isprint #undef isprint #endif #ifndef IN_SCP_C #define isprint(chr) sim_isprint (chr) #endif int sim_isdigit (int c); #ifdef isdigit #undef isdigit #endif #ifndef IN_SCP_C #define isdigit(chr) sim_isdigit (chr) #endif int sim_isgraph (int c); #ifdef isgraph #undef isgraph #endif #ifndef IN_SCP_C #define isgraph(chr) sim_isgraph (chr) #endif int sim_isalnum (int c); #ifdef isalnum #undef isalnum #endif #ifndef IN_SCP_C #define isalnum(chr) sim_isalnum (chr) #endif int sim_toupper (int c); int sim_tolower (int c); #ifdef toupper #undef toupper #endif #define toupper(chr) sim_toupper(chr) #ifdef tolower #undef tolower #endif #define tolower(chr) sim_tolower(chr) 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); #ifndef strlcpy #define strlcpy(dst, src, size) sim_strlcpy((dst), (src), (size)) #endif #ifndef strlcat #define strlcat(dst, src, size) sim_strlcat((dst), (src), (size)) #endif #ifndef strncasecmp #define strncasecmp(str1, str2, len) sim_strncasecmp((str1), (str2), (len)) #endif #ifndef strcasecmp #define strcasecmp(str1, str2) sim_strcasecmp ((str1), (str2)) #endif 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); |
︙ | ︙ | |||
182 183 184 185 186 187 188 189 190 191 192 193 194 195 | 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); | > | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | 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); char *read_line_p (const char *prompt, char *ptr, 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); |
︙ | ︙ | |||
233 234 235 236 237 238 239 | 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 | < < < < < < < < < | < | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | 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 #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 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, ...); |
︙ | ︙ | |||
270 271 272 273 274 275 276 277 278 279 280 281 282 283 | /* 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 */ | > | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 | /* 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_switch_number; 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 */ |
︙ | ︙ |
︙ | ︙ | |||
224 225 226 227 228 229 230 | 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, | | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | 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 | DEV_NOSAVE, 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 = {0, &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) |
︙ | ︙ | |||
336 337 338 339 340 341 342 | { "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 }, | | | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | { "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, -1 }, { "INPUT", &sim_show_cons_send_input, 0 }, { "RESPONSE", &sim_show_cons_send_input, -1 }, { "DELAY", &sim_show_cons_expect, -1 }, { 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 }, |
︙ | ︙ | |||
407 408 409 410 411 412 413 | { char gbuf[CBUFSIZE]; SHTAB *shptr; int32 i; if (*cptr == 0) { /* show all */ for (i = 0; show_con_tab[i].name; i++) | > | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | { char gbuf[CBUFSIZE]; SHTAB *shptr; int32 i; if (*cptr == 0) { /* show all */ for (i = 0; show_con_tab[i].name; i++) if (show_con_tab[i].arg != -1) 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; |
︙ | ︙ | |||
475 476 477 478 479 480 481 482 483 484 485 486 487 488 | 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; | > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | 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 */ uint32 idx; /* Register index */ 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; |
︙ | ︙ | |||
498 499 500 501 502 503 504 505 506 507 508 509 510 511 | 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 */ | > < | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | 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 */ int smp_sample_dither_pct; /* dithering of cycles interval */ 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 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 */ |
︙ | ︙ | |||
529 530 531 532 533 534 535 | 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; | > > > | | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | 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; if (rem->smp_regs[reg].reg->depth > 1) fprintf (st, "}%s %s[%d] %s %d:", rem->smp_regs[reg].dptr->name, rem->smp_regs[reg].reg->name, rem->smp_regs[reg].idx, rem->smp_regs[reg].indirect ? " -I" : "", rem->smp_regs[reg].bits[0].depth); else 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; } |
︙ | ︙ | |||
610 611 612 613 614 615 616 | 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; | > > > | > > > | | 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 | 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; if (rem->smp_sample_dither_pct) fprintf (st, "Register Bit Sampling is occurring every %d cycles (dithered %d percent)\n", rem->smp_sample_interval, rem->smp_sample_dither_pct); else 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); if (rem->smp_regs[reg].reg->depth > 1) fprintf (st, "%s[%d]%s", rem->smp_regs[reg].reg->name, rem->smp_regs[reg].idx, ((reg + 1) < rem->smp_reg_count) ? ", " : ""); else 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); } } |
︙ | ︙ | |||
857 858 859 860 861 862 863 | 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; | | > > | 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 | 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; 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_vm_post != NULL) /* optionally let the simulator know */ (*sim_vm_post) (TRUE); /* something might have changed */ 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 */ } |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 | /* 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]; | | | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 | /* 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, dither_pct; 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? */ |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 | } } 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 */ | > | 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 | } } else stat = sim_messagef (SCPE_ARG, "Expected value or STOP found: %s\n", gbuf); } else { const char *tptr; int32 event_time = rem->smp_sample_interval; 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 */ |
︙ | ︙ | |||
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 | 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'; | > > > > > > > > > > > > > > > > > > | 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 | 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); } cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ if ((MATCH_CMD (gbuf, "DITHER") != 0) || (*cptr == 0)) { *iptr = cptr; return sim_messagef (SCPE_ARG, "Expected DITHER found: %s\n", gbuf); } cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ dither_pct = (int32) get_uint (gbuf, 10, INT_MAX, &stat); if ((stat != SCPE_OK) || /* error? */ (dither_pct < 0) || (dither_pct > 25)) { *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, "PERCENT") != 0) || (*cptr == 0)) { *iptr = cptr; return sim_messagef (SCPE_ARG, "Expected PERCENT 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; uint32 idx; int32 saved_switches = sim_switches; t_bool indirect = FALSE; BITSAMPLE_REG *smp_regs; if (comma) { strncpy (tbuf, cptr, comma - cptr); tbuf[comma - cptr] = '\0'; |
︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | 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) { | > > > > > > > > > > > > > > > > > > > > | 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 | 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; } if (*tptr == '[') { /* subscript? */ const char *tgptr = ++tptr; if (reg->depth <= 1) { /* array register? */ stat = sim_messagef (SCPE_SUB, "Not Array Register: %s\n", reg->name); break; } idx = (uint32) strtotv (tgptr, &tptr, 10); /* convert index */ if ((tgptr == tptr) || (*tptr++ != ']')) { stat = sim_messagef (SCPE_SUB, "Missing or Invalid Register Subscript: %s[%s\n", reg->name, tgptr); break; } if (idx >= reg->depth) { /* validate subscript */ stat = sim_messagef (SCPE_SUB, "Invalid Register Subscript: %s[%d]\n", reg->name, idx); break; } } else idx = 0; /* not array */ 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].idx = idx; 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) { |
︙ | ︙ | |||
1163 1164 1165 1166 1167 1168 1169 | } if (stat != SCPE_OK) { /* Error? */ *iptr = cptr; cptr = strcpy (gbuf, "STOP"); sim_rem_collect_cmd_setup (line, &cptr);/* Cleanup mess */ return stat; } | > > | | 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 | } if (stat != SCPE_OK) { /* Error? */ *iptr = cptr; cptr = strcpy (gbuf, "STOP"); sim_rem_collect_cmd_setup (line, &cptr);/* Cleanup mess */ return stat; } if (rem->smp_sample_dither_pct) event_time = (((rand() % (2 * rem->smp_sample_dither_pct)) - rem->smp_sample_dither_pct) * event_time) / 100; sim_activate (&rem_con_smp_smpl_units[rem->line], event_time); } *iptr = cptr; return stat; } t_stat sim_rem_con_repeat_svc (UNIT *uptr) { |
︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 | 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; | | | 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 | 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, reg->idx); 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 (®->bits[i], val&1); |
︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 | } t_stat sim_rem_con_smp_collect_svc (UNIT *uptr) { int line = uptr - rem_con_smp_smpl_units; REMOTE *rem = &sim_rem_consoles[line]; | | > > > > | | 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 | } 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, dither=%d%%\n", line, rem->smp_sample_interval, rem->smp_sample_dither_pct); if (rem->smp_sample_interval && (rem->smp_reg_count != 0)) { int32 event_time = rem->smp_sample_interval; if (rem->smp_sample_dither_pct) event_time = (((rand() % (2 * rem->smp_sample_dither_pct)) - rem->smp_sample_dither_pct) * event_time) / 100; sim_rem_collect_registers (rem); sim_activate (uptr, event_time); /* reschedule */ } return SCPE_OK; } /* Unit service for remote console data polling */ t_stat sim_rem_con_data_svc (UNIT *uptr) |
︙ | ︙ | |||
1345 1346 1347 1348 1349 1350 1351 | 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) { | | | 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 | 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", rem->read_timeout); 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) */ |
︙ | ︙ | |||
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 | 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; | > > > > > > > | 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 | 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; sim_last_cmd_stat = SCPE_OK; 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); } sim_debug (DBG_MOD, &sim_remote_console, "Master Session Returned: Status - %d Active_Line: %d, Mode: %s, Active Cmd: %s\n", stat, sim_rem_cmd_active_line, sim_rem_consoles[0].single_mode ? "Single" : "^E Stopped", sim_rem_active_command ? sim_rem_active_command->name : ""); if (stat == SCPE_EXIT) sim_rem_master_mode = FALSE; sim_rem_cmd_active_line = 0; /* Make it look like */ sim_rem_consoles[0].single_mode = FALSE; if (stat != SCPE_STEP) sim_rem_active_command = &allowed_single_remote_cmds[0];/* Dummy */ sim_last_cmd_stat = SCPE_BARE_STATUS(stat); /* make exit status available to remote console */ } 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; |
︙ | ︙ | |||
2202 2203 2204 2205 2206 2207 2208 | 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) && | | | | 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 | 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->debflags)) && (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->debflags)) && (dptr->dctrl)) { fprintf (st, "Device: %-6s ", dptr->name); show_dev_debug (st, dptr, NULL, 0, NULL); } } } else |
︙ | ︙ | |||
2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 | 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 */ | > | 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 | 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) { fprintf (st, "Console Expect processing:\n"); return sim_exp_show (st, &sim_con_expect, cptr); } /* Log File Open/Close/Show Support */ /* Open log file */ |
︙ | ︙ | |||
2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 | 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 */ | > > | > > | 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 | 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) { fprintf (st, "Console Send processing:\n"); 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 */ if (sim_ttisatty ()) c = sim_os_poll_kbd (); /* get character */ else c = SCPE_OK; 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? */ |
︙ | ︙ | |||
2978 2979 2980 2981 2982 2983 2984 | if (r1 != SCPE_OK) return r1; return r2; } t_bool sim_ttisatty (void) { | > > > | > | 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 | if (r1 != SCPE_OK) return r1; return r2; } t_bool sim_ttisatty (void) { static int answer = -1; if (answer == -1) answer = sim_os_ttisatty (); return (t_bool)answer; } /* Platform specific routine definitions */ /* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */ |
︙ | ︙ | |||
3214 3215 3216 3217 3218 3219 3220 | (std_output != INVALID_HANDLE_VALUE)) GetConsoleMode (std_output, &saved_output_mode); /* Save Output Mode */ return SCPE_OK; } static t_stat sim_os_ttrun (void) { | > | | | | > > | | 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 | (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 ((sim_ttisatty ()) && (std_input) && /* If Not Background process? */ (std_input != INVALID_HANDLE_VALUE)) { if (!GetConsoleMode(std_input, &saved_input_mode)) return sim_messagef (SCPE_TTYERR, "GetConsoleMode() error: 0x%X\n", (unsigned int)GetLastError ()); if ((!SetConsoleMode(std_input, ENABLE_VIRTUAL_TERMINAL_INPUT)) && (!SetConsoleMode(std_input, RAW_MODE))) return sim_messagef (SCPE_TTYERR, "SetConsoleMode() error: 0x%X\n", (unsigned int)GetLastError ()); } if ((std_output) && /* If Not Background process? */ (std_output != INVALID_HANDLE_VALUE)) { if (GetConsoleMode(std_output, &saved_output_mode)) if (!SetConsoleMode(std_output, ENABLE_VIRTUAL_TERMINAL_PROCESSING|ENABLE_PROCESSED_OUTPUT)) SetConsoleMode(std_output, 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 ((sim_ttisatty ()) && (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; |
︙ | ︙ | |||
3594 3595 3596 3597 3598 3599 3600 | SIOUXSettings.asktosaveonclose = FALSE; SIOUXSettings.showstatusline = FALSE; SIOUXSettings.columns = 80; SIOUXSettings.rows = 40; SIOUXSettings.toppixel = 42; SIOUXSettings.leftpixel = 6; iBeamCursorH = GetCursor(iBeamCursor); | | | | 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 | SIOUXSettings.asktosaveonclose = FALSE; SIOUXSettings.showstatusline = FALSE; SIOUXSettings.columns = 80; SIOUXSettings.rows = 40; SIOUXSettings.toppixel = 42; SIOUXSettings.leftpixel = 6; iBeamCursorH = GetCursor(iBeamCursor); strlcat(title, sim_name, sizeof(title)); 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; } |
︙ | ︙ | |||
3879 3880 3881 3882 3883 3884 3885 | } static t_bool sim_os_poll_kbd_ready (int ms_timeout) { fd_set readfds; struct timeval timeout; | | | 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 | } static t_bool sim_os_poll_kbd_ready (int ms_timeout) { fd_set readfds; struct timeval timeout; if (!sim_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; |
︙ | ︙ | |||
3953 3954 3955 3956 3957 3958 3959 | 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)); | > | | 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 | 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_switches = EXP_TYP_PERSIST; sim_set_expect (&sim_con_expect, mbuf); free (mbuf); free (mbuf2); } return SCPE_OK; } |
︙ | ︙ | |||
3976 3977 3978 3979 3980 3981 3982 | uint8 *rbuf; if (cptr == NULL || *cptr == 0) return SCPE_2FARG; /* need arg */ rbuf = (uint8 *)malloc (1 + strlen(cptr)); | | > > < > | > | 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 | uint8 *rbuf; if (cptr == NULL || *cptr == 0) return SCPE_2FARG; /* need arg */ rbuf = (uint8 *)malloc (1 + strlen(cptr)); decode ((char *)rbuf, cptr); /* decode 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? */ char gbuf[CBUFSIZE]; snprintf (gbuf, sizeof (gbuf), "HALTAFTER=%d", val); expect_cmd (1, gbuf); } return r; } |
︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 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> | > > > > > > | 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 | print_sym print symbolic output parse_sym parse symbolic input */ #ifndef SIM_DEFS_H_ #define SIM_DEFS_H_ 0 #include "sim_rev.h" #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 #if defined(__VAX) extern int sim_vax_snprintf(char *buf, size_t buf_size, const char *fmt, ...); #define snprintf sim_vax_snprintf #endif #include <stdarg.h> #include <string.h> #include <errno.h> #include <limits.h> #include <ctype.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> |
︙ | ︙ | |||
175 176 177 178 179 180 181 182 183 | */ #ifndef CONST #define CONST const #endif /* Length specific integer declarations */ #if defined (VMS) #include <ints.h> | > | | | | | | | | > > > > > > > > > > > | 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 | */ #ifndef CONST #define CONST const #endif /* Length specific integer declarations */ /* Handle the special/unusual cases first with everything else leveraging stdints.h */ #if defined (VMS) #include <ints.h> #elif defined(_MSC_VER) && (_MSC_VER < 1600) typedef __int8 int8; typedef __int16 int16; typedef __int32 int32; typedef unsigned __int8 uint8; typedef unsigned __int16 uint16; typedef unsigned __int32 uint32; #else /* All modern/standard compiler environments */ /* any other environment needa a special case above */ #include <stdint.h> typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; #endif /* end standard integers */ typedef int t_stat; /* status */ typedef int t_bool; /* boolean */ /* 64b integers */ #if defined (__GNUC__) /* GCC */ typedef signed long long t_int64; |
︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | #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 */ | > > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | #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 */ #define T_VALUE_MAX 0xffffffffffffffffuLL #else /* 32b data */ typedef int32 t_svalue; typedef uint32 t_value; #define T_VALUE_MAX 0xffffffffUL #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 */ |
︙ | ︙ | |||
405 406 407 408 409 410 411 | /* Convert switch letter to bit mask */ #define SWMASK(x) (1u << (((int) (x)) - ((int) 'A'))) /* String match - at least one character required */ | | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | /* 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)) || 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) */ |
︙ | ︙ | |||
630 631 632 633 634 635 636 | 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 */ | < > > | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | 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 qptr; /* circ q ptr */ size_t str_size; /* structure size */ /* NOTE: Flags MUST always be last since it is initialized outside of macro definitions */ uint32 flags; /* flags */ }; /* Register flags */ #define REG_FMT 00003 /* see PV_x */ #define REG_RO 00004 /* read only */ #define REG_HIDDEN 00010 /* hidden */ |
︙ | ︙ | |||
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 | /* 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 */ | > < > | 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 | /* Expect rule */ struct EXPTAB { uint8 *match; /* match string */ uint32 size; /* match string size */ char *match_pattern; /* match pattern for format */ int32 cnt; /* proceed count */ uint32 after; /* delay before halting */ 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 */ 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 */ uint32 buf_data; /* count of data in buffer */ }; /* Send Context */ struct SEND { uint32 delay; /* instruction delay between sent data */ #define SEND_DEFAULT_DELAY 1000 /* default delay instruction count */ |
︙ | ︙ | |||
835 836 837 838 839 840 841 842 843 844 845 | 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 | > > > > | | > > | > > > > > | > > > > > | > > > > > | > > > > > | > > > > > | > > > > > | < < < < < < | | < > | > > | > | > | > > | > | > | > > > > | > > > | > > > > > > | > > > > > > | > > > > > > | | < < | > | > > | | | > > > > > > | > > > > > > | > | > > | > | > | > > | > | > | > < < < < < < < < < < < < < < < < | 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 | 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 /* Internal use ONLY (see below) Generic Register declaration for all fields */ #define _REGDATANF(nm,loc,rdx,wd,off,dep,desc,flds,qptr,siz) \ nm, (loc), (rdx), (wd), (off), (dep), (desc), (flds), (qptr), (siz) #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 internal macro will be provided that populates the new register structure */ #define REGDATA(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,qptr,siz),(fl) #define REGDATAC(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,qptr,siz),(fl) /* Right Justified Octal Register Data */ #define ORDATA(nm,loc,wd) \ _REGDATANF(#nm,&(loc),8,wd,0,1,NULL,NULL,0,0) #define ORDATAD(nm,loc,wd,desc) \ _REGDATANF(#nm,&(loc),8,wd,0,1,desc,NULL,0,0) #define ORDATADF(nm,loc,wd,desc,flds) \ _REGDATANF(#nm,&(loc),8,wd,0,1,desc,flds,0,0) /* Right Justified Decimal Register Data */ #define DRDATA(nm,loc,wd) \ _REGDATANF(#nm,&(loc),10,wd,0,1,NULL,NULL,0,0) #define DRDATAD(nm,loc,wd,desc) \ _REGDATANF(#nm,&(loc),10,wd,0,1,desc,NULL,0,0) #define DRDATADF(nm,loc,wd,desc,flds) \ _REGDATANF(#nm,&(loc),10,wd,0,1,desc,flds,0,0) /* Right Justified Hexadecimal Register Data */ #define HRDATA(nm,loc,wd) \ _REGDATANF(#nm,&(loc),16,wd,0,1,NULL,NULL,0,0) #define HRDATAD(nm,loc,wd,desc) \ _REGDATANF(#nm,&(loc),16,wd,0,1,desc,NULL,0,0) #define HRDATADF(nm,loc,wd,desc,flds) \ _REGDATANF(#nm,&(loc),16,wd,0,1,desc,flds,0,0) /* Right Justified Binary Register Data */ #define BINRDATA(nm,loc,wd) \ _REGDATANF(#nm,&(loc),2,wd,0,1,NULL,NULL,0,0) #define BINRDATAD(nm,loc,wd,desc) \ _REGDATANF(#nm,&(loc),2,wd,0,1,desc,NULL,0,0) #define BINRDATADF(nm,loc,wd,desc,flds) \ _REGDATANF(#nm,&(loc),2,wd,0,1,desc,flds,0,0) /* One-bit binary flag at an arbitrary offset in a 32-bit word Register */ #define FLDATA(nm,loc,pos) \ _REGDATANF(#nm,&(loc),2,1,pos,1,NULL,NULL,0,0) #define FLDATAD(nm,loc,pos,desc) \ _REGDATANF(#nm,&(loc),2,1,pos,1,desc,NULL,0,0) #define FLDATADF(nm,loc,pos,desc,flds) \ _REGDATANF(#nm,&(loc),2,1,pos,1,desc,flds,0,0) /* Arbitrary location and Radix Register */ #define GRDATA(nm,loc,rdx,wd,pos) \ _REGDATANF(#nm,&(loc),rdx,wd,pos,1,NULL,NULL,0,0) #define GRDATAD(nm,loc,rdx,wd,pos,desc) \ _REGDATANF(#nm,&(loc),rdx,wd,pos,1,desc,NULL,0,0) #define GRDATADF(nm,loc,rdx,wd,pos,desc,flds) \ _REGDATANF(#nm,&(loc),rdx,wd,pos,1,desc,flds,0,0) /* Arrayed register whose data is kept in a standard C array Register */ #define BRDATA(nm,loc,rdx,wd,dep) \ _REGDATANF(#nm,loc,rdx,wd,0,dep,NULL,NULL,0,0) #define BRDATAD(nm,loc,rdx,wd,dep,desc) \ _REGDATANF(#nm,loc,rdx,wd,0,dep,desc,NULL,0,0) #define BRDATADF(nm,loc,rdx,wd,dep,desc,flds) \ _REGDATANF(#nm,loc,rdx,wd,0,dep,desc,flds,0,0) /* Arrayed register whose data is part of the UNIT structure */ #define URDATA(nm,loc,rdx,wd,off,dep,fl) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,NULL,NULL,0,0),((fl) | REG_UNIT) #define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,NULL,0,0),((fl) | REG_UNIT) #define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc,flds) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,0,0),((fl) | REG_UNIT) /* Arrayed register whose data is part of an arbitrary structure */ #define STRDATA(nm,loc,rdx,wd,off,dep,siz,fl) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,NULL,NULL,0,siz),((fl) | REG_STRUCT) #define STRDATAD(nm,loc,rdx,wd,off,dep,siz,fl,desc) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,NULL,0,siz),((fl) | REG_STRUCT) #define STRDATADF(nm,loc,rdx,wd,off,dep,siz,fl,desc,flds) \ _REGDATANF(#nm,&(loc),rdx,wd,off,dep,desc,flds,0,siz),((fl) | REG_STRUCT) #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 # */ /* 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) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,qptr,siz),(fl) #define REGDATAC(nm,loc,rdx,wd,off,dep,desc,flds,fl,qptr,siz) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,qptr,siz),(fl) /* Right Justified Octal Register Data */ #define ORDATA(nm,loc,wd) \ _REGDATANF("nm",&(loc),8,wd,0,1,NULL,NULL,0,0) #define ORDATAD(nm,loc,wd,desc) \ _REGDATANF("nm",&(loc),8,wd,0,1,desc,NULL,0,0) #define ORDATADF(nm,loc,wd,desc,flds) \ _REGDATANF("nm",&(loc),8,wd,0,1,desc,flds,0,0) /* Right Justified Decimal Register Data */ #define DRDATA(nm,loc,wd) \ _REGDATANF("nm",&(loc),10,wd,0,1,NULL,NULL,0,0) #define DRDATAD(nm,loc,wd,desc) \ _REGDATANF("nm",&(loc),10,wd,0,1,desc,NULL,0,0) #define DRDATADF(nm,loc,wd,desc,flds) \ _REGDATANF("nm",&(loc),10,wd,0,1,desc,flds,0,0) /* Right Justified Hexadecimal Register Data */ #define HRDATA(nm,loc,wd) \ _REGDATANF("nm",&(loc),16,wd,0,1,NULL,NULL,0,0) #define HRDATAD(nm,loc,wd,desc) \ _REGDATANF("nm",&(loc),16,wd,0,1,desc,NULL,0,0) #define HRDATADF(nm,loc,wd,desc,flds) \ _REGDATANF("nm",&(loc),16,wd,0,1,desc,flds,0,0) /* Right Justified Binary Register Data */ #define BINRDATA(nm,loc,wd) \ _REGDATANF("nm",&(loc),2,wd,0,1,NULL,NULL,0,0) #define BINRDATAD(nm,loc,wd,desc) \ _REGDATANF("nm",&(loc),2,wd,0,1,desc,NULL,0,0) #define BINRDATADF(nm,loc,wd,desc,flds) \ _REGDATANF("nm",&(loc),2,wd,0,1,desc,flds,0,0) /* One-bit binary flag at an arbitrary offset in a 32-bit word Register */ #define FLDATA(nm,loc,pos) \ _REGDATANF("nm",&(loc),2,1,pos,1,NULL,NULL,0,0) #define FLDATAD(nm,loc,pos,desc) \ _REGDATANF("nm",&(loc),2,1,pos,1,desc,NULL,0,0) #define FLDATADF(nm,loc,pos,desc,flds) \ _REGDATANF("nm",&(loc),2,1,pos,1,desc,flds,0,0) /* Arbitrary location and Radix Register */ #define GRDATA(nm,loc,rdx,wd,pos) \ _REGDATANF("nm",&(loc),rdx,wd,pos,1,NULL,NULL,0,0) #define GRDATAD(nm,loc,rdx,wd,pos,desc) \ _REGDATANF("nm",&(loc),rdx,wd,pos,1,desc,NULL,0,0) #define GRDATADF(nm,loc,rdx,wd,pos,desc,flds) \ _REGDATANF("nm",&(loc),rdx,wd,pos,1,desc,flds,0,0) /* Arrayed register whose data is kept in a standard C array Register */ #define BRDATA(nm,loc,rdx,wd,dep) \ _REGDATANF("nm",loc,rdx,wd,0,dep,NULL,NULL,0,0) #define BRDATAD(nm,loc,rdx,wd,dep,desc) \ _REGDATANF("nm",loc,rdx,wd,0,dep,desc,NULL,0,0) #define BRDATADF(nm,loc,rdx,wd,dep,desc,flds) \ _REGDATANF("nm",loc,rdx,wd,0,dep,desc,flds,0,0) /* Arrayed register whose data is part of the UNIT structure */ #define URDATA(nm,loc,rdx,wd,off,dep,fl) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,NULL,NULL,0,0),((fl) | REG_UNIT) #define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,NULL,0,0),((fl) | REG_UNIT) #define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc,flds) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,0,0),((fl) | REG_UNIT) /* Arrayed register whose data is part of an arbitrary structure */ #define STRDATA(nm,loc,rdx,wd,off,dep,siz,fl) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,NULL,NULL,0,siz),((fl) | REG_STRUCT) #define STRDATAD(nm,loc,rdx,wd,off,dep,siz,fl,desc) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,NULL,0,siz),((fl) | REG_STRUCT) #define STRDATADF(nm,loc,rdx,wd,off,dep,siz,fl,desc,flds) \ _REGDATANF("nm",&(loc),rdx,wd,off,dep,desc,flds,0,siz),((fl) | REG_STRUCT) #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 */ /* Function prototypes */ #include "scp.h" #include "sim_console.h" #include "sim_timer.h" #include "sim_fio.h" |
︙ | ︙ |
︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 | /* 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); } | < | < < | < | | | | < < | | 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 | /* 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); } sim_messagef (SCPE_OK, "%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) { sim_messagef (SCPE_OK, "%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 (r == SCPE_OK) sim_messagef (SCPE_OK, "\n%s%d: Copied %dMB. Done.\n", sim_dname (dptr), (int)(uptr-dptr->units), (int)(((t_offset)lba*sector_size)/1000000)); else sim_messagef (r, "\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) { sim_messagef (SCPE_OK, "%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; |
︙ | ︙ | |||
1435 1436 1437 1438 1439 1440 1441 | if (0 != memcmp (copy_buf, verify_buf, 1024*1024)) r = SCPE_IOERR; } } } if (!sim_quiet) { if (r == SCPE_OK) | | | 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 | if (0 != memcmp (copy_buf, verify_buf, 1024*1024)) r = SCPE_IOERR; } } } if (!sim_quiet) { if (r == SCPE_OK) sim_messagef (r, "\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)) |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 | 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 */ | < | < < | < | | 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 | 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 */ sim_messagef (SCPE_OK, "%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 */ sim_messagef (SCPE_OK, "%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 */ sim_messagef (SCPE_OK, "%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); |
︙ | ︙ | |||
1651 1652 1653 1654 1655 1656 1657 | 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; } | < | < | | 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 | 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; } sim_messagef (SCPE_OK, "%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)); } sim_messagef (SCPE_OK, "%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')) { |
︙ | ︙ | |||
1704 1705 1706 1707 1708 1709 1710 | 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; } } } | < | < | | 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 | 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; } } } sim_messagef (SCPE_OK, "%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)); } sim_messagef (SCPE_OK, "%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)) { |
︙ | ︙ | |||
2153 2154 2155 2156 2157 2158 2159 | } if ((dwStatus >= ERROR_INVALID_STARTING_CODESEG) && (dwStatus <= ERROR_INFLOOP_IN_RELOC_CHAIN)) { errno = ENOEXEC; return; } errno = EINVAL; } | | | 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 | } if ((dwStatus >= ERROR_INVALID_STARTING_CODESEG) && (dwStatus <= ERROR_INFLOOP_IN_RELOC_CHAIN)) { errno = ENOEXEC; return; } errno = EINVAL; } #if defined(__GNUC__) && defined(HAVE_NTDDDISK_H) #include <ddk/ntddstor.h> #include <ddk/ntdddisk.h> #else #include <winioctl.h> #endif #if defined(__cplusplus) |
︙ | ︙ | |||
3639 3640 3641 3642 3643 3644 3645 | 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; } | < | | 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 | 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; } sim_messagef (SCPE_OK, "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)); |
︙ | ︙ | |||
3663 3664 3665 3666 3667 3668 3669 | if (WriteVirtualDiskSectors (Parent, (uint8*)BlockData, BlockSectors, &SectorsWritten, SectorSize, SectorsPerBlock*BlockNumber)) break; | < | < | | 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 | if (WriteVirtualDiskSectors (Parent, (uint8*)BlockData, BlockSectors, &SectorsWritten, SectorSize, SectorsPerBlock*BlockNumber)) break; sim_messagef (SCPE_OK, "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; sim_messagef (SCPE_OK, "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: |
︙ | ︙ |
︙ | ︙ | |||
707 708 709 710 711 712 713 | size_t n; int i, found; found = 0; n = strlen(name); for (i=0; i<count && !found; i++) { if ((n == strlen(list[i].name)) && | | | | 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 | size_t n; int i, found; found = 0; n = strlen(name); for (i=0; i<count && !found; i++) { if ((n == strlen(list[i].name)) && (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)) && (strncasecmp(name, list[i].name, n) == 0)) { found = 1; strcpy(temp, list[i].desc); } } return (found ? temp : NULL); } |
︙ | ︙ | |||
903 904 905 906 907 908 909 | /* 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; | | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | /* 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)) { 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)); |
︙ | ︙ | |||
1134 1135 1136 1137 1138 1139 1140 | 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); | | | | | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 | 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(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA"); p_GetSystemDirectory = (UINT(WINAPI *)(LPTSTR, UINT)) GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetSystemDirectoryA"); if (p_SetDllDirectory && p_GetSystemDirectory) { char npcap_path[512] = ""; if (p_GetSystemDirectory (npcap_path, sizeof(npcap_path) - 7)) 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); } |
︙ | ︙ | |||
1699 1700 1701 1702 1703 1704 1705 | memset(&header, 0, sizeof(header)); header.caplen = header.len = len; _eth_callback((u_char *)opaque, &header, buf); } #endif #if defined (USE_READER_THREAD) | < < | 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 | memset(&header, 0, sizeof(header)); header.caplen = header.len = len; _eth_callback((u_char *)opaque, &header, buf); } #endif #if defined (USE_READER_THREAD) static void * _eth_reader(void *arg) { ETH_DEV* volatile dev = (ETH_DEV*)arg; int status = 0; int sel_ret = 0; int do_select = 0; |
︙ | ︙ | |||
3613 3614 3615 3616 3617 3618 3619 | 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]; | < | 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 | 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 mac[20]; char* buf2; t_stat status; #ifdef USE_BPF struct bpf_program bpf; #endif |
︙ | ︙ | |||
3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 | /* 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)); | > | 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 | /* 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) { char errbuf[PCAP_ERRBUF_SIZE]; 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)); |
︙ | ︙ | |||
3820 3821 3822 3823 3824 3825 3826 | returned by pcap_findalldevs. */ int eth_host_devices(int used, int max, ETH_LIST* list) { pcap_t* conn = NULL; int i, j, datalink = 0; | < > > | 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 | returned by pcap_findalldevs. */ int eth_host_devices(int used, int max, ETH_LIST* list) { pcap_t* conn = NULL; int i, j, datalink = 0; for (i=0; i<used; ++i) { /* Cull any non-ethernet interface types */ #if defined(HAVE_PCAP_NETWORK) char errbuf[PCAP_ERRBUF_SIZE]; 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) |
︙ | ︙ | |||
3921 3922 3923 3924 3925 3926 3927 | return used; } int eth_devices(int max, ETH_LIST* list) { int i = 0; | | | 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 | 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 */ |
︙ | ︙ |
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #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 */ | > > > | 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 | #define PCAP_READ_TIMEOUT -1 #else #define PCAP_READ_TIMEOUT 1 #endif /* set related values to have correct relationships */ #if defined (USE_READER_THREAD) #include <pthread.h> #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 #else #include <time.h> #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 */ |
︙ | ︙ |
︙ | ︙ | |||
371 372 373 374 375 376 377 378 379 380 381 382 383 384 | 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) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | int sim_fseek (FILE *st, t_addr offset, int whence) { return sim_fseeko (st, (t_offset)offset, whence); } #if defined(_WIN32) static const char * GetErrorText(DWORD dwError) { static char szMsgBuffer[2048]; DWORD dwStatus; dwStatus = FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM| FORMAT_MESSAGE_IGNORE_INSERTS, // __in DWORD dwFlags, NULL, // __in_opt LPCVOID lpSource, dwError, // __in DWORD dwMessageId, 0, // __in DWORD dwLanguageId, szMsgBuffer, // __out LPTSTR lpBuffer, sizeof (szMsgBuffer) -1, // __in DWORD nSize, NULL); // __in_opt va_list *Arguments if (0 == dwStatus) snprintf(szMsgBuffer, sizeof(szMsgBuffer) - 1, "Error Code: 0x%lX", dwError); while (sim_isspace (szMsgBuffer[strlen (szMsgBuffer)-1])) szMsgBuffer[strlen (szMsgBuffer) - 1] = '\0'; return szMsgBuffer; } t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing) { if (CopyFileA (source_file, dest_file, !overwrite_existing)) return SCPE_OK; return sim_messagef (SCPE_ARG, "Error Copying '%s' to '%s': %s\n", source_file, dest_file, GetErrorText (GetLastError ())); } #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) |
︙ | ︙ | |||
435 436 437 438 439 440 441 442 443 444 445 446 447 448 | 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; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | int sim_set_fsize (FILE *fptr, t_addr size) { return ftruncate(fileno(fptr), (off_t)size); } #include <sys/stat.h> #include <fcntl.h> #if HAVE_UTIME #include <utime.h> #endif t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing) { FILE *fIn = NULL, *fOut = NULL; t_stat st = SCPE_OK; char *buf = NULL; size_t bytes; fIn = sim_fopen (source_file, "rb"); if (!fIn) { st = sim_messagef (SCPE_ARG, "Can't open '%s' for input: %s\n", source_file, strerror (errno)); goto Cleanup_Return; } fOut = sim_fopen (dest_file, "wb"); if (!fOut) { st = sim_messagef (SCPE_ARG, "Can't open '%s' for output: %s\n", dest_file, strerror (errno)); goto Cleanup_Return; } buf = (char *)malloc (BUFSIZ); while ((bytes = fread (buf, 1, BUFSIZ, fIn))) fwrite (buf, 1, bytes, fOut); Cleanup_Return: free (buf); if (fIn) fclose (fIn); if (fOut) fclose (fOut); #if defined(HAVE_UTIME) if (st == SCPE_OK) { struct stat statb; if (!stat (source_file, &statb)) { struct utimbuf utim; utim.actime = statb.st_atime; utim.modtime = statb.st_mtime; if (utime (dest_file, &utim)) st = SCPE_IOERR; } else st = SCPE_IOERR; } #endif return st; } int sim_set_fifo_nonblock (FILE *fptr) { struct stat stbuf; if (!fptr || fstat (fileno(fptr), &stbuf)) return -1; |
︙ | ︙ | |||
519 520 521 522 523 524 525 | munmap (shmem->shm_base, shmem->shm_size); if (shmem->shm_fd != -1) close (shmem->shm_fd); free (shmem); } #endif | > > > > > > > > > > > > > > > > > | 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | munmap (shmem->shm_base, shmem->shm_size); if (shmem->shm_fd != -1) close (shmem->shm_fd); free (shmem); } #endif #if defined(__VAX) /* * We privide a 'basic' snprintf, which 'might' overrun a buffer, but * the actual use cases don't on other platforms and none of the callers * care about the function return value. */ int sim_vax_snprintf(char *buf, size_t buf_size, const char *fmt, ...) { va_list arglist; va_start (arglist, fmt); vsprintf (buf, fmt, arglist); va_end (arglist); return 0; } #endif |
︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 | 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 */ | > | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 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); t_stat sim_copyfile (const char *source_file, const char *dest_file, t_bool overwrite_existing); 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 */ |
︙ | ︙ |
︙ | ︙ | |||
52 53 54 55 56 57 58 | extern "C" { #endif #include <stdlib.h> #if !defined(__VAX) /* Unsupported platform */ | | | | 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 | extern "C" { #endif #include <stdlib.h> #if !defined(__VAX) /* Unsupported platform */ #define SIM_FRONTPANEL_VERSION 8 /** 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 merely 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). |
︙ | ︙ | |||
190 191 192 193 194 195 196 | /** 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. | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | /** 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 (whenever 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. |
︙ | ︙ | |||
225 226 227 228 229 230 231 | 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 | | > > > > > > > > > > > < > > > > > | 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 | 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. The dithering percentage must be 25% or less and when non 0 causes the sample frequency to vary by plus or minus a random percentage value up to the specified value. sim_panel_set_sampling_parameters sim_panel_set_sampling_parameters_ex sample_frequency cycles/instructions between sample captures sample_dither_pct percentage of sample_frequency to vary randomly 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_ex (PANEL *panel, unsigned int sample_frequency, unsigned int sample_dither_pct, unsigned int sample_depth); 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_start - Start a simulator running instructions after resetting all devices 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_start (PANEL *panel); int sim_panel_exec_run (PANEL *panel); int sim_panel_exec_step (PANEL *panel); /** |
︙ | ︙ | |||
458 459 460 461 462 463 464 | sim_panel_get_state (PANEL *panel); /** All APIs routines which return an int return 0 for success and -1 for an error. | | > > < > < < < > > > > > | 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 | 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 except to possibly set the panel state to Error if the panel condition is no longer useful. 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_mode - Specifies the debug detail to be recorded sim_panel_flush_debug - Flushes debug output to disk sim_panel_debug - Write message to the 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 */ #define DBG_THR 16 /* Thread Activities */ #define DBG_APP 32 /* Application Activities */ void sim_panel_set_debug_mode (PANEL *panel, int debug_bits); void sim_panel_debug (PANEL *panel, const char *fmt, ...); void sim_panel_flush_debug (PANEL *panel); #endif /* !defined(__VAX) */ #ifdef __cplusplus } #endif #endif /* SIM_FRONTPANEL_H_ */ |
1 2 | /* sim_serial.c: OS-dependent serial port routines | | | 1 2 3 4 5 6 7 8 9 10 | /* sim_serial.c: OS-dependent serial port routines Copyright (c) 2008, J. David Bryan, 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: |
︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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 | > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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 22-Apr-12 MP Adapted from code originally written by J. David Bryan 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 |
︙ | ︙ | |||
298 299 300 301 302 303 304 | size_t n; int i, found; found = 0; n = strlen(name); for (i=0; i<count && !found; i++) { if ((n == strlen(list[i].name)) && | | | | 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 | size_t n; int i, found; found = 0; n = strlen(name); for (i=0; i<count && !found; i++) { if ((n == strlen(list[i].name)) && (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)) && (strncasecmp(name, list[i].name, n) == 0)) { found = 1; strcpy(temp, list[i].desc); } } return (found ? temp : NULL); } |
︙ | ︙ | |||
875 876 877 878 879 880 881 | "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) { | < < < < < < < < | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 | "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 ((!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 */ } return count; /* return number of characters written/queued */ } /* Close a serial port. |
︙ | ︙ |
1 2 | /* sim_serial.h: OS-dependent serial port routines header file | | | 1 2 3 4 5 6 7 8 9 10 | /* sim_serial.h: OS-dependent serial port routines header file Copyright (c) 2008, J. David Bryan, 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: |
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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 | > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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 22-Apr-12 MP Adapted from code originally written by J. David Bryan */ #ifndef SIM_SERIAL_H_ #define SIM_SERIAL_H_ 0 #ifdef __cplusplus |
︙ | ︙ |
︙ | ︙ | |||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 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 | > > | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 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_errecf erase record forward sim_tape_errecr erase record reverse 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 |
︙ | ︙ | |||
316 317 318 319 320 321 322 | 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 */ | > > > | > > > > > > | 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 | 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->asynch_io) pthread_mutex_lock (&ctx->io_lock); if (ctx->callback) { ctx->callback = NULL; if (ctx->asynch_io) pthread_mutex_unlock (&ctx->io_lock); callback (uptr, ctx->io_status); } else { if (ctx->asynch_io) pthread_mutex_unlock (&ctx->io_lock); } } static t_bool _tape_is_active (UNIT *uptr) { struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; if (ctx) { |
︙ | ︙ | |||
363 364 365 366 367 368 369 | /* Enable asynchronous operation */ t_stat sim_tape_set_async (UNIT *uptr, int latency) { #if !defined(SIM_ASYNCH_IO) | | < | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | /* Enable asynchronous operation */ t_stat sim_tape_set_async (UNIT *uptr, int latency) { #if !defined(SIM_ASYNCH_IO) return sim_messagef (SCPE_NOFNC, "Tape: can't operate asynchronously\r\n"); #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) { |
︙ | ︙ | |||
442 443 444 445 446 447 448 | t_stat sim_tape_attach (UNIT *uptr, CONST char *cptr) { DEVICE *dptr; if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; | | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | 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) || (dptr->debflags)) ? 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; |
︙ | ︙ | |||
603 604 605 606 607 608 609 | if (ctx == NULL) return; if (sim_deb && (ctx->dptr->dctrl & reason)) sim_data_trace(ctx->dptr, uptr, (detail ? data : NULL), "", len, txt, reason); } | | | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | 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 |
︙ | ︙ | |||
626 627 628 629 630 631 632 | 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. | | | | > | > > > > | | < | | | | | | < < | > > | > | > | | | | | | | | | | > | > > > > | | | | | | > > | > | | | | | > | | | < > | | | > | > > | > | | | | > > | | | | | > | | > > > > > > > > > > > > > > | > | | | 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 | 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.22, 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 or EOF 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 "tape_erase_fwd" 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 "tape_erase_fwd" 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 "runaway_counter" cannot decrement to zero (or below) in the presence of an error that terminates the gap-search loop. Therefore, the test after the loop exit need not check for error status. 4. 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 5. 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) { 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 status = 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 (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the initial tape position; if it fails */ MT_SET_PNU (uptr); /* then set position not updated */ status = sim_tape_ioerr (uptr); /* and quit with I/O error status */ } else switch (f) { /* otherwise 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 */ status = MTSE_RUNAWAY; /* then report a tape runaway */ else /* otherwise report the physical EOF */ status = 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 */ status = 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 */ status = 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 */ status = MTSE_RUNAWAY; /* then report a tape runaway */ else /* otherwise report the physical EOF */ status = 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 */ status = MTSE_RUNAWAY; /* then report a tape runaway */ else /* otherwise report the physical EOF */ status = 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 */ status = 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 and resync */ if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the tape position; if it fails */ status = sim_tape_ioerr (uptr); /* then quit with I/O error status */ break; } 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; if it fails */ status = sim_tape_ioerr (uptr); /* then quit with I/O error status */ break; } 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 (runaway_counter <= 0) /* if a tape runaway occurred */ status = 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 */ status = sim_tape_ioerr (uptr); } else if (feof (uptr->fileref)) { /* eof? */ MT_SET_PNU (uptr); /* pos not upd */ status = MTSE_EOM; } else { uptr->pos = uptr->pos + sizeof (t_tpclnt); /* spc over reclnt */ if (tpcbc == TPC_TMK) /* tape mark? */ status = MTSE_TMK; else 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 */ status = sim_tape_ioerr (uptr); break; } else if (feof (uptr->fileref)) { /* eof? */ if (sbc == 0) /* no data? eom */ status = MTSE_EOM; break; /* treat like eor */ } else if ((sbc != 0) && (c & P7B_SOR)) /* next record? */ break; else if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0; } if (status == MTSE_OK) { *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? */ status = MTSE_TMK; } break; default: status = MTSE_FMT; } return status; } static t_stat sim_tape_rdrlfwd (UNIT *uptr, t_mtrlnt *bc) { struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; t_stat status; if (ctx == NULL) /* if not properly attached? */ return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */ status = sim_tape_rdlntf (uptr, bc); /* read the record length */ sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", status, *bc, uptr->pos); return status; } /* Read record length reverse (internal routine). Inputs: uptr = pointer to tape unit bc = pointer to returned record length Outputs: status = operation status |
︙ | ︙ | |||
895 896 897 898 899 900 901 | 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. | > > > > > > > > > | | < | | | | | | | < < | | | | | | > > > | > > > > | | | > > | > | | < | < < < < | > | | > > > > | | > | | | | < | | | | < | > > | | > > | | > | | | | | > > > | | | | | > | > > > > > > > > > > > > > > | > | | 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 | 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. Implementation notes: 1. The "sim_fread" call cannot return 0 in the absence of an error condition. The preceding "sim_tape_bot" test ensures that "pos" >= 4, so "sim_fseek" will back up at least that far, so "sim_fread" will read at least one element. If the call returns zero, an error must have occurred, so the "ferror" call must succeed. 2. See the notes at "sim_tape_rdlntf" and "tape_erase_fwd" regarding tape runaway and the erase gap implementation, respectively. */ static t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc) { 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 status = 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 (sim_tape_bot (uptr)) /* if the unit is positioned at the BOT */ status = MTSE_BOT; /* then reading backward is not possible */ else switch (f) { /* otherwise 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 == 0) { /* if the buffer is empty then refill it */ if (sim_tape_bot (uptr)) { /* if the search has backed into the BOT */ status = MTSE_BOT; /* then quit with an error */ break; } else if (bufcap == 0) /* otherwise if this is the initial read */ bufcap = 1; /* then start with just one marker */ else if (uptr->pos < sizeof (buffer)) /* otherwise if less than a full buffer remains */ bufcap = (uint32) uptr->pos /* then reduce the capacity accordingly */ / sizeof (t_mtrlnt); else /* otherwise reset the capacity */ bufcap = sizeof (buffer) /* to the full size of the buffer */ / sizeof (buffer [0]); if (sim_fseek (uptr->fileref, /* seek back to the location */ uptr->pos - bufcap * sizeof (t_mtrlnt), /* corresponding to the start */ SEEK_SET)) { /* of the buffer; if it fails */ status = sim_tape_ioerr (uptr); /* and fail with I/O error status */ break; } 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 */ status = sim_tape_ioerr (uptr); /* then report the error and quit */ break; } } *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 */ status = 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 */ if (sim_fseek (uptr->fileref, /* seek to the start of the data area; if it fails */ uptr->pos + sizeof (t_mtrlnt), /* then return with I/O error status */ SEEK_SET)) { status = sim_tape_ioerr (uptr); break; } } } while (*bc == MTR_GAP && runaway_counter > 0); /* continue until data or runaway occurs */ if (runaway_counter <= 0) /* if a tape runaway occurred */ status = 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? */ status = sim_tape_ioerr (uptr); else if (feof (uptr->fileref)) /* eof? */ status = MTSE_EOM; else { uptr->pos = ppos; /* spc over record */ if (*bc == MTR_TMK) /* tape mark? */ status = MTSE_TMK; else 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? */ status = sim_tape_ioerr (uptr); break; } else if (feof (uptr->fileref)) { /* eof? */ status = MTSE_EOM; break; } else { if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0; if (c & P7B_SOR) /* start of record? */ break; } } if (status == MTSE_OK) { 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? */ status = MTSE_TMK; } break; default: status = MTSE_FMT; } return status; } static t_stat sim_tape_rdrlrev (UNIT *uptr, t_mtrlnt *bc) { struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; t_stat status; if (ctx == NULL) /* if not properly attached? */ return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */ status = sim_tape_rdlntr (uptr, bc); /* read the record length */ sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", status, *bc, uptr->pos); return status; } /* Read record forward Inputs: uptr = pointer to tape unit buf = pointer to buffer |
︙ | ︙ | |||
1087 1088 1089 1090 1091 1092 1093 | 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 */ | | > | | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 | 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 */ st = sim_tape_rdrlfwd (uptr, &tbc); /* read rec lnt */ if (st != MTSE_OK) 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; |
︙ | ︙ | |||
1152 1153 1154 1155 1156 1157 1158 | 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); | | > | | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 | 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); st = sim_tape_rdrlrev (uptr, &tbc); /* read rec lnt */ if (st != MTSE_OK) 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); |
︙ | ︙ | |||
1359 1360 1361 1362 1363 1364 1365 | 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; } | < < < | < > > | | | | | | | | | > > > > > | | | | < < < < < < < < < | < | 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 | 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; } /* Erase a gap in the forward direction (internal routine). An erase gap is written in the forward direction on the tape unit specified by "uptr" for the number of bytes specified by "bc". The status of the operation is returned, and the file position is altered as follows: Exit Condition File Position ------------------ ------------------ unit unattached unchanged unsupported format unchanged write protected unchanged read error unchanged, PNU set write error unchanged, PNU set gap written updated If the requested byte count equals the metadatum size, then the routine succeeds only if it can overlay a single metadatum (i.e., a tape mark, an end-of-medium marker, or an existing erase gap marker); otherwise, the file position is not altered, PNU is set, and MTSE_INVRL (invalid record length) status is returned. An erase gap is represented in the tape image file by a special metadata value repeated throughout the gap. The 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. 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. 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 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). |
︙ | ︙ | |||
1448 1449 1450 1451 1452 1453 1454 | 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) | < | | < < < < | | | > > > > > > | < > | < | | | > | | | < < < < < | < < < < < | > | > > | > | > | | | | > > > > > > > | > > > > > > > | > > < | | | > > | > > | 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 | 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 current tape format supports erase gaps, then this routine will write a gap of the requested size. If the format does not, then no action will be taken, and MTSE_OK status will be returned. 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. A request for an erase gap of zero length also succeeds with no action taken. Implementation notes: 1. Erase gaps are currently supported only in SIMH (MTUF_F_STD) tape format. */ static t_stat tape_erase_fwd (UNIT *uptr, t_mtrlnt gap_size) { size_t xfer; t_stat st; t_mtrlnt meta, sbc, new_len, rec_size; uint32 file_size, marker_count; int32 gap_needed = (int32) gap_size; /* the gap remaining to be allocated from the tape */ uint32 gap_alloc = 0; /* the gap currently allocated from the tape */ const t_addr gap_pos = uptr->pos; /* the file position where the gap will start */ const uint32 format = MT_GET_FMT (uptr); /* the tape format */ const uint32 meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */ const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2; /* the smallest data record size */ 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 */ else if (gap_size == 0 || format != MTUF_F_STD) /* otherwise if zero length or gaps aren't supported */ return MTSE_OK; /* then take no action */ file_size = sim_fsize (uptr->fileref); /* get the file size */ if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* position the tape; if it fails */ MT_SET_PNU (uptr); /* then set position not updated */ return sim_tape_ioerr (uptr); /* and quit with I/O error status */ } /* Read tape records and allocate them to the gap until the amount required is consumed. Read the 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 the bytes needed = 0. */ do { xfer = sim_fread (&meta, meta_size, 1, uptr->fileref); /* read a 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 if (xfer != 1 && feof (uptr->fileref) == 0) { /* otherwise if a partial metadatum was read */ uptr->pos = gap_pos; /* then restore the original position */ MT_SET_PNU (uptr); /* set the position-not-updated flag */ return MTSE_INVRL; /* and return an invalid record length error */ } else /* otherwise we had a good read */ uptr->pos = uptr->pos + meta_size; /* so move the tape over the 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 (gap_size == meta_size) { /* otherwise if the request is for a single metadatum */ uptr->pos = gap_pos; /* then restore the original position */ MT_SET_PNU (uptr); /* set the position-not-updated flag */ return MTSE_INVRL; /* and return an invalid record length error */ } else if (meta == MTR_FHGAP) { /* half gap? */ uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */ if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */ 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 */ if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */ 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 */ |
︙ | ︙ | |||
1582 1583 1584 1585 1586 1587 1588 | } gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ gap_needed = 0; } } } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | > | 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 | } gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ gap_needed = 0; } } } while (gap_needed > 0); /* loop until all of the gap has been allocated */ 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; } /* Erase a gap in the reverse direction (internal routine). An erase gap is written in the reverse direction on the tape unit specified by "uptr" for the number of bytes specified by "bc". The status of the operation is returned, and the file position is altered as follows: Exit Condition File Position ------------------ ------------------ unit unattached unchanged unsupported format unchanged write protected unchanged read error unchanged, PNU set write error unchanged, PNU set gap written updated If the requested byte count equals the metadatum size, then the routine succeeds only if it can overlay a single metadatum (i.e., a tape mark or an existing erase gap marker); otherwise, the file position is not altered, and MTSE_INVRL (invalid record length) status is returned. Implementation notes: 1. Erase gaps are currently supported only in SIMH (MTUF_F_STD) tape format. 2. Erasing a record in the reverse direction currently succeeds only if the gap requested occupies the same space as the record located immediately before the current file position. This limitation may be lifted in a future update. 3. The "sim_fread" call cannot return 0 in the absence of an error condition. The preceding "sim_tape_bot" test ensures that "pos" >= 4, so "sim_fseek" will back up at least that far, so "sim_fread" will read at least one element. If the call returns zero, an error must have occurred, so the "ferror" call must succeed. */ static t_stat tape_erase_rev (UNIT *uptr, t_mtrlnt gap_size) { const uint32 format = MT_GET_FMT (uptr); /* the tape format */ const uint32 meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */ t_stat status; t_mtrlnt rec_size, metadatum; t_addr gap_pos; size_t xfer; 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 we cannot proceed */ else if (sim_tape_wrp (uptr)) /* otherwise if the unit is write protected */ return MTSE_WRP; /* then we cannot write */ else if (gap_size == 0 || format != MTUF_F_STD) /* otherwise if the gap length is zero or unsupported */ return MTSE_OK; /* then take no action */ gap_pos = uptr->pos; /* save the starting position */ if (gap_size == meta_size) { /* if the request is for a single metadatum */ if (sim_tape_bot (uptr)) /* then if the unit is positioned at the BOT */ return MTSE_BOT; /* then erasing backward is not possible */ else /* otherwise */ uptr->pos -= meta_size; /* back up the file pointer */ if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */ sim_fread (&metadatum, meta_size, 1, uptr->fileref); /* read a metadatum */ if (ferror (uptr->fileref)) /* if a file I/O error occurred */ return sim_tape_ioerr (uptr); /* then report the error and quit */ else if (metadatum == MTR_TMK) /* otherwise if a tape mark is present */ if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* then reposition the tape; if it fails */ return sim_tape_ioerr (uptr); /* then quit with I/O error status */ else { /* otherwise */ metadatum = MTR_GAP; /* replace it with an erase gap marker */ xfer = sim_fwrite (&metadatum, meta_size, /* write the gap marker */ 1, uptr->fileref); if (ferror (uptr->fileref) || xfer == 0) /* if a file I/O error occurred */ return sim_tape_ioerr (uptr); /* report the error and quit */ else /* otherwise the write succeeded */ status = MTSE_OK; /* so return success */ } else if (metadatum == MTR_GAP) /* otherwise if a gap already exists */ status = MTSE_OK; /* then take no additional action */ else { /* otherwise a data record is present */ uptr->pos = gap_pos; /* so restore the starting position */ return MTSE_INVRL; /* and fail with invalid record length status */ } } else { /* otherwise it's an erase record request */ status = sim_tape_rdlntr (uptr, &rec_size); /* so get the length of the preceding record */ if (status == MTSE_OK /* if the read succeeded */ && gap_size == rec_size + 2 * meta_size) { /* and the gap will exactly overlay the record */ gap_pos = uptr->pos; /* then save the gap start position */ status = tape_erase_fwd (uptr, gap_size); /* erase the record */ if (status == MTSE_OK) /* if the gap write succeeded */ uptr->pos = gap_pos; /* the reposition back to the start of the gap */ } else { /* otherwise the read failed or is the wrong size */ uptr->pos = gap_pos; /* so restore the starting position */ if (status != MTSE_OK) /* if the record was not found */ return status; /* then return the failure reason */ else /* otherwise the record is the wrong size */ return MTSE_INVRL; /* so report an invalid record length */ } } return status; /* return the status of the erase operation */ } /* Write an erase gap. An erase gap is written in on the tape unit specified by "uptr" for the length specified by "gap_size" in tenths of an inch, and the status of the operation is returned. The tape density must have been set via a previous sim_tape_set_dens call; if it has not, then no action is taken, and MTSE_IOERR is returned. If the requested gap length is zero, or the tape format currently selected does not support erase gaps, the call succeeds with no action taken. 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. Because SIMH tape images do not carry physical parameters (e.g., recording density), overwriting a tape image file containing a gap 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. */ t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen) { struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; const uint32 density = bpi [MT_DENS (uptr->dynflags)]; /* the tape density in bits per inch */ const uint32 byte_length = (gaplen * density) / 10; /* the size of the requested gap in bytes */ 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); if (density == 0) /* if the density has not been set */ return MTSE_IOERR; /* then report an I/O error */ else /* otherwise */ return tape_erase_fwd (uptr, byte_length); /* erase the requested gap size in bytes */ } 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. If a length of 0 is specified, then the metadatum marker at the current tape position will be erased. If the tape is not positioned at a metadatum marker, the routine fails with MTSE_INVRL, and the tape position is unchanged. */ 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 */ if (bc == 0) /* if a zero-length erase is requested */ return tape_erase_fwd (uptr, meta_size); /* then erase a metadatum marker */ else /* otherwise */ return tape_erase_fwd (uptr, gap_size); /* erase the requested gap */ } /* 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. If a length of 0 is specified, then the metadatum marker preceding the current tape position will be erased. If the tape is not positioned after a metadatum marker, the routine fails with MTSE_INVRL, and the tape position is unchanged. */ 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 */ if (bc == 0) /* if a zero-length erase is requested */ return tape_erase_rev (uptr, meta_size); /* then erase a metadatum marker */ else /* otherwise */ return tape_erase_rev (uptr, gap_size); /* erase the requested gap */ } /* Space record forward Inputs: uptr = pointer to tape unit bc = pointer to size of record skipped |
︙ | ︙ | |||
1684 1685 1686 1687 1688 1689 1690 | 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)); | | | 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 | 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_rdrlfwd (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; |
︙ | ︙ | |||
1779 1780 1781 1782 1783 1784 1785 | 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; } | | | 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 | 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_rdrlrev (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; |
︙ | ︙ | |||
1877 1878 1879 1880 1881 1882 1883 | 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; | | | | 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 | 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_rdrlrev (uptr, &rbc); last_tapemark = (MTSE_TMK == st); if ((st == MTSE_OK) || (st == MTSE_TMK)) sim_tape_rdrlfwd (uptr, &rbc); } *skipped = 0; *recsskipped = 0; while (*skipped < count) { /* loopo */ while (1) { st = sim_tape_sprecsf (uptr, 0x1ffffff, &filerecsskipped);/* spc recs */ *recsskipped += filerecsskipped; |
︙ | ︙ | |||
2392 2393 2394 2395 2396 2397 2398 | 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. | | | 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 | 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 |
︙ | ︙ |
︙ | ︙ | |||
157 158 159 160 161 162 163 164 165 166 167 168 169 170 | 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; | > | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | 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 double sim_timer_stop_time = 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; |
︙ | ︙ | |||
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 | 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++) | > > > > > | 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 | 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_stop_unit; /* Stop unit */ 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); t_stat sim_timer_stop_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*/ #define DBG_INT 0x200 /* internal timer activities */ 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"}, {"INTER", DBG_INT, "Internal timer 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; extern DEVICE sim_stop_dev; void sim_rtcn_init_all (void) { int32 tmr; for (tmr = 0; tmr <= SIM_NTIMERS; tmr++) |
︙ | ︙ | |||
896 897 898 899 900 901 902 | 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 */ | < < < < < < < | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 | 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 (!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 internal 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) */ |
︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | 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 */ | > | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | 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_stop_unit.action = &sim_timer_stop_svc; 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 */ |
︙ | ︙ | |||
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | 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)) { | > > > > > > > > > > > > > > > > > > > > | 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 | 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 stop time */ t_stat sim_timer_set_stop (int32 flag, CONST char *cptr) { t_stat r; t_value stop_time; if (cptr == NULL) return SCPE_ARG; stop_time = get_uint (cptr, 10, T_VALUE_MAX, &r); if (r != SCPE_OK) return r; if (stop_time <= (t_value)sim_gtime()) return SCPE_ARG; sim_register_internal_device (&sim_stop_dev); /* Register Stop Device */ sim_timer_stop_time = (double)stop_time; sim_activate_abs (&sim_stop_unit, (int32)(sim_timer_stop_time - sim_gtime())); 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)) { |
︙ | ︙ | |||
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 | #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, | > > > > > > | > > > > > > > > > | | > > | 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 | #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 }, { "STOP", &sim_timer_set_stop, 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_int_stop_description (DEVICE *dptr) { return "Stop facility"; } 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_stop_dev = { "INT-STOP", &sim_stop_unit, NULL, NULL, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, DEV_NOSAVE, 0, NULL, NULL, NULL, NULL, NULL, NULL, sim_int_stop_description}; DEVICE sim_throttle_dev = { "INT-THROTTLE", &sim_throttle_unit, sim_throttle_reg, NULL, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, DEV_NOSAVE}; /* SET CLOCK command */ t_stat sim_set_timers (int32 arg, CONST char *cptr) { char *cvptr, gbuf[CBUFSIZE]; CTAB *ctptr; |
︙ | ︙ | |||
1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 | 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 */ | > > > > > | | 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 | 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_throt_state = SIM_THROT_STATE_THROTTLE; /* force state */ sim_throt_wait = sim_throt_val; } } sim_register_internal_device (&sim_throttle_dev); /* Register Throttle Device */ if (sim_throt_type == SIM_THROT_SPC) /* Set initial value while correct one is determined */ sim_throt_cps = (int32)((1000.0 * sim_throt_val) / (double)sim_throt_sleep_time); else sim_throt_cps = SIM_INITIAL_IPS; 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"); |
︙ | ︙ | |||
1631 1632 1633 1634 1635 1636 1637 | 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: | > | | 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 | 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: %d/%d\n", sim_throt_val, sim_throt_sleep_time); fprintf (st, "Throttling by sleeping for: %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) { |
︙ | ︙ | |||
1673 1674 1675 1676 1677 1678 1679 | */ t_stat sim_throt_svc (UNIT *uptr) { int32 tmr; uint32 delta_ms; double a_cps, d_cps; | < < < < | > | | > > > > > > | 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 | */ t_stat sim_throt_svc (UNIT *uptr) { int32 tmr; uint32 delta_ms; double a_cps, d_cps; switch (sim_throt_state) { case SIM_THROT_STATE_INIT: /* take initial reading */ sim_idle_ms_sleep (sim_idle_rate_ms); /* start on a tick boundary to calibrate */ sim_throt_ms_start = sim_os_msec (); sim_throt_inst_start = sim_gtime(); if (sim_throt_type != SIM_THROT_SPC) { /* dynamic? */ sim_throt_wait = SIM_THROT_WST; sim_throt_state = SIM_THROT_STATE_TIME; /* next state */ } else { /* Non dynamic? */ sim_throt_wait = sim_throt_val; sim_throt_state = SIM_THROT_STATE_THROTTLE; /* force state */ sim_throt_cps = (int32)((1000.0 * sim_throt_val) / (double)sim_throt_sleep_time); } 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? */ |
︙ | ︙ | |||
1746 1747 1748 1749 1750 1751 1752 | } } break; case SIM_THROT_STATE_THROTTLE: /* throttling */ sim_idle_ms_sleep (sim_throt_sleep_time); delta_ms = sim_os_msec () - sim_throt_ms_start; | < | | > | > < > > > > | < | > | 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 | } } 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 (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_SPC) { /* when not dynamic throttling */ 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_inst_start = sim_gtime(); } else { /* record instruction rate */ sim_throt_cps = (int32)a_cps; sim_debug (DBG_THR, &sim_timer_dev, "sim_throt_svc() Recalibrating Special %d/%u Cycles Per Second of %f\n", sim_throt_wait, sim_throt_sleep_time, sim_throt_cps); } sim_throt_ms_start = sim_os_msec (); } break; } sim_activate (uptr, sim_throt_wait); /* reschedule */ return SCPE_OK; } |
︙ | ︙ | |||
1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 | 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 { | > > > > | < < < > > > > > > > > > > < | | < < > > > > > > | 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 | 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)) { UNIT *sptr = sim_clock_cosched_queue[tmr]; UNIT *cptr = 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; } /* First gather the queued events that are scheduled for now */ do { cptr = sim_clock_cosched_queue[tmr]; sim_clock_cosched_queue[tmr] = cptr->next; 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; } while ((sim_cosched_interval[tmr] <= 0) && (sim_clock_cosched_queue[tmr] != QUEUE_LIST_END)); if (cptr != QUEUE_LIST_END) cptr->next = QUEUE_LIST_END; /* Now dispatch that list (in order). */ while (sptr != QUEUE_LIST_END) { cptr = sptr; sptr = sptr->next; cptr->next = NULL; cptr->cancel = NULL; cptr->time = 0; if (cptr->usecs_remaining) { sim_debug (DBG_QUE, &sim_timer_dev, " remnant: %.0f - next %s after cosched interval: %d ticks\n", cptr->usecs_remaining, (sptr != QUEUE_LIST_END) ? sim_uname (sptr) : "", 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", (sptr != QUEUE_LIST_END) ? sim_uname (sptr) : "", sim_cosched_interval[tmr]); _sim_activate (cptr, 0); } } } return stat; } t_stat sim_timer_stop_svc (UNIT *uptr) { return SCPE_STOP; } 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); } |
︙ | ︙ | |||
2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 | #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 | > | 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 | #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_debug(DBG_INT, &sim_timer_dev, "sim_timer_clock_tick_svc()\n"); 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 |
︙ | ︙ | |||
2120 2121 2122 2123 2124 2125 2126 | 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; | | | | 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 | 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|DBG_INT, &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|DBG_INT, &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 { |
︙ | ︙ | |||
2159 2160 2161 2162 2163 2164 2165 | _sim_coschedule_cancel (uptr); _sim_activate (uptr, 1); uptr->usecs_remaining = usecs_remaining; } rtc_hz[sim_calb_tmr] = 0; /* back to 0 */ } | | > > > | 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 | _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|DBG_INT, &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; sim_stop_dev.description = &sim_int_stop_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 (sim_timer_stop_time > sim_gtime()) sim_activate_abs (&sim_stop_unit, (int32)(sim_timer_stop_time - sim_gtime())); #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); |
︙ | ︙ | |||
2217 2218 2219 2220 2221 2222 2223 | 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 */ | > | < | 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 | 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 */ if (sim_is_active (&sim_timer_units[tmr])) { sim_cancel (&sim_timer_units[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]; |
︙ | ︙ | |||
2353 2354 2355 2356 2357 2358 2359 | 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? */ | | | 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 | 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; |
︙ | ︙ |
︙ | ︙ | |||
460 461 462 463 464 465 466 | { 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 */ | | | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | { 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 = lp->txstall = 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); |
︙ | ︙ | |||
528 529 530 531 532 533 534 | 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)); | | > > > > > > > > > | 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 | 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 = lp->txstall = 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 */ if ((lp->serport) && (!sim_is_running)) { sim_os_ms_sleep (TMXR_DTR_DROP_TIME); /* Wait for DTR to be noticed */ lp->ser_connect_pending = FALSE; /* Mark line as ready for action */ lp->conn = TRUE; } tmxr_linemsg (lp, msgbuf); /* beginning of buffer */ lp->txbpi = psave; /* restore insertion pointer */ unwritten = tmxr_send_buffered_data (lp); /* send the message */ if ((lp->serport) && (!sim_is_running)) { lp->ser_connect_pending = TRUE; /* Mark line as not yet ready for action */ lp->conn = FALSE; } if (unwritten == 0) /* buffer now empty? */ lp->xmte = 1; /* reenable transmission if paused */ lp->txcnt -= (int32)strlen (msgbuf); /* adjust statistics */ return; } |
︙ | ︙ | |||
693 694 695 696 697 698 699 | int32 written; int32 i = lp->txbpr; if (lp->loopback) return loop_write (lp, &(lp->txb[i]), length); if (lp->serport) { /* serial port connection? */ | | | | | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | 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) && (sim_is_running)) return 0; written = sim_write_serial (lp->serport, &(lp->txb[i]), length); if ((written > 0) && (sim_is_running)) lp->txnexttime = floor (sim_gtime () + (written * 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) |
︙ | ︙ | |||
2052 2053 2054 2055 2056 2057 2058 2059 2060 | 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 */ } | > > > > > | | 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 | 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 */ if ((sim_interval > 0) && /* not called within sim_process_event? */ (lp->txbps) && (lp->txdelta > 1000)) { /* and rate limiting output slower than 1000 cps */ tmxr_send_buffered_data (lp); /* put data on wire */ sim_os_ms_sleep((lp->txdelta - 1000) / 1000); /* wait an approximate character delay */ } return SCPE_OK; /* char sent */ } ++lp->txstall; lp->xmte = 0; /* no room, dsbl line */ return SCPE_STALL; /* char not sent */ } /* Store packet in line buffer Inputs: *lp = pointer to line descriptor |
︙ | ︙ | |||
2385 2386 2387 2388 2389 2390 2391 | 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; | < | 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 | 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; 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; |
︙ | ︙ | |||
2439 2440 2441 2442 2443 2444 2445 | 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"); | | | 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 | 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"); strlcpy(logfiletmpl, cptr, sizeof(logfiletmpl)); 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; |
︙ | ︙ | |||
2505 2506 2507 2508 2509 2510 2511 | 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"); | | | | 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 | 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"); strlcpy (destination, cptr, sizeof(destination)); 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 : "")); strlcpy (speed, cptr, sizeof(speed)); 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); |
︙ | ︙ | |||
2563 2564 2565 2566 2567 2568 2569 | 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)); | | | 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 | 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)); strlcpy (hostport, destination, sizeof(hostport)); 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 |
︙ | ︙ | |||
2590 2591 2592 2593 2594 2595 2596 | 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]) { | | > | | | 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 | 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]) { strlcpy(mp->logfiletmpl, logfiletmpl, sizeof(mp->logfiletmpl)); 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); lp->txlogname[CBUFSIZE-1] = '\0'; if (mp->lines > 1) snprintf(lp->txlogname, CBUFSIZE-1, "%s_%d", mp->logfiletmpl, i); else strlcpy (lp->txlogname, mp->logfiletmpl, CBUFSIZE); r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref); if (r != SCPE_OK) { free (lp->txlogname); lp->txlogname = NULL; break; } } |
︙ | ︙ | |||
2650 2651 2652 2653 2654 2655 2656 | 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; } | < | | 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 | 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; } sim_messagef (SCPE_OK, "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; |
︙ | ︙ | |||
2684 2685 2686 2687 2688 2689 2690 | 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"); | < | | 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 | 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"); sim_messagef (SCPE_OK, "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); } } |
︙ | ︙ | |||
2716 2717 2718 2719 2720 2721 2722 | 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 */ | | < < | 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 | 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 */ 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 */ |
︙ | ︙ | |||
2803 2804 2805 2806 2807 2808 2809 | 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); | < | | 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 | 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); sim_messagef (SCPE_OK, "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; |
︙ | ︙ | |||
2826 2827 2828 2829 2830 2831 2832 | 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 */ | | < < | 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 | 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 */ 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 */ |
︙ | ︙ | |||
2862 2863 2864 2865 2866 2867 2868 | } 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); | < | | 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 | } 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); sim_messagef (SCPE_OK, "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; } } |
︙ | ︙ | |||
3533 3534 3535 3536 3537 3538 3539 | 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++) | | < | 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 | 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++) mux->ldsc[i].send.after = mux->ldsc[i].send.delay = 0; } #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 } |
︙ | ︙ | |||
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 | 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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | 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 | 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); } static const char *_tmxr_send_expect_line_name (const SEND *snd, const EXPECT *exp) { static char line_name[CBUFSIZE]; int i, j; strcpy (line_name, ""); for (i=0; i<tmxr_open_device_count; ++i) for (j=0; j<tmxr_open_devices[i]->lines; ++j) if ((snd == &tmxr_open_devices[i]->ldsc[j].send) || (exp == &tmxr_open_devices[i]->ldsc[j].expect)) { if (tmxr_open_devices[i]->lines > 1) snprintf (line_name, sizeof (line_name), "%s:%d", tmxr_open_devices[i]->ldsc[j].send.dptr->name, j); else strlcpy (line_name, tmxr_open_devices[i]->ldsc[j].send.dptr->name, sizeof (line_name)); break; } return line_name; } const char *tmxr_send_line_name (const SEND *snd) { if (snd == sim_cons_get_send ()) return "CONSOLE"; else return _tmxr_send_expect_line_name (snd, NULL); } const char *tmxr_expect_line_name (const EXPECT *exp) { if (exp == sim_cons_get_expect ()) return "CONSOLE"; else return _tmxr_send_expect_line_name (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; if (mp->dptr == NULL) /* has device been set? */ mp->dptr = find_dev_from_unit (uptr); /* no, so set device now */ 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) { 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; } |
︙ | ︙ | |||
4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 | 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 | > > | 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 | 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); if (lp->txstall) fprintf (st, " stalled = %d\n", lp->txstall); return; } /* Disconnect a line. Disconnect a line of the multiplexer associated with descriptor "desc" from a |
︙ | ︙ | |||
4410 4411 4412 4413 4414 4415 4416 | 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 */ | | > > | 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 | 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 */ if (lp->serport && (sim_switches & SWMASK ('C'))) return tmxr_detach_ln (lp); return tmxr_reset_ln_ex (lp, FALSE); /* drop the line */ } return SCPE_OK; } /* Enable logging for line */ |
︙ | ︙ | |||
4434 4435 4436 4437 4438 4439 4440 | 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; | | | 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 | 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; strlcpy (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); |
︙ | ︙ |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 | 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 */ | > | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | 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 txstall; /* xmt stall 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 */ |
︙ | ︙ | |||
283 284 285 286 287 288 289 290 291 292 293 294 295 296 | 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) | > > | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | 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); const char *tmxr_send_line_name (const SEND *snd); const char *tmxr_expect_line_name (const 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) |
︙ | ︙ |
︙ | ︙ | |||
27 28 29 30 31 32 33 | 11-Jun-2013 MB First version */ #include "sim_video.h" #include "scp.h" t_bool vid_active = FALSE; | < < | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 11-Jun-2013 MB First version */ #include "sim_video.h" #include "scp.h" t_bool vid_active = FALSE; 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; |
︙ | ︙ | |||
92 93 94 95 96 97 98 | /* * 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) \ | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | /* * 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 */ |
︙ | ︙ | |||
519 520 521 522 523 524 525 | 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); | < < | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | 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_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; |
︙ | ︙ | |||
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | 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); | > > > < < < < | 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 | 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 (vid_flags & SIM_VID_INPUTCAPTURED) return; 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); ev->x_rel += x_delta; ev->y_rel += y_delta; } 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()); } |
︙ | ︙ | |||
1246 1247 1248 1249 1250 1251 1252 | 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); } | < < | | | | | 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 | 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_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_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_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)\n", tail->x_rel, tail->y_rel); } 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; } |
︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 | 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 */ | > > > | 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 | 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; case SDL_WINDOWEVENT_EXPOSED: vid_update (); break; } } break; #endif case SDL_USEREVENT: /* There are 6 user events generated */ |
︙ | ︙ |
︙ | ︙ | |||
193 194 195 196 197 198 199 | 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]; | < < < < < | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | 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]; 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 |
︙ | ︙ |
︙ | ︙ | |||
161 162 163 164 165 166 167 168 169 170 171 172 173 174 | 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. | > > > > > > | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | 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 cl=/boot/cmdline.txt if ! grep -Fq ' init=' $cl then sudo sed -i -e 's#$# init=/usr/lib/raspi-config/init_resize.sh#' $cl fi 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. |
︙ | ︙ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/python # -*- coding: utf-8 -*- ######################################################################## # cc8-tu56-update - Rebuilds cc8.tu56 from source code. # # It is intended to be be called manually whenever a file in src/cc8/os8 # changes. It is not called automatically from the top-level Makefile # because not all end user systems will be able to run it, since our # dependencies (host-side cc8 and SABR) are not always present. # # 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. ######################################################################## # Bring in just the basics so we can bring in our local modules import os import sys sys.path.insert (0, os.path.dirname (__file__) + '/../lib') sys.path.insert (0, os.getcwd () + '/lib') # Our local modules from pidp8i import * from simh import * # Other global Python modules import glob import subprocess #### GLOBALS AND CONSTANTS ############################################# # Path to the cross-compiler version of cc8. cc8_cross = os.path.join (dirs.build, 'bin', 'cc8') # Path to the CC8 sources cc8_src = os.path.join (dirs.src, 'src', 'cc8') #### cross_compile ##################################################### # Cross-compile a *.c file on the local machine to a *.s file we can # send into the OS/8 instance. The parameter should have no extension. def cross_compile (module): inf = module + '.c' outf = module + '.s' if os.path.exists (outf) and \ os.path.getmtime (inf) <= os.path.getmtime (outf): print outf + " up-to-date." else: print "Building " + outf + "..." rc = subprocess.call ([cc8_cross, inf]) if rc == 0: print inf + " -> " + outf else: print "Failed to cross-compile the " + module.upper() + " module!" exit (1) #### main ############################################################## def main (): # We have to do much of the following from within the CC8 source dir # since the same source code is used for both versions of CC8, so the # compiler assumes a flat filesystem, hence no "include path", hence # all headers and such must be symlinked or copied into the same # directory as our primary inputs. os.chdir (os.path.join (cc8_src, 'os8')) # Cross-compile the OS/8 version of CC8's C sources to SABR. These # files are listed in dependency order, in case that later matters. modules = [ 'libc', 'c8', 'n8', 'p8' ] try: for m in modules: cross_compile (m) except OSError as e: print "Cross-compilation steps failed: " + e.strerror + '!' exit (1) # Create the SIMH child instance and tell it where to send log output try: s = simh (dirs.build, True) except (RuntimeError) as e: print "Could not start simulator: " + e.message + '!' exit (1) s.set_logfile (os.fdopen (sys.stdout.fileno (), 'w', 0)) # Zero core before beginning. SIMH's PDP-8 simulator doesn't do it, # on purpose, because the actual hardware did not do that. SIMH does # not attempt to simulate the persistence of core memory by saving it # to disk between runs, but the developers are right: you cannot trust # the prior state of core before initializing it yourself. Rather # than do that in some OS/8 specific way, we tell SIMH to do it. s.send_cmd ('de all 0') # Attach an empty DECtape to the simulator to hold our output. tape = os.path.join (dirs.os8mi, 'subsys', 'cc8.tu56') if os.path.exists (tape): os.remove (tape) s.send_cmd ("att dt0 " + tape) # Find and boot the bootable OS/8 disk. Use the "patched" version # because that is what "make run" uses; we use that command to # inspect this script's work. rk = os.path.join (dirs.os8mo, 'os8v3d-patched.rk05') if not os.path.isfile (rk): print "Could not find " + rk + "; OS/8 media not yet built?" exit (1) print "Booting " + rk + "..." s.send_cmd ("att rk0 " + rk) s.send_cmd ("boot rk0") # Get rid of any C program sources that may happen to be laying around # on the RK05 disk image we start with so we don't copy any working # files created by hand to the cc8.tu56 tape with the wildcard below. s.os8_send_cmd ('\\.', 'DEL *.C') # Copy the SABR files produced above by the host-side cross-compiler # to the OS/8 environment's RK05 disk. for m in modules: s.os8_send_file (m + '.sb') # Copy example programs in as well. # # We have to filter these files' content for the reasons given at the # top of cc8-to-os8. # # We don't let os8_send_file build the destination file name because # the source is a random-named temp file. tool = os.path.join (dirs.bin, 'cc8-to-os8') for src in glob.glob ('../examples/*.c'): if 'basic.c' not in src: # else: leave this one out. The OS/8 compiler can't cope with it. ctf = tempfile.NamedTemporaryFile () ctn = ctf.name os.system (tool + ' < ' + src + ' > ' + ctn) s.os8_send_file (ctn, os.path.basename (src).upper ()) # Copy the remaining static OS/8 CC8 text files in. We purposely do # not send init.h or libc.h because OS/8 CC8 doesn't process #include, # so it has those bits hard-coded into the compiler at the moment. for src in [ 'bldcc8.bi', 'cc.bi', 'header.sb' ]: s.os8_send_file (src) # Build the OS/8 version of CC8 using the batch file we copied in. s.os8_send_cmd ('\\.', 'EXE BLDCC8.BI') # Get rid of intermediary files on DSK: so the subsequent COPY # commands don't add them to the DECtape image. s.os8_send_cmd ('\\.', 'DEL ?8.RL,?8.SB,LIBC.SB') # Save all the remaining involved files to the cc8.tu56 tape, giving # DIR DTA0: output approximately like this: # # CC .SV 27 CC1 .SV 41 CC2 .SV 41 # FIB .C 1 CALC .C 5 BASIC .C 11 # PS .C 1 CC .BI 1 HEADER.SB 6 # LIBC .RL 22 s.os8_send_cmd ('\\.', 'ZERO DTA0:') s.os8_send_cmd ('\\.', 'COPY DTA0:<SYS:CC.SV,SYS:CC1.SV,SYS:CC2.SV') s.os8_send_cmd ('\\.', 'COPY DTA0:<DSK:HEADER.SB,DSK:LIBC.RL,DSK:*.C,DSK:CC.BI') # Exit simulator nicely so that tape detaches cleanly s.back_to_cmd ('\\.') s.send_cmd ('quit') if __name__ == "__main__": main() |
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/bin/bash if [ $# = 2 ] then cmp <(lz4 -dq "$1") <(lz4 -dq "$2") exit $? else cat <<USAGE usage: $0 <file1.lz> <file2.lz> Compares two lz4-compressed files, reporting differences in hex form. USAGE exit 99 fi |
> > > | 1 2 3 | #!/bin/bash files=$(ls | grep -v -e autosetup -e test | tr '\n' ' ') fossil diff --internal --from release $files | diffstat |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/env perl ######################################################################## # mkadrules - Write .c.o Makefile rules that also do autodependency # generation to $adf for each source subdirectory named on the command # line to avoid the need to manually maintain these near-identical # Makefile rule sets. # # Each *.o file gets a *.d file generated by the compiler listing the # object file's dependencies as discovered by the compiler at build # time, using the same build options used to generate the *.o file. # These automatically generated dependency rule sets are therefore # inherently accurate and comprehensive, which hand-written rules # virtually never are, particularly for software that builds on # multiple platforms, where out-of-tree dependencies (e.g. the # location of stdio.h) vary from one platform to another. # # This mechanism depends on the -M feature of GCC and Clang, which # means our build system is probably not as widely portable as it # might otherwise be. # # Based on http://scottmcpeak.com/autodepend/autodepend.html # # 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; # The basic rule set we generate, which is repeatedly modified and # written to the output file. my $template = <<'TEMPLATE'; 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 TEMPLATE # Parse command line die "usage: $0 <srcdir> <paths...>\n\n" unless @ARGV >= 2; my $srcdir = shift @ARGV; die "Source tree $srcdir does not exist!\n" unless -d $srcdir; my @dirs = @ARGV; for (@dirs) { die "Source subdir $_ does not exist!\n" unless -d "$srcdir/$_"; } # Create the output file my $adf = 'adrules.mk'; unlink $adf; open my $ad, '>', $adf, or die "Could not write to $adf: $!\n"; print $ad "## DO NOT MODIFY. GENERATED BY tools/mkadrules! ##\n"; print $ad "## -------------------------------------------- ##\n\n"; # If we're building in-tree, we can simplify $srcdir. my $intree = $srcdir eq getcwd; if ($intree) { $srcdir = '.'; } # Write rule set for each dir passed for my $sdir (@dirs) { my $rule = $template; my $odir = 'obj/' . $sdir; $odir =~ s{/src}{}; my $cflags = uc $sdir; $cflags =~ s{SRC}{}; $cflags =~ s{^/}{}; $cflags =~ s{/}{_}g; $cflags = $cflags ? "${cflags}_CFLAGS" : 'TOP_CFLAGS'; $rule =~ s{obj/}{$odir/}g; $rule =~ s{src/}{$sdir/}g; $rule =~ s{CFLAGS}{$cflags}g; $rule =~ s{SRCDIR}{$srcdir}g; $rule =~ s{ \./}{ }g; print $ad $rule, "\n"; } # If we're building out-of-tree, some of the *.c files were written # by autosetup from $srcdir/*.c.in, so we need an additional copy of # the top src dir rule set especially for them. unless ($intree) { my $rule = $template; $rule =~ s{SRCDIR/}{}g; print $ad $rule, "\n"; } # Finish up close $ad; chmod 0440, $adf; print "Generated $adf for ", join(', ', @dirs), ".\n"; |
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash -e lr=/usr/bin/lsb_release if [ -x $lr ] then vs=$(lsb_release -sicr | tr '\n' - | tr '[A-Z]' '[a-z]' | sed -e 's/-$//') d=fossil-$vs cp /usr/local/bin/fossil $d fossil uv add $d fossil uv sync rm $d else echo Could not find $lr! fi |
> > > > | 1 2 3 4 | #!/bin/sh -e cd bin fossil uv add os8v3d-*.rk05 fossil uv sync |
︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 148 | 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 | > > | | > > > > | > | > > | | | | | | | | | | | | | | | | > > > > | 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 | 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" pdfdir=doc/simh mkdir -p $pdfdir 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=$pdfdir/$ft.pdf pdftmp="$fs.pdf" say -n "Converting upstream $fs.doc to $pdfout..." if [ ! -e "$pdfout" ] then # Pull a copy out of the unversioned store fossil uv export $pdfout $pdfout fi if "$SOFFICE" --convert-to pdf "$CURR_SIMH_DIR/doc/$fs.doc" then szo=$(stat -f %z $pdfout) szt=$(stat -f %z $pdftmp) if [ -n "$szo" ] && [ -n "$szt" ] && [ "$szo" != "$szt" ] 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 else say "generation failed!" exit 1 fi done say "Syncing new PDFs..." fossil uv sync popd # Rename upstream Git paths to match our *.in files so that our produced |
︙ | ︙ |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/env perl ######################################################################## # test-mkos8 - Collects the set of all --*-os8-* options from the # configure script, generates all unique subsets of that option set, # runs configure with each of those subsets, and compares the output # OS/8 bin RK05 disk to the previous run's version. If there is a # discrepancy, generate a diff against the build log for that option # set and report the problem for the user to diagnose. # # The first time the script is run, or the first time a new unique # option subset is generated, we save the build results as the # exemplar to use in later tests. # # 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. ######################################################################## use strict; use warnings; # Modules from CPAN use Math::Subsets::List; use Parallel::Loops; # Core modules use Cwd qw(getcwd abs_path); use Digest::SHA qw(sha256_hex); use English; use File::Basename; use File::Copy; use Getopt::Std; use List::Util qw(shuffle); use Term::ANSIColor; # Perl::Critic rules we're willing to bend ## no critic (InputOutput::RequireBriefOpen ) #### GLOBALS ########################################################### my @tests; my $tests_mf; my (%generated, %tested); my $currlog = 'obj/mkos8-bin.log'; my $cmplz = abs_path (dirname ($0)) . '/cmplz'; # Command line option values my ($dry_run, $existing_only, $generate_only, $single_core, $shuffle, $verbose); #### sanitize_log ###################################################### # Copy the given input log file to the ouptut file, expurgating bits # that change from one run to the next without being meaningful. sub sanitize_log { my ($ifile, $ofile) = @_; open my $if, '<', $ifile or die "Cannot read $ifile: $!\n"; open my $of, '>', $ofile or die "Cannot write $ofile: $!\n"; while (<$if>) { # Strip all the CRs out. We only need the LFs. s{\r}{}gs; my $original = $_; # save it post-strip # Strip variable parts of SIMH line following each Ctrl-E: # # "Simulation stopped, PC: 01210 (JMP 1207)" s{ (Simulation\ stopped) # bit to preserve ,\ PC:\ \d+\ \([A-Z]+(\ \d+)?\) # variable bit }{$1.}x; # Rewrite SIMH ATTACH commands to remove pointless differences # in absolute paths between machines or Fossil checkouts. s{ (attach\ ) # SIMH command (-r\ )? # optional flag ([a-z0-9]+\ ) # SIMH device name (.*test/tmp/[0-9]+/) # noise parts of image file name thru PID }{$1$3.../}x; s{ (attach\ ) (-r\ )? ([a-z0-9]+\ ) (.*/(media/os8)/) # also squish this noise }{$1$3.../$5/}x; # Add cleaned line to ofile print $of $_; } close $if; close $of; return; } #### construct_test #################################################### # Assembles a test record for a single permutation sub construct_test { my @opts = @_; # Distill this option set to a hash value after which we will # name the output files. We don't want to name files with a # leading hyphen or with long variable-length names, potentially # multiple lines long. my $optstr = join ' ', @opts; my $hash = sha256_hex($optstr); my $hdir = "test/$hash"; # test hash dir relative to our CWD my $rhdir = "../../$hash"; # $hdir relative to builddir test/tmp/$PID my $test = { hash => $hash, hdir => $rhdir, log => "$rhdir/last.log", name => '{' . substr ($hash, 0, 12) . '}', optstr => $optstr, rklz => "$rhdir/last.rklz", }; # Skip this one if it already exists and we're in -g mode. if ($generate_only) { if (-d $hdir) { if (-f "$hdir/last.log") { if (-f "$hdir/last.rklz") { print "Skipping $test->{name}: already done.\n"; return; } elsif ($verbose) { print "Must re-gen $hash despite -g: rklz missing!\n"; } } elsif ($verbose) { print "Must re-gen $hash despite -g: log missing!\n"; } } elsif ($verbose) { print "Will generate $hash.\n"; } } elsif (-d $hdir) { print "Will test $optstr against $hash.\n" if $verbose; } elsif ($verbose) { print "Must generate missing test set $hash.\n"; } push @tests, $test; return; } #### compare_rklz ###################################################### # Compare two lz4-compressed RK05 disk images, returning true if they # are the same. If they are different, also outputs a binary difference # report. # # We call a separate shell script instead of use inline shell code here # because the helper code uses a Bash feature, and /bin/sh might not be # bash, as on a Raspbian box. sub compare_rklz { my ($r1, $r2) = @_; return system("$cmplz '$r1' '$r2'") == 0; } #### do_test ########################################################### # Test a single permutation sub do_test { # Set up working directory my $test = $_; print "Configuring test $test->{name}, PID $PID...\n"; return if $dry_run; chdir "test/tmp" or die "Could not CD to tmp dir: $!\n"; mkdir $PID; chdir $PID; die "Could not mkdir $test->{hdir}: $!\n" unless -d $test->{hdir} || mkdir($test->{hdir}); # Are we building the -patched disk or the -bin disk? my $patched = $test->{optstr} !~ m{--disable-os8-patches}x; my $typestr = $patched ? 'patched' : 'bin'; my $currdsk = "bin/os8v3d-$typestr.rk05"; my $currdlz = substr ($currdsk, 0, length ($currdsk) - 2) . 'lz'; my $target = 'os8-' . $typestr; # Configure the test disk image system "../../../configure $test->{optstr} > cfg.log 2>&1" and die "Failed to configure $test->{name}!\n"; link "../../../bin/pidp8i-sim", "bin/pidp8i-sim"; # no sense rebuilding it open my $itf, '>', 'media/os8/init.tx' # avoid a pointless diff or die "Cannot overwrite init.tx with neutral version: $!\n"; print $itf "TEST-MKOS8 BUILT THIS DISK IMAGE.\n\n"; close $itf; # Build the test disk image print "Building $currdsk for test $test->{name} (PID $PID)...\n"; system "make $target > make.log 2>&1" and die "Failed to build $currdsk!\n"; # Quickly compress the test disk: we don't want to store all the # "air" in an RK05 in our test corpus. system("lz4 -q $currdsk > $currdlz"); if (not -f $test->{log} or not -f $test->{rklz}) { # This test hasn't run here yet, so save it as our exemplar for # this optstr, to be compared to future builds. sanitize_log ($currlog, $test->{log}); move ($currdlz, $test->{rklz}); # Log the mapping between the hash and the options it # represents, so the user can reverse it. print $tests_mf "$test->{hash} $test->{optstr}\n"; $generated{$test->{hash}} = 1; } elsif (compare_rklz ($currdlz, $test->{rklz})) { # We had this test examplar here already and on re-doing it we # got the same result. print colored(['green'], "mkos8 $test->{name} test passed."), "\n"; $tested{$test->{hash}} = 1; } else { # This build resulted in a difference, so yell and save the # results for manual comparison. my $fdiff = "$test->{hdir}/fail.diff"; my $faillog = "$test->{hdir}/fail.log"; sanitize_log ($currlog, $faillog); move ($currdlz, $test->{hdir} . '/fail.rklz'); system "diff -wu $test->{log} $faillog > $fdiff"; print colored(['bold red'], 'RESULT DIFFERS! See test/', substr($fdiff, 6)), "\n"; $tested{$test->{hash}} = 0; } system("cd .. ; rm -fr $PID"); # -f because there are read-only files return; } #### remove_missing #################################################### # Implements -e: given a list of mkos8 options, returns only those for # which we have a valid test set. sub remove_missing { my (@tests) = @_; my $all = @tests; # First read in the set of prebuilt tests, filtering out those that # refer to output files that do not exist here. (This happens when # copying over the manifest file but only a subset of the actual # test output files.) my %existing; my $genned = 0; my $mff = 'test/tests-manifest.txt'; open my $mf, '<', $mff or die "Could not read from $mff: $!\n"; while (<$mf>) { chomp; my ($hash, @opts) = split ' '; my $dir = 'test/' . $hash; if (-d $dir and -f "$dir/last.rklz" and -f "$dir/last.log") { $existing{join ' ', @opts} = $hash; } ++$genned; } close $mf; # Now filter the test set to remove those that do not exist my @filtered = grep { $existing{$_->{optstr}} } @tests; print "Filtered $genned of $all tests down to ", scalar(@filtered), " for -e.\n"; return @filtered; } #### report* ########################################################### # Print on-exit status report. sub report_part { my ($partref, $kind) = @_; return unless keys %$partref; my ($successes, $tries) = (0, 0); for my $s (values %$partref) { ++$tries; ++$successes if $s; } my $extra = $successes == $tries ? '' : " of $tries"; print colored ([ $successes == 0 ? 'bold red' : $successes != $tries ? 'bold yellow' : 'green' ], "Successfully $kind $successes$extra tests.\n"); } sub report { print "\n", '=' x 79, "\n"; report_part (\%generated, 'generated'); report_part (\%tested, 'built'); print "\n"; return; } #### main ############################################################## # Parse command line my %clopts; getopts('egnsv1', \%clopts) or die "Failed to parse command line!\n"; $dry_run = $clopts{n}; $existing_only = $clopts{e}; $generate_only = $clopts{g}; $shuffle = $clopts{s}; $verbose = $clopts{v}; $single_core = $clopts{1}; # Init global resources mkdir 'test'; system("rm -rf test/tmp"); mkdir 'test/tmp'; open $tests_mf, '>>', 'test/tests-manifest.txt' or die "Cannot append to test manifest: $!\n"; $SIG{INT} = $SIG{TERM} = sub { report; exit 1 }; $SIG{PIPE} = 'IGNORE'; # Get all current --*-os8-* options, filtering out those we know should # not be tried for this: # # * No --os8-minimal because that just turns on all --disable-os8-* # options, so it's already covered. # * No --disable-os8-src because we don't test the src disk; it's # always generated the same way. # * No --disable-os8-focal because it disables the other two FOCAL # options, which we're already going to test singly and together. my @cmd = ( "./configure --help", "grep -- -os8-", "sed -Ee 's/^ +//'", "cut -f1 -d' '", "grep -v -e 'os8-minimal' -e 'os8-src' -e 'os8-focal\$'" ); open my $ocmd, '-|', join('|', @cmd) or die "Failed to get os8 option set: $!\n"; my @cfgOpts = <$ocmd>; close $ocmd; chomp @cfgOpts; # Generate all possible permutations of those options. Shuffle them if # requested. subsets \&construct_test, @cfgOpts; @tests = remove_missing(@tests) if $existing_only; @tests = shuffle @tests if $shuffle; # Run the tests my $tdir = abs_path(dirname($0)); my $cores = $single_core ? 1 : int(`$tdir/corecount`); my $pl = Parallel::Loops->new($cores); $pl->share (\%generated, \%tested); $pl->foreach ( \@tests, \&do_test); report; |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #!/usr/bin/python # -*- coding: utf-8 -*- ######################################################################## # test-os8-send-file - Repeatedly sends random files through class simh # method os8_send_file() and pulls it back through os8_get_file(), # then checks that the file is unchanged. # # 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. ######################################################################## # Bring in just the basics so we can bring in our local modules import os import sys sys.path.insert (0, os.path.dirname (__file__) + '/../lib') sys.path.insert (0, os.getcwd () + '/lib') # Our local modules from pidp8i import * from simh import * # Other core modules we need import filecmp import os.path import random import tempfile #### gen_file ########################################################## # Generate a random text file. In order that the process be lossless # through the txt2ptp/ptp2txt filters and the SIMH + OS/8 terminal # handling, we use only printable ASCII plus CR+LF characters. Returns # the name of the generated file. def gen_file (): f = tempfile.NamedTemporaryFile (delete = False, suffix = '.tmp') for i in range (0, random.randint (10, 4000)): if random.randint (0, 10) != 0: # Normal case: write some number of printable ASCII characters # on this line. for j in range (0, random.randint (1, 79)): f.write (chr (random.randint (32, 126))) # else: Every now and then, just write a blank line f.write ('\r\n') f.close () return f.name #### main ############################################################## def main (): # Create the SIMH child instance and tell it where to send log output try: s = simh (dirs.build) except (RuntimeError) as e: print "Could not start simulator: " + e.message + '!' exit (1) s.set_logfile (os.fdopen (sys.stdout.fileno (), 'w', 0)) # Find and boot the built OS/8 bin disk rk = os.path.join (dirs.os8mo, 'os8v3d-bin.rk05') if not os.path.isfile (rk): print "Could not find " + rk + "; OS/8 media not yet built?" exit (1) print "Booting " + rk + "..." s.send_cmd ("att rk0 " + rk) s.send_cmd ("boot rk0") # Setup random.seed () # Transfer several random files through. Beware increasing the range # too far: max is 99999 due to the file name length limit of OS/8 due # to the temporary file naming scheme we use in the loop. for i in range (0, 1000): # Build another temp file ifn = gen_file () of = tempfile.NamedTemporaryFile (suffix = '.out', delete = False) of.close () # Send it ofn = of.name tfn = 'T%05d.TX' % i s.os8_send_file (ifn, tfn) s.os8_get_file (tfn, ofn) # Did it change? if filecmp.cmp (ifn, ofn): print ifn + ' transferred successfully.' s.os8_send_cmd ('\\.', 'DEL ' + tfn) os.remove (ifn) os.remove (ofn) elif os.path.getsize (ofn) == 0: print "\nDifferences found: output is empty!\n" else: print "\nDifferences found:\n--------------------------------" os.system ('diff -wu "' + ifn + '" "' + ofn + '"') print 'Left ' + tfn + ' inside OS/8.' if __name__ == "__main__": main() |
︙ | ︙ | |||
28 29 30 31 32 33 34 | # use or other dealings in this Software without prior written # authorization from those authors. ######################################################################## use strict; use warnings; | | > > > > > > > > > > | 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 | # use or other dealings in this Software without prior written # authorization from those authors. ######################################################################## use strict; use warnings; use Cwd qw(abs_path getcwd); use File::Basename; # Give dummy result when run via test-mkos8. A proper version string # isn't helpful, and fossil isn't intended to be run in parallel # multiple times in the same directory. We could retry several times # until we succeed, but again, it doesn't really help us to bother. my $cwd = getcwd; if ($cwd =~ m{/test/tmp/}x) { print "test:id[00000000]\n"; exit 0; } my $topdir = dirname($0) . '/..'; if (-e "$topdir/.fslckout") { # Get version info from Fossil my ($branch, $checkout, $version, $comment); chdir $topdir; # we might be building out-of-tree |
︙ | ︙ |