├── .classpath ├── .gitignore ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── License.txt ├── disks-6085 ├── readme.md ├── vp2.0.5.zdisk ├── xde5.0.zdisk └── xde5.0_2xTajo+hacks.zdisk ├── dist.zip ├── images ├── Dwarf-Button-Bar.png ├── Dwarf-Status-Line.png ├── draco-vp2.0.5.png ├── draco-xde5.0_2xTajo+hacks.png └── duchess-gvwin-2.1.png ├── keyboard-maps └── kbd_linux_de_DE.map ├── readme.md └── src ├── dev └── hawala │ └── dmachine │ ├── CnvDmk2Imd.java │ ├── Draco.java │ ├── Duchess.java │ ├── DwarfMain.java │ ├── Utils.java │ ├── dwarf │ ├── DebuggerSubstituteMpHandler.java │ ├── Display8BitColorPane.java │ ├── DisplayMonochromePane.java │ ├── DisplayPane.java │ ├── KeyHandler.java │ ├── KeyboardMapper.java │ ├── MainUI.java │ ├── MouseHandler.java │ ├── PropertiesExt.java │ ├── TestUiDataConsumer.java │ ├── UiRefresher.java │ ├── WindowStateListener.java │ ├── eKeyEventCode.java │ └── package-info.java │ ├── engine │ ├── Config.java │ ├── Cpu.java │ ├── InitialMesaMicrocode.java │ ├── Mem.java │ ├── Opcodes.java │ ├── PilotDefs.java │ ├── PrincOpsDefs.java │ ├── Processes.java │ ├── Xfer.java │ ├── agents │ │ ├── Agent.java │ │ ├── AgentDevice.java │ │ ├── Agents.java │ │ ├── BeepAgent.java │ │ ├── DiskAgent.java │ │ ├── DiskState.java │ │ ├── DisplayAgent.java │ │ ├── FloppyAgent.java │ │ ├── KeyboardAgent.java │ │ ├── MouseAgent.java │ │ ├── NetworkAgent.java │ │ ├── NetworkHubInterface.java │ │ ├── NetworkInternalTimeService.java │ │ ├── NullAgent.java │ │ ├── ParallelAgent.java │ │ ├── ProcessorAgent.java │ │ ├── ReservedAgent.java │ │ ├── SerialAgent.java │ │ ├── StreamAgent.java │ │ ├── TtyAgent.java │ │ ├── iNetDeviceInterface.java │ │ └── package-info.java │ ├── eLevelVKey.java │ ├── iMesaMachineDataAccessor.java │ ├── iUiDataConsumer.java │ ├── iop6085 │ │ ├── DeviceHandler.java │ │ ├── HBeep.java │ │ ├── HDisk.java │ │ ├── HDisplay.java │ │ ├── HEthernet.java │ │ ├── HFloppy.java │ │ ├── HKeyboardMouse.java │ │ ├── HProcessor.java │ │ ├── HTTY.java │ │ ├── IOP.java │ │ ├── IOPTypes.java │ │ ├── IORegion.java │ │ └── package-info.java │ ├── opcodes │ │ ├── Ch03_Memory_Organization.java │ │ ├── Ch05_Stack_Instructions.java │ │ ├── Ch06_Jump_Instructions.java │ │ ├── Ch07_Assignment_Instructions.java │ │ ├── Ch08_Block_Transfers.java │ │ ├── Ch09_Control_Transfers.java │ │ ├── Ch10_Processes.java │ │ ├── ChXX_Undocumented.java │ │ └── package-info.java │ └── package-info.java │ ├── package-info.java │ └── unittest │ ├── AbstractInstructionTest.java │ ├── Ch03_MemoryOrganizationTest.java │ ├── Ch05_StackInsnsTest.java │ ├── Ch06_JumpInsnsTest.java │ ├── Ch07_AssignInsnsTest.java │ ├── Ch08_BlockTrfInsnsTest.java │ ├── Misc_Tests.java │ └── package-info.java └── resources └── base144.raw /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | dist-bld 3 | /dwarf 4 | /tests 5 | .readme.md.html 6 | dwarf.jardesc 7 | dwarf.manifest 8 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | dwarf 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | 19 | 1531113568765 20 | 21 | 5 22 | 23 | org.eclipse.ui.ide.multiFilter 24 | 1.0-name-matches-false-false-*.raw 25 | 26 | 27 | 28 | 1531113568771 29 | 30 | 5 31 | 32 | org.eclipse.ui.ide.multiFilter 33 | 1.0-name-matches-false-false-*.md 34 | 35 | 36 | 37 | 1531113568778 38 | 39 | 5 40 | 41 | org.eclipse.ui.ide.multiFilter 42 | 1.0-name-matches-false-false-*.zip 43 | 44 | 45 | 46 | 1531113568781 47 | 48 | 5 49 | 50 | org.eclipse.ui.ide.multiFilter 51 | 1.0-name-matches-false-false-* 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.8 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled 12 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 13 | org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning 14 | org.eclipse.jdt.core.compiler.release=disabled 15 | org.eclipse.jdt.core.compiler.source=1.8 16 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Dr. Hans-Walter Latz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * The name of the author may not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 17 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /disks-6085/readme.md: -------------------------------------------------------------------------------- 1 | ## Disk image files for Draco 6085 emulation 2 | 3 | The files in this directory provide the basic disk images for ViewPoint and XDE that can be used 4 | with the Draco 6085 emulator. 5 | 6 | All 3 disks "descend" from the same XDE 5.0 disk found at Bitsavers (archive 7 | [Micropolis_1325_XDE_5.0_Install.zip](http://bitsavers.informatik.uni-stuttgart.de/bits/Xerox/6085/Disk_Emulator_Images/Micropolis_1325_XDE_5.0_Install.zip)). As the extracted disk image in this archive only contains the sector 8 | data, but not the labels also required by the Pilot OS, the raw emulator image file (`microp1325_xde5_937.em`) 9 | had to be reprocessed with David Gesswein's MFM-tools (see [MFM Hard Disk Reader/Emulator](https://github.com/dgesswein/mfm)) 10 | to regenerate both the label and the data areas of the disk sectors for a Xerox 6085 system. Based on the 2 files created 11 | by the mfm-tools from the raw emulator image, the initial emulation disk to be used by Draco could be created, allowing to 12 | implement and test Draco's rigid disk emulation part. 13 | 14 | The 3 disk files are intended to be used with the sample configurations in the distribution archive, but can be 15 | used as starting point for own machine configurations. The reason for separating the configurations from the 16 | disk images is simply to reduce network traffic: only the disk for the system to be used needs to be downloaded from 17 | Github, one the other hand, no need to upload the disk package set (with over 16 MBytes) just because one file changes. 18 | So in addition to the distribution package, the respective disk images must be downloaded as required. 19 | 20 | The following disk image files for Draco are available: 21 | 22 | - `xde5.0.zdisk` 23 | this is the original disk image regenerated from the archive at Bitsavers; it contains an XDE 5.0 environment 24 | as installed from the XDE 5.0 distribution floppies, having a debugger boot file (`CoPilotDove.boot`) 25 | on the CoPilot volume, a normal boot file (`TajoDove.boot`) on the Tajo volume and all provided standard XDE tools and tutorials installed on CoPilot (but no development tools like compiler, binder etc., as these are not contained on 26 | the XDE 5.0 distribution floppies). 27 | To use this disk with the sample configuration, copy the file into the `xde5.0` subdirectory of the 28 | unpacked distribution. 29 | As this disk seems to have been created with a real Xerox 6085 workstation, it can be considered as a reference 30 | for Dracos rigid disk emulation quality. To be honest, the results are mixed: booting the disk from the CoPilot volume 31 | and working with XDE (list, create, edit or delete files, access network services or the like) works as expected; 32 | but anything involving world-swapping fails with varying MP codes (mostly with 0921 - boot loader device error) 33 | and any attempt to stop the system with XDE context menus leave the disk in an unusable state (MP code 0915 34 | on next reboots). In other words: Pilot 12.3 on an original 6085 disk is not fully satisfied with the hard disk 35 | emulation provided by Draco. So: 36 | - NEVER shutdown the system with one of the XDE menu items ("Boot button", "Quit" or "Power off")! 37 | - ALWAYS shutdown the system running from this disk ONLY with the "Stop"-button of the emulator! 38 | - if the system comes into this state, fall back to a working state by deleting the last delta file for 39 | the disk and renaming a working archived delta file to the .zdisk.zdelta extension 40 | 41 | - `xde5.0_2xTajo+hacks.zdisk` 42 | this is a XDE 5.0 environment completely rebuilt using the various floppy disk sets for XDE 5.0 available 43 | at Bitsavers. It has the standard volumes (CoPilot and Tajo), but having the normal boot file (`TajoDove.boot`) 44 | on both volumes; in addition to the standard installation files (XDE tools and tutorials), a large set of the 45 | so-called unsupported tools (or "hacks") found on the XDE 5.0 floppy disk sets for 6085 and 8010 were copied 46 | to the CoPilot volume and some of them are run at startup by User.cm (an early restricted Sword version, SmoothScroll, 47 | Clock with DisplayImpl). 48 | To use this disk with the sample configuration, copy the file into the `xde5.0_2xTajo+hacks` subdirectory of the 49 | unpacked distribution. 50 | This XDE setup has more stability than the original disk, as even if not all possible shutdown options of XDE 51 | work correctly, the disk stays the disk in an usable state: 52 | - "Boot button" from the HeraldWindow context menu works (system can be restarted) 53 | - "Quit" from the "Exec Ops" desktop background menu works (equivalent to "Boot button") 54 | - "Power off" from the "Exec Ops" desktop background menu locks up the system (MP goes back to 0990 after 55 | transiting through 0910/0920) but the system can be started normally after killing Dwarf/Draco 56 | 57 | - `vp2.0.5.zdisk` 58 | this is a ViewPoint 2.0 environment built starting with the XDE 5.0 disk using the VP 2.0.5 floppy disk set for 6085 59 | available at Bitsavers. In addition to the basic workstation (BWS, VP Editor), many tools from the additional VP 2.0 60 | floppy disks were installed (VP Netcomm, Essentials Applications, Office Accessories, Document editor extensions, 61 | Spreadsheet, File Converters, Help documents). 62 | Using the procedure provided at the end of section 3.3.3 in the 63 | [Darkstar readme](https://github.com/livingcomputermuseum/Darkstar#333-installing-an-operating-system), the "Software 64 | Options" of the system were set to allow all applications and the netcomm option. This is however bound to the 65 | machine id `10-00-FE-31-AB-21`, so setting a different processor id in the configuration using this disk 66 | will require to set the software options again using the mentioned procedure. 67 | To use this disk with the sample configuration, copy the file into the `vp2.0.5` subdirectory of the 68 | unpacked distribution. 69 | As Viewpoint 2.0 does not have an option for halting the system at logoff (and "Power off quick restart" 70 | does not work with Draco and was uninstalled again), the only way for shutting down the ViewPoint system is 71 | to logoff with any variant (retain, delete or transfer the desktop to the file server), wait until the screen 72 | turns black with the bouncing keyboard and then simply halt the system with the "Stop"-button of the Dwarf/Draco 73 | emulator (which will save disk changes as new delta file). 74 | 75 | 76 | 77 | Remark: as all attempts to create an empty disk from scratch using head/cylinder geometries of various disks 78 | available in the 1980's failed (the disks were not accepted by the installer), the Micropolis 1325 used as 79 | starting point is currently the only disk type available for 6085 machines emulated with Draco. 80 | This disk has a raw capacity of 85 MByte and a formatted capacity of ~ 61 MByte (formatted for Pilot, 122880 sectors). -------------------------------------------------------------------------------- /disks-6085/vp2.0.5.zdisk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/disks-6085/vp2.0.5.zdisk -------------------------------------------------------------------------------- /disks-6085/xde5.0.zdisk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/disks-6085/xde5.0.zdisk -------------------------------------------------------------------------------- /disks-6085/xde5.0_2xTajo+hacks.zdisk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/disks-6085/xde5.0_2xTajo+hacks.zdisk -------------------------------------------------------------------------------- /dist.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/dist.zip -------------------------------------------------------------------------------- /images/Dwarf-Button-Bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/images/Dwarf-Button-Bar.png -------------------------------------------------------------------------------- /images/Dwarf-Status-Line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/images/Dwarf-Status-Line.png -------------------------------------------------------------------------------- /images/draco-vp2.0.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/images/draco-vp2.0.5.png -------------------------------------------------------------------------------- /images/draco-xde5.0_2xTajo+hacks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/images/draco-xde5.0_2xTajo+hacks.png -------------------------------------------------------------------------------- /images/duchess-gvwin-2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/images/duchess-gvwin-2.1.png -------------------------------------------------------------------------------- /keyboard-maps/kbd_linux_de_DE.map: -------------------------------------------------------------------------------- 1 | # 2 | # Dwarf keyboard mapping for a german keyboard on linux 3 | # 4 | 5 | # 6 | # Syntax: 7 | # 8 | # - empty lines or lines starting with a # character are ignored 9 | # 10 | # - each other line defines a single mapping from a real key to a key 11 | # of the emulated Xerox 6085 keyboard 12 | # 13 | # - a mapping consists of an optional modifier and a key identification, 14 | # followed by a colon (:) followed by the key name of a Xerox Level V keyboard 15 | # 16 | # - the key identification is either the Java name of the key as defined 17 | # in the AWT-class KeyEvent or the hexcode of the extended keycode for the key 18 | # in the form xHHHHHHHH 19 | # Example: the "zero" key can be given either as VK_0 or x00000030 20 | # (Dwarfs enum eKeyEventCode also defines the key names a transliteration of 21 | # the original KeyEvent constants) 22 | # 23 | # - the Control-key (left or right) is the modifier, allowing to generate alternative 24 | # Xerox keys; to specify this modifier, prefix the Java key identification with: Ctrl! 25 | # Example: the letter key P with the modifier can be given alternatively as: 26 | # Ctrl!VK_P 27 | # Ctrl!0x000050 28 | # 29 | # - the Xerox key names identify the key of a 6085 workstation keyboard, the key names 30 | # are listed in the Dwarf enum eLevelVKey and (probably) identify the key positions 31 | # on an english keyboard 32 | # 33 | # - Examples: 34 | # -> define the mapping of the "P" key as both the letter and the "Props" key: 35 | # VP_P : P 36 | # Ctrl!VK_P : Props 37 | # -> define the Alt-key (left to space bar) as the "Keyboard" key: 38 | # VK_ALT : Special 39 | # -> define the AltGr-key (right to the space bar) as the "Expand" key for 40 | # both Linux (first line) and Window (second line): 41 | # VK_ALT_GRAPH : Expand 42 | # Ctrl!VK_ALT : Expand 43 | # 44 | # - attention: 45 | # -> the interpretation of the tokens is case-sensitive, i.e. the 46 | # following lines will not be recognized and logged to the console: 47 | # Ctrl!0X000050 : Props (uppercase X) 48 | # ctrl!VK_P : Props (lowercase c) 49 | # Ctrl!VP_P : props (props instead of Props) 50 | # -> if a keyboard mapping file is used, there are no defaults, i.e. keyboard 51 | # keys not mapped in the file will not be usable in Dwarf 52 | # 53 | # - hint: the Java identification for keyboard key can be determined by starting 54 | # Dwarf with the -logkeypressed command line parameter, so each key press (except 55 | # for the Control key) dispatched to Dwarfs screen subwindow will be logged to 56 | # the console with both the hexcode and the key name (if available) 57 | # 58 | 59 | 60 | # first row: ^1234567890ß' 61 | VK_DEAD_CIRCUMFLEX : Bullet 62 | VK_1 : One 63 | VK_2 : Two 64 | VK_3 : Three 65 | VK_4 : Four 66 | VK_5 : Five 67 | VK_6 : Six 68 | VK_7 : Seven 69 | VK_8 : Eight 70 | VK_9 : Nine 71 | VK_0 : Zero 72 | x010000DF : Dash 73 | VK_DEAD_GRAVE : Equal 74 | VK_DEAD_ACUTE : Equal 75 | VK_DELETE : Delete 76 | 77 | # second row: qwertzuiopü+ 78 | VK_Q : Q 79 | VK_W : W 80 | VK_E : E 81 | VK_R : R 82 | VK_T : T 83 | VK_Z : Z 84 | VK_U : U 85 | VK_I : I 86 | VK_O : O 87 | VK_P : P 88 | x010000FC : LeftBracket 89 | VK_PLUS : RightBracket 90 | 91 | # third row: asdfghjklöä# 92 | VK_A : A 93 | VK_S : S 94 | VK_D : D 95 | VK_F : F 96 | VK_G : G 97 | VK_H : H 98 | VK_J : J 99 | VK_K : K 100 | VK_L : L 101 | x010000D6 : SemiColon 102 | x010000C4 : Quote 103 | VK_NUMBER_SIGN : DoubleQuote 104 | 105 | # fourth row: free) 144 | 145 | # Xerox special keys 146 | VK_ESCAPE : Stop 147 | Ctrl!VK_ESCAPE : Stop 148 | Ctrl!VK_M : Move 149 | Ctrl!VK_C : Copy 150 | Ctrl!VK_S : Same 151 | Ctrl!VK_O : Open 152 | Ctrl!VK_P : Props 153 | Ctrl!VK_F : Find 154 | Ctrl!VK_H : Help 155 | Ctrl!VK_U : Undo 156 | Ctrl!VK_A : Again 157 | Ctrl!VK_N : Next 158 | 159 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/CnvDmk2Imd.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine; 28 | 29 | import java.io.BufferedOutputStream; 30 | import java.io.File; 31 | import java.io.FileOutputStream; 32 | import java.io.IOException; 33 | import java.io.OutputStream; 34 | 35 | import dev.hawala.dmachine.engine.agents.FloppyAgent.DMKFloppyDisk; 36 | 37 | /** 38 | * Conversion utility for creating an equivalent IMD floppy 39 | * disk image for a DMK image, preferably (because tested with) 40 | * a 8010 8" disk. 41 | *

42 | * The conversion reuses largely Dwarf floppy code: the DMK image is 43 | * loaded through the implementation for DMK legacy floppies, the 44 | * {@code DiskConverter} simply subclassing that class for writing 45 | * the IMD file (named after the original file with the ".imd" extension) 46 | * directly in the constructor. 47 | *

48 | * 49 | * @author Dr. Hans-Walter Latz / Berlin (2018) 50 | */ 51 | public class CnvDmk2Imd extends DMKFloppyDisk { 52 | 53 | private boolean doLog = false; // prevent logging the DMK reading 54 | 55 | public CnvDmk2Imd(File dmkFile, File imdFile) throws IOException { 56 | super(dmkFile); 57 | 58 | /* 59 | * create the IMD from the DMK sectors and disk characteristics 60 | */ 61 | 62 | // re-enable logging for issuing the disk characteristics 63 | this.doLog = true; 64 | 65 | // write the imd file from the sectors found in the dmk file 66 | logf("# Cyl0Sectors = %s sectors\n", this.cyl0Sectors); // track 0 and 1 67 | logf("# DataSectors = %s sectors\n", this.dataSectors); 68 | logf("# cylinders = %d\n", this.cylinders); 69 | 70 | int expectedSectorCount = ((this.cylinders - 1) * this.dataSectors * 2) + (this.cyl0Sectors * 2); 71 | logf("# expectedSectors = %d ?=? this.sectors.length = %d\n", expectedSectorCount, this.sectors.size()); 72 | 73 | try (OutputStream imd = new BufferedOutputStream(new FileOutputStream(imdFile))) { 74 | // write the human readable header 75 | imd.write("IMD converted from DMK".getBytes()); 76 | imd.write(0x1A); // EOF is end marker for the header 77 | 78 | // which sector loaded from the DMK to write next to IMD 79 | int sectorStartIndex = 0; 80 | 81 | // write track 0 (cyl 0, head 0): 128 bytes sector length (sectInfo = 0), mode = 2 (experimental) 82 | sectorStartIndex = this.writeTrack(imd, 2, 0, 0, this.cyl0Sectors, 0, sectorStartIndex); 83 | 84 | // write track 1 (cyl 0, head 1): 256 bytes per sector, mode = 5 from here (experimental) 85 | sectorStartIndex = this.writeTrack(imd, 5, 0, 1, this.cyl0Sectors, 1, sectorStartIndex); 86 | 87 | // write the other sectors 88 | int cyl = 1; 89 | int head = 0; 90 | while(cyl < this.cylinders) { 91 | sectorStartIndex = this.writeTrack(imd, 5, cyl, head, this.dataSectors, 2, sectorStartIndex); 92 | head++; 93 | if (head > 1) { 94 | head = 0; 95 | cyl++; 96 | } 97 | } 98 | } 99 | } 100 | 101 | private int writeTrack(OutputStream imd, int mode, int cylNo, int headNo, int numSects, int sectInfo, int sectorStartIndex) throws IOException { 102 | // track header 103 | imd.write(mode); 104 | imd.write(cylNo); 105 | imd.write(headNo & 0x3F); 106 | imd.write(numSects); 107 | imd.write(sectInfo); 108 | 109 | // sector numbering map (Xerox floppies have linear ascending sector ordering, as seens so far...) 110 | for (int i = 0; i < numSects; i++) { 111 | imd.write(i + 1); 112 | } 113 | 114 | // no sectorCylinder map present, as we write (headNo & 0x80) == 0 115 | 116 | // no sectorHead map present, as we write (headNo & 0x40) == 0 117 | 118 | // write sectors 119 | for (int i = 0; i < numSects; i++) { 120 | this.writeSectorContent(imd, this.sectors.get(sectorStartIndex + i)); 121 | } 122 | 123 | // done with this track 124 | return sectorStartIndex + numSects; 125 | } 126 | 127 | private void writeSectorContent(OutputStream imd, short[] sector) throws IOException { 128 | // sector content type: full content, no filling with constant byte or 0 129 | imd.write(1); 130 | 131 | // sector bytes 132 | for (int i = 0; i < sector.length; i++) { 133 | int word = sector[i]; 134 | int upperByte = (word >> 8) & 0x00FF; 135 | int lowerByte = word & 0x00FF; 136 | imd.write(upperByte); 137 | imd.write(lowerByte); 138 | } 139 | } 140 | 141 | protected void logf(String template, Object... args) { 142 | if (this.doLog) { 143 | System.out.printf(template, args); 144 | } 145 | } 146 | 147 | public static void main(String[] args) throws IOException { 148 | if (args.length < 1) { 149 | System.err.printf("missing DMK filename parameter\n"); 150 | return; 151 | } 152 | 153 | File dmkFile = new File(args[0]); 154 | File imdFile = new File(args[0] + ".imd"); 155 | new CnvDmk2Imd(dmkFile, imdFile); 156 | 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/DwarfMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine; 28 | 29 | import java.io.IOException; 30 | import java.util.ArrayList; 31 | import java.util.List; 32 | 33 | /** 34 | * Main program for the Dwarf Mesa emulator family, dispatching to 35 | * either the Guam machine emulation (Duchess) or the 6085/daybreak 36 | * emulation (Draco), depending on the machine type selection argument 37 | * and passing the remaining command line arguments to the invoked 38 | * emulation program. 39 | * 40 | * @author Dr. Hans-Walter Latz / Berlin (2020) 41 | */ 42 | public class DwarfMain { 43 | 44 | private static void usage() { 45 | System.out.println("Usage: Dwarf -duchess|-draco "); 46 | System.exit(0); 47 | } 48 | 49 | public static void main(String[] args) throws IOException { 50 | int argCount = args.length; 51 | if (argCount < 1) { 52 | usage(); 53 | } 54 | 55 | List newArgs = new ArrayList<>(); 56 | 57 | boolean isDuchess = false; 58 | boolean isDraco = false; 59 | for (String arg : args) { 60 | String lcArg = arg.toLowerCase(); 61 | if ("-duchess".equals(lcArg)) { 62 | isDuchess = true; 63 | } else if ("-draco".equals(lcArg)) { 64 | isDraco = true; 65 | } else { 66 | newArgs.add(arg); 67 | } 68 | } 69 | 70 | if (isDuchess == isDraco) { 71 | usage(); 72 | } 73 | 74 | if (isDuchess) { 75 | Duchess.main(newArgs.toArray(new String[newArgs.size()])); 76 | } else { 77 | Draco.main(newArgs.toArray(new String[newArgs.size()])); 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine; 28 | 29 | import java.io.File; 30 | 31 | import dev.hawala.dmachine.dwarf.eKeyEventCode; 32 | 33 | /** 34 | * Utilities for Dwarf main programs. 35 | * 36 | * @author Dr. Hans-Walter Latz / Berlin (2019,2020) 37 | */ 38 | public class Utils { 39 | 40 | 41 | // check if the filename identifies an readably file 42 | public static boolean isFileOk(String kind, String filename) { 43 | if (filename == null) { 44 | System.err.printf("Error: no filename given for %s\n", kind); 45 | return false; 46 | } 47 | File f = new File(filename); 48 | if (!f.canRead()) { 49 | System.err.printf("Error: file '%s' given for %s does not exist or is not readable\n", filename, kind); 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | // parse the mac (machine address, processor id) from the given string 56 | public static String parseMac(String mac, int[] macBytes, int[] macWords) { 57 | String[] submacs = mac.split("-"); 58 | if (submacs.length != macBytes.length) { 59 | System.err.printf("Error: invalid processor id format (not XX-XX-XX-XX-XX-XX): %s\n", mac); 60 | return ""; 61 | } 62 | 63 | for (int i = 0; i < macBytes.length; i++) { 64 | try { 65 | macBytes[i] = Integer.parseInt(submacs[i], 16) & 0xFF; 66 | } catch (Exception e) { 67 | System.err.printf("Error: invalid processor id format (not XX-XX-XX-XX-XX-XX): %s\n", mac); 68 | return ""; 69 | } 70 | } 71 | 72 | String recognizedMacId = String.format( 73 | "%02X-%02X-%02X-%02X-%02X-%02X", 74 | macBytes[0], macBytes[1], macBytes[2], macBytes[3], macBytes[4], macBytes[5]); 75 | macWords[0] = (macBytes[0] << 8) | macBytes[1]; 76 | macWords[1] = (macBytes[2] << 8) | macBytes[3]; 77 | macWords[2] = (macBytes[4] << 8) | macBytes[5]; 78 | return recognizedMacId; 79 | } 80 | 81 | // parse the keycode either as 0x-hexcode or as VK_-name of the key 82 | public static int parseKeycode(String keycode) { 83 | if (keycode.startsWith("x")) { 84 | try { 85 | return Integer.parseInt(keycode.substring(1), 16); 86 | } catch (NumberFormatException nfe) { 87 | System.out.printf("Invalid hex-code for keycode '%s', using Ctrl-Key instead\n", keycode); 88 | return eKeyEventCode.VK_CONTROL.getCode(); 89 | } 90 | } else { 91 | eKeyEventCode javaKey = null; 92 | try { 93 | javaKey = eKeyEventCode.valueOf(keycode); 94 | } catch (Exception e) { 95 | // ignored 96 | } 97 | if (javaKey == null) { 98 | System.out.printf("Invalid key-name '%s' for keycode, using Ctrl-Key instead\n", keycode); 99 | return eKeyEventCode.VK_CONTROL.getCode(); 100 | } 101 | return javaKey.getCode(); 102 | } 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/DebuggerSubstituteMpHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | import dev.hawala.dmachine.engine.Cpu; 33 | import dev.hawala.dmachine.engine.Cpu.MPHandler; 34 | import dev.hawala.dmachine.engine.Cpu.MesaERROR; 35 | 36 | /** 37 | * Maintenance Code handler looking for a crash of the mesa OS signaled 38 | * by the debugger substitute build in BWS. The idea is to interpret 39 | * the MP codes issued by the debugger substitute until the MP codes 40 | * begin to loop, stopping the mesa engine with a message built from 41 | * the MP codes, (very) roughly indicating the reason for the crash. 42 | *
43 | * (see the 6085 field training document for details on the MP 44 | * codes generated by the debugger substitute) 45 | *

46 | * Furthermore, the MP code 0915 is intercepted by default and halts 47 | * the mesa engine, as no networking is currently available, so no 48 | * remote debugger can connect to this machine (if an XDE with a debugger 49 | * should ever be available...). 50 | *

51 | * 52 | * @author Dr. Hans-Walter Latz / Berlin (2017) 53 | */ 54 | public class DebuggerSubstituteMpHandler implements MPHandler { 55 | 56 | // intercept MP code 0915 (waiting for remote debugger to connect)? 57 | private final boolean stopOn0915; 58 | 59 | /** 60 | * Constructor with parametrization for MP 915. 61 | * 62 | * @param stopOn0915 should a MP 0915 stop the mesa engine? 63 | */ 64 | public DebuggerSubstituteMpHandler(boolean stopOn0915) { 65 | this.stopOn0915 = stopOn0915; 66 | } 67 | 68 | /** 69 | * Default constructor, activating MP 0915 interception. 70 | */ 71 | public DebuggerSubstituteMpHandler() { 72 | this(true); 73 | } 74 | 75 | // did we see the characteristic debugger substitue MP code? 76 | private boolean inDebuggerSubstitute = false; 77 | 78 | // the list of the substitutes MP codes seen so far 79 | private List codes = new ArrayList<>(); 80 | 81 | // did we have the MP code for the crash location and reason? 82 | private boolean hadLocationAndKind = false; 83 | 84 | // StringBuilder to collect the characters encoded in the MP codes 85 | private StringBuilder sb = new StringBuilder(); 86 | 87 | // the letters indexed by the MP code nibbles 88 | private final char[] letters = { 89 | ' ', 90 | 'A', 'B', 'C', 'D', 'E', 'F', 91 | 'G', 'H', 'I', 'J', 'K', 'L', 92 | 'M', 'N', 'O', 'P', 'Q', 'R', 93 | 'S', 'T', 'U', 'V', 'W', 'X', 94 | 'Y', 'Z' 95 | }; 96 | 97 | // safe get the character for an MP code nibble 98 | private char letter(int l) { 99 | if (l >= 0 && l <= 26) { 100 | return this.letters[l]; 101 | } 102 | return '?'; 103 | } 104 | 105 | @Override 106 | public void newMP(int mp) { 107 | // special case "wait for remote debugger to connect" 108 | if (mp == 915) { 109 | if (this.stopOn0915) { 110 | throw new Cpu.MesaStopped("Start waiting for remote debugger to connect (MP 0915)"); 111 | } 112 | return; 113 | } 114 | 115 | // handle debugger substitute MP sequences indicating where the crash occured 116 | 117 | if (mp == 8888 && this.inDebuggerSubstitute) { 118 | // the debugger substitute seems to interspread dummy 8888 codes between real codes 119 | // => ignore them 120 | return; 121 | } 122 | 123 | if (mp == 9999 && this.inDebuggerSubstitute) { 124 | // beginning new mp code loop => the sequence is complete, so finalize the crash reason message and stop 125 | sb.append(" ["); 126 | for (Integer c : codes) { 127 | sb.append(String.format(" %04d", c.intValue())); 128 | } 129 | sb.append(" ]"); 130 | throw new MesaERROR(sb.toString()); 131 | } 132 | 133 | if (mp == 9999 && !this.inDebuggerSubstitute) { 134 | // start of debugger substitute mp code sequence 135 | codes.add(mp); 136 | sb.append("DbgSubst :: "); 137 | this.inDebuggerSubstitute = true; 138 | return; 139 | } 140 | 141 | if (this.inDebuggerSubstitute) { 142 | codes.add(mp); 143 | if (!this.hadLocationAndKind) { 144 | int location = mp / 100; 145 | int kind = mp % 100; 146 | 147 | switch(location) { 148 | case 76: sb.append("BWS boot, "); break; 149 | case 77: sb.append("BWS common software, "); break; 150 | case 78: sb.append("BWS applications, "); break; 151 | default: sb.append("?unknown(").append(location).append(")?, "); 152 | } 153 | 154 | switch(kind) { 155 | case 40: sb.append("address fault : "); break; 156 | case 41: sb.append("breakpoint : "); break; 157 | case 42: sb.append("bug : "); break; 158 | case 43: sb.append("call debugger : "); break; 159 | case 44: sb.append("map log : "); break; 160 | case 45: sb.append("disk error : "); break; 161 | case 46: sb.append("interrupt : "); break; 162 | case 47: sb.append("return : "); break; 163 | case 48: sb.append("return aborted : "); break; 164 | case 49: sb.append("uncaught signal : "); break; 165 | case 50: sb.append("visit debugger : "); break; 166 | case 51: sb.append("write protect : "); break; 167 | default: sb.append("?unknown(").append(location).append(")? : "); 168 | } 169 | 170 | this.hadLocationAndKind = true; 171 | } else { 172 | // here we have more letters for the message 173 | int l1 = mp / 100; 174 | int l2 = mp % 100; 175 | sb.append(this.letter(l1)); 176 | sb.append(this.letter(l2)); 177 | } 178 | } 179 | } 180 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/Display8BitColorPane.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | import java.awt.image.BufferedImage; 30 | import java.awt.image.DataBufferInt; 31 | 32 | import dev.hawala.dmachine.engine.PrincOpsDefs; 33 | 34 | /** 35 | * Java swing pane representing the screen of a Dwarf machine, providing 36 | * a 8-bit lookup table color display. 37 | *

38 | * The basic functionality for the Dwarf UI is inherited from the parent 39 | * class {@code DisplayPane}. 40 | *

41 | * 42 | * @author Dr. Hans-Walter Latz / Berlin (2020) 43 | */ 44 | public class Display8BitColorPane extends DisplayPane { 45 | 46 | private static final long serialVersionUID = 1679737299827954144L; 47 | 48 | // number of pixels in a memory page: 49 | // with 8-bit color display data having 2 pixels per mesa word 50 | private static final int PIXELS_PER_PAGE = PrincOpsDefs.WORDS_PER_PAGE * 2; 51 | 52 | // Pilot/BWS does have "line breaks" in a display page for 8-bit colors, 53 | // so a scanline is a multiple of pages => multiple of 512 pixels 54 | private static int getEffectiveWidth(int displayWidth) { 55 | return ((displayWidth + PIXELS_PER_PAGE - 1) / PIXELS_PER_PAGE) * PIXELS_PER_PAGE; 56 | } 57 | 58 | public Display8BitColorPane(int displayWidth, int displayHeight) { 59 | super(getEffectiveWidth(displayWidth), displayHeight); 60 | } 61 | 62 | @Override 63 | protected BufferedImage createBackingImage(int displayWidth, int displayHeight) { 64 | return new BufferedImage(displayWidth, displayHeight, BufferedImage.TYPE_INT_RGB); 65 | } 66 | 67 | @Override 68 | public boolean copyDisplayContent(short[] mem, int start, int count, short[] pageFlags, int firstPage, int[] colorTable) { 69 | DataBufferInt dbb = (DataBufferInt)bi.getRaster().getDataBuffer(); 70 | int[] pixels = dbb.getData(); 71 | 72 | boolean bitmapWasUpdated = false; 73 | int end = start + Math.min(Math.min(count, pixels.length / 2), mem.length - start); 74 | int bitmapIdx = 0; 75 | int memIdx = start; 76 | int pageIdx = firstPage; 77 | int pageCount = (count + PrincOpsDefs.WORDS_PER_PAGE - 1) / PrincOpsDefs.WORDS_PER_PAGE; 78 | while (pageCount-- > 0) { 79 | short flags = pageFlags[pageIdx++]; 80 | if ((flags & PrincOpsDefs.MAPFLAGS_DIRTY) == 0) { 81 | memIdx += PrincOpsDefs.WORDS_PER_PAGE; 82 | bitmapIdx += PrincOpsDefs.WORDS_PER_PAGE * 2; // 2 pixels per mesa word in display data 83 | continue; 84 | } 85 | for (int i = 0; i < PrincOpsDefs.WORDS_PER_PAGE && memIdx < end; i++) { 86 | int w = mem[memIdx++] & 0xFFFF; 87 | pixels[bitmapIdx++] = colorTable[w >>> 8]; 88 | pixels[bitmapIdx++] = colorTable[w & 0x00FF]; 89 | } 90 | bitmapWasUpdated = true; 91 | } 92 | 93 | return bitmapWasUpdated; 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/DisplayMonochromePane.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017,2020, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | import java.awt.image.BufferedImage; 30 | import java.awt.image.DataBufferByte; 31 | 32 | import dev.hawala.dmachine.engine.PrincOpsDefs; 33 | 34 | /** 35 | * Java swing pane representing the screen of a Dwarf machine, providing 36 | * a Black&White display. 37 | *

38 | * The basic functionality for the Dwarf UI is inherited from the parent 39 | * class {@code DisplayPane}. 40 | *

41 | * 42 | * @author Dr. Hans-Walter Latz / Berlin (2017,2020) 43 | */ 44 | public class DisplayMonochromePane extends DisplayPane { 45 | 46 | private static final long serialVersionUID = 7037553149132148980L; 47 | 48 | public DisplayMonochromePane(int displayWidth, int displayHeight) { 49 | super(displayWidth, displayHeight); 50 | } 51 | 52 | @Override 53 | protected BufferedImage createBackingImage(int displayWidth, int displayHeight) { 54 | return new BufferedImage(displayWidth, displayHeight, BufferedImage.TYPE_BYTE_BINARY); 55 | } 56 | 57 | @Override 58 | public boolean copyDisplayContent(short[] mem, int start, int count, short[] pageFlags, int firstPage, int[] colorTable) { 59 | DataBufferByte dbb = (DataBufferByte)bi.getRaster().getDataBuffer(); 60 | byte[] data = dbb.getData(); 61 | 62 | boolean bitmapWasUpdated = false; 63 | int end = start + Math.min(Math.min(count, data.length / 2), mem.length - start); 64 | int bitmapIdx = 0; 65 | int memIdx = start; 66 | int pageIdx = firstPage; 67 | int pageCount = (count + PrincOpsDefs.WORDS_PER_PAGE - 1) / PrincOpsDefs.WORDS_PER_PAGE; 68 | while (pageCount-- > 0) { 69 | short flags = pageFlags[pageIdx++]; 70 | if ((flags & PrincOpsDefs.MAPFLAGS_DIRTY) == 0) { 71 | memIdx += PrincOpsDefs.WORDS_PER_PAGE; 72 | bitmapIdx += PrincOpsDefs.WORDS_PER_PAGE * 2; 73 | continue; 74 | } 75 | for (int i = 0; i < PrincOpsDefs.WORDS_PER_PAGE && memIdx < end; i++) { 76 | short w = (short)(mem[memIdx++] ^ 0xFFFF); // TODO: really invert manually ?? 77 | data[bitmapIdx++] = (byte)((w >>> 8)); 78 | data[bitmapIdx++] = (byte)((w & 0x00FF)); 79 | } 80 | bitmapWasUpdated = true; 81 | } 82 | 83 | return bitmapWasUpdated; 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/KeyHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | import java.awt.event.KeyEvent; 30 | import java.awt.event.KeyListener; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | import java.util.concurrent.ExecutorService; 34 | import java.util.concurrent.Executors; 35 | 36 | import dev.hawala.dmachine.engine.Config; 37 | import dev.hawala.dmachine.engine.Processes; 38 | 39 | /** 40 | * Key stroke listener for the Dwarf screen pane, forwarding the key-pressed and 41 | * key-released event to the keyboard-mapper. 42 | *

43 | * Handling diacritical start characters (also called dead keys, for example the 44 | * accent-grave (forward-tick), accent-aigue (back-tick), accent-circonflex (^) etc.) 45 | * is a problem under Linux, as modern Linuces think to be smart in prehandling those 46 | * characters to combine them with the next pressed key: this has the net effect 47 | * that for a press-release cycle, only the release event arrives in the Java window 48 | * key listener (using the focus management listening alternative does not help, 49 | * as even being a level deeper in the event pipeline did not help). 50 | *
51 | * This is handled here in a questionable, but seemingly working way: if a key-release 52 | * event arrives for which the key-pressed is missing, first a synthetic key-pressed 53 | * event is sent to the keyboard-mapper, and the key-release event is delayed by 50 msecs. 54 | *

55 | * 56 | * @author Dr. Hans-Walter Latz / Berlin (2017) 57 | */ 58 | public class KeyHandler implements KeyListener { 59 | 60 | // executor service for delaying diacritical key events 61 | private static final ExecutorService executor = Executors.newCachedThreadPool(); 62 | 63 | // the current pressed keys, for finding missing key-pressed events 64 | private final List currPressed = new ArrayList<>(); 65 | 66 | // the target for keyboard events 67 | private final KeyboardMapper keyMapper; 68 | 69 | /** 70 | * Constructor. 71 | * 72 | * @param keyMapper the target for keyboard events 73 | */ 74 | public KeyHandler(KeyboardMapper keyMapper) { 75 | this.keyMapper = keyMapper; 76 | } 77 | 78 | // wait 50 ms 79 | private static void safeWait() { 80 | try { 81 | Thread.sleep(50); 82 | } catch (InterruptedException e) { 83 | } 84 | } 85 | 86 | private boolean dumpOnVkLess = false; 87 | 88 | @Override 89 | public void keyPressed(KeyEvent evt) { 90 | if (Config.USE_DEBUG_INTERPRETER && evt.getExtendedKeyCode() == KeyEvent.VK_LESS) { 91 | // System.out.println("key VK_LESS..."); 92 | // System.out.flush(); 93 | 94 | if (this.dumpOnVkLess) { 95 | Processes.requestFlightRecorderStopAndDump(); 96 | this.dumpOnVkLess = false; 97 | } else { 98 | Processes.requestFlightRecorderStart(); 99 | this.dumpOnVkLess = true; 100 | } 101 | 102 | return; 103 | } 104 | 105 | // System.out.printf("at %d : panel.keyPressed -> keyCode = %03d, extKeyCode = %05d\n", 106 | // System.currentTimeMillis(), evt.getKeyCode(), evt.getExtendedKeyCode()); 107 | this.keyMapper.pressed(evt.getExtendedKeyCode()); 108 | 109 | Integer code = Integer.valueOf(evt.getExtendedKeyCode()); 110 | if (!this.currPressed.contains(code)) { this.currPressed.add(code); } 111 | } 112 | 113 | @Override 114 | public void keyReleased(KeyEvent evt) { 115 | // System.out.printf("at %d : panel.keyReleased -> keyCode = %03d, extKeyCode = %05d\n", 116 | // System.currentTimeMillis(), evt.getKeyCode(), evt.getExtendedKeyCode()); 117 | 118 | this.keyMapper.released(evt.getExtendedKeyCode()); 119 | 120 | Integer code = Integer.valueOf(evt.getExtendedKeyCode()); 121 | if (this.currPressed.contains(code)) { 122 | this.currPressed.remove(code); 123 | } else { 124 | // System.out.printf("dead key char: 0x%04X\n", code.intValue()); 125 | this.keyMapper.pressed(code.intValue()); 126 | executor.execute(() -> { safeWait(); this.keyMapper.released(code.intValue()); }); 127 | } 128 | } 129 | 130 | @Override 131 | public void keyTyped(KeyEvent evt) { 132 | // System.out.printf("panel.keyTyped -> keyCode = %03d, extKeyCode = %05d, keyLocation = %d, keyChar = %c\n", 133 | // evt.getKeyCode(), evt.getExtendedKeyCode(), evt.getKeyLocation(), evt.getKeyChar()); 134 | char c = evt.getKeyChar(); 135 | if (c == 0xFFFD) { // if (c == '�') { 136 | this.keyMapper.pressed(0x000081); 137 | } else if (c == '`') { 138 | this.keyMapper.pressed(0x000080); 139 | } 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/MouseHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | import java.awt.event.MouseEvent; 30 | import java.awt.event.MouseListener; 31 | import java.awt.event.MouseMotionListener; 32 | 33 | import dev.hawala.dmachine.engine.iUiDataConsumer; 34 | 35 | /** 36 | * Listener for mouse events for the Dwarf screen pane, forwarding 37 | * new pointer coordinates or mouse button state changes to the mesa engine. 38 | *
39 | * Any mouse event will grab the input focus to the Dwarf window. 40 | * 41 | * @author Dr. Hans-Walter Latz / Berlin (2017) 42 | */ 43 | public class MouseHandler implements MouseListener, MouseMotionListener { 44 | 45 | private final MainUI mainWindow; 46 | private final iUiDataConsumer mesaEngine; 47 | 48 | private final int maxX; 49 | private final int maxY; 50 | 51 | private int lastX = Integer.MIN_VALUE; 52 | private int lastY = Integer.MIN_VALUE; 53 | 54 | /** 55 | * Constructor. 56 | * 57 | * @param window the main window of the Dwarf application 58 | * @param consumer the ui event ccallbacks of the mesa engine 59 | * @param displayWidth the horizontal size of the mesa display 60 | * @param displayHeight the vertical size of the mesa display 61 | */ 62 | public MouseHandler(MainUI window, iUiDataConsumer consumer, int displayWidth, int displayHeight) { 63 | this.mainWindow = window; 64 | this.mesaEngine = consumer; 65 | 66 | this.maxX = displayWidth - 1; 67 | this.maxY = displayHeight - 1; 68 | } 69 | 70 | private void handleNewMousePosition(MouseEvent ev) { 71 | if (ev == null) { return; } 72 | 73 | if (!this.mainWindow.getDisplayPane().hasFocus()) { 74 | this.mainWindow.getDisplayPane().grabFocus(); 75 | } 76 | 77 | int newX = Math.min(Math.max(0, ev.getX()), this.maxX); 78 | int newY = Math.min(Math.max(0, ev.getY()), this.maxY); 79 | 80 | if (this.lastX != newX || this.lastY != newY) { 81 | this.lastX = newX; 82 | this.lastY = newY; 83 | this.mesaEngine.acceptMousePosition(this.lastX, this.lastY); 84 | } 85 | } 86 | 87 | @Override 88 | public void mouseDragged(MouseEvent ev) { 89 | this.handleNewMousePosition(ev); 90 | } 91 | 92 | @Override 93 | public void mouseMoved(MouseEvent ev) { 94 | this.handleNewMousePosition(ev); 95 | } 96 | 97 | @Override 98 | public void mouseClicked(MouseEvent ev) { 99 | this.handleNewMousePosition(ev); 100 | } 101 | 102 | @Override 103 | public void mouseEntered(MouseEvent ev) { 104 | this.handleNewMousePosition(ev); 105 | } 106 | 107 | @Override 108 | public void mouseExited(MouseEvent ev) { 109 | this.handleNewMousePosition(ev); 110 | } 111 | 112 | @Override 113 | public void mousePressed(MouseEvent ev) { 114 | this.handleNewMousePosition(ev); 115 | this.mesaEngine.acceptMouseKey(ev.getButton(), true); 116 | } 117 | 118 | @Override 119 | public void mouseReleased(MouseEvent ev) { 120 | this.handleNewMousePosition(ev); 121 | this.mesaEngine.acceptMouseKey(ev.getButton(), false); 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/PropertiesExt.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | import java.util.Properties; 30 | 31 | /** 32 | * Extension of plain Java Properties allowing to access properties 33 | * with specific data types as well as with default values if no 34 | * configured value is present. 35 | * 36 | * @author Dr. Hans-Walter Latz / Berlin (2017) 37 | */ 38 | public class PropertiesExt extends Properties { 39 | private static final long serialVersionUID = -2593299943684111928L; 40 | 41 | /** 42 | * Read a string property with a default value. 43 | * @param name the name of the property to read 44 | * @param defValue default value if no value is present in the properties 45 | * @return the string value for the property 46 | */ 47 | public String getString(String name, String defValue) { 48 | if (!this.containsKey(name)) { return defValue; } 49 | String val = this.getProperty(name); 50 | if (val == null || val.length() == 0) { return null; } 51 | return val; 52 | } 53 | 54 | /** 55 | * Read a string with the empty string as default value. 56 | * @param name the name of the property to read 57 | * @return the string value for the property 58 | */ 59 | public String getString(String name) { 60 | return this.getString(name, ""); 61 | } 62 | 63 | /** 64 | * Read an integer property with as default value. 65 | * @param name the name of the property to read 66 | * @param defValue the default value to return if the property 67 | * is not configured of the value cannot be converted to an integer 68 | * @return the integer value 69 | */ 70 | public int getInt(String name, int defValue) { 71 | if (!this.containsKey(name)) { return defValue; } 72 | try { 73 | return Integer.parseInt(this.getProperty(name)); 74 | } catch (NumberFormatException exc) { 75 | return defValue; 76 | } 77 | } 78 | 79 | /** 80 | * Read an integer property with default value {@code 0}. 81 | * @param name the name of the property to read 82 | * @return the integer value 83 | */ 84 | public int getInt(String name) { 85 | return this.getInt(name, 0); 86 | } 87 | 88 | /** 89 | * Read a boolean property with a default value. 90 | * @param name the name of the property to read 91 | * @param defValue value to return if the property has no 92 | * value. 93 | * @return {@code true} if the text value of the property is 94 | * one of 'true', 'yes' or 'y' (resp. the default value) 95 | */ 96 | public boolean getBoolean(String name, boolean defValue) { 97 | if (!this.containsKey(name)) { return defValue; } 98 | String val = this.getProperty(name); 99 | if (val == null || val.length() == 0) { return false; } 100 | val = val.toLowerCase(); 101 | return val.equals("true") || val.equals("yes") || val.equals("y"); 102 | } 103 | 104 | /** 105 | * Read a boolean property with default value {@code false}. 106 | * @param name the name of the property to read 107 | * @return {@code true} if the text value of the property is 108 | * one of 'true', 'yes' or 'y' or else {@code false} 109 | */ 110 | public boolean getBoolean(String name) { 111 | return this.getBoolean(name, false); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/WindowStateListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | import java.awt.event.WindowEvent; 30 | import java.awt.event.WindowListener; 31 | import java.util.function.BooleanSupplier; 32 | 33 | import javax.swing.JOptionPane; 34 | 35 | import dev.hawala.dmachine.engine.Processes; 36 | 37 | /** 38 | * State listener for the Mesa-Emulator main window. 39 | *

40 | * The main purpose is to handle closing the main window while 41 | * the mesa engine is running: a confirmation dialog is showed and 42 | * if closing is confirmed, the mesa engine is halted gracefully 43 | * by shutting down the devices, which saves buffered data of 44 | * the harddisk resp. the currently loaded floppy disk. 45 | *

46 | *

47 | * Additionally refreshing of the Java UI is paused if the application 48 | * is iconized. 49 | *

50 | * 51 | * @author Dr. Hans-Walter Latz / Berlin (2017) 52 | */ 53 | public class WindowStateListener implements WindowListener { 54 | 55 | private final MainUI mainWindow; 56 | private final UiRefresher uiRefresher; 57 | private final BooleanSupplier runningIndicator; 58 | private final Runnable windowCloser; 59 | 60 | /** 61 | * Constructor. 62 | * 63 | * @param mainWindow the main window of the Dwarf application 64 | * @param uiRefresher the ui refresher handling the Java ui updates 65 | * @param runningIndicator function indicating if the emulator engine is currently running 66 | * @param windowCloser function for allowing to close the main window when the engine finally stops 67 | */ 68 | public WindowStateListener(MainUI mainWindow, UiRefresher uiRefresher, BooleanSupplier runningIndicator, Runnable windowCloser) { 69 | this.mainWindow = mainWindow; 70 | this.uiRefresher = uiRefresher; 71 | this.runningIndicator = runningIndicator; 72 | this.windowCloser = windowCloser; 73 | } 74 | 75 | @Override 76 | public void windowOpened(WindowEvent e) { } 77 | 78 | @Override 79 | public void windowClosing(WindowEvent e) { 80 | // check if the mesa engine is running and handle accordingly 81 | if (!this.runningIndicator.getAsBoolean()) { 82 | // simply terminate the program 83 | System.exit(0); 84 | } 85 | 86 | // the mesa engine is running, so ask what to do 87 | int result = JOptionPane.showConfirmDialog( 88 | this.mainWindow.getFrame(), 89 | "OK to close window and shutdown the running mesa engine?", 90 | "Dwarf: Mesa Engine is currently running", 91 | JOptionPane.YES_NO_OPTION); 92 | if (result == JOptionPane.YES_OPTION) { 93 | // halt the engine, let Agent states be saved and let the program be stopped 94 | Processes.requestMesaEngineStop(); // this stops the engine and lets the mesa engine thread shut down the agents 95 | this.windowCloser.run(); // this closes the main window when the mesa engine thread is done 96 | } 97 | } 98 | 99 | @Override 100 | public void windowClosed(WindowEvent e) { } 101 | 102 | @Override 103 | public void windowIconified(WindowEvent e) { 104 | this.uiRefresher.setDoRefreshUi(false); 105 | } 106 | 107 | @Override 108 | public void windowDeiconified(WindowEvent e) { 109 | this.uiRefresher.setDoRefreshUi(true); 110 | } 111 | 112 | @Override 113 | public void windowActivated(WindowEvent e) { } 114 | 115 | @Override 116 | public void windowDeactivated(WindowEvent e) { } 117 | 118 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/eKeyEventCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.dwarf; 28 | 29 | /** 30 | * Enumeration of the keyboard key names in Java, as defined as constants 31 | * in the class {@code KeyEvent}, with the corresppnding extended key code.. 32 | * 33 | * @author Dr. Hans-Walter Latz / Berlin (2017) 34 | */ 35 | public enum eKeyEventCode { 36 | VK_0(48), 37 | VK_1(49), 38 | VK_2(50), 39 | VK_3(51), 40 | VK_4(52), 41 | VK_5(53), 42 | VK_6(54), 43 | VK_7(55), 44 | VK_8(56), 45 | VK_9(57), 46 | VK_A(65), 47 | VK_ACCEPT(30), 48 | VK_ADD(107), 49 | VK_AGAIN(65481), 50 | VK_ALL_CANDIDATES(256), 51 | VK_ALPHANUMERIC(240), 52 | VK_ALT(18), 53 | VK_ALT_GRAPH(65406), 54 | VK_AMPERSAND(150), 55 | VK_ASTERISK(151), 56 | VK_AT(512), 57 | VK_B(66), 58 | VK_BACK_QUOTE(192), 59 | VK_BACK_SLASH(92), 60 | VK_BACK_SPACE(8), 61 | VK_BEGIN(65368), 62 | VK_BRACELEFT(161), 63 | VK_BRACERIGHT(162), 64 | VK_C(67), 65 | VK_CANCEL(3), 66 | VK_CAPS_LOCK(20), 67 | VK_CIRCUMFLEX(514), 68 | VK_CLEAR(12), 69 | VK_CLOSE_BRACKET(93), 70 | VK_CODE_INPUT(258), 71 | VK_COLON(513), 72 | VK_COMMA(44), 73 | VK_COMPOSE(65312), 74 | VK_CONTEXT_MENU(525), 75 | VK_CONTROL(17), 76 | VK_CONVERT(28), 77 | VK_COPY(65485), 78 | VK_CUT(65489), 79 | VK_D(68), 80 | VK_DEAD_ABOVEDOT(134), 81 | VK_DEAD_ABOVERING(136), 82 | VK_DEAD_ACUTE(129), 83 | VK_DEAD_BREVE(133), 84 | VK_DEAD_CARON(138), 85 | VK_DEAD_CEDILLA(139), 86 | VK_DEAD_CIRCUMFLEX(130), 87 | VK_DEAD_DIAERESIS(135), 88 | VK_DEAD_DOUBLEACUTE(137), 89 | VK_DEAD_GRAVE(128), 90 | VK_DEAD_IOTA(141), 91 | VK_DEAD_MACRON(132), 92 | VK_DEAD_OGONEK(140), 93 | VK_DEAD_SEMIVOICED_SOUND(143), 94 | VK_DEAD_TILDE(131), 95 | VK_DEAD_VOICED_SOUND(142), 96 | VK_DECIMAL(110), 97 | VK_DELETE(127), 98 | VK_DIVIDE(111), 99 | VK_DOLLAR(515), 100 | VK_DOWN(40), 101 | VK_E(69), 102 | VK_END(35), 103 | VK_ENTER(10), 104 | VK_EQUALS(61), 105 | VK_ESCAPE(27), 106 | VK_EURO_SIGN(516), 107 | VK_EXCLAMATION_MARK(517), 108 | VK_F(70), 109 | VK_F1(112), 110 | VK_F10(121), 111 | VK_F11(122), 112 | VK_F12(123), 113 | VK_F13(61440), 114 | VK_F14(61441), 115 | VK_F15(61442), 116 | VK_F16(61443), 117 | VK_F17(61444), 118 | VK_F18(61445), 119 | VK_F19(61446), 120 | VK_F2(113), 121 | VK_F20(61447), 122 | VK_F21(61448), 123 | VK_F22(61449), 124 | VK_F23(61450), 125 | VK_F24(61451), 126 | VK_F3(114), 127 | VK_F4(115), 128 | VK_F5(116), 129 | VK_F6(117), 130 | VK_F7(118), 131 | VK_F8(119), 132 | VK_F9(120), 133 | VK_FINAL(24), 134 | VK_FIND(65488), 135 | VK_FULL_WIDTH(243), 136 | VK_G(71), 137 | VK_GREATER(160), 138 | VK_H(72), 139 | VK_HALF_WIDTH(244), 140 | VK_HELP(156), 141 | VK_HIRAGANA(242), 142 | VK_HOME(36), 143 | VK_I(73), 144 | VK_INPUT_METHOD_ON_OFF(263), 145 | VK_INSERT(155), 146 | VK_INVERTED_EXCLAMATION_MARK(518), 147 | VK_J(74), 148 | VK_JAPANESE_HIRAGANA(260), 149 | VK_JAPANESE_KATAKANA(259), 150 | VK_JAPANESE_ROMAN(261), 151 | VK_K(75), 152 | VK_KANA(21), 153 | VK_KANA_LOCK(262), 154 | VK_KANJI(25), 155 | VK_KATAKANA(241), 156 | VK_KP_DOWN(225), 157 | VK_KP_LEFT(226), 158 | VK_KP_RIGHT(227), 159 | VK_KP_UP(224), 160 | VK_L(76), 161 | VK_LEFT(37), 162 | VK_LEFT_PARENTHESIS(519), 163 | VK_LESS(153), 164 | VK_M(77), 165 | VK_META(157), 166 | VK_MINUS(45), 167 | VK_MODECHANGE(31), 168 | VK_MULTIPLY(106), 169 | VK_N(78), 170 | VK_NONCONVERT(29), 171 | VK_NUM_LOCK(144), 172 | VK_NUMBER_SIGN(520), 173 | VK_NUMPAD0(96), 174 | VK_NUMPAD1(97), 175 | VK_NUMPAD2(98), 176 | VK_NUMPAD3(99), 177 | VK_NUMPAD4(100), 178 | VK_NUMPAD5(101), 179 | VK_NUMPAD6(102), 180 | VK_NUMPAD7(103), 181 | VK_NUMPAD8(104), 182 | VK_NUMPAD9(105), 183 | VK_O(79), 184 | VK_OPEN_BRACKET(91), 185 | VK_P(80), 186 | VK_PAGE_DOWN(34), 187 | VK_PAGE_UP(33), 188 | VK_PASTE(65487), 189 | VK_PAUSE(19), 190 | VK_PERIOD(46), 191 | VK_PLUS(521), 192 | VK_PREVIOUS_CANDIDATE(257), 193 | VK_PRINTSCREEN(154), 194 | VK_PROPS(65482), 195 | VK_Q(81), 196 | VK_QUOTE(222), 197 | VK_QUOTEDBL(152), 198 | VK_R(82), 199 | VK_RIGHT(39), 200 | VK_RIGHT_PARENTHESIS(522), 201 | VK_ROMAN_CHARACTERS(245), 202 | VK_S(83), 203 | VK_SCROLL_LOCK(145), 204 | VK_SEMICOLON(59), 205 | VK_SEPARATER(108), 206 | VK_SEPARATOR(108), 207 | VK_SHIFT(16), 208 | VK_SLASH(47), 209 | VK_SPACE(32), 210 | VK_STOP(65480), 211 | VK_SUBTRACT(109), 212 | VK_T(84), 213 | VK_TAB(9), 214 | VK_U(85), 215 | VK_UNDEFINED(0), 216 | VK_UNDERSCORE(523), 217 | VK_UNDO(65483), 218 | VK_UP(38), 219 | VK_V(86), 220 | VK_W(87), 221 | VK_WINDOWS(524), 222 | VK_X(88), 223 | VK_Y(89), 224 | VK_Z(90) 225 | ; 226 | 227 | private final int code; 228 | 229 | private eKeyEventCode(int code) { 230 | this.code = code; 231 | } 232 | 233 | public int getCode() { 234 | return this.code; 235 | } 236 | 237 | public static eKeyEventCode get(int code) { 238 | for (eKeyEventCode kec : eKeyEventCode.values()) { 239 | if (kec.code == code) { 240 | return kec; 241 | } 242 | } 243 | return null; 244 | } 245 | 246 | } 247 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/dwarf/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The package {@code dev.hawala.dmachine.dwarf} contains the 3 | * technical components that make up the Dwarf application UI 4 | * for a single mesa engine. 5 | *

6 | * These are classes necessary to give the mesa engine as visible interface 7 | * (black and white display pane for visualizing the mesa display memory, 8 | * callbacks implementation) as well as the main UI frame window for Dwarf 9 | * including classes for Java Swing event handling (listeners for keyboard, 10 | * mouse etc.) 11 | *

12 | */ 13 | package dev.hawala.dmachine.dwarf; -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/Config.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine; 28 | 29 | /** 30 | * Configuration constants (with one exception) controlling the logging 31 | * and debugging behavior of the mesa engine, 32 | * 33 | * @author Dr. Hans-Walter Latz / Berlin (2017/2020) 34 | */ 35 | public class Config { 36 | 37 | /** 38 | * log recognized opcode implementations as they are scanned and added to dispatch tables? 39 | */ 40 | public static final boolean LOG_OPCODE_INSTALLATION = false; 41 | 42 | /** 43 | * log opcodes and their locations as they are executed? 44 | */ 45 | public static final boolean LOG_OPCODES = false; 46 | 47 | /** 48 | * log as flight recorder? 49 | * (i.e.: collect but do not write the data to stdout, speeding up 50 | * things, but having them at hand if needed, e.g. if a stack trap happens) 51 | * (slows down things, but not to the point as writing to stdout) 52 | */ 53 | public static final boolean LOG_OPCODES_AS_FLIGHTRECORDER = false; 54 | 55 | /** 56 | * prepend the stack data before the logged instruction in flight recorder mode? 57 | */ 58 | public static final boolean FLIGHTRECORDER_WITH_STACK = false; 59 | 60 | /** 61 | * log memory access locations and operations? 62 | */ 63 | public static final boolean LOG_MEM_ACCESS = false; 64 | 65 | /** 66 | * use interactive utility for debugging opcode execution? 67 | */ 68 | public static final boolean USE_DEBUG_INTERPRETER = false; 69 | 70 | /** 71 | * log BITBLT/BITBLTX/COLORBLT arguments and the like 72 | */ 73 | public static final boolean LOG_BITBLT_INSNS = false; 74 | 75 | /** 76 | * If LOG_BITBLT_INSNS is true, logging of BITBLT and friends will 77 | * only occur if they are executed while this flag is true. 78 | *
79 | * At runtime, pressing a specific key (normally F1, see class 80 | * KeyboardMapper) will set this variable to true, allowing to 81 | * restrict logging to specific situations in the UI. 82 | */ 83 | public static volatile boolean dynLogBitblts = false; 84 | 85 | 86 | /* 87 | * logging in io processors (agents / iop-handlers) 88 | */ 89 | 90 | public static final boolean IO_LOG_DISPLAY = false; 91 | 92 | public static final boolean IO_LOG_MOUSE = false; 93 | 94 | public static final boolean IO_LOG_KEYBOARD = false; 95 | 96 | public static final boolean IO_LOG_DISK = false; 97 | 98 | public static final boolean IO_LOG_FLOPPY = false; 99 | 100 | public static final boolean IO_LOG_NETWORK = false; 101 | 102 | public static final boolean IO_LOG_PROCESSOR = false; 103 | 104 | public static final boolean IO_LOG_TTY = false; 105 | 106 | /* 107 | * IORegion logging (6085/daybreak only) 108 | */ 109 | 110 | public static final boolean IOR_LOG_MEM_ACCESS = false; 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/PilotDefs.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine; 28 | 29 | /** 30 | * Constants specific to Pilot. 31 | * 32 | * @author Dr. Hans-Walter Latz / Berlin (2017) 33 | */ 34 | public class PilotDefs { 35 | 36 | /* 37 | * AV / fsi configuration 38 | */ 39 | 40 | public static final int AVHeapSize = 32; // 00B 41 | public static final int LastAVHeapSlot = AVHeapSize - 2; // ==> the last entry is unused?? 42 | 43 | /** the local frame sizes used by Pilot (data area only) at the fsi slots */ 44 | public static final int FRAME_SIZE_MAP[] = { 45 | 8, 12, 16, 20, 24, 46 | 28, 32, 40, 48, 56, 47 | 68, 80, 96, 112, 128, 48 | 148, 168, 192, 224, 252, 49 | 508, 764, 1020, 1276, 1532, 50 | 1788, 2044, 2556, 3068, 3580, 4092 51 | }; 52 | 53 | /** number of pre-allocated local frames for each slot */ 54 | public static final int FRAME_WEIGHT_MAP[] = { 55 | 20, 26, 15, 16, 16, 56 | 12, 8, 8, 5, 5, 57 | 7, 2, 2, 1, 1, 58 | 1, 1, 1, 1, 0, 59 | 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 0 61 | }; 62 | 63 | /* 64 | * devices 65 | */ 66 | 67 | public enum DisplayType { 68 | monochrome(0, 1), 69 | fourBitPlaneColor(1, 4), 70 | byteColor(2, 8); 71 | 72 | private final int type; 73 | private final int bitDepth; 74 | 75 | private DisplayType(int type, int depth) { 76 | this.type = type; 77 | this.bitDepth = depth; 78 | } 79 | 80 | public int getType() { 81 | return this.type; 82 | } 83 | 84 | public int getBitDepth() { 85 | return this.bitDepth; 86 | } 87 | } 88 | 89 | public static final int Device_anyFloppy = 17; 90 | public static final int Device_microFloppy = 23; // 1.44MB, 3 1/2" disks 91 | 92 | public static final int Device_anyPilotDisk = 64; 93 | } 94 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/PrincOpsDefs.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine; 28 | 29 | /** 30 | * Constants defined in the Mesa Processor Principles of Operation Version 31 | * 4.0 (May85) document as wells as the Changed chapters document, 32 | * as required/useful for the implementation of the mesa engine. 33 | * 34 | * @author Dr. Hans-Walter Latz / Berlin (2017) 35 | */ 36 | public class PrincOpsDefs { 37 | 38 | /* 39 | * basic sizes of a word, a page etc. 40 | */ 41 | public static final int WORD_BITS = 16; 42 | 43 | public static final int ADDRESSBITS_IN_PAGE = 8; 44 | public static final int WORDS_PER_PAGE = 256; 45 | public static final int BYTES_PER_PAGE = 512; 46 | 47 | public static final int PAGES_PER_SEGMENT = 256; // giving 64K words per segment 48 | 49 | /* 50 | * basic values 51 | */ 52 | public static final short FALSE = 0; 53 | public static final short TRUE = 1; 54 | 55 | /* 56 | * sizes of structures 57 | */ 58 | 59 | // cSS : Mesa evaluation stack depth 60 | public static final int cSTACK_LENGTH = 14; // fixed by PrincOps (probably: 16 less first/last as guards for StackError) 61 | 62 | // cSV : State vector size 63 | public static final int cSTATE_VECTOR_SIZE = 18; // SlZE[StateVector] + MAX[SIZE [Control Link], 51ZE[FSlndex], SIZE[LONG POINTER]] 64 | 65 | // cWM : wake-up mask 66 | public static final int cWAKEUP_MASK = 10; // ?? processor dependent... ?? 67 | 68 | // cWDC : maximum wake-up disable counter 69 | public static final int cWAKEUP_DISABLE_COUNTER = 7; // minimal value fixed by PrincOps 70 | public static final int WdcMax = 64; // any value > cWAKEUP_DISABLE_COUNTER will do... 71 | 72 | // cTickMin/cTickMax : minimum / maximum tick size in milliseconds 73 | public static final int cTICK_MIN = 15; 74 | public static final int cTICK_MAX = 60; 75 | 76 | // TYPE CodeSegment 77 | public static final int cCODESEGMENT_SIZE = 4; // 4 words available at the begin 78 | 79 | /* 80 | * Constant memory locations 81 | */ 82 | 83 | // mPDA : process data area (LONG POINTER, absolute) 84 | public static final int mPROCESS_DATA_AREA = 0x00010000; // 0200000B 85 | 86 | // mGFT : global frame table (LONG POINTER, absolute) (PrincOps post-4.0) 87 | public static final int mGLOBAL_FRAME_TABLE = 0x00020000; // 0400000B 88 | 89 | // mAV : allocation vector (POINTER, MDS-relative) 90 | public static final int mALLOCATION_VECTOR = 0x0100; // 0400B = start of page one in MDS 91 | 92 | // mSD : system data table (POINTER, MDS-relative, table element: ControlLink = LONG UNSPECIFIED, count: 256 elements) 93 | private static final int mSYSTEM_DATA_TBL = 0x0200; // 01000B = start of page two in MDS 94 | public static int getSdMdsPtr(int index) { 95 | return mSYSTEM_DATA_TBL + ((index & 0xFF) * 2); 96 | } 97 | 98 | // mETT : ESC trap table (POINTER, MDS-relative, table element: ControlLink = LONG UNSPECIFIED, count: 256 elements) 99 | private static final int mESC_TRAP_TBL = 0x0400; // 02000B = start of page three in MDS, four pages long 100 | public static int getEttMdsPtr(int index) { 101 | return mESC_TRAP_TBL + ((index & 0xFF) * 2); 102 | } 103 | 104 | /* 105 | * fault queue indexes (3 of 8 possible entries) 106 | */ 107 | 108 | // qFrameFault 109 | public static final int qFRAME_FAULT = 0; 110 | 111 | // qPagefault 112 | public static final int qPAGE_FAULT = 1; 113 | 114 | // qWriteProtectFault 115 | public static final int qWRITE_PROTECT_FAULT = 2; 116 | 117 | /* 118 | * system data table indexes 119 | */ 120 | 121 | public static final int sBoot = 1; // 1B 122 | public static final int sBoundsTrap = 14; // 16B 123 | public static final int sBreakTrap = 0; // 0B 124 | public static final int sCodeTrap = 7; // 7B 125 | public static final int sControlTrap = 6; // 6B 126 | public static final int sDivCheckTrap = 11; // 13B 127 | public static final int sDivZeroTrap = 10; // 12B 128 | public static final int sInterruptError = 12; // 14B 129 | public static final int sHardwareError = 8; // 10B 130 | public static final int sOpcodeTrap = 5; // 5B 131 | public static final int sPointerTrap = 15; // 17B 132 | public static final int sProcessTrap = 13; // 15B 133 | public static final int sRescheduleError = 3; // 3B 134 | public static final int sStackError = 2; // 2B 135 | public static final int sUnboundTrap = 9; // 11B 136 | public static final int sXferTrap = 4; // 4B 137 | 138 | 139 | /* 140 | * VM mapping - flags 141 | */ 142 | 143 | public static final short MAPFLAGS_MASK = (short)0x0007; // PrincOps defines the lower 3 bits, the upper bits are free for use 144 | public static final short MAPFLAGS_CLEAR = (short)0x0000; 145 | public static final short MAPFLAGS_PROTECTED = (short)0x0004; 146 | public static final short MAPFLAGS_DIRTY = (short)0x0002; 147 | public static final short MAPFLAGS_REFERENCED = (short)0x0001; 148 | public static final short MAPFLAGS_VACANT = (short)0x0006; // PROTECTED and DIRTY but not REFERENCED 149 | 150 | /* 151 | * AVItem-flag-values 152 | */ 153 | 154 | public static final int AVITEM_FRAME = 0; 155 | public static final int AVITEM_EMPTY = 1; 156 | public static final int AVITEM_INDIRECT = 2; 157 | public static final int AVITEM_UNUSED = 3; 158 | 159 | /* 160 | * Overhead locations of global and local frames 161 | */ 162 | 163 | // global frame overhead for PrincOps up to 4.0: 164 | // - global frames are always located in an MDS 165 | // - register GF is a POINTER (16 bit) 166 | // - the global frame overhead also holds the code base reference 167 | public static final int GLOBALOVERHEAD40_SIZE = 4; 168 | public static final int GlobalOverhead40_available = -4; // unspecified 169 | public static final int GlobalOverhead40_word = -3; // flags: 0x0002 = trapxfers ; 0x0001 = codelinks 170 | public static final int GlobalOverhead40_codebase = -2; // long pointer to CodeSegment 171 | 172 | // global frame overhead for PrincOps > 4.0: 173 | // - global frames are outside an MDS (or not necessary in an MDS) 174 | // - register GF is a LONG POINTER (32 bit) 175 | // - the global frame overhead lacks the code base reference 176 | public static final int GLOBALOVERHEAD4x_SIZE = 2; 177 | public static final int GlobalOverhead4x_available = -2; // unspecified 178 | public static final int GlobalOverhead4x_word = -1; // flags: 0x0002 = trapxfers ; 0x0001 = codelinks 179 | 180 | // flags in global frame overhead word: again common for all PrincOps versions 181 | public static final int GlobalLinkage_CodeLinks = 0x0001; 182 | public static final int GlobalLinkage_TrapXfers = 0x0002; 183 | 184 | // local frame overhead 185 | public static final int LOCALOVERHEAD_SIZE = 4; 186 | public static final int LocalOverhead_word = -4; // available: byte , fsi: FSIndex 187 | public static final int LocalOverhead_returnlink = -3; // ShortControlLink 188 | public static final int LocalOverhead_globallink = -2; // GlobalFrameHandle 189 | public static final int LocalOverhead_pc = -1; // cardinal 190 | 191 | /* 192 | * offsets in global frame table entries 193 | */ 194 | public static final int GFTItem_SIZE = 4; // 4 words long 195 | public static final int GFTItem_globalFrame = 0; // LONG POINTER (GlobalFrameHandle) 196 | public static final int GFTItem_codebase = 2; // LONG POINTER (TO CodeSegment) 197 | 198 | /* 199 | * offsets in a PortLink 200 | */ 201 | public static final int Port_inport = 0; 202 | public static final int Port_outport = 2; 203 | 204 | 205 | /* 206 | * not part of PrincOps in the strong sense (ok, not at all) 207 | * but in fact limits of this specific mesa engine implementation (Dwarf). 208 | */ 209 | 210 | public static final int MIN_REAL_ADDRESSBITS = 18; // 18 bits => 1024 pages => 256 kwords = 512 KByte real memory 211 | public static final int MAX_REAL_ADDRESSBITS = 23; // 23 bits => 32768 pages => 8192 kwords = 16 MByte real memory 212 | 213 | public static final int MAX_VIRTUAL_ADDRESSBITS = 25; // 25 bits => 131072 pages => 32768 kwords = 64 MByte virtual memory 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/Agent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | import dev.hawala.dmachine.engine.Mem; 31 | 32 | /** 33 | * Abstract base class for all agents defining the common public interface 34 | * and providing the common functionality. 35 | *

36 | * A derived class usually defines a set of constants for the structure of the 37 | * FCB ({@code fcb_*}), commands ({@code Command_*}), status codes ({@code Status_*}) 38 | * etc., as necessary for communicating with Pilot. 39 | *

40 | *

41 | * Important fine point: When an agent asynchronously receives data from the device 42 | * it represents (e.g. from the UI or from the network), this data must be buffered 43 | * and may not be written directly to the mesa engines memory space, as the necessary 44 | * synchronizations would excessively slow down the mesa engine. 45 | *
46 | * An agent can freely access mesa memory when executing the {@code call()} method (thus 47 | * servicing a CALLAGENT instruction) and when executing the {@code refreshMesaMemory()} method, 48 | * which is called at more or less regular intervals by the mesa engine for exactly the purpose 49 | * of synchronizing the mesa memory with the external data changes accumulated so far. 50 | *

51 | * 52 | * @author Dr. Hans-Walter Latz / Berlin (2017) 53 | */ 54 | public abstract class Agent { 55 | 56 | // the agent type (needed for logging only) 57 | protected final AgentDevice agentType; 58 | 59 | // the own FCB address 60 | protected final int fcbAddress; // virtual memory long pointer 61 | 62 | // the size of the FCB 63 | protected final int fcbSize; // in words 64 | 65 | // should this agent log the own actions? 66 | protected boolean logging = false; 67 | 68 | /** 69 | * Enable or disable logging for this agent. 70 | * @param enabled the new logging flag. 71 | */ 72 | public void enableLogging(boolean enabled) { 73 | this.logging = enabled; 74 | } 75 | 76 | /** 77 | * Base constructor with minimal required parameters. 78 | * 79 | * @param agentType the own type for the agent (for logging). 80 | * @param fcbAddress the base address of the own FCB. 81 | * @param fcbSize the size of the own FCB. 82 | */ 83 | protected Agent(AgentDevice agentType, int fcbAddress, int fcbSize) { 84 | this.agentType = agentType; 85 | this.fcbAddress = fcbAddress; 86 | this.fcbSize = fcbSize; 87 | 88 | this.logf("ctor - fcbAddress = 0x%08X , fcbSize = %d , initializing FCB\n", fcbAddress, fcbSize); 89 | this.initializeFcb(); 90 | } 91 | 92 | /** 93 | * @return the type of this agent. 94 | */ 95 | public AgentDevice getAgentType() { 96 | return this.agentType; 97 | } 98 | 99 | /** 100 | * @return the address of this agents FCB 101 | */ 102 | public int getFcbAddress() { 103 | return this.fcbAddress; 104 | } 105 | 106 | /** 107 | * @return the FCB size for this agent. 108 | */ 109 | public int getFcbSize() { 110 | return this.fcbSize; 111 | } 112 | 113 | /** 114 | * Logging for this agent if enabled, issuing a line prefix identifying the agent type. 115 | * 116 | * @param template {@code printf} template for the line. 117 | * @param args arguments for the template. 118 | */ 119 | protected void logf(String template, Object... args) { 120 | if (!this.logging) { return; } 121 | System.out.printf("Agent " + agentType + ": " + template, args); 122 | } 123 | 124 | /** 125 | * Logging for this agent if enabled, but without a line prefix. 126 | * 127 | * @param template {@code printf} template for the line. 128 | * @param args arguments for the template. 129 | */ 130 | protected void slogf(String template, Object... args) { 131 | if (!this.logging) { return; } 132 | System.out.printf(template, args); 133 | } 134 | 135 | /* 136 | * general public interface of an Agent 137 | */ 138 | 139 | /** 140 | * Fill the agents FCB with the initial data for the agent configuration. 141 | */ 142 | protected abstract void initializeFcb(); 143 | 144 | /** 145 | * Execute the agent operation(s) as instructed in the FCB of the agent. 146 | */ 147 | public abstract void call(); 148 | 149 | /** 150 | * Shutdown the agent, possibly saving back all buffered data to the 151 | * external media hosting the agents content. 152 | * 153 | * @param errMsgTarget for collecting warnings and error messages 154 | * during shutdown. 155 | */ 156 | public abstract void shutdown(StringBuilder errMsgTarget); 157 | 158 | /** 159 | * Copy all buffered new external data into mesa memory space. 160 | */ 161 | public abstract void refreshMesaMemory(); 162 | 163 | /* 164 | * common internal functionality provided to agents 165 | */ 166 | 167 | /** 168 | * Read a word from the agents FCB. 169 | * 170 | * @param offset position of the word in the FCB. 171 | * @return the FCB word at {@code offset}. 172 | */ 173 | protected short getFcbWord(int offset) { 174 | if (offset < 0 || offset >= this.fcbSize) { 175 | Cpu.ERROR("Agent.getFcbWord :: offset out of range: " + offset); 176 | } 177 | return Mem.readWord(this.fcbAddress + offset); 178 | } 179 | 180 | /** 181 | * Read a double-word from the agents FCB. 182 | * 183 | * @param offset position of the double-word in the FCB. 184 | * @return the FCB double-word at {@code offset}. 185 | */ 186 | protected int getFcbDblWord(int offset) { 187 | if (offset < 0 || (offset + 1) >= this.fcbSize) { 188 | Cpu.ERROR("Agent.getFcbWord :: offset out of range: " + offset); 189 | } 190 | return Mem.readDblWord(this.fcbAddress + offset); 191 | } 192 | 193 | /** 194 | * Write a word (given as {@code short}) into the agents FCB. 195 | * 196 | * @param offset position of the word in the FCB. 197 | * @param word the data to be written. 198 | */ 199 | protected void setFcbWord(int offset, short word) { 200 | if (offset < 0 || offset >= this.fcbSize) { 201 | Cpu.ERROR("Agent.getFcbWord :: offset out of range: " + offset); 202 | } 203 | Mem.writeWord(this.fcbAddress + offset, word); 204 | } 205 | 206 | /** 207 | * Write a word (given as {@code int}) into the agents FCB. 208 | * 209 | * @param offset position of the word in the FCB. 210 | * @param word the data to be written. 211 | */ 212 | protected void setFcbWord(int offset, int word) { 213 | if (offset < 0 || offset >= this.fcbSize) { 214 | Cpu.ERROR("Agent.getFcbWord :: offset out of range: " + offset); 215 | } 216 | Mem.writeWord(this.fcbAddress + offset, (short)(word & 0xFFFF)); 217 | } 218 | 219 | /** 220 | * Write a double-word into the agents FCB. 221 | * 222 | * @param offset position of the double-word in the FCB. 223 | * @param dblWord the data to be written. 224 | */ 225 | protected void setFcbDblWord(int offset, int dblWord) { 226 | if (offset < 0 || (offset + 1) >= this.fcbSize) { 227 | Cpu.ERROR("Agent.getFcbWord :: offset out of range: " + offset); 228 | } 229 | Mem.writeDblWord(this.fcbAddress + offset, dblWord); 230 | } 231 | 232 | } 233 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/AgentDevice.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | /** 30 | * Definition of all agent types in the PrincOps Guam (? Pilot 15.3 ?) architecture. 31 | * 32 | * @author Dr. Hans-Walter Latz / Berlin (2017) 33 | */ 34 | public enum AgentDevice { 35 | nullAgent(0), 36 | diskAgent(1), 37 | floppyAgent(2), 38 | networkAgent(3), 39 | parallelAgent(4), 40 | keyboardAgent(5), 41 | beepAgent(6), 42 | mouseAgent(7), 43 | processorAgent(8), 44 | streamAgent(9), 45 | serialAgent(10), 46 | ttyAgent(11), 47 | displayAgent(12), 48 | reserved3Agent(13), 49 | reserved2Agent(14), 50 | reserved1Agent(15); 51 | 52 | private final int index; 53 | 54 | private AgentDevice(int idx) { 55 | this.index = idx; 56 | } 57 | 58 | /** 59 | * @return the index position reserved for this agent 60 | * in the LONG POINTER TO FCB array at the ioArea start. 61 | */ 62 | public int getIndex() { 63 | return this.index; 64 | } 65 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/BeepAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | /** 30 | * Agent for the "beep" device (not implemented, Dwarf is "noiseless"). 31 | * 32 | * @author Dr. Hans-Walter Latz / Berlin (2017) 33 | */ 34 | public class BeepAgent extends Agent { 35 | 36 | /* 37 | * BeepFCBType 38 | */ 39 | private static final int fcb_w_frequency = 0; 40 | private static final int FCB_SIZE = 1; 41 | 42 | public BeepAgent(int fcbAddress) { 43 | super(AgentDevice.beepAgent, fcbAddress, FCB_SIZE); 44 | } 45 | 46 | @Override 47 | public void shutdown(StringBuilder errMsgTarget) { 48 | // nothing to shutdown for this agent 49 | } 50 | 51 | @Override 52 | public void refreshMesaMemory() { 53 | // nothing to transfer to mesa memory for this agent 54 | } 55 | 56 | @Override 57 | public void call() { 58 | int frequency = this.getFcbWord(fcb_w_frequency); 59 | this.logf("frequency = %d\n", frequency); 60 | } 61 | 62 | @Override 63 | protected void initializeFcb() { 64 | this.setFcbWord(fcb_w_frequency, 0); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/DiskState.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | /** 30 | * State or result of an emulated disk operation for hard-disks or floppy disks. 31 | */ 32 | public enum DiskState { 33 | 34 | /** last operation was successful */ 35 | OK, 36 | 37 | /** the medium was forced to read-only mode, changes cannot be saved */ 38 | ReadOnly, 39 | 40 | /** the delta file was incomplete or invalid for some other reason, the disk is probably invalid */ 41 | Corrupted, 42 | 43 | /** delta file could not be created or not completely (directory of disk file has no more room or became r/o) */ 44 | SaveDeltaFailed, 45 | 46 | /** last operation failed for some other reason */ 47 | Other; 48 | } 49 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/KeyboardAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.Config; 30 | import dev.hawala.dmachine.engine.Processes; 31 | import dev.hawala.dmachine.engine.eLevelVKey; 32 | 33 | /** 34 | * Agent for the keyboard of a Dwarf machine. 35 | *

36 | * The purpose of this agent is to transfer the keyboard 37 | * events (already translated to {@code eLevelVKey}s) into 38 | * the bits in the FCB of this agent representing each key. 39 | *

40 | * 41 | * @author Dr. Hans-Walter Latz / Berlin (2017) 42 | */ 43 | public class KeyboardAgent extends Agent { 44 | 45 | /* 46 | * KeyboardFCBType (7 words for keystates) 47 | */ 48 | 49 | private static final int FCB_SIZE = 7; 50 | 51 | /* 52 | * key states 53 | */ 54 | private static final short ALL_KEYS_UP = (short)0xFFFF; 55 | 56 | private short[] uiKeys = new short[FCB_SIZE]; 57 | private boolean uiKeysChanged = false; 58 | 59 | public KeyboardAgent(int fcbAddress) { 60 | super(AgentDevice.keyboardAgent, fcbAddress, FCB_SIZE); 61 | 62 | this.enableLogging(Config.IO_LOG_KEYBOARD); 63 | 64 | for (int i = 0; i < FCB_SIZE; i++) { 65 | this.uiKeys[i] = ALL_KEYS_UP; 66 | } 67 | } 68 | 69 | @Override 70 | public void shutdown(StringBuilder errMsgTarget) { 71 | // nothing to shutdown for this agent 72 | } 73 | 74 | @Override 75 | public void call() { 76 | logf("call() - irrelevant, why is this called???\n"); 77 | } 78 | 79 | @Override 80 | protected void initializeFcb() { 81 | for (int i = 0; i < FCB_SIZE; i++) { 82 | this.setFcbWord(i, ALL_KEYS_UP); 83 | } 84 | } 85 | 86 | public synchronized void resetKeys() { 87 | for (int i = 0; i < FCB_SIZE; i++) { 88 | this.uiKeys[i] = ALL_KEYS_UP; 89 | } 90 | this.uiKeysChanged = true; 91 | this.logf("resetKeys()\n"); 92 | Processes.requestDataRefresh(); 93 | } 94 | 95 | public synchronized void handleKeyUsage(eLevelVKey key, boolean isPressed) { 96 | if (isPressed) { 97 | key.setPressed(this.uiKeys); 98 | } else { 99 | key.setReleased(this.uiKeys); 100 | } 101 | this.uiKeysChanged = true; 102 | this.logf("handleKeyUsage( key = %s, isPressed = %s )\n", key.toString(), (isPressed) ? "true" : "false"); 103 | Processes.requestDataRefresh(); 104 | } 105 | 106 | public synchronized void refreshMesaMemory() { 107 | if (this.uiKeysChanged) { 108 | this.logf("refreshMesaMemory() -> \n"); 109 | for (int i = 0; i < FCB_SIZE; i++) { 110 | short keySetting = this.uiKeys[i]; 111 | // logf(" | %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s |\n", 112 | // ((keySetting & 0x8000) != 0) ? "x" : " ", 113 | // ((keySetting & 0x4000) != 0) ? "x" : " ", 114 | // ((keySetting & 0x2000) != 0) ? "x" : " ", 115 | // ((keySetting & 0x1000) != 0) ? "x" : " ", 116 | // ((keySetting & 0x0800) != 0) ? "x" : " ", 117 | // ((keySetting & 0x0400) != 0) ? "x" : " ", 118 | // ((keySetting & 0x0200) != 0) ? "x" : " ", 119 | // ((keySetting & 0x0100) != 0) ? "x" : " ", 120 | // ((keySetting & 0x0080) != 0) ? "x" : " ", 121 | // ((keySetting & 0x0040) != 0) ? "x" : " ", 122 | // ((keySetting & 0x0020) != 0) ? "x" : " ", 123 | // ((keySetting & 0x0010) != 0) ? "x" : " ", 124 | // ((keySetting & 0x0008) != 0) ? "x" : " ", 125 | // ((keySetting & 0x0004) != 0) ? "x" : " ", 126 | // ((keySetting & 0x0002) != 0) ? "x" : " ", 127 | // ((keySetting & 0x0001) != 0) ? "x" : " " 128 | // ); 129 | this.setFcbWord(i, keySetting); 130 | } 131 | this.uiKeysChanged = false; 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/NetworkInternalTimeService.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | /** 30 | * Implementation of an intenal time service in case no network access is 31 | * configured. 32 | * 33 | * @author Dr. Hans-Walter Latz / Berlin (2018) 34 | */ 35 | public class NetworkInternalTimeService implements iNetDeviceInterface { 36 | 37 | private PacketActor notifier = null; 38 | private short[] timeResponse = null; 39 | 40 | private final short direction; // 0 = west, 1 = east 41 | private final short offsetHours; 42 | private final short offsetMinutes; 43 | 44 | private static long timeShiftMilliSeconds = 0; 45 | 46 | /** 47 | * Set the time adjustment ("days back in time") offset to be used 48 | * when the "current" time is retrieved by the mesa machine programs. 49 | * 50 | * @param seconds adjustment offset in seconds (negative values for shifting 51 | * the current time to the past. 52 | */ 53 | public static void setTimeShiftSeconds(long seconds) { 54 | timeShiftMilliSeconds = seconds * 1000; 55 | } 56 | 57 | /** 58 | * Initialize the internal time service with the time zone information 59 | * (without DST, meaning if DST is active, the {@code gmtOffsetMinutes} 60 | * value must be adjusted accordingly). 61 | * 62 | * @param gmtOffsetMinutes difference between local time and GMT in 63 | * minutes, with positive values being to the east and negative 64 | * to the west (e.g. Germany is +60 without DST and +120 with DST 65 | * whereas Alaska is -560 without DST resp -480 with DST). 66 | */ 67 | public NetworkInternalTimeService(int gmtOffsetMinutes) { 68 | if (gmtOffsetMinutes >= 0) { 69 | this.direction = 1; 70 | } else { 71 | this.direction = 0; 72 | gmtOffsetMinutes = -gmtOffsetMinutes; 73 | } 74 | gmtOffsetMinutes = gmtOffsetMinutes % 720; 75 | this.offsetHours = (short)(gmtOffsetMinutes / 60); 76 | this.offsetMinutes = (short)(gmtOffsetMinutes % 60); 77 | } 78 | 79 | @Override 80 | public void shutdown() { 81 | // nothing to shutdown... 82 | } 83 | 84 | @Override 85 | public synchronized void setNewPacketNotifier(PacketActor notifier) { 86 | this.notifier = notifier; 87 | } 88 | 89 | @Override 90 | public int enqueuePacket(byte[] srcBuffer, int byteCount, boolean feedback) { 91 | if ( this.readWord(srcBuffer, 0) != -1 92 | || this.readWord(srcBuffer, 1) != -1 93 | || this.readWord(srcBuffer, 2) != -1 94 | || this.readWord(srcBuffer, 6) != 0x0600) { // not broadcast or not xns 95 | return byteCount; 96 | } 97 | 98 | if (srcBuffer.length < 54 99 | || this.readWord(srcBuffer, 15) != 0x0008 100 | || this.readWord(srcBuffer, 9) != 0x0004) { // wrong length, target port not time or not PEX 101 | return byteCount; 102 | } 103 | 104 | if ( this.readWord(srcBuffer, 24) != 0x0001 105 | || this.readWord(srcBuffer, 25) != 0x0002 106 | || this.readWord(srcBuffer, 26) != 0x0001) { // not time packet type, wrong version, not request 107 | return byteCount; 108 | } 109 | 110 | // create time request response 111 | 112 | // the raw packet 113 | short[] b = new short[37]; 114 | 115 | // address components 116 | short myNet0 = 0x0004; 117 | short myNet1 = 0x0001; 118 | short myMac0 = 0x1000; 119 | short myMac1 = 0x1A33; 120 | short myMac2 = 0x3333; 121 | short mySocket = 8; 122 | short mac0 = this.readWord(srcBuffer, 3); 123 | short mac1 = this.readWord(srcBuffer, 4); 124 | short mac2 = this.readWord(srcBuffer, 5); 125 | 126 | // time data 127 | long unixTimeMillis = System.currentTimeMillis() + timeShiftMilliSeconds; 128 | int milliSecs = (int)(unixTimeMillis % 1000); 129 | long unixTimeSecs = unixTimeMillis / 1000; 130 | int mesaSecs = (int)((unixTimeSecs + (731 * 86400) + 2114294400) & 0x00000000FFFFFFFFL); 131 | short mesaSecs0 = (short)(mesaSecs >>> 16); 132 | short mesaSecs1 = (short)(mesaSecs & 0xFFFF); 133 | 134 | // build the packet component-wise 135 | 136 | // eth: dst 137 | b[0] = mac0; 138 | b[1] = mac1; 139 | b[2] = mac2; 140 | 141 | // eth: src 142 | b[3] = myMac0; 143 | b[4] = myMac1; 144 | b[5] = myMac2; 145 | 146 | // eth: type 147 | b[6] = 0x0600; 148 | 149 | // xns: ckSum 150 | b[7] = (short)0xFFFF; // no checksum 151 | 152 | // xns: length 153 | b[8] = 60; // payload length 154 | 155 | // xns: transport control & packet type 156 | b[9] = 4; // hop count = 0 & packet type = PEX 157 | 158 | // xns: destination endpoint: copy the source destination of the ingone packet 159 | b[10] = this.readWord(srcBuffer, 16); 160 | b[11] = this.readWord(srcBuffer, 17); 161 | b[12] = this.readWord(srcBuffer, 18); 162 | b[13] = this.readWord(srcBuffer, 19); 163 | b[14] = this.readWord(srcBuffer, 20); 164 | b[15] = this.readWord(srcBuffer, 21); 165 | 166 | // xns: source endpoint: put "our" address with the "local" net and "our" socket 167 | b[16] = myNet0; 168 | b[17] = myNet1; 169 | b[18] = myMac0; 170 | b[19] = myMac1; 171 | b[20] = myMac2; 172 | b[21] = mySocket; 173 | 174 | // pex: identification from request 175 | b[22] = this.readWord(srcBuffer, 22); 176 | b[23] = this.readWord(srcBuffer, 23); 177 | 178 | // pex: client type 179 | b[24] = 1; // clientType "time" 180 | 181 | // payload: time response 182 | b[25] = 2; // version(0): WORD -- TimeVersion = 2 183 | b[26] = 2; // tsBody(1): SELECT type(1): PacketType FROM -- timeResponse = 2 184 | b[27] = mesaSecs0; // time(2): WireLong -- computed time 185 | b[28] = mesaSecs1; 186 | b[29] = this.direction; // zoneS(4): System.WestEast -- east 187 | b[30] = this.offsetHours; // zoneH(5): [0..177B] -- +1 hour 188 | b[31] = this.offsetMinutes; // zoneM(6): [0..377B] -- +0 minutes 189 | b[32] = 0; // beginDST(7): WORD -- no dst (temp) 190 | b[33] = 0; // endDST(8): WORD -- no dst (temp) 191 | b[34] = 1; // errorAccurate(9): BOOLEAN -- true 192 | b[35] = 0; // absoluteError(10): WireLong] 193 | b[36] = (short)((milliSecs > 500) ? 1000 - milliSecs : milliSecs); // no direction ?? (plus or minus)? 194 | 195 | // enqueue for "receiving" the the service response 196 | this.setPacket(b); 197 | 198 | // done 199 | return byteCount; 200 | } 201 | 202 | @Override 203 | public int dequeuePacket(byte[] trgBuffer, int maxLength) { 204 | short[] packet = this.getPacket(); 205 | if (packet == null || trgBuffer == null || maxLength < 2) { 206 | return 0; 207 | } 208 | this.setPacket(null); // the only one was received... 209 | 210 | int trfWords = Math.min(maxLength / 2, packet.length); 211 | int bpos = 0; 212 | for (int i = 0; i < trfWords; i++) { 213 | trgBuffer[bpos++] = (byte)((packet[i] >> 8) & 0xFF); 214 | trgBuffer[bpos++] = (byte)(packet[i] & 0xFF); 215 | } 216 | 217 | return trfWords * 2; 218 | } 219 | 220 | /* 221 | * internals 222 | */ 223 | 224 | private short readWord(byte[] b, int wpos) { 225 | int bpos = wpos * 2; 226 | if (bpos < 0 || (bpos + 1) >= b.length) { 227 | return 0; 228 | } 229 | int hi = b[bpos++] & 0xFF; 230 | int lo = b[bpos] & 0xFF; 231 | short res = (short)(((hi << 8) | lo) & 0xFFFF); 232 | return res; 233 | } 234 | 235 | private synchronized short[] getPacket() { 236 | return this.timeResponse; 237 | } 238 | 239 | private synchronized void setPacket(short[] p) { 240 | this.timeResponse = p; 241 | 242 | if (this.notifier != null) { 243 | try { 244 | this.notifier.handleSinglePacket(); 245 | } catch (InterruptedException e) { 246 | // ignored 247 | } 248 | } 249 | } 250 | 251 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/NullAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | 31 | /** 32 | * Agent for the null device, doing effectively nothing. 33 | * 34 | * @author Dr. Hans-Walter Latz / Berlin (2017) 35 | */ 36 | public class NullAgent extends Agent { 37 | 38 | private static final int FCB_SIZE = 0; 39 | 40 | public NullAgent(int fcbAddress) { 41 | super(AgentDevice.nullAgent, fcbAddress, FCB_SIZE); 42 | } 43 | 44 | @Override 45 | public void shutdown(StringBuilder errMsgTarget) { 46 | // nothing to shutdown for this agent 47 | } 48 | 49 | @Override 50 | public void refreshMesaMemory() { 51 | // nothing to transfer to mesa memory for this agent 52 | } 53 | 54 | @Override 55 | public void call() { 56 | Cpu.ERROR("NullAgent.call :: invalid invocation of nullAgent"); 57 | } 58 | 59 | @Override 60 | protected void initializeFcb() { 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/ParallelAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | 31 | /** 32 | * Agent for the parallel interface of a Dwarf engine (unsupported). 33 | * 34 | * @author Dr. Hans-Walter Latz / Berlin (2017) 35 | */ 36 | public class ParallelAgent extends Agent { 37 | 38 | /* 39 | * unsupported so far 40 | */ 41 | private static final int FCB_SIZE = 0; 42 | 43 | public ParallelAgent(int fcbAddress) { 44 | super(AgentDevice.parallelAgent, fcbAddress, FCB_SIZE); 45 | } 46 | 47 | @Override 48 | public void shutdown(StringBuilder errMsgTarget) { 49 | // nothing to shutdown for this agent 50 | } 51 | 52 | @Override 53 | public void refreshMesaMemory() { 54 | // nothing to transfer to mesa memory for this agent 55 | } 56 | 57 | @Override 58 | public void call() { 59 | Cpu.ERROR("ParallelAgent.call :: invalid invocation of parallelAgent"); 60 | } 61 | 62 | @Override 63 | protected void initializeFcb() { 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/ProcessorAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import java.time.LocalDate; 30 | import java.util.Date; 31 | 32 | import dev.hawala.dmachine.engine.Cpu; 33 | import dev.hawala.dmachine.engine.Mem; 34 | 35 | /** 36 | * Agent providing access to machine characteristics and the clock 37 | * of a Dwarf machine, 38 | * 39 | * @author Dr. Hans-Walter Latz / Berlin (2017) 40 | */ 41 | public class ProcessorAgent extends Agent { 42 | 43 | /* 44 | * ProcessorFCBType 45 | */ 46 | private static final int fcb_w_processorID0 = 0; 47 | private static final int fcb_w_processorID1 = 1; 48 | private static final int fcb_w_processorID2 = 2; 49 | private static final int fcb_w_microsecondsPerHundredPulses = 3; 50 | private static final int fcb_w_millisecondsPerTick = 4; 51 | private static final int fcb_w_alignmentFiller = 5; 52 | private static final int fcb_dbl_realMemoryPageCount = 6; 53 | private static final int fcb_dbl_virtualMemoryPageCount = 8; 54 | private static final int fcb_dbl_gmt = 10; 55 | private static final int fcb_w_command = 12; 56 | private static final int fcb_w_status = 13; // ProcessorStatus 57 | private static final int FCB_SIZE = 14; 58 | 59 | // ProcessorCommand: TYPE = MACHINE DEPENDENT {noop(0), readGMT(1), writeGMT(2)}; 60 | private static final short Command_noop = 0; 61 | private static final short Command_readGMT = 1; 62 | private static final short Command_writeGMT = 2; 63 | 64 | // ProcessorStatus: TYPE = MACHINE DEPENDENT { 65 | // inProgress(0), success(1), failure(2)}; 66 | private static final short Status_inProgress = 0; 67 | private static final short Status_success = 1; 68 | private static final short Status_failure = 2; 69 | 70 | // difference between (our) simulated GMT and (Pilots) expected GMT 71 | private int gmtCorrection = 0; 72 | 73 | // work-around for XDE HeraldWindow having a blinking warning instead of the date 74 | // if the "current" time is not in the expected time frame (somewhere between the bootfile 75 | // build date and some (4 or 5) years later) 76 | // so the system date can be faked (at a 2nd level :-)) to a given date for the first n-thousand 77 | // instructions, so the HeraldWindow sees a specific date when it checks for a plausible boot time 78 | // and the "correct" date is returned after that number of instructions when "the rest of XDE" asks 79 | // for the time 80 | private static long xdeNoBlinkInsnLimit = 0; 81 | private static long xdeNoBlinkBaseMSecs = 0; 82 | private static long xdeNoBlinkDateMSecs = 0; 83 | 84 | public static void installXdeNoBlinkWorkAround(LocalDate noBlinkTargetDate, long insnsLimit) { 85 | xdeNoBlinkInsnLimit = insnsLimit; 86 | xdeNoBlinkBaseMSecs = (System.currentTimeMillis() / 86_400_000L) * 86_400_000L; // midnight of today 87 | xdeNoBlinkDateMSecs = noBlinkTargetDate.toEpochDay() * 86_400_000L; // date to be returned until insnsLimit instructions are reached 88 | } 89 | 90 | public ProcessorAgent(int fcbAddress) { 91 | super(AgentDevice.processorAgent, fcbAddress, FCB_SIZE); 92 | } 93 | 94 | @Override 95 | public void shutdown(StringBuilder errMsgTarget) { 96 | // nothing to shutdown for this agent 97 | } 98 | 99 | @Override 100 | public void refreshMesaMemory() { 101 | // nothing to transfer to mesa memory for this agent 102 | } 103 | 104 | @Override 105 | public void call() { 106 | short cmd = this.getFcbWord(fcb_w_command); 107 | switch(cmd) { 108 | case Command_noop: 109 | this.setFcbWord(fcb_w_status, Status_success); 110 | break; 111 | 112 | case Command_readGMT: 113 | if (Cpu.insns > xdeNoBlinkInsnLimit) { 114 | this.setFcbDblWord(fcb_dbl_gmt, getRawPilotTime() + gmtCorrection); 115 | } else { 116 | this.setFcbDblWord(fcb_dbl_gmt, getRawPilotTime(xdeNoBlinkDateMSecs + (System.currentTimeMillis() - xdeNoBlinkBaseMSecs))); 117 | } 118 | this.setFcbWord(fcb_w_status, Status_success); 119 | break; 120 | 121 | case Command_writeGMT: 122 | gmtCorrection = this.getFcbDblWord(fcb_dbl_gmt) - getRawPilotTime(); 123 | this.setFcbWord(fcb_w_status, Status_success); 124 | break; 125 | 126 | default: 127 | this.setFcbWord(fcb_w_status, Status_failure); 128 | break; 129 | } 130 | } 131 | 132 | @Override 133 | protected void initializeFcb() { 134 | this.setFcbWord(fcb_w_processorID0, Cpu.getPIDword(1)); 135 | this.setFcbWord(fcb_w_processorID1, Cpu.getPIDword(2)); 136 | this.setFcbWord(fcb_w_processorID2, Cpu.getPIDword(3)); 137 | this.setFcbWord(fcb_w_microsecondsPerHundredPulses, Cpu.MicrosecondsPerPulse * 100); 138 | this.setFcbWord(fcb_w_millisecondsPerTick, (Cpu.MicrosecondsPerPulse * Cpu.TimeOutInterval) / 1000); 139 | this.setFcbWord(fcb_w_alignmentFiller, 0); 140 | this.setFcbDblWord(fcb_dbl_realMemoryPageCount, Mem.getRealPagesSize()); 141 | this.setFcbDblWord(fcb_dbl_virtualMemoryPageCount, Mem.getVirtualPagesSize()); 142 | this.setFcbDblWord(fcb_dbl_gmt, getRawPilotTime() + gmtCorrection); 143 | this.setFcbWord(fcb_w_command, Command_noop); 144 | this.setFcbWord(fcb_w_status, Status_success); 145 | } 146 | 147 | 148 | // Java Time base :: 1970-01-01 00:00:00 149 | // Pilot Time base :: 1968-01-01 00:00:00 150 | // => difference is 1 year + 1 leap-year => 731 days. 151 | private static final int UnixToPilotSecondsDiff = 731 * 86400; // seconds 152 | 153 | // this is some unexplainable Xerox constant whatever for, but we have to use it... 154 | private static final int MesaGmtEpoch = 2114294400; 155 | 156 | // get seconds since 1968-01-01 00:00:00 for a given Jaja milliseconds timestamp 157 | private static int getRawPilotTime(long msecs) { 158 | long currJavaTimeInSeconds = msecs / 1000; 159 | return (int)((currJavaTimeInSeconds + UnixToPilotSecondsDiff + MesaGmtEpoch) & 0x00000000FFFFFFFFL); 160 | } 161 | 162 | // get seconds since 1968-01-01 00:00:00 for "now" 163 | private static int getRawPilotTime() { 164 | return getRawPilotTime(System.currentTimeMillis()); 165 | } 166 | 167 | /** 168 | * Get the corresponding Java-{@code Date} for a given mesa-time. 169 | * 170 | * @param mesaTime the mesa time value to translate. 171 | * @return the Java-{@code Date} corrsponding to {@code mesaQTime}. 172 | */ 173 | public static Date getJavaTime(int mesaTime) { 174 | long javaMillis = (mesaTime - UnixToPilotSecondsDiff - MesaGmtEpoch) * 1000L; 175 | return new Date(javaMillis); 176 | } 177 | 178 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/ReservedAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | 31 | /** 32 | * Implementation for one of the "reserved" agents. 33 | * 34 | * @author Dr. Hans-Walter Latz / Berlin (2017) 35 | */ 36 | public class ReservedAgent extends Agent { 37 | 38 | private static final int FCB_SIZE = 0; 39 | 40 | public ReservedAgent(AgentDevice device, int fcbAddress) { 41 | super(device, fcbAddress, FCB_SIZE); 42 | } 43 | 44 | @Override 45 | public void shutdown(StringBuilder errMsgTarget) { 46 | // nothing to shutdown for this agent 47 | } 48 | 49 | @Override 50 | public void refreshMesaMemory() { 51 | // nothing to transfer to mesa memory for this agent 52 | } 53 | 54 | @Override 55 | public void call() { 56 | Cpu.ERROR("ReservedAgent.call :: invalid invocation of " + this.agentType.name()); 57 | } 58 | 59 | @Override 60 | protected void initializeFcb() { 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/SerialAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | 31 | /** 32 | * Agent for the RS-232 serial interface of a Dwarf machine 33 | * (unsupported). 34 | * 35 | * @author Dr. Hans-Walter Latz / Berlin (2017) 36 | */ 37 | public class SerialAgent extends Agent { 38 | 39 | private static final int FCB_SIZE = 0; 40 | 41 | public SerialAgent(int fcbAddress) { 42 | super(AgentDevice.serialAgent, fcbAddress, FCB_SIZE); 43 | } 44 | 45 | @Override 46 | public void shutdown(StringBuilder errMsgTarget) { 47 | // currently nothing to shutdown for this agent 48 | } 49 | 50 | @Override 51 | public void refreshMesaMemory() { 52 | // nothing to transfer to mesa memory for this agent 53 | } 54 | 55 | @Override 56 | public void call() { 57 | Cpu.ERROR("SerialAgent.call :: invalid invocation of serialAgent"); 58 | } 59 | 60 | @Override 61 | protected void initializeFcb() { 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/StreamAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.PrincOpsDefs; 30 | 31 | /** 32 | * Agent for stream-attached "devices" or "coprocessors", i.e. external 33 | * programs and libraries on the "outside" of the mesa engine (i.e. the 34 | * OS where the mesa emulator runs), providing various services like local 35 | * printing, access to the file system, document conversion, copy&paste, 36 | * drag&drop or the like. 37 | *
38 | * (unsupported) 39 | * 40 | * @author Dr. Hans-Walter Latz / Berlin (2017) 41 | */ 42 | public class StreamAgent extends Agent { 43 | 44 | /* 45 | * CoProcessorFCBType 46 | */ 47 | private static final int fcb_lp_iocbHead = 0; 48 | private static final int fcb_lp_iocbNext = 2; 49 | private static final int fcb_w_headCommand = 4; 50 | private static final int fcb_w_filler5 = 5; 51 | private static final int fcb_w_headResult = 6; 52 | private static final int fcb_w_filler7 = 7; 53 | private static final int fcb_w_interruptSelector = 8; 54 | private static final int fcb_w_stopAgent = 9; 55 | private static final int fcb_w_agentStopped = 10; 56 | private static final int fcb_w_streamWordSize = 11; 57 | private static final int FCB_SIZE = 12; 58 | 59 | //CommandType: TYPE = MACHINE DEPENDENT 60 | // {idle(0), accept(1), connect(2), delete(3), read(4), write(5)}; 61 | private static final int Command_idle = 0; 62 | private static final int Command_accept = 1; 63 | private static final int Command_connect = 2; 64 | private static final int Command_delete = 3; 65 | private static final int Command_read = 4; 66 | private static final int Command_write = 5; 67 | 68 | //ConnectionStateType: TYPE = MACHINE DEPENDENT 69 | // {idle(0), accepting(1), connected(2), deleted(3)}; 70 | private static final int ConnState_idle = 0; 71 | private static final int ConnState_accepting = 1; 72 | private static final int ConnState_connected = 2; 73 | private static final int ConnState_deleted = 3; 74 | 75 | //ResultType: TYPE = MACHINE DEPENDENT 76 | // {completed(0), inProgress(1), error(2)}; 77 | private static final int Result_completed = 0; 78 | private static final int Result_inProgress = 1; 79 | private static final int Result_error = 2; 80 | 81 | public StreamAgent(int fcbAddress) { 82 | super(AgentDevice.streamAgent, fcbAddress, FCB_SIZE); 83 | } 84 | 85 | @Override 86 | public void shutdown(StringBuilder errMsgTarget) { 87 | // currently nothing to shutdown for this agent 88 | } 89 | 90 | @Override 91 | public void refreshMesaMemory() { 92 | // TODO: ?? nothing to transfer to mesa memory for this agent 93 | } 94 | 95 | @Override 96 | public void call() { 97 | boolean stop = (this.getFcbWord(fcb_w_stopAgent) != PrincOpsDefs.FALSE); 98 | if (stop) { 99 | logf("call() - stopAgent = true\n"); 100 | this.setFcbWord(fcb_w_agentStopped, PrincOpsDefs.TRUE); 101 | return; 102 | } 103 | this.setFcbWord(fcb_w_agentStopped, PrincOpsDefs.FALSE); 104 | 105 | int command = this.getFcbWord(fcb_w_headCommand); 106 | int interruptSelector = this.getFcbWord(fcb_w_interruptSelector); 107 | int iocbHead = this.getFcbWord(fcb_lp_iocbHead); 108 | int iocbNext = this.getFcbWord(fcb_lp_iocbNext); 109 | switch(command) { 110 | case Command_idle: 111 | logf("call() - headCommand = idle , iocbHead = 0x%08X , iocbNext = 0x%08X , intrSel = 0x%04X\n", 112 | iocbHead, iocbNext, interruptSelector); 113 | break; 114 | 115 | case Command_accept: 116 | logf("call() - headCommand = accept , iocbHead = 0x%08X , iocbNext = 0x%08X , intrSel = 0x%04X\n", 117 | iocbHead, iocbNext, interruptSelector); 118 | break; 119 | 120 | case Command_connect: 121 | logf("call() - headCommand = connect , iocbHead = 0x%08X , iocbNext = 0x%08X , intrSel = 0x%04X\n", 122 | iocbHead, iocbNext, interruptSelector); 123 | break; 124 | 125 | case Command_delete: 126 | logf("call() - headCommand = delete , iocbHead = 0x%08X , iocbNext = 0x%08X , intrSel = 0x%04X\n", 127 | iocbHead, iocbNext, interruptSelector); 128 | break; 129 | 130 | case Command_read: 131 | logf("call() - headCommand = read , iocbHead = 0x%08X , iocbNext = 0x%08X , intrSel = 0x%04X\n", 132 | iocbHead, iocbNext, interruptSelector); 133 | break; 134 | 135 | case Command_write: 136 | logf("call() - headCommand = write , iocbHead = 0x%08X , iocbNext = 0x%08X , intrSel = 0x%04X\n", 137 | iocbHead, iocbNext, interruptSelector); 138 | break; 139 | 140 | default: 141 | logf("call() - *invalid* headCommand = %d , iocbHead = 0x%08X , iocbNext = 0x%08X , intrSel = 0x%04X\n", 142 | command, iocbHead, iocbNext, interruptSelector); 143 | break; 144 | } 145 | 146 | // TODO: implement 147 | this.setFcbWord(fcb_w_headResult, Result_error); 148 | } 149 | 150 | @Override 151 | protected void initializeFcb() { 152 | this.setFcbDblWord(fcb_lp_iocbHead, 0); 153 | this.setFcbDblWord(fcb_lp_iocbNext, 0); 154 | this.setFcbWord(fcb_w_headCommand, 0); 155 | this.setFcbWord(fcb_w_filler5, 0); 156 | this.setFcbWord(fcb_w_headResult, 0); 157 | this.setFcbWord(fcb_w_filler7, 0); 158 | this.setFcbWord(fcb_w_interruptSelector, 0); 159 | this.setFcbWord(fcb_w_stopAgent, 0); 160 | this.setFcbWord(fcb_w_agentStopped, PrincOpsDefs.TRUE); 161 | this.setFcbWord(fcb_w_streamWordSize, 0); 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/TtyAgent.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | 31 | /** 32 | * Agent for interfacing an external terminal attached through 33 | * the TTY interface of a Dwarf machine (unsupported). 34 | * 35 | * @author Dr. Hans-Walter Latz / Berlin (2017) 36 | */ 37 | public class TtyAgent extends Agent { 38 | 39 | private static final int FCB_SIZE = 0; 40 | 41 | public TtyAgent(int fcbAddress) { 42 | super(AgentDevice.ttyAgent, fcbAddress, FCB_SIZE); 43 | } 44 | 45 | @Override 46 | public void shutdown(StringBuilder errMsgTarget) { 47 | // currently nothing to shutdown for this agent 48 | } 49 | 50 | @Override 51 | public void refreshMesaMemory() { 52 | // nothing to transfer to mesa memory for this agent 53 | } 54 | 55 | @Override 56 | public void call() { 57 | Cpu.ERROR("TtyAgent.call :: invalid invocation of ttyAgent"); 58 | } 59 | 60 | @Override 61 | protected void initializeFcb() { 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/iNetDeviceInterface.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.agents; 28 | 29 | /** 30 | * Interface between the NetworkAgent and the implementation of 31 | * the network device. 32 | * 33 | * @author Dr. Hans-Walter Latz / Berlin (2018) 34 | */ 35 | public interface iNetDeviceInterface { 36 | 37 | /** 38 | * Callback for signaling that a new packet arrived. 39 | */ 40 | @FunctionalInterface 41 | public interface PacketActor { 42 | void handleSinglePacket() throws InterruptedException; 43 | } 44 | 45 | /** 46 | * Stop sending/receiving ("unplug the network cable"). 47 | */ 48 | void shutdown(); 49 | 50 | /** 51 | * Register the callback to be called when a new packet arrived. 52 | * 53 | * @param notifier the callback to use. 54 | */ 55 | void setNewPacketNotifier(PacketActor notifier); 56 | 57 | /** 58 | * Put a raw packet in the send queue for transmission 59 | * to the hub. 60 | * 61 | * @param srcBuffer buffer holding the packet raw content 62 | * @param byteCount number of bytes to send from {@code byteCount}, 63 | * this should be between 14 (ethernet header length) and 766 64 | * (max. packet length supported here), 65 | * @param feedback is the packet also to be sent to the originator? 66 | * @return the number of bytes enqueued for this packet or 0 if 67 | * the packet was not accepted (send queue full, too small, ...) 68 | */ 69 | int enqueuePacket(byte[] srcBuffer, int byteCount, boolean feedback); 70 | 71 | /** 72 | * Attempt to retrieve a raw packet from the receive queue. 73 | * 74 | * @param trgBuffer buffer where 75 | * to put the packet raw content. 76 | * @param maxLength the maximum length allowed to use in {@code trgBuffer} 77 | * @return the number of bytes received or 0 if the receive queue 78 | * is empty. 79 | */ 80 | int dequeuePacket(byte[] trgBuffer, int maxLength); 81 | 82 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/agents/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The package {@code dev.hawala.dmachine.engine.agents} has the 3 | * implementations for the so-called Agents which provide the virtual 4 | * devices attached to the mesa engine. 5 | */ 6 | package dev.hawala.dmachine.engine.agents; 7 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/eLevelVKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine; 28 | 29 | /** 30 | * Enumeration of the keys on a (6085) Xerox keyboard, along 31 | * with the bit position in the FCB of the keyboard agent used 32 | * to inform the running program which key is pressed. 33 | * 34 | * @author Dr. Hans-Walter Latz / Berlin (2017) 35 | */ 36 | public enum eLevelVKey { 37 | // fcb word[0] 38 | knull (0), // "null" is a reserved word in Java => "knull" 39 | Bullet (1), 40 | SuperSub (2), 41 | Case (3), 42 | Strikeout (4), 43 | KeypadTwo (5), 44 | KeypadThree (6), 45 | SingleQuote (7), 46 | KeypadAdd (8), 47 | KeypadSubtract (9), 48 | KeypadMultiply (10), 49 | KeypadDivide (11), 50 | KeypadClear (12), 51 | Point (13), // left mouse button 52 | Adjust (14), // right mouse button 53 | Menu (15), // middle mouse button 54 | // fcb word[1] 55 | Five (16), 56 | Four (17), 57 | Six (18), 58 | E (19), 59 | Seven (20), 60 | D (21), 61 | U (22), 62 | V (23), 63 | Zero (24), 64 | K (25), 65 | Dash (26), 66 | P (27), 67 | Slash (28), 68 | Font (29), 69 | Same (30), 70 | BS (31), 71 | // fcb word[2] 72 | Three (32), 73 | Two (33), 74 | W (34), 75 | Q (35), 76 | S (36), 77 | A (37), 78 | Nine (38), 79 | I (39), 80 | X (40), 81 | O (41), 82 | L (42), 83 | Comma (43), 84 | Quote (44), 85 | RightBracket (45), 86 | Open (46), 87 | Special (47), 88 | // fcb word[3] 89 | One (48), 90 | Tab (49), 91 | ParaTab (50), 92 | F (51), 93 | Props (52), 94 | C (53), 95 | J (54), 96 | B (55), 97 | Z (56), 98 | LeftShift (57), 99 | Period (58), 100 | SemiColon (59), 101 | NewPara (60), 102 | OpenQuote (61), 103 | Delete (62), 104 | Next (63), 105 | // fcb word[4] 106 | R (64), 107 | T (65), 108 | G (66), 109 | Y (67), 110 | H (68), 111 | Eight (69), 112 | N (70), 113 | M (71), 114 | Lock (72), 115 | Space (73), 116 | LeftBracket (74), 117 | Equal (75), 118 | RightShift (76), 119 | Stop (77), 120 | Move (78), 121 | Undo (79), 122 | // fcb word[5] 123 | Margins (80), 124 | KeypadSeven (81), 125 | KeypadEight (82), 126 | KeypadNine (83), 127 | KeypadFour (84), 128 | KeypadFive (85), 129 | English (86), 130 | KeypadSix (87), 131 | Katakana (88), 132 | Copy (89), 133 | Find (90), 134 | Again (91), 135 | Help (92), 136 | Expand (93), 137 | KeypadOne (94), 138 | DiagnosticBitTwo (95), 139 | // fcb word[6] 140 | DiagnosticBitOne (96), 141 | Center (97), 142 | KeypadZero (98), 143 | Bold (99), 144 | Italic (100), 145 | Underline (101), 146 | Superscript (102), 147 | Subscript (103), 148 | Smaller (104), 149 | KeypadPeriod (105), 150 | KeypadComma (106), 151 | LeftShiftAlt (107), 152 | DoubleQuote (108), 153 | Defaults (109), 154 | Hiragana (110), 155 | RightShiftAlt (111); 156 | 157 | private final int idx; 158 | 159 | private final int word; 160 | 161 | private final short bit; 162 | 163 | private final short mask; 164 | 165 | private eLevelVKey(int i) { 166 | this.idx = i; 167 | this.word = i / PrincOpsDefs.WORD_BITS; 168 | this.bit = (short)(1 << (PrincOpsDefs.WORD_BITS - 1 - (i % PrincOpsDefs.WORD_BITS))); 169 | this.mask = (short)~this.bit; 170 | } 171 | 172 | public int getAbsoluteBit() { return this.idx; } 173 | 174 | public int getWord() { return this.word; } 175 | 176 | public short getBit() { return this.bit; } 177 | 178 | public short getMask() { return this.mask; } 179 | 180 | public void setPressed(short[] kbdWords) { 181 | kbdWords[this.word] &= this.mask; 182 | } 183 | 184 | public void setReleased(short[] kbdWords) { 185 | kbdWords[this.word] |= this.bit; 186 | } 187 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/iMesaMachineDataAccessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine; 28 | 29 | /** 30 | * UI callbacks that can be registered with the mesa engine, allowing the engine 31 | * to provide data at a suitable moment in the instruction processing (i.e. when 32 | * checking for interrupts or timeouts), ensuring that no concurrent changes occur 33 | * while the callback is active. 34 | * 35 | * @author Dr. Hans-Walter Latz / Berlin (2017) 36 | */ 37 | public interface iMesaMachineDataAccessor { 38 | 39 | /** 40 | * Callback allowing the UI to transfer the display bits from the display 41 | * memory in the real memory space of the mesa engine for updating the 42 | * UIs pixelmap. 43 | *
44 | * Using the {@code pageFlags} and {@code firstPage} values, transferring 45 | * the display memory can be restricted to changed pages in the display memory, 46 | * as the mesa engine can reset the dirty flag of the virtual display memory pages 47 | * after the UI has accessed the display memory. 48 | * 49 | * @param realMemory the real memory used by the mesa engine. 50 | * @param memOffset the real address of the display memory in {@code realMemory}, starting at a memory page 51 | * @param memWords the length in addressable words of the display memory 52 | * @param pageFlags the virtual page map used by the mesa engine 53 | * @param firstPage index of the virtual page for {@code memOffset} in {@code pageFlags} 54 | */ 55 | void accessRealMemory( 56 | short[] realMemory, int memOffset, int memWords, 57 | short[] pageFlags, int firstPage); 58 | 59 | /** 60 | * Callback informing the UI of a value change on the Maintenance Panel. 61 | * 62 | * @param mp the new MP code to display. 63 | */ 64 | void acceptMP(int mp); 65 | 66 | /** 67 | * Callback informing about some statistical values from the mesa engine 68 | * accumulated since starting the mesa engine. 69 | * 70 | * @param counterInstructions number of instructions executed. 71 | * @param counterDiskReads number of hard-disk page reads. 72 | * @param counterDiskWrites number of hard-disk page writes. 73 | * @param counterFloppyReads number of floppy-disk page reads. 74 | * @param counterFloppyWrites number of floppy-disk page writes. 75 | * @param counterNetworkPacketsReceived number of network packes received. 76 | * @param counterNetworkPacketsSent number of network packets sent. 77 | */ 78 | void acceptStatistics( 79 | long counterInstructions, 80 | int counterDiskReads, 81 | int counterDiskWrites, 82 | int counterFloppyReads, 83 | int counterFloppyWrites, 84 | int counterNetworkPacketsReceived, 85 | int counterNetworkPacketsSent 86 | ); 87 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/iUiDataConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine; 28 | 29 | import java.util.function.Supplier; 30 | 31 | /** 32 | * Callbacks provided by the (device-) Agents of the mesa engine to the UI 33 | * for asynchronously receiving UI events or initiating display updates. 34 | * 35 | * @author Dr. Hans-Walter Latz / Berlin (2017) 36 | */ 37 | public interface iUiDataConsumer { 38 | 39 | /** 40 | * Agent callback to inform the mesa engine that a keyboard key 41 | * was pressed or released. 42 | * 43 | * @param key the logical mesa engine key that changed its state. 44 | * @param isPressed is the button identified by {@code key} currently 45 | * pressed ({@code true}) or released ({@code false})? 46 | */ 47 | void acceptKeyboardKey(eLevelVKey key, boolean isPressed); 48 | 49 | /** 50 | * Agent callback to inform the mesa engine that no keys are to 51 | * be considered pressed. 52 | */ 53 | void resetKeys(); 54 | 55 | /** 56 | * Agent callback to inform the mesa engine about a change 57 | * of the mouse buttons depressions. 58 | * 59 | * @param key the mouse key pressed or released, with one of the 60 | * values 1 for the left mouse button, 2 for the middle mouse button 61 | * and 3 for the right mouse button. 62 | * @param isPressed if the button identified by {@code key} currently 63 | * pressed ({@code true}) or released ({@code false})? 64 | */ 65 | void acceptMouseKey(int key, boolean isPressed); 66 | 67 | /** 68 | * Agent callback to inform the mesa engine about a new mouse pointer 69 | * position. 70 | * 71 | * @param x the new x coordinate of the mouse pointer. 72 | * @param y the new y coordinate of the mouse pointer. 73 | */ 74 | void acceptMousePosition(int x, int y); 75 | 76 | /** 77 | * Functional interface (lambda) defining the method for setting the cursor bitmap. 78 | */ 79 | @FunctionalInterface 80 | public interface PointerBitmapAcceptor { 81 | 82 | /** 83 | * Method for setting the cursor bitmap. 84 | * 85 | * @param bitmap bits for the cursor, with each entry in the array defining 86 | * a 16 bit line of the cursor, the array should have a length of 16 entries. 87 | * @param hotspotX horizontal position of the hotspot in the cursors bitmap. 88 | * @param hotspotY vertical position of the hotspot in the cursors bitmap. 89 | */ 90 | void setPointerBitmap(short[] bitmap, int hotspotX, int hotspotY); 91 | } 92 | 93 | /** 94 | * Register the callback to be used by the mesa engine to set a 95 | * new shape for the cursor bitmap. The callback is registered once 96 | * at initialization time of the UI. 97 | * 98 | * @param acpt the callback for setting a new cursor bitmap. 99 | */ 100 | void registerPointerBitmapAcceptor(PointerBitmapAcceptor acpt); 101 | 102 | /** 103 | * Register the callback to be used by the mesa machine to refresh the visible 104 | * UI state, i.e. the display bitmap or the MP code or the statistics. 105 | * The callback is registered once at initialization time of the UI. 106 | * 107 | * @param refresher the set of callbacks to the UI to used by the mesa engine, 108 | * @return callback returning the current color table. may be {@code null} for B/W display; 109 | * the {@code int}-values returned by the callback kust be {@code 0x00rrggbb} 110 | */ 111 | Supplier registerUiDataRefresher(iMesaMachineDataAccessor refresher); 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/iop6085/DeviceHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.iop6085; 28 | 29 | /** 30 | * Common interface and functionality of the Daybreak/6085 device handlers. 31 | * 32 | *@author Dr. Hans-Walter Latz / Berlin (2019,2020) 33 | */ 34 | public abstract class DeviceHandler { 35 | 36 | // generation of bit masks for identifying a single device 37 | // for notifications by the mesa engine 38 | private static int nextNotifyMaskLow = 1; 39 | private static int nextNotifyMaskHigh = 1; 40 | protected static short mkMask() { 41 | int res = (nextNotifyMaskHigh << 8) | nextNotifyMaskLow; 42 | nextNotifyMaskLow <<= 1; 43 | if (nextNotifyMaskLow > 0x0080) { 44 | nextNotifyMaskLow = 1; 45 | nextNotifyMaskHigh++; 46 | } 47 | return (short)res; 48 | } 49 | 50 | // handler name for logging 51 | private final String handlerName; 52 | 53 | // should this agent log the own actions? 54 | protected boolean logging = false; 55 | 56 | // constructor 57 | protected DeviceHandler(String handlerName, boolean loggingEnabled) { 58 | this.handlerName = handlerName; 59 | this.logging = loggingEnabled; 60 | } 61 | 62 | /** 63 | * Enable or disable logging for this device-handler. 64 | * @param enabled the new logging flag. 65 | */ 66 | public void enableLogging(boolean enabled) { 67 | this.logging = enabled; 68 | } 69 | 70 | /** 71 | * Logging for this device-handler if enabled, issuing a line prefix identifying the agent type. 72 | * 73 | * @param template {@code printf} template for the line. 74 | * @param args arguments for the template. 75 | */ 76 | protected void logf(String template, Object... args) { 77 | if (!this.logging) { return; } 78 | System.out.printf("DevHandler " + this.handlerName + ": " + template, args); 79 | } 80 | 81 | /** 82 | * Logging for this device-handler if enabled, but without a line prefix. 83 | * 84 | * @param template {@code printf} template for the line. 85 | * @param args arguments for the template. 86 | */ 87 | protected void slogf(String template, Object... args) { 88 | if (!this.logging) { return; } 89 | System.out.printf(template, args); 90 | } 91 | 92 | /** 93 | * @return the real-memory address of the FCB 94 | */ 95 | public abstract int getFcbRealAddress(); 96 | 97 | /** 98 | * @return the segment of the FCB in the IOP memory address space 99 | */ 100 | public abstract short getFcbSegment(); 101 | 102 | /** 103 | * Check if the {@code notifyMask} identifies this device handler and if so process 104 | * the request(s) currently present in the FCB of the device handler 105 | *

106 | * When a NotifyIOP instruction is executed, this method will be called for all device 107 | * handlers up to the first handler returning {@code true}. 108 | *

109 | * 110 | * @return {@code true} if this device handler was identified by the {@code notifyMask} 111 | * (independently of the outcome (successful or not) if processing happened). 112 | */ 113 | public abstract boolean processNotify(short notifyMask); 114 | 115 | /** 116 | * Operation codes for LOCKMEM instruction 117 | */ 118 | public enum MemOperation { add(0), and(1), or(2), xchg(3), overwriteIfNil(4); 119 | public final int code; 120 | private MemOperation(int code) { this.code = code; } 121 | } 122 | 123 | /** 124 | * Handle synchronized access to memory among the mesa machine and the IOP. 125 | * 126 | * @param lockMask 127 | * @param realAddress 128 | * @param memOp 129 | * @param oldValue 130 | * @param newValue 131 | */ 132 | public abstract void handleLockmem(short lockMask, int realAddress, MemOperation memOp, short oldValue, short newValue); 133 | 134 | /** 135 | * Optionally cleanup at the end of the LOCKMEM processing. 136 | * 137 | * @param lockMask 138 | * @param realAddress 139 | */ 140 | public void cleanupAfterLockmem(short lockMask, int realAddress) { 141 | // default: do nothing 142 | } 143 | 144 | public abstract void handleLockqueue(int vAddr, int rAddr); 145 | 146 | /** 147 | * Copy all buffered new external data into mesa memory space. 148 | */ 149 | public abstract void refreshMesaMemory(); 150 | 151 | /** 152 | * Stop usage of the device and save buffers or the devices state if necessary. 153 | * 154 | * @param errMsgTarget target for messages during shutdown, indicating that there were errors 155 | */ 156 | public abstract void shutdown(StringBuilder errMsgTarget); 157 | 158 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/iop6085/HBeep.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.iop6085; 28 | 29 | import static dev.hawala.dmachine.engine.iop6085.IORegion.*; 30 | 31 | import dev.hawala.dmachine.engine.Config; 32 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.IOPCondition; 33 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.NotifyMask; 34 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.TaskContextBlock; 35 | import dev.hawala.dmachine.engine.iop6085.IORegion.IORAddress; 36 | 37 | /** 38 | * IOP device handler for the beeper (dummy, no sounds provided for now). 39 | * 40 | * @author Dr. Hans-Walter Latz / Berlin (2019,2020) 41 | */ 42 | public class HBeep extends DeviceHandler { 43 | 44 | private static final String BeepFCB = "BeepFCB"; 45 | 46 | private static class FCB implements IORAddress { 47 | private final int startAddress; 48 | 49 | public final TaskContextBlock beepTask; 50 | public final IOPCondition beepCndt; 51 | public final NotifyMask beepMask; 52 | public final Word frequency; 53 | 54 | private FCB() { 55 | this.startAddress = IORegion.syncToSegment() + IORegion.IOR_BASE; 56 | 57 | this.beepTask = new TaskContextBlock(BeepFCB, "beepTask"); 58 | this.beepCndt = new IOPCondition(BeepFCB, "beepCndt"); 59 | this.beepMask = new NotifyMask(BeepFCB, "beepMask"); 60 | this.frequency = mkByteSwappedWord(BeepFCB, "frequency"); 61 | 62 | this.beepMask.byteMaskAndOffset.set(mkMask()); 63 | } 64 | 65 | 66 | @Override 67 | public String getName() { 68 | return BeepFCB; 69 | } 70 | 71 | 72 | @Override 73 | public int getRealAddress() { 74 | return this.startAddress; 75 | } 76 | } 77 | 78 | /* 79 | * implementation of the iop6085 beep device handler 80 | */ 81 | 82 | private final FCB fcb; 83 | 84 | public HBeep() { 85 | super(BeepFCB, Config.IO_LOG_DISPLAY); 86 | this.fcb = new FCB(); 87 | } 88 | 89 | @Override 90 | public int getFcbRealAddress() { 91 | return this.fcb.getRealAddress(); 92 | } 93 | 94 | @Override 95 | public short getFcbSegment() { 96 | return this.fcb.getIOPSegment(); 97 | } 98 | 99 | @Override 100 | public boolean processNotify(short notifyMask) { 101 | // check if it's for us 102 | if (notifyMask != this.fcb.beepMask.byteMaskAndOffset.get()) { 103 | return false; 104 | } 105 | 106 | // simulate beeping on / off 107 | this.logf("processNotify -> frequency = %d (units??)\n", this.fcb.frequency.get() & 0xFFFF); 108 | // megaHertz: LONG CARDINAL <- 2764800; 109 | // fcb.frequency <- ByteSwap[Inline.LowHalf[Inline.LongDiv[megaHertz, MAX[frequency, 43]]]] 110 | 111 | // done 112 | return true; 113 | } 114 | 115 | @Override 116 | public void handleLockmem(short lockMask, int realAddress, MemOperation memOp, short oldValue, short newValue) { 117 | // not relevant 118 | } 119 | 120 | @Override 121 | public void handleLockqueue(int vAddr, int rAddr) { 122 | // not relevant for beep handler 123 | } 124 | 125 | @Override 126 | public synchronized void refreshMesaMemory() { 127 | // not relevant 128 | } 129 | 130 | @Override 131 | public void shutdown(StringBuilder errMsgTarget) { 132 | // nothing to save or shutdown 133 | } 134 | 135 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/iop6085/HKeyboardMouse.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.iop6085; 28 | 29 | import static dev.hawala.dmachine.engine.iop6085.IORegion.*; 30 | 31 | import dev.hawala.dmachine.engine.Config; 32 | import dev.hawala.dmachine.engine.Processes; 33 | import dev.hawala.dmachine.engine.eLevelVKey; 34 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.TaskContextBlock; 35 | import dev.hawala.dmachine.engine.iop6085.IORegion.IORAddress; 36 | 37 | /** 38 | * IOP device handler for the keyboard and mouse of a Daybreak/6085 machine. 39 | * 40 | * @author Dr. Hans-Walter Latz / Berlin (2019,2020) 41 | */ 42 | public class HKeyboardMouse extends DeviceHandler { 43 | 44 | /* 45 | * key states 46 | */ 47 | private static final int KEYBITS_WORDS = 9; 48 | 49 | private static final short ALL_KEYS_UP = (short)0xFFFF; 50 | 51 | private short[] uiKeys = new short[KEYBITS_WORDS]; 52 | private boolean uiKeysChanged = false; 53 | 54 | /* 55 | * Function Control Block 56 | */ 57 | 58 | private static final String KeyMoFCB = "KeyboardMouseFCB"; 59 | 60 | private static class FCB implements IORAddress { 61 | private final int startAddress; 62 | 63 | public final TaskContextBlock keyBoardAndMouseTask; 64 | public final Word hexValue_convertKeyCodeToBit; 65 | public final Word frameErrorCnt; 66 | public final Word overRunErrorCnt; 67 | public final Word parityErrorCnt; 68 | public final Word spuriousIntCnt; 69 | public final Word watchDogCnt; 70 | public final Word badInterruptCnt; 71 | public final Word mouseX; 72 | public final Word mouseY; 73 | public final Word[] kBbase = new Word[KEYBITS_WORDS]; 74 | public final Word[] kBindex = new Word[128]; 75 | 76 | private FCB() { 77 | this.startAddress = IORegion.syncToSegment() + IORegion.IOR_BASE; 78 | 79 | this.keyBoardAndMouseTask = new TaskContextBlock(KeyMoFCB, "displayTCB"); 80 | this.hexValue_convertKeyCodeToBit = mkWord(KeyMoFCB, "hexValue+convertKeyCodeToBit"); 81 | this.frameErrorCnt = mkByteSwappedWord(KeyMoFCB, "frameErrorCnt"); 82 | this.overRunErrorCnt = mkByteSwappedWord(KeyMoFCB, "overRunErrorCnt"); 83 | this.parityErrorCnt = mkByteSwappedWord(KeyMoFCB, "parityErrorCnt"); 84 | this.spuriousIntCnt = mkByteSwappedWord(KeyMoFCB, "spuriousIntCnt"); 85 | this.watchDogCnt = mkByteSwappedWord(KeyMoFCB, "watchDogCnt"); 86 | this.badInterruptCnt = mkByteSwappedWord(KeyMoFCB, "badInterruptCnt"); 87 | this.mouseX = mkWord(KeyMoFCB, "mouseX"); 88 | this.mouseY = mkWord(KeyMoFCB, "mouseY"); 89 | for (int i = 0; i < this.kBbase.length; i++) { 90 | this.kBbase[i] = mkWord(KeyMoFCB, "kBbase[" + i +"]"); 91 | } 92 | for (int i = 0; i < this.kBindex.length; i++) { 93 | this.kBindex[i] = mkWord(KeyMoFCB, "kBindex[" + i +"]"); 94 | } 95 | 96 | } 97 | 98 | @Override 99 | public String getName() { 100 | return KeyMoFCB; 101 | } 102 | 103 | @Override 104 | public int getRealAddress() { 105 | return this.startAddress; 106 | } 107 | 108 | } 109 | 110 | /* 111 | * implementation of the iop6085 keyboard and mouse interface 112 | */ 113 | 114 | private final FCB fcb; 115 | 116 | public HKeyboardMouse() { 117 | super(KeyMoFCB, Config.IO_LOG_KEYBOARD | Config.IO_LOG_MOUSE); 118 | 119 | this.fcb = new FCB(); 120 | 121 | for (int i = 0; i < KEYBITS_WORDS; i++) { 122 | this.fcb.kBbase[i].set(ALL_KEYS_UP); 123 | this.uiKeys[i] = ALL_KEYS_UP; 124 | } 125 | this.uiKeysChanged = false; 126 | } 127 | 128 | @Override 129 | public int getFcbRealAddress() { 130 | return this.fcb.getRealAddress(); 131 | } 132 | 133 | @Override 134 | public short getFcbSegment() { 135 | return this.fcb.getIOPSegment(); 136 | } 137 | 138 | @Override 139 | public boolean processNotify(short notifyMask) { 140 | // no active notifications by client 141 | return false; 142 | } 143 | 144 | @Override 145 | public void handleLockmem(short lockMask, int realAddress, MemOperation memOp, short oldValue, short newValue) { 146 | // no synchronization necessary with client (access to fcb fields serialized through refreshMesaMemory(), see below) 147 | } 148 | 149 | @Override 150 | public void handleLockqueue(int vAddr, int rAddr) { 151 | // not relevant for keyboard/mouse handler 152 | } 153 | 154 | @Override 155 | public void shutdown(StringBuilder errMsgTarget) { 156 | // nothing to save or shutdown 157 | } 158 | 159 | @Override 160 | public synchronized void refreshMesaMemory() { 161 | // transfer keyboard states from UI area to mesa memory 162 | if (this.uiKeysChanged) { 163 | for (int i = 0; i < KEYBITS_WORDS; i++) { 164 | this.fcb.kBbase[i].set(this.uiKeys[i]); 165 | } 166 | this.uiKeysChanged = false; 167 | } 168 | } 169 | 170 | public synchronized void handleKeyUsage(eLevelVKey key, boolean isPressed) { 171 | if (isPressed) { 172 | key.setPressed(this.uiKeys); 173 | } else { 174 | key.setReleased(this.uiKeys); 175 | } 176 | this.uiKeysChanged = true; 177 | this.logf("handleKeyUsage( key = %s, isPressed = %s )\n", key.toString(), (isPressed) ? "true" : "false"); 178 | Processes.requestDataRefresh(); 179 | } 180 | 181 | public synchronized void resetKeys() { 182 | for (int i = 0; i < KEYBITS_WORDS; i++) { 183 | this.uiKeys[i] = ALL_KEYS_UP; 184 | } 185 | this.uiKeysChanged = true; 186 | Processes.requestDataRefresh(); 187 | } 188 | 189 | // must be called by the display device during a refreshMesaMemory() method, i.e. from the mesa processor thread! 190 | public void setNewCursorPosition(short x, short y) { 191 | this.fcb.mouseX.set(x); 192 | this.fcb.mouseY.set(y); 193 | } 194 | 195 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/iop6085/HTTY.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.iop6085; 28 | 29 | import static dev.hawala.dmachine.engine.iop6085.IORegion.mkByteSwappedWord; 30 | import static dev.hawala.dmachine.engine.iop6085.IORegion.mkIOPBoolean; 31 | import static dev.hawala.dmachine.engine.iop6085.IORegion.mkWord; 32 | 33 | import dev.hawala.dmachine.engine.Config; 34 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.ClientCondition; 35 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.IOPCondition; 36 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.NotifyMask; 37 | import dev.hawala.dmachine.engine.iop6085.IOPTypes.TaskContextBlock; 38 | import dev.hawala.dmachine.engine.iop6085.IORegion.IOPBoolean; 39 | import dev.hawala.dmachine.engine.iop6085.IORegion.IORAddress; 40 | import dev.hawala.dmachine.engine.iop6085.IORegion.Word; 41 | 42 | /** 43 | * IOP device handler for the unsupported TTY device of a Daybreak/6085 machine. 44 | * 45 | * @author Dr. Hans-Walter Latz / Berlin (2019,2020) 46 | */ 47 | public class HTTY extends DeviceHandler { 48 | 49 | /* 50 | * Function Control Block 51 | */ 52 | 53 | private static final String TTYFCB = "TTYFCB"; 54 | 55 | private static class WorkListType { 56 | private final IOPBoolean writeBaudRate; 57 | 58 | private WorkListType(String name) { 59 | this.writeBaudRate = mkIOPBoolean(name, "writeBaudRate"); 60 | } 61 | } 62 | 63 | private static class FCB implements IORAddress { 64 | private final int startAddress; 65 | 66 | public final TaskContextBlock txTcb; 67 | public final TaskContextBlock specRxTcb; 68 | public final TaskContextBlock rxTaskChBTcb; 69 | 70 | public final Word ttyLockMask; 71 | public final NotifyMask ttyWorkMask; 72 | public final ClientCondition ttyClientCondition; 73 | public final IOPCondition ttyWorkCondition; 74 | 75 | public final Word txBuffer; // CHARACTER 76 | public final Word rxBuffer; // CHARACTER 77 | 78 | public final Word ttyWorkList; // MACHINE DEPENDENT with 16 BOOLEANs 79 | 80 | public final Word ttyBaudRate; 81 | public final Word wr1_wr3; 82 | public final Word wr4_wr5; 83 | 84 | public final Word iopSystemInputPort_rr0; 85 | public final Word rr1_rr2; 86 | 87 | public final Word ttyStatusWord; 88 | 89 | public final Word eepromImage_type; // MACHINE DEPENDENT {none(0), DCE(2), (LAST [CARDINAL])} 90 | public final Word eepromImage_attributes1; 91 | public final Word eepromImage_attributes2; 92 | public final Word eepromImage_attributes3; 93 | public final Word eepromImage_attributes4; 94 | 95 | private FCB() { 96 | this.startAddress = IORegion.syncToSegment() + IORegion.IOR_BASE; 97 | 98 | this.txTcb = new TaskContextBlock(TTYFCB, "txTcb"); 99 | this.specRxTcb = new TaskContextBlock(TTYFCB, "specRxTcb"); 100 | this.rxTaskChBTcb = new TaskContextBlock(TTYFCB, "rxTaskChBTcb"); 101 | 102 | this.ttyLockMask = mkWord(TTYFCB, "ttyLockMask"); 103 | this.ttyWorkMask = new NotifyMask(TTYFCB, "ttyWorkMask"); 104 | this.ttyClientCondition = new ClientCondition(TTYFCB, "ttyClientCondition"); 105 | this.ttyWorkCondition = new IOPCondition(TTYFCB, "ttyWorkCondition"); 106 | 107 | this.txBuffer = mkWord(TTYFCB, "txBuffer"); 108 | this.rxBuffer = mkWord(TTYFCB, "rxBuffer"); 109 | 110 | this.ttyWorkList = mkWord(TTYFCB, "ttyWorkList"); 111 | 112 | this.ttyBaudRate = mkByteSwappedWord(TTYFCB, "ttyBaudRate"); 113 | this.wr1_wr3 = mkWord(TTYFCB, "wr1+wr3"); 114 | this.wr4_wr5 = mkWord(TTYFCB, "wr4+wr5"); 115 | 116 | this.iopSystemInputPort_rr0 = mkWord(TTYFCB, "iopSystemInputPort+rr0"); 117 | this.rr1_rr2 = mkWord(TTYFCB, "rr1+rr2"); 118 | 119 | this.ttyStatusWord = mkWord(TTYFCB, "ttyStatusWord"); 120 | 121 | this.eepromImage_type = mkWord(TTYFCB, "eepromImage.type"); 122 | this.eepromImage_attributes1 = mkWord(TTYFCB, "eepromImage_attributes[1]"); 123 | this.eepromImage_attributes2 = mkWord(TTYFCB, "eepromImage_attributes[2]"); 124 | this.eepromImage_attributes3 = mkWord(TTYFCB, "eepromImage_attributes[3]"); 125 | this.eepromImage_attributes4 = mkWord(TTYFCB, "eepromImage_attributes[4]"); 126 | 127 | // initialize notification mask 128 | this.ttyWorkMask.byteMaskAndOffset.set(mkMask()); 129 | } 130 | 131 | @Override 132 | public String getName() { 133 | return TTYFCB; 134 | } 135 | 136 | @Override 137 | public int getRealAddress() { 138 | return this.startAddress; 139 | } 140 | 141 | } 142 | 143 | /* 144 | * implementation of the iop6085 tty interface 145 | */ 146 | 147 | private final FCB fcb; 148 | 149 | public HTTY() { 150 | super(TTYFCB, Config.IO_LOG_TTY); 151 | 152 | this.fcb = new FCB(); 153 | } 154 | 155 | @Override 156 | public int getFcbRealAddress() { 157 | return this.fcb.getRealAddress(); 158 | } 159 | 160 | @Override 161 | public short getFcbSegment() { 162 | return this.fcb.getIOPSegment(); 163 | } 164 | 165 | @Override 166 | public boolean processNotify(short notifyMask) { 167 | // check if it's for us 168 | if (notifyMask != this.fcb.ttyWorkMask.byteMaskAndOffset.get()) { 169 | return false; 170 | } 171 | 172 | this.logf("IOP::HTTY.processNotify() - unimplemented yet ...\n"); 173 | 174 | return true; 175 | } 176 | 177 | @Override 178 | public void handleLockmem(short lockMask, int realAddress, MemOperation memOp, short oldValue, short newValue) { 179 | // TTY device currently unsupported/unused 180 | } 181 | 182 | @Override 183 | public void handleLockqueue(int vAddr, int rAddr) { 184 | // TTY device currently unsupported/unused 185 | } 186 | 187 | @Override 188 | public void refreshMesaMemory() { 189 | // TTY device currently unsupported/unused 190 | } 191 | 192 | @Override 193 | public void shutdown(StringBuilder errMsgTarget) { 194 | // TTY device currently unsupported/unused 195 | } 196 | 197 | } -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/iop6085/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The package {@code dev.hawala.dmachine.engine.iop6085} has the 3 | * implementations for the device handlers which provide the emulated 4 | * devices of a 6085/daybreak machine attached to the mesa engine. 5 | *

6 | * For the network device, the network classes implementing the interface to 7 | * Dodos nethub resp. the internal time service are re-used from the sibling 8 | * Agents package. 9 | *

10 | */ 11 | package dev.hawala.dmachine.engine.iop6085; -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/opcodes/Ch03_Memory_Organization.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.opcodes; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | import dev.hawala.dmachine.engine.Mem; 31 | import dev.hawala.dmachine.engine.Opcodes.OpImpl; 32 | import dev.hawala.dmachine.engine.PrincOpsDefs; 33 | import dev.hawala.dmachine.engine.Processes; 34 | 35 | /** 36 | * Implementation of instructions defined in PrincOps 4.0 37 | * in chapter: 3 Memory Organization. 38 | * 39 | * @author Dr. Hans-Walter Latz / Berlin (2017) 40 | */ 41 | public class Ch03_Memory_Organization { 42 | 43 | /* 44 | * 3.1.2 Memory Map Instructions 45 | */ 46 | 47 | // SM - Set Map 48 | public static final OpImpl ESC_x07_SM = () -> { 49 | short mf = Cpu.pop(); 50 | int rp = Cpu.popLong(); 51 | int vp = Cpu.popLong(); 52 | 53 | Mem.setMap("SM", vp, rp, mf); 54 | }; 55 | 56 | // GMF - Get Map Flags 57 | public static final OpImpl ESC_x09_GMF = () -> { 58 | int vp = Cpu.popLong(); 59 | short mf = Mem.getVPageFlags(vp); 60 | int rp = Mem.getVPageRealPage(vp); 61 | 62 | Cpu.push(mf); 63 | Cpu.pushLong(rp); 64 | }; 65 | 66 | // SMF - Set Map Flags 67 | public static final OpImpl ESC_x08_SMF = () -> { 68 | short newMf = Cpu.pop(); 69 | int vp = Cpu.popLong(); 70 | short mf = Mem.getVPageFlags(vp); 71 | int rp = Mem.getVPageRealPage(vp); 72 | 73 | Cpu.push(mf); 74 | Cpu.pushLong(rp); 75 | if (!Mem.isVacant(mf)) { 76 | Cpu.logf(" SMF -> setMap(vp, rp, newMf)\n"); 77 | Mem.setMap("SMF", vp, rp, newMf); 78 | } 79 | }; 80 | 81 | /* 82 | * 3.2.1 Main Data Space Access 83 | */ 84 | 85 | // LP - Lengthen Pointer 86 | public static final OpImpl OPC_xF7_LP = () -> { 87 | short ptr = Cpu.pop(); 88 | Cpu.pushLong((ptr == 0) ? 0 : Cpu.lengthenPointer(ptr)); 89 | }; 90 | 91 | /* 92 | * 3.2.3 Frame Overhead Access 93 | */ 94 | 95 | // ROB - Read Overhead Byte 96 | public static final OpImpl ESC_x1E_ROB_alpha = () -> { 97 | int alpha = Mem.getNextCodeByte(); 98 | int ptr = Cpu.pop() & 0xFFFF; 99 | if (alpha < 1 || alpha > 4) { Cpu.ERROR("ROB :: invalid alpha = " + alpha); } 100 | Cpu.push(Mem.readMDSWord(ptr - alpha)); 101 | }; 102 | 103 | // WOB - Write Overhead Byte 104 | public static final OpImpl ESC_x1F_WOB_alpha = () -> { 105 | int alpha = Mem.getNextCodeByte(); 106 | int ptr = Cpu.pop() & 0xFFFF; 107 | if (alpha < 1 || alpha > 4) { Cpu.ERROR("WOB :: invalid alpha = " + alpha); } 108 | Mem.writeMDSWord(ptr - alpha, Cpu.pop()); 109 | }; 110 | 111 | /* 112 | * 3.3.4 Register Instructions 113 | */ 114 | 115 | // RRIT - Read Register IT 116 | public static final OpImpl ESC_x7D_RRIT = () -> { 117 | Cpu.pushLong(Cpu.IT()); 118 | }; 119 | 120 | // RRMDS - Read Register MDS 121 | public static final OpImpl ESC_x79_RRMDS = () -> { 122 | Cpu.push(Cpu.MDS >>> PrincOpsDefs.WORD_BITS); 123 | }; 124 | 125 | // RRPSB - Read Register PSB 126 | public static final OpImpl ESC_x78_RRPSB = () -> { 127 | Cpu.push(Processes.psbHandle(Cpu.PSB)); 128 | }; 129 | 130 | // RRPTC - Read Register PTC 131 | public static final OpImpl ESC_x7C_RRPTC = () -> { 132 | Cpu.push(Cpu.PTC); 133 | }; 134 | 135 | // RRWDC - Read Register WDC 136 | public static final OpImpl ESC_x7B_RRWDC = () -> { 137 | Cpu.push(Cpu.WDC); 138 | }; 139 | 140 | // RRWP - Read Register WP 141 | public static final OpImpl ESC_x7A_RRWP = () -> { 142 | Cpu.push(Cpu.WP.get()); 143 | }; 144 | 145 | // RRXTS - Read Register XTS 146 | public static final OpImpl ESC_x7E_RRXTS = () -> { 147 | Cpu.push(Cpu.XTS); 148 | }; 149 | 150 | // WRIT - Write Register IT 151 | public static final OpImpl ESC_x75_WRIT = () -> { 152 | Cpu.setIT(Cpu.popLong()); 153 | }; 154 | 155 | // WRMDS - Write Register MDS 156 | public static final OpImpl ESC_x71_WRMDS = () -> { 157 | Cpu.MDS = Cpu.pop() << PrincOpsDefs.WORD_BITS; 158 | }; 159 | 160 | // WRMP - Write Register MP 161 | public static final OpImpl ESC_x77_WRMP = () -> { 162 | Cpu.setMP(Cpu.pop()); 163 | }; 164 | 165 | // WRPSB - Write Register PSB 166 | public static final OpImpl ESC_x70_WRPSB = () -> { 167 | Cpu.PSB = Processes.psbIndex(Cpu.pop()); 168 | }; 169 | 170 | // WRPTC - Write Register PTC 171 | public static final OpImpl ESC_x74_WRPTC = () -> { 172 | Processes.resetPTC(Cpu.pop() & 0xFFFF); 173 | }; 174 | 175 | // WRWDC - Write Register WDC 176 | public static final OpImpl ESC_x73_WRWDC = () -> { 177 | Cpu.WDC = Cpu.pop(); 178 | }; 179 | 180 | // WRWP - Write Register WP 181 | public static final OpImpl ESC_x72_WRWP = () -> { 182 | Cpu.WP.set(Cpu.pop() & 0xFFFF); 183 | }; 184 | 185 | // WRXTS - Write Register XTS 186 | public static final OpImpl ESC_x76_WRXTS = () -> { 187 | Cpu.XTS = Cpu.pop() & 0xFFFF; 188 | }; 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/opcodes/Ch10_Processes.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.engine.opcodes; 28 | 29 | import dev.hawala.dmachine.engine.Cpu; 30 | import dev.hawala.dmachine.engine.Mem; 31 | import dev.hawala.dmachine.engine.Opcodes.OpImpl; 32 | import dev.hawala.dmachine.engine.PrincOpsDefs; 33 | import dev.hawala.dmachine.engine.Processes; 34 | 35 | /** 36 | * Implementation of instructions defined in PrincOps 4.0 37 | * in chapter: 10 Processes 38 | * 39 | * @author Dr. Hans-Walter Latz / Berlin (2017) 40 | */ 41 | public class Ch10_Processes { 42 | 43 | /* 44 | * 10.2 Process Instructions 45 | */ 46 | 47 | /* 48 | * 10.2.1 Monitor Entry 49 | */ 50 | 51 | // ME - Monitor Entry 52 | public static final OpImpl OPC_xF1_ME = () -> { 53 | int m = Cpu.popLong(); 54 | Cpu.checkEmptyStack(); 55 | 56 | short mon = Mem.readWord(m); 57 | if (!Processes.isMonitorLocked(mon)) { 58 | mon = Processes.setMonitorLocked(mon); 59 | Mem.writeWord(m, mon); 60 | Cpu.push(PrincOpsDefs.TRUE); 61 | } else { 62 | Processes.enterFailed(m); 63 | } 64 | }; 65 | 66 | /* 67 | * 10.2.2 Monitor Exit 68 | */ 69 | 70 | // MX - Monitor Exit 71 | public static final OpImpl OPC_xF2_MX = () -> { 72 | int m = Cpu.popLong(); 73 | Cpu.checkEmptyStack(); 74 | 75 | if (Processes.exit(m)) { 76 | Processes.reschedule(false); 77 | } 78 | }; 79 | 80 | /* 81 | * 10.2.3 Monitor Wait 82 | */ 83 | 84 | // MW - Monitor Wait 85 | public static final OpImpl ESC_x02_MW = () -> { 86 | int t = Cpu.pop() & 0xFFFF; 87 | int c = Cpu.popLong(); 88 | int m = Cpu.popLong(); 89 | Cpu.checkEmptyStack(); 90 | 91 | Processes.cleanupCondition(c); 92 | 93 | boolean requeue = Processes.exit(m); 94 | short flags = Processes.fetchPSB_flags(Cpu.PSB); 95 | short cond = Mem.readWord(c); 96 | 97 | if (!Processes.isPsbFlagsAbort(flags) || !Processes.isConditionAbortable(cond)) { 98 | if (Processes.isConditionWakeup(cond)) { 99 | cond = Processes.unsetConditionWakeup(cond); 100 | Mem.writeWord(c, cond); 101 | } else { 102 | Processes.storePSB_timeout(Cpu.PSB, (t == 0) ? 0 : (short)Math.max(1, (Cpu.PTC + t) & 0xFFFF)); 103 | flags = Processes.setPsbFlagsWaiting(flags); 104 | Processes.storePSB_flags(Cpu.PSB, flags); 105 | Processes.requeue(Processes.PDA_LP_header_ready, c, Cpu.PSB); 106 | requeue = true; 107 | } 108 | } 109 | if (requeue) { 110 | Processes.reschedule(false); 111 | } 112 | }; 113 | 114 | /* 115 | * 10.2.4 Monitor Reentry 116 | */ 117 | 118 | // MR - Monitor Reentry 119 | public static final OpImpl ESC_x03_MR = () -> { 120 | int c = Cpu.popLong(); 121 | int m = Cpu.popLong(); 122 | Cpu.checkEmptyStack(); 123 | 124 | short mon = Mem.readWord(m); 125 | if (!Processes.isMonitorLocked(mon)) { 126 | Processes.cleanupCondition(c); 127 | short flags = Processes.fetchPSB_flags(Cpu.PSB); 128 | flags = Processes.setPsbFlags_cleanup(flags, Processes.PsbNull); 129 | Processes.storePSB_flags(Cpu.PSB, flags); 130 | if (Processes.isPsbFlagsAbort(flags)) { 131 | short cond = Mem.readWord(c); 132 | if (Processes.isConditionAbortable(cond)) { Cpu.processTrap(); } 133 | } 134 | mon = Processes.setMonitorLocked(mon); 135 | Mem.writeWord(m, mon); 136 | Cpu.push(PrincOpsDefs.TRUE); 137 | } else { 138 | Processes.enterFailed(m); 139 | } 140 | }; 141 | 142 | /* 143 | * 10.2.5 Notify and Broadcast 144 | */ 145 | 146 | // NC - Notify Condition 147 | public static final OpImpl ESC_x04_NC = () -> { 148 | int c = Cpu.popLong(); 149 | Cpu.checkEmptyStack(); 150 | 151 | Processes.cleanupCondition(c); 152 | short cond = Mem.readWord(c); 153 | if (Processes.getCondition_tail(cond) != Processes.PsbNull) { 154 | Processes.wakeHead(c); 155 | Processes.reschedule(false); 156 | } 157 | }; 158 | 159 | // BC - Broadcast Condition 160 | public static final OpImpl ESC_x05_BC = () -> { 161 | boolean requeue = false; 162 | int c = Cpu.popLong(); 163 | Cpu.checkEmptyStack(); 164 | 165 | Processes.cleanupCondition(c); 166 | short cond = Mem.readWord(c); 167 | while (Processes.getCondition_tail(cond) != Processes.PsbNull) { 168 | Processes.wakeHead(c); 169 | requeue = true; 170 | cond = Mem.readWord(c); 171 | } 172 | if (requeue) { 173 | Processes.reschedule(false); 174 | } 175 | }; 176 | 177 | /* 178 | * 10.2.6 Requeue 179 | */ 180 | 181 | // REQ - Requeue 182 | public static final OpImpl ESC_x06_REQ = () -> { 183 | int psbHandle = Cpu.pop(); 184 | int dstQue = Cpu.popLong(); 185 | int srcQue = Cpu.popLong(); 186 | Cpu.checkEmptyStack(); 187 | Processes.requeue(srcQue, dstQue, Processes.psbIndex(psbHandle)); 188 | Processes.reschedule(false); 189 | }; 190 | 191 | /* 192 | * 10.2.7 Set Process Priority 193 | */ 194 | 195 | // SPP - Set Process Priority 196 | public static final OpImpl ESC_x0F_SPP = () -> { 197 | int priority = Cpu.pop() & 0xFFFF; 198 | Cpu.checkEmptyStack(); 199 | 200 | short link = Processes.fetchPSB_link(Cpu.PSB); 201 | link = Processes.setPsbLink_priority(link, priority); 202 | Processes.storePSB_link(Cpu.PSB, link); 203 | Processes.requeue(Processes.PDA_LP_header_ready, Processes.PDA_LP_header_ready, Cpu.PSB); 204 | Processes.reschedule(false); 205 | }; 206 | 207 | /* 208 | * 10.4.4.3 Disabling Interrupts 209 | */ 210 | 211 | // DI - Disable Interrupts 212 | public static final OpImpl ESC_x10_DI = () -> { 213 | if (Cpu.WDC == PrincOpsDefs.WdcMax) { 214 | Cpu.interruptError(); 215 | } 216 | Processes.disableInterrupts(); 217 | }; 218 | 219 | // EI - Enable Interrupts 220 | public static final OpImpl ESC_x11_EI = () -> { 221 | if (Cpu.WDC == 0) { 222 | Cpu.interruptError(); 223 | } 224 | Processes.enableInterrupts(); 225 | }; 226 | 227 | } 228 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/opcodes/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The package {@code dev.hawala.dmachine.engine.opcodes} contains the 3 | * implementation of the mesa instructions. 4 | *

5 | * The instructions are automatically bound to the opcodes using the naming 6 | * convention defined by the class {@link dev.hawala.dmachine.engine.Opcodes}. 7 | *

8 | *

9 | * The implementations of the instructions are grouped in classes organized along 10 | * the chapters 3 to 10 of the Mesa Processor Principles of Operation Version 11 | * 4.0 (May85) document. An additional class (for chapter "XX") holds the instructions 12 | * that became available after version 4.0 of the PrincOps (being in fact undocumented), 13 | * as far as these instructions are used. 14 | *

15 | */ 16 | package dev.hawala.dmachine.engine.opcodes; 17 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/engine/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The package {@code dev.hawala.dmachine.engine} encompasses all 3 | * components implementing the mesa engine for Dwarf. 4 | *
5 | * The components are organized as follows: 6 | *
    7 | *
  • the package itself contains the infrastructure components 8 | * of the mesa engine like the real/virtual memory implementation, 9 | * the cpu registers etc. 10 | *
  • 11 | *
  • the sub-package {@code .opcodes} contains the implementation 12 | * of the instructions, organized by the chapters of the document 13 | * Mesa Processor Principles of Operation Version 4.0 (May85). 14 | *
  • 15 | *
  • the sub-package {@code .agents} holds the implementation of 16 | * the hardware-interfacing (or simulating) Agents which provide access 17 | * to the peripherals of a workstation like display, keyboard, mouse, 18 | * disk, floppy etc. 19 | *
  • 20 | *
  • the sub-package {@code .unittest} holds the more or less systematic 21 | * tests for the mesa instructions (with the exception of the control 22 | * transfer and processes instructions, sorry). 23 | *
  • 24 | *
25 | */ 26 | package dev.hawala.dmachine.engine; -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The package {@code dev.hawala.dmachine} is the base package 3 | * for the Dwarf Mesa emulator family, containing the main programs 4 | * (classes {@code Duchess}, {@code Draco} and {@code DwarfMain}) and the 5 | * following sub-packages: 6 | *
    7 | *
  • 8 | * {@code dev.hawala.dmachine.engine} containing the mesa engine as Dwarfs 9 | * Mesa PrincOps implementation including the hardware/peripherals interfaces for 10 | * building up a workstation-like environment 11 | *
  • 12 | *
  • 13 | * {@code dev.hawala.dmachine.dwarf} containing the Java Swing UI and 14 | * related classes as well as the items to connect the UI components with their 15 | * counterparts in the mesa engine. 16 | *
  • 17 | *
18 | */ 19 | package dev.hawala.dmachine; -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/unittest/Ch03_MemoryOrganizationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.unittest; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | 31 | import org.junit.After; 32 | import org.junit.Test; 33 | 34 | import dev.hawala.dmachine.engine.Cpu; 35 | import dev.hawala.dmachine.engine.Mem; 36 | import dev.hawala.dmachine.engine.opcodes.Ch03_Memory_Organization; 37 | 38 | /** 39 | * Unittests for instructions implemented in class Ch03_Memory_Organization. 40 | * 41 | * @author Dr. Hans-Walter Latz / Berlin (2017) 42 | */ 43 | public class Ch03_MemoryOrganizationTest extends AbstractInstructionTest { 44 | 45 | private int getRpForVp(int vp) { 46 | Cpu.pushLong(vp); 47 | 48 | Ch03_Memory_Organization.ESC_x09_GMF.execute(); 49 | 50 | int rp = Cpu.popLong(); 51 | short mf = Cpu.pop(); 52 | 53 | return rp; 54 | } 55 | 56 | private short getMfForVp(int vp) { 57 | Cpu.pushLong(vp); 58 | 59 | Ch03_Memory_Organization.ESC_x09_GMF.execute(); 60 | 61 | int rp = Cpu.popLong(); 62 | short mf = Cpu.pop(); 63 | 64 | return mf; 65 | } 66 | 67 | private void setMfForVp(int vp, short newMf) { 68 | Cpu.pushLong(vp); 69 | Cpu.push(newMf); 70 | 71 | Ch03_Memory_Organization.ESC_x08_SMF.execute(); 72 | Cpu.popLong(); // drop rp 73 | Cpu.pop(); // drop mf 74 | } 75 | 76 | private void setMap(int vp, short mf, int rp) { 77 | Cpu.pushLong(vp); 78 | Cpu.pushLong(rp); 79 | Cpu.push(mf); 80 | 81 | Ch03_Memory_Organization.ESC_x07_SM.execute(); 82 | } 83 | 84 | private static short MF_CLEAN = 0x0000; 85 | private static short MF_READ = 0x0001; 86 | private static short MF_WRITTEN = 0x0003; 87 | private static short MF_VACANT = 0x0006; 88 | 89 | @After 90 | public void postTest() { 91 | Mem.createInitialPageMappingGuam(); 92 | } 93 | 94 | @Test 95 | public void testVpToRealMapping() { 96 | int rp = 0x00000100; 97 | int vp = 0; 98 | int lp = 0x00000011; 99 | short data = 0x1234; 100 | 101 | // implant the start value 102 | Mem.writeWord((rp << 8) | lp, data); 103 | 104 | // place the real page in virtual page 0 to start testing 105 | setMfForVp(rp, MF_VACANT); // unmap the test rp , located in the area where vp == rp 106 | assertEquals("getMfForVp(rp) after unmapping rp", MF_VACANT, getMfForVp(rp)); 107 | setMap(vp, MF_CLEAN, rp); 108 | 109 | while(vp < firstUnmappedPage) { 110 | // unmap the real page 111 | setMfForVp(vp, MF_VACANT); 112 | 113 | // map the real page to the next virtual page to test 114 | vp++; 115 | lp += 256; 116 | setMap(vp, MF_CLEAN, rp); 117 | 118 | // check initial state 119 | assertEquals("mapFlags for mapped vp", MF_CLEAN, getMfForVp(vp)); 120 | assertEquals("rp for mapped vp", rp, getRpForVp(vp)); 121 | 122 | // read from the page 123 | short memValue = Mem.readWord(lp); 124 | assertEquals("value at mapped virtual page address", data, memValue); 125 | assertEquals("mapFlags for vp after read", MF_READ, getMfForVp(vp)); 126 | setMfForVp(vp, MF_CLEAN); 127 | 128 | // change data and write it to page 129 | data = (short)((data + 17) & 0xFFFF); 130 | Mem.writeWord(lp, data); 131 | assertEquals("mapFlags for vp after read", MF_WRITTEN, getMfForVp(vp)); 132 | } 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/unittest/Misc_Tests.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017, Dr. Hans-Walter Latz 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS 16 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package dev.hawala.dmachine.unittest; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | import static org.junit.Assert.fail; 31 | 32 | import org.junit.Test; 33 | 34 | import dev.hawala.dmachine.engine.Cpu; 35 | import dev.hawala.dmachine.engine.Cpu.MesaAbort; 36 | import dev.hawala.dmachine.engine.Cpu.MesaERROR; 37 | import dev.hawala.dmachine.engine.Mem; 38 | import dev.hawala.dmachine.engine.Opcodes; 39 | import dev.hawala.dmachine.engine.Processes; 40 | 41 | /** 42 | * Unittests for checking the concept of timeout check throttling 43 | * (as well as a little performance measuring). 44 | * 45 | * @author Dr. Hans-Walter Latz / Berlin (2017) 46 | */ 47 | public class Misc_Tests extends AbstractInstructionTest { 48 | 49 | @Test 50 | public void test_SampleCode() { 51 | // prepare global frame 52 | mkGlobalFrame( // offset / content 53 | 0x1234, // [0] parameter for 2. 54 | 0, // [1] unused 55 | testLongMemLow, // [2] address of ... 56 | testLongMemHigh // [3] long-pointer storage 57 | ); 58 | 59 | // prepare local frame 60 | mkLocalFrame( // offset / content 61 | 0x1122, // [0] dbl-data for 5. (low-word) 62 | 0x3344, // [1] dbl-data for 5. (high-word) 63 | 0x0000, // [2] target for 4. 64 | testShortMem // [3] address of (short-)pointer storage 65 | ); 66 | 67 | // prepare short pointer memory 68 | mkShortMem( // offset / content 69 | 0x0000, // [0] unused 70 | 0x0000, // [1] unused 71 | 0x0000, // [2] unused 72 | 0x0000, // [3] unused 73 | 0x5566, // [4] dbl-data for 6. (low-word) 74 | 0x7788 // [5] dbl-data for 6. (high-word) 75 | ); 76 | 77 | // prepare long pointer memory 78 | mkLongMem( // offset / content 79 | 0x4321 // [0] parameter for 1. 80 | ); 81 | 82 | // hand-crafted loop adding 2 shorts and 2 longs from varying locations in memory 83 | mkCode( 84 | // 0. starting point for execution 85 | PC, 86 | 87 | // 1. load word from long pointer [0] using address in global frame[2] 88 | 0x39, // LGD2 - Load Global Double 2 :: get long-pointer from global frame at offset 2 89 | 0x43, // RL0 - Read Long 0 :: dereference long-pointer with offset 0 90 | 91 | // 2. load word from global frame [0] 92 | 0x34, // LG0 - Load Global 0 :: get word form global frame at offset 0 93 | 94 | // 3. add words 95 | 0xB5, // ADD - Add :: word-add stacked values 96 | 97 | // 4. store word in local frame [2] 98 | 0x1B, // SL2 - Store Local 2 :: store stacked result-word in local frame at offset 2 99 | 100 | // 5. load dbl-word from local frame [0] 101 | 0x0E, // LLD0 - Load Local Double 0 :: load long-value from local frame at offset 0 102 | 103 | // 6. load dbl-word from short pointer [4] 104 | 0x04, // LL3 - Load Local 3 :: load short address from local frame (offset 3) 105 | 0x46, 0x04, // RDB - Read Double Byte , alpha = 4 :: load long-value through this pointer with offset 4 106 | 107 | // 7. subtract 108 | 0xB8, // DSUB - Double Subtract ::subtract long-values 109 | 110 | // 8 store dbl-word in long pointer [2] 111 | 0x39, // LGD2 - Load Global Double 2 :: get long-pointer from global frame at offset 2 112 | 0x51, 0x02, // WDLB - Write Double Long Byte , alpha = 2 :: store long value at long-pointer + 2 113 | 114 | // 9. jump to 1. (offset = -13 = code bytes so far) 115 | 0x88, -13 // JB - Jump Byte , offset = -13 :: jump back to start 116 | ); 117 | 118 | // initialize the engine to use PrincOps 4.0 instruction (registers are already reset by @Before) 119 | Opcodes.initializeInstructionsPrincOps40(); 120 | 121 | // run the loop a defined number of times repeatedly 122 | final int sleepTime = 40; // 40 milliseconds, give the Java JIT a chance to (re)compile to native 123 | runLoop(); 124 | sleep(sleepTime); 125 | runLoop(); 126 | sleep(sleepTime); 127 | runLoop(); 128 | sleep(sleepTime); 129 | runLoop(); 130 | sleep(sleepTime); 131 | runLoop(); 132 | sleep(sleepTime); 133 | runLoop(); 134 | } 135 | 136 | private void sleep(int amount) { 137 | try { 138 | Thread.sleep(amount); 139 | } catch(InterruptedException ie) { 140 | // ignored 141 | } 142 | } 143 | 144 | /* 145 | * copy of the main interpreter loop (from Cpu) with initial implementation of timeout check throttling 146 | */ 147 | 148 | private static final int timeoutThrottleCount = 32 * 1024; 149 | /* 150 | * 10.4.5 Timeouts 151 | * ... 152 | * Timeouts are measured in ticks, where the conversion between ticks and real time is 153 | * processor-dependent. A tick is on the order of 40 milliseconds. 154 | * ... 155 | * 156 | * Appendix A 157 | * ... 158 | * cTick Mininum and Maximum Tick Size 159 | * cTickMin: CARDINAL = 15; 160 | * cTickMax: CARDINAL = 60; 161 | * (milliseconds!) 162 | * 163 | * 2.4 GHz CoreDuo2: 164 | * 32768 gives at the very least 20 Mips 165 | * => ~50 nanosecs per instruction 166 | * => timeout check interval ~ 1,7 millisecs 167 | * => better than cTickMin! 168 | */ 169 | 170 | private void runLoop() { 171 | // simulated code interpreter loop 172 | final int loopInstructions = 12; 173 | final int loopCount = 1_000_000; 174 | final int maxInstructions = loopInstructions * loopCount; 175 | int count = 0; 176 | int startPC = Cpu.PC; 177 | long startMs = System.currentTimeMillis(); 178 | int timeoutCountDown = timeoutThrottleCount; 179 | try { 180 | while(count < maxInstructions) { 181 | try { 182 | boolean interrupt = Processes.checkforInterrupts(); 183 | boolean timeout = false; 184 | if (timeoutCountDown < 1) { 185 | timeout = Processes.checkForTimeouts(); 186 | timeoutCountDown = timeoutThrottleCount; 187 | } else { 188 | timeoutCountDown--; 189 | } 190 | if (interrupt || timeout) { 191 | fail("Simulated interpreter loop should not get interrupts or timeouts"); 192 | } else if (Cpu.running) { 193 | // execute(); 194 | count++; 195 | Cpu.savedPC = Cpu.PC; 196 | Cpu.savedSP = Cpu.SP; 197 | Opcodes.dispatch(Mem.getNextCodeByte()); 198 | } else { 199 | fail("Simulated interpreter loop should not stop running"); 200 | } 201 | } catch (MesaAbort ma) { 202 | fail("Simulated interpreter loop should not get an MesaAbort");; 203 | } 204 | } 205 | } catch (MesaERROR me) { 206 | fail("unexpected MesaERROR"); 207 | } catch (RuntimeException re) { 208 | re.printStackTrace(); 209 | fail("Unexpected RuntimeException: " + re); 210 | } 211 | long endMs = System.currentTimeMillis(); 212 | assertEquals("PC after all loops", startPC, Cpu.PC); 213 | 214 | long runtime = endMs + 1 - startMs; 215 | System.out.printf("\n** time elapsed for %d instructions : %d millisecs => %d insns/sec\n", 216 | maxInstructions, runtime, (maxInstructions * 1000L) / runtime); 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /src/dev/hawala/dmachine/unittest/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * UnitTests for the mesa engine instructions. 3 | *

4 | * As for the instruction implementations, the tests are grouped by 5 | * the chapters of the PrincOps document where the instructions 6 | * are specified. 7 | *
8 | * However, there are currently no tests for the Control Transfer (chapter 9) 9 | * and Processes (chapter 10) instructions. The reason is partly laziness and 10 | * partly the fact that the environment required to test most of these instructions 11 | * (code segments, linkages, process table setups) encompasses half an OS like Pilot. 12 | *

13 | *

14 | * The problem with the last point is that building that environment based on the 15 | * same assumptions used to implement the instructions will not result in an useful 16 | * test. The real test environment for testing control transfer is in fact Pilot, 17 | * So the "strategy" for these 2 chapters was to implement the instructions, review the 18 | * implementation twice in longer time intervals, correcting recognized deviations from 19 | * the PrincOps. This approach worked well for the Processes instructions (which worked 20 | * fine from the start on when booting Pilot), but however only in the second attempt 21 | * for the control transfer instructions. 22 | *

23 | */ 24 | package dev.hawala.dmachine.unittest; -------------------------------------------------------------------------------- /src/resources/base144.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devhawala/dwarf/c264af5e37f89d7aa0eec968aa23818bf5a89837/src/resources/base144.raw --------------------------------------------------------------------------------