├── .gitignore ├── .paket ├── Paket.Restore.targets ├── paket.bootstrapper.exe └── paket.exe ├── LICENSE ├── Nuget.Config ├── README.md ├── Visual2.sln ├── app ├── css │ ├── material-icons.css │ ├── photon.css │ ├── vex-theme-default.css │ ├── vex-theme-flat-attack.css │ ├── vex-theme-os.css │ ├── vex-theme-plain.css │ ├── vex-theme-top.css │ ├── vex-theme-wireframe.css │ ├── vex.css │ └── vistally.css ├── fonts │ ├── fira-code.eot │ ├── fira-code.ttf │ ├── fira-code.woff │ ├── material-icons.woff2 │ ├── photon-entypo.eot │ ├── photon-entypo.ttf │ └── photon-entypo.woff ├── hovers │ ├── testhover.md │ └── testhover1.md ├── index.html ├── js │ └── monaco-init.js ├── resources │ ├── errortest.html │ └── visual.ico ├── samples │ └── karatsuba.s ├── test-data │ ├── ALLOWEDdp2ImmAll.txt │ ├── ALLOWEDdp2ShiftsAll.txt │ ├── ALLOWEDdp3ImmAll.txt │ ├── ALLOWEDdp3ShiftsAll.txt │ ├── ComputedBranchesAll.txt │ ├── ConditionalBranchesAll.txt │ ├── MemLoadsAll.txt │ ├── MemStoresAll.txt │ ├── MiscInstrAll.txt │ ├── MultMemLoadsAll.txt │ ├── MultMemStoresAll.txt │ ├── dp2ImmAll.txt │ ├── dp2ShiftsAll.txt │ ├── dp3ImmAll.txt │ └── dp3ShiftsAll.txt └── test-results │ ├── BETTERsMemLoadsAll.txt │ ├── BETTERsMemStoresAll.txt │ ├── ERRORsMemLoadsAll.txt │ ├── ERRORsMemStoresAll.txt │ ├── ERRORsdp2ImmAll.txt │ ├── ERRORsdp3ImmAll.txt │ ├── OKsMemLoadsAll.txt │ ├── OKsMemStoresAll.txt │ ├── OKsdp2ImmAll.txt │ ├── OKsdp2ShiftsAll.txt │ ├── OKsdp3ImmAll.txt │ └── OKsdp3ShiftsAll.txt ├── build ├── icon.icns └── icon.ico ├── docs └── visual-screen.png ├── package.json ├── packages └── build │ └── FAKE │ └── [Content_Types].xml ├── paket.dependencies ├── paket.lock ├── setup.bat ├── setup.sh ├── src ├── Emulator │ ├── Branch.fs │ ├── CommonData.fs │ ├── CommonLex.fs │ ├── DP.fs │ ├── Emulator.fsproj │ ├── Errors.fs │ ├── ExecutionTop.fs │ ├── Expressions.fs │ ├── Extensions.fs │ ├── Helpers.fs │ ├── Memory.fs │ ├── Misc.fs │ ├── ParseTop.fs │ ├── Testlib.fs │ └── paket.references ├── Main │ ├── Main.fs │ ├── Main.fsproj │ └── paket.references └── Renderer │ ├── Editors.fs │ ├── ErrorDocs.fs │ ├── Files.fs │ ├── Integration.fs │ ├── MenuBar.fs │ ├── Refs.fs │ ├── Renderer.fs │ ├── Renderer.fsproj │ ├── Settings.fs │ ├── Stats.fs │ ├── Tabs.fs │ ├── Testbench.fs │ ├── Tests.fs │ ├── Tooltips.fs │ ├── Views.fs │ └── paket.references ├── webpack.config.js └── yarn.lock /.paket/paket.bootstrapper.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/.paket/paket.bootstrapper.exe -------------------------------------------------------------------------------- /.paket/paket.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/.paket/paket.exe -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 scc416 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Nuget.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VisUAL2: ARM assembler and simulator (Written in F#) with elmish, React Monaco Editor, Electron & Fable 2 | Read the [full user guide](https://scc416.github.io/Visual2-doc/) 3 | ![VisUAl2 screen](https://github.com/scc416/Visual2/blob/master/docs/visual-screen.png) 4 | -------------------------------------------------------------------------------- /Visual2.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3E8DACEA-3E56-456A-A973-EC6F4AA8CFEA}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Emulator", "src\Emulator\Emulator.fsproj", "{B6AA1962-6D10-412A-A9B5-F573F68D47F6}" 9 | EndProject 10 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Main", "src\Main\Main.fsproj", "{953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}" 11 | EndProject 12 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Renderer", "src\Renderer\Renderer.fsproj", "{4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Debug|x64.ActiveCfg = Debug|x64 30 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Debug|x64.Build.0 = Debug|x64 31 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Debug|x86.ActiveCfg = Debug|x86 32 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Debug|x86.Build.0 = Debug|x86 33 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Release|x64.ActiveCfg = Release|x64 36 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Release|x64.Build.0 = Release|x64 37 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Release|x86.ActiveCfg = Release|x86 38 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6}.Release|x86.Build.0 = Release|x86 39 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Debug|x64.ActiveCfg = Debug|x64 42 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Debug|x64.Build.0 = Debug|x64 43 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Debug|x86.ActiveCfg = Debug|x86 44 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Debug|x86.Build.0 = Debug|x86 45 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Release|x64.ActiveCfg = Release|x64 48 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Release|x64.Build.0 = Release|x64 49 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Release|x86.ActiveCfg = Release|x86 50 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF}.Release|x86.Build.0 = Release|x86 51 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Debug|x64.ActiveCfg = Debug|x64 54 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Debug|x64.Build.0 = Debug|x64 55 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Debug|x86.ActiveCfg = Debug|x86 56 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Debug|x86.Build.0 = Debug|x86 57 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Release|Any CPU.ActiveCfg = Release|Any CPU 58 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Release|Any CPU.Build.0 = Release|Any CPU 59 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Release|x64.ActiveCfg = Release|x64 60 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Release|x64.Build.0 = Release|x64 61 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Release|x86.ActiveCfg = Release|x86 62 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC}.Release|x86.Build.0 = Release|x86 63 | EndGlobalSection 64 | GlobalSection(NestedProjects) = preSolution 65 | {B6AA1962-6D10-412A-A9B5-F573F68D47F6} = {3E8DACEA-3E56-456A-A973-EC6F4AA8CFEA} 66 | {953E9E20-5D1A-4B0F-93B2-FD6C331D67AF} = {3E8DACEA-3E56-456A-A973-EC6F4AA8CFEA} 67 | {4E732969-F73D-4B87-8F9F-BA8FCDDE01FC} = {3E8DACEA-3E56-456A-A973-EC6F4AA8CFEA} 68 | EndGlobalSection 69 | EndGlobal 70 | -------------------------------------------------------------------------------- /app/css/material-icons.css: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: url("../fonts/material-icons.woff2") format('woff2'); 7 | } 8 | 9 | .material-icons { 10 | font-family: 'Material Icons'; 11 | font-weight: normal; 12 | font-style: normal; 13 | font-size: 24px; 14 | line-height: 1; 15 | letter-spacing: normal; 16 | text-transform: none; 17 | display: inline-block; 18 | white-space: nowrap; 19 | word-wrap: normal; 20 | direction: ltr; 21 | -webkit-font-feature-settings: 'liga'; 22 | -webkit-font-smoothing: antialiased; 23 | } -------------------------------------------------------------------------------- /app/css/vex-theme-default.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes vex-flyin { 2 | 0% { 3 | opacity: 0; 4 | -webkit-transform: translateY(-40px); 5 | transform: translateY(-40px); } 6 | 100% { 7 | opacity: 1; 8 | -webkit-transform: translateY(0); 9 | transform: translateY(0); } } 10 | 11 | @keyframes vex-flyin { 12 | 0% { 13 | opacity: 0; 14 | -webkit-transform: translateY(-40px); 15 | transform: translateY(-40px); } 16 | 100% { 17 | opacity: 1; 18 | -webkit-transform: translateY(0); 19 | transform: translateY(0); } } 20 | 21 | @-webkit-keyframes vex-flyout { 22 | 0% { 23 | opacity: 1; 24 | -webkit-transform: translateY(0); 25 | transform: translateY(0); } 26 | 100% { 27 | opacity: 0; 28 | -webkit-transform: translateY(-40px); 29 | transform: translateY(-40px); } } 30 | 31 | @keyframes vex-flyout { 32 | 0% { 33 | opacity: 1; 34 | -webkit-transform: translateY(0); 35 | transform: translateY(0); } 36 | 100% { 37 | opacity: 0; 38 | -webkit-transform: translateY(-40px); 39 | transform: translateY(-40px); } } 40 | 41 | @-webkit-keyframes vex-pulse { 42 | 0% { 43 | box-shadow: inset 0 0 0 300px transparent; } 44 | 70% { 45 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 46 | 100% { 47 | box-shadow: inset 0 0 0 300px transparent; } } 48 | 49 | @keyframes vex-pulse { 50 | 0% { 51 | box-shadow: inset 0 0 0 300px transparent; } 52 | 70% { 53 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 54 | 100% { 55 | box-shadow: inset 0 0 0 300px transparent; } } 56 | 57 | .vex.vex-theme-default { 58 | padding-top: 160px; 59 | padding-bottom: 160px; } 60 | .vex.vex-theme-default.vex-closing .vex-content { 61 | -webkit-animation: vex-flyout .5s forwards; 62 | animation: vex-flyout .5s forwards; } 63 | .vex.vex-theme-default .vex-content { 64 | -webkit-animation: vex-flyin .5s; 65 | animation: vex-flyin .5s; } 66 | .vex.vex-theme-default .vex-content { 67 | border-radius: 5px; 68 | font-family: "Helvetica Neue", sans-serif; 69 | background: #f0f0f0; 70 | color: #444; 71 | padding: 1em; 72 | position: relative; 73 | margin: 0 auto; 74 | max-width: 100%; 75 | width: 450px; 76 | font-size: 1.1em; 77 | line-height: 1.5em; } 78 | .vex.vex-theme-default .vex-content h1, .vex.vex-theme-default .vex-content h2, .vex.vex-theme-default .vex-content h3, .vex.vex-theme-default .vex-content h4, .vex.vex-theme-default .vex-content h5, .vex.vex-theme-default .vex-content h6, .vex.vex-theme-default .vex-content p, .vex.vex-theme-default .vex-content ul, .vex.vex-theme-default .vex-content li { 79 | color: inherit; } 80 | .vex.vex-theme-default .vex-close { 81 | border-radius: 5px; 82 | position: absolute; 83 | top: 0; 84 | right: 0; 85 | cursor: pointer; } 86 | .vex.vex-theme-default .vex-close:before { 87 | border-radius: 3px; 88 | position: absolute; 89 | content: "\00D7"; 90 | font-size: 26px; 91 | font-weight: normal; 92 | line-height: 31px; 93 | height: 30px; 94 | width: 30px; 95 | text-align: center; 96 | top: 3px; 97 | right: 3px; 98 | color: #bbb; 99 | background: transparent; } 100 | .vex.vex-theme-default .vex-close:hover:before, .vex.vex-theme-default .vex-close:active:before { 101 | color: #777; 102 | background: #e0e0e0; } 103 | .vex.vex-theme-default .vex-dialog-form .vex-dialog-message { 104 | margin-bottom: .5em; } 105 | .vex.vex-theme-default .vex-dialog-form .vex-dialog-input { 106 | margin-bottom: 1em; } 107 | .vex.vex-theme-default .vex-dialog-form .vex-dialog-input select, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input textarea, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="date"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="datetime"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="datetime-local"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="email"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="month"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="number"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="password"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="search"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="tel"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="text"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="time"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="url"], .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="week"] { 108 | border-radius: 3px; 109 | background: #fff; 110 | width: 100%; 111 | padding: .25em .67em; 112 | border: 0; 113 | font-family: inherit; 114 | font-weight: inherit; 115 | font-size: inherit; 116 | min-height: 2.5em; 117 | margin: 0 0 .25em; } 118 | .vex.vex-theme-default .vex-dialog-form .vex-dialog-input select:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input textarea:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="date"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="datetime"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="datetime-local"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="email"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="month"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="number"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="password"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="search"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="tel"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="text"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="time"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="url"]:focus, .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="week"]:focus { 119 | box-shadow: inset 0 0 0 2px #8dbdf1; 120 | outline: none; } 121 | .vex.vex-theme-default .vex-dialog-form .vex-dialog-buttons { 122 | *zoom: 1; } 123 | .vex.vex-theme-default .vex-dialog-form .vex-dialog-buttons:after { 124 | content: ""; 125 | display: table; 126 | clear: both; } 127 | .vex.vex-theme-default .vex-dialog-button { 128 | border-radius: 3px; 129 | border: 0; 130 | float: right; 131 | margin: 0 0 0 .5em; 132 | font-family: inherit; 133 | text-transform: uppercase; 134 | letter-spacing: .1em; 135 | font-size: .8em; 136 | line-height: 1em; 137 | padding: .75em 2em; } 138 | .vex.vex-theme-default .vex-dialog-button.vex-last { 139 | margin-left: 0; } 140 | .vex.vex-theme-default .vex-dialog-button:focus { 141 | -webkit-animation: vex-pulse 1.1s infinite; 142 | animation: vex-pulse 1.1s infinite; 143 | outline: none; } 144 | @media (max-width: 568px) { 145 | .vex.vex-theme-default .vex-dialog-button:focus { 146 | -webkit-animation: none; 147 | animation: none; } } 148 | .vex.vex-theme-default .vex-dialog-button.vex-dialog-button-primary { 149 | background: #3288e6; 150 | color: #fff; } 151 | .vex.vex-theme-default .vex-dialog-button.vex-dialog-button-secondary { 152 | background: #e0e0e0; 153 | color: #777; } 154 | 155 | .vex-loading-spinner.vex-theme-default { 156 | box-shadow: 0 0 0 0.5em #f0f0f0, 0 0 1px 0.5em rgba(0, 0, 0, 0.3); 157 | border-radius: 100%; 158 | background: #f0f0f0; 159 | border: .2em solid transparent; 160 | border-top-color: #bbb; 161 | top: -1.1em; 162 | bottom: auto; } 163 | -------------------------------------------------------------------------------- /app/css/vex-theme-os.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes vex-flyin { 2 | 0% { 3 | opacity: 0; 4 | -webkit-transform: translateY(-40px); 5 | transform: translateY(-40px); } 6 | 100% { 7 | opacity: 1; 8 | -webkit-transform: translateY(0); 9 | transform: translateY(0); } } 10 | 11 | @keyframes vex-flyin { 12 | 0% { 13 | opacity: 0; 14 | -webkit-transform: translateY(-40px); 15 | transform: translateY(-40px); } 16 | 100% { 17 | opacity: 1; 18 | -webkit-transform: translateY(0); 19 | transform: translateY(0); } } 20 | 21 | @-webkit-keyframes vex-flyout { 22 | 0% { 23 | opacity: 1; 24 | -webkit-transform: translateY(0); 25 | transform: translateY(0); } 26 | 100% { 27 | opacity: 0; 28 | -webkit-transform: translateY(-40px); 29 | transform: translateY(-40px); } } 30 | 31 | @keyframes vex-flyout { 32 | 0% { 33 | opacity: 1; 34 | -webkit-transform: translateY(0); 35 | transform: translateY(0); } 36 | 100% { 37 | opacity: 0; 38 | -webkit-transform: translateY(-40px); 39 | transform: translateY(-40px); } } 40 | 41 | @-webkit-keyframes vex-pulse { 42 | 0% { 43 | box-shadow: inset 0 0 0 300px transparent; } 44 | 70% { 45 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 46 | 100% { 47 | box-shadow: inset 0 0 0 300px transparent; } } 48 | 49 | @keyframes vex-pulse { 50 | 0% { 51 | box-shadow: inset 0 0 0 300px transparent; } 52 | 70% { 53 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 54 | 100% { 55 | box-shadow: inset 0 0 0 300px transparent; } } 56 | 57 | .vex.vex-theme-os { 58 | padding-top: 160px; 59 | padding-bottom: 160px; } 60 | .vex.vex-theme-os.vex-closing .vex-content { 61 | -webkit-animation: vex-flyout .5s forwards; 62 | animation: vex-flyout .5s forwards; } 63 | .vex.vex-theme-os .vex-content { 64 | -webkit-animation: vex-flyin .5s; 65 | animation: vex-flyin .5s; } 66 | .vex.vex-theme-os .vex-content { 67 | border-radius: 5px; 68 | box-shadow: inset 0 1px #a6a6a6, 0 0 0 1px rgba(0, 0, 0, 0.08); 69 | font-family: "Helvetica Neue", sans-serif; 70 | border-top: 20px solid #bbb; 71 | background: #f0f0f0; 72 | color: #444; 73 | padding: 1em; 74 | position: relative; 75 | margin: 0 auto; 76 | max-width: 100%; 77 | width: 450px; 78 | font-size: 1.1em; 79 | line-height: 1.5em; } 80 | .vex.vex-theme-os .vex-content h1, .vex.vex-theme-os .vex-content h2, .vex.vex-theme-os .vex-content h3, .vex.vex-theme-os .vex-content h4, .vex.vex-theme-os .vex-content h5, .vex.vex-theme-os .vex-content h6, .vex.vex-theme-os .vex-content p, .vex.vex-theme-os .vex-content ul, .vex.vex-theme-os .vex-content li { 81 | color: inherit; } 82 | .vex.vex-theme-os .vex-close { 83 | border-radius: 0 5px 0 0; 84 | position: absolute; 85 | top: 0; 86 | right: 0; 87 | cursor: pointer; } 88 | .vex.vex-theme-os .vex-close:before { 89 | border-radius: 3px; 90 | position: absolute; 91 | content: "\00D7"; 92 | font-size: 26px; 93 | font-weight: normal; 94 | line-height: 31px; 95 | height: 30px; 96 | width: 30px; 97 | text-align: center; 98 | top: 3px; 99 | right: 3px; 100 | color: #bbb; 101 | background: transparent; } 102 | .vex.vex-theme-os .vex-close:hover:before, .vex.vex-theme-os .vex-close:active:before { 103 | color: #777; 104 | background: #e0e0e0; } 105 | .vex.vex-theme-os .vex-dialog-form .vex-dialog-message { 106 | margin-bottom: .5em; } 107 | .vex.vex-theme-os .vex-dialog-form .vex-dialog-input { 108 | margin-bottom: 1em; } 109 | .vex.vex-theme-os .vex-dialog-form .vex-dialog-input select, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input textarea, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="date"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="datetime"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="datetime-local"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="email"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="month"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="number"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="password"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="search"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="tel"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="text"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="time"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="url"], .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="week"] { 110 | border-radius: 3px; 111 | background: #fff; 112 | width: 100%; 113 | padding: .25em .67em; 114 | border: 0; 115 | font-family: inherit; 116 | font-weight: inherit; 117 | font-size: inherit; 118 | min-height: 2.5em; 119 | margin: 0 0 .25em; } 120 | .vex.vex-theme-os .vex-dialog-form .vex-dialog-input select:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input textarea:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="date"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="datetime"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="datetime-local"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="email"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="month"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="number"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="password"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="search"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="tel"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="text"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="time"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="url"]:focus, .vex.vex-theme-os .vex-dialog-form .vex-dialog-input input[type="week"]:focus { 121 | box-shadow: inset 0 0 0 1px #3288e6; 122 | outline: none; } 123 | .vex.vex-theme-os .vex-dialog-form .vex-dialog-buttons { 124 | *zoom: 1; } 125 | .vex.vex-theme-os .vex-dialog-form .vex-dialog-buttons:after { 126 | content: ""; 127 | display: table; 128 | clear: both; } 129 | .vex.vex-theme-os .vex-dialog-button { 130 | border-radius: 3px; 131 | border: 0; 132 | float: right; 133 | margin: 0 0 0 .5em; 134 | font-family: inherit; 135 | text-transform: uppercase; 136 | letter-spacing: .1em; 137 | font-size: .8em; 138 | line-height: 1em; 139 | padding: .75em 2em; } 140 | .vex.vex-theme-os .vex-dialog-button.vex-last { 141 | margin-left: 0; } 142 | .vex.vex-theme-os .vex-dialog-button:focus { 143 | -webkit-animation: vex-pulse 1.1s infinite; 144 | animation: vex-pulse 1.1s infinite; 145 | outline: none; } 146 | @media (max-width: 568px) { 147 | .vex.vex-theme-os .vex-dialog-button:focus { 148 | -webkit-animation: none; 149 | animation: none; } } 150 | .vex.vex-theme-os .vex-dialog-button.vex-dialog-button-primary { 151 | background: #3288e6; 152 | color: #fff; } 153 | .vex.vex-theme-os .vex-dialog-button.vex-dialog-button-secondary { 154 | background: #e0e0e0; 155 | color: #777; } 156 | 157 | .vex-loading-spinner.vex-theme-os { 158 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2), 0 0 0.5em rgba(0, 0, 0, 0.2); 159 | border-radius: 100%; 160 | background: rgba(255, 255, 255, 0.2); 161 | width: 0; 162 | height: 0; 163 | border: 1.2em solid #bbb; 164 | border-top-color: #f0f0f0; 165 | border-bottom-color: #f0f0f0; } 166 | -------------------------------------------------------------------------------- /app/css/vex-theme-plain.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes vex-pulse { 2 | 0% { 3 | box-shadow: inset 0 0 0 300px transparent; } 4 | 70% { 5 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 6 | 100% { 7 | box-shadow: inset 0 0 0 300px transparent; } } 8 | 9 | @keyframes vex-pulse { 10 | 0% { 11 | box-shadow: inset 0 0 0 300px transparent; } 12 | 70% { 13 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 14 | 100% { 15 | box-shadow: inset 0 0 0 300px transparent; } } 16 | 17 | .vex.vex-theme-plain { 18 | padding-top: 160px; 19 | padding-bottom: 160px; } 20 | .vex.vex-theme-plain .vex-content { 21 | font-family: "Helvetica Neue", sans-serif; 22 | background: #fff; 23 | color: #444; 24 | padding: 1em; 25 | position: relative; 26 | margin: 0 auto; 27 | max-width: 100%; 28 | width: 450px; 29 | font-size: 1.1em; 30 | line-height: 1.5em; } 31 | .vex.vex-theme-plain .vex-content h1, .vex.vex-theme-plain .vex-content h2, .vex.vex-theme-plain .vex-content h3, .vex.vex-theme-plain .vex-content h4, .vex.vex-theme-plain .vex-content h5, .vex.vex-theme-plain .vex-content h6, .vex.vex-theme-plain .vex-content p, .vex.vex-theme-plain .vex-content ul, .vex.vex-theme-plain .vex-content li { 32 | color: inherit; } 33 | .vex.vex-theme-plain .vex-close { 34 | position: absolute; 35 | top: 0; 36 | right: 0; 37 | cursor: pointer; } 38 | .vex.vex-theme-plain .vex-close:before { 39 | position: absolute; 40 | content: "\00D7"; 41 | font-size: 26px; 42 | font-weight: normal; 43 | line-height: 31px; 44 | height: 30px; 45 | width: 30px; 46 | text-align: center; 47 | top: 3px; 48 | right: 3px; 49 | color: #bbb; 50 | background: transparent; } 51 | .vex.vex-theme-plain .vex-close:hover:before, .vex.vex-theme-plain .vex-close:active:before { 52 | color: #777; 53 | background: #e0e0e0; } 54 | .vex.vex-theme-plain .vex-dialog-form .vex-dialog-message { 55 | margin-bottom: .5em; } 56 | .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input { 57 | margin-bottom: 1em; } 58 | .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input select, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input textarea, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="date"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="datetime"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="datetime-local"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="email"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="month"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="number"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="password"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="search"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="tel"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="text"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="time"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="url"], .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="week"] { 59 | background: #f0f0f0; 60 | width: 100%; 61 | padding: .25em .67em; 62 | border: 0; 63 | font-family: inherit; 64 | font-weight: inherit; 65 | font-size: inherit; 66 | min-height: 2.5em; 67 | margin: 0 0 .25em; } 68 | .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input select:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input textarea:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="date"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="datetime"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="datetime-local"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="email"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="month"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="number"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="password"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="search"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="tel"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="text"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="time"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="url"]:focus, .vex.vex-theme-plain .vex-dialog-form .vex-dialog-input input[type="week"]:focus { 69 | box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.2); 70 | outline: none; } 71 | .vex.vex-theme-plain .vex-dialog-form .vex-dialog-buttons { 72 | *zoom: 1; } 73 | .vex.vex-theme-plain .vex-dialog-form .vex-dialog-buttons:after { 74 | content: ""; 75 | display: table; 76 | clear: both; } 77 | .vex.vex-theme-plain .vex-dialog-button { 78 | border-radius: 0; 79 | border: 0; 80 | float: right; 81 | margin: 0 0 0 .5em; 82 | font-family: inherit; 83 | text-transform: uppercase; 84 | letter-spacing: .1em; 85 | font-size: .8em; 86 | line-height: 1em; 87 | padding: .75em 2em; } 88 | .vex.vex-theme-plain .vex-dialog-button.vex-last { 89 | margin-left: 0; } 90 | .vex.vex-theme-plain .vex-dialog-button:focus { 91 | -webkit-animation: vex-pulse 1.1s infinite; 92 | animation: vex-pulse 1.1s infinite; 93 | outline: none; } 94 | @media (max-width: 568px) { 95 | .vex.vex-theme-plain .vex-dialog-button:focus { 96 | -webkit-animation: none; 97 | animation: none; } } 98 | .vex.vex-theme-plain .vex-dialog-button.vex-dialog-button-primary { 99 | background: #3288e6; 100 | color: #fff; } 101 | .vex.vex-theme-plain .vex-dialog-button.vex-dialog-button-secondary { 102 | background: #e0e0e0; 103 | color: #777; } 104 | 105 | .vex-loading-spinner.vex-theme-plain { 106 | height: 2.5em; 107 | width: 2.5em; } 108 | -------------------------------------------------------------------------------- /app/css/vex-theme-top.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes vex-dropin { 2 | 0% { 3 | -webkit-transform: translateY(0); 4 | transform: translateY(0); 5 | opacity: 0; } 6 | 1% { 7 | -webkit-transform: translateY(-800px); 8 | transform: translateY(-800px); 9 | opacity: 0; } 10 | 2% { 11 | -webkit-transform: translateY(-800px); 12 | transform: translateY(-800px); 13 | opacity: 1; } 14 | 100% { 15 | -webkit-transform: translateY(0); 16 | transform: translateY(0); 17 | opacity: 1; } } 18 | 19 | @keyframes vex-dropin { 20 | 0% { 21 | -webkit-transform: translateY(0); 22 | transform: translateY(0); 23 | opacity: 0; } 24 | 1% { 25 | -webkit-transform: translateY(-800px); 26 | transform: translateY(-800px); 27 | opacity: 0; } 28 | 2% { 29 | -webkit-transform: translateY(-800px); 30 | transform: translateY(-800px); 31 | opacity: 1; } 32 | 100% { 33 | -webkit-transform: translateY(0); 34 | transform: translateY(0); 35 | opacity: 1; } } 36 | 37 | @-webkit-keyframes vex-dropout { 38 | 0% { 39 | -webkit-transform: translateY(0); 40 | transform: translateY(0); } 41 | 100% { 42 | -webkit-transform: translateY(-800px); 43 | transform: translateY(-800px); } } 44 | 45 | @keyframes vex-dropout { 46 | 0% { 47 | -webkit-transform: translateY(0); 48 | transform: translateY(0); } 49 | 100% { 50 | -webkit-transform: translateY(-800px); 51 | transform: translateY(-800px); } } 52 | 53 | @-webkit-keyframes vex-pulse { 54 | 0% { 55 | box-shadow: inset 0 0 0 300px transparent; } 56 | 70% { 57 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 58 | 100% { 59 | box-shadow: inset 0 0 0 300px transparent; } } 60 | 61 | @keyframes vex-pulse { 62 | 0% { 63 | box-shadow: inset 0 0 0 300px transparent; } 64 | 70% { 65 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 66 | 100% { 67 | box-shadow: inset 0 0 0 300px transparent; } } 68 | 69 | .vex.vex-theme-top.vex-closing .vex-content { 70 | -webkit-animation: vex-dropout .5s forwards; 71 | animation: vex-dropout .5s forwards; } 72 | 73 | .vex.vex-theme-top .vex-content { 74 | -webkit-animation: vex-dropin .5s; 75 | animation: vex-dropin .5s; } 76 | 77 | .vex.vex-theme-top .vex-content { 78 | border-radius: 0 0 5px 5px; 79 | font-family: "Helvetica Neue", sans-serif; 80 | background: #f0f0f0; 81 | color: #444; 82 | padding: 1em; 83 | position: relative; 84 | margin: 0 auto; 85 | max-width: 100%; 86 | width: 450px; 87 | font-size: 1.1em; 88 | line-height: 1.5em; } 89 | .vex.vex-theme-top .vex-content h1, .vex.vex-theme-top .vex-content h2, .vex.vex-theme-top .vex-content h3, .vex.vex-theme-top .vex-content h4, .vex.vex-theme-top .vex-content h5, .vex.vex-theme-top .vex-content h6, .vex.vex-theme-top .vex-content p, .vex.vex-theme-top .vex-content ul, .vex.vex-theme-top .vex-content li { 90 | color: inherit; } 91 | 92 | .vex.vex-theme-top .vex-close { 93 | border-radius: 5px; 94 | position: absolute; 95 | top: 0; 96 | right: 0; 97 | cursor: pointer; } 98 | .vex.vex-theme-top .vex-close:before { 99 | border-radius: 3px; 100 | position: absolute; 101 | content: "\00D7"; 102 | font-size: 26px; 103 | font-weight: normal; 104 | line-height: 31px; 105 | height: 30px; 106 | width: 30px; 107 | text-align: center; 108 | top: 3px; 109 | right: 3px; 110 | color: #bbb; 111 | background: transparent; } 112 | .vex.vex-theme-top .vex-close:hover:before, .vex.vex-theme-top .vex-close:active:before { 113 | color: #777; 114 | background: #e0e0e0; } 115 | 116 | .vex.vex-theme-top .vex-dialog-form .vex-dialog-message { 117 | margin-bottom: .5em; } 118 | 119 | .vex.vex-theme-top .vex-dialog-form .vex-dialog-input { 120 | margin-bottom: 1em; } 121 | .vex.vex-theme-top .vex-dialog-form .vex-dialog-input select, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input textarea, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="date"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="datetime"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="datetime-local"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="email"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="month"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="number"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="password"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="search"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="tel"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="text"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="time"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="url"], .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="week"] { 122 | border-radius: 3px; 123 | background: #fff; 124 | width: 100%; 125 | padding: .25em .67em; 126 | border: 0; 127 | font-family: inherit; 128 | font-weight: inherit; 129 | font-size: inherit; 130 | min-height: 2.5em; 131 | margin: 0 0 .25em; } 132 | .vex.vex-theme-top .vex-dialog-form .vex-dialog-input select:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input textarea:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="date"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="datetime"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="datetime-local"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="email"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="month"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="number"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="password"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="search"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="tel"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="text"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="time"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="url"]:focus, .vex.vex-theme-top .vex-dialog-form .vex-dialog-input input[type="week"]:focus { 133 | box-shadow: inset 0 0 0 2px #8dbdf1; 134 | outline: none; } 135 | 136 | .vex.vex-theme-top .vex-dialog-form .vex-dialog-buttons { 137 | *zoom: 1; } 138 | .vex.vex-theme-top .vex-dialog-form .vex-dialog-buttons:after { 139 | content: ""; 140 | display: table; 141 | clear: both; } 142 | 143 | .vex.vex-theme-top .vex-dialog-button { 144 | border-radius: 3px; 145 | border: 0; 146 | float: right; 147 | margin: 0 0 0 .5em; 148 | font-family: inherit; 149 | text-transform: uppercase; 150 | letter-spacing: .1em; 151 | font-size: .8em; 152 | line-height: 1em; 153 | padding: .75em 2em; } 154 | .vex.vex-theme-top .vex-dialog-button.vex-last { 155 | margin-left: 0; } 156 | .vex.vex-theme-top .vex-dialog-button:focus { 157 | -webkit-animation: vex-pulse 1.1s infinite; 158 | animation: vex-pulse 1.1s infinite; 159 | outline: none; } 160 | @media (max-width: 568px) { 161 | .vex.vex-theme-top .vex-dialog-button:focus { 162 | -webkit-animation: none; 163 | animation: none; } } 164 | .vex.vex-theme-top .vex-dialog-button.vex-dialog-button-primary { 165 | background: #3288e6; 166 | color: #fff; } 167 | .vex.vex-theme-top .vex-dialog-button.vex-dialog-button-secondary { 168 | background: #e0e0e0; 169 | color: #777; } 170 | 171 | .vex-loading-spinner.vex-theme-top { 172 | box-shadow: 0 0 0 0.5em #f0f0f0, 0 0 1px 0.5em rgba(0, 0, 0, 0.3); 173 | border-radius: 100%; 174 | background: #f0f0f0; 175 | border: .2em solid transparent; 176 | border-top-color: #bbb; 177 | top: -1.1em; 178 | bottom: auto; } 179 | -------------------------------------------------------------------------------- /app/css/vex-theme-wireframe.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes vex-pulse { 2 | 0% { 3 | box-shadow: inset 0 0 0 300px transparent; } 4 | 70% { 5 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 6 | 100% { 7 | box-shadow: inset 0 0 0 300px transparent; } } 8 | 9 | @keyframes vex-pulse { 10 | 0% { 11 | box-shadow: inset 0 0 0 300px transparent; } 12 | 70% { 13 | box-shadow: inset 0 0 0 300px rgba(255, 255, 255, 0.25); } 14 | 100% { 15 | box-shadow: inset 0 0 0 300px transparent; } } 16 | 17 | .vex.vex-theme-wireframe { 18 | padding-top: 160px; 19 | padding-bottom: 160px; } 20 | .vex.vex-theme-wireframe .vex-overlay { 21 | background: rgba(255, 255, 255, 0.4); } 22 | .vex.vex-theme-wireframe .vex-content { 23 | font-family: "Helvetica Neue", sans-serif; 24 | background: #fff; 25 | color: #000; 26 | border: 2px solid #000; 27 | padding: 2em; 28 | position: relative; 29 | margin: 0 auto; 30 | max-width: 100%; 31 | width: 400px; 32 | font-size: 1.1em; 33 | line-height: 1.5em; } 34 | .vex.vex-theme-wireframe .vex-content h1, .vex.vex-theme-wireframe .vex-content h2, .vex.vex-theme-wireframe .vex-content h3, .vex.vex-theme-wireframe .vex-content h4, .vex.vex-theme-wireframe .vex-content h5, .vex.vex-theme-wireframe .vex-content h6, .vex.vex-theme-wireframe .vex-content p, .vex.vex-theme-wireframe .vex-content ul, .vex.vex-theme-wireframe .vex-content li { 35 | color: inherit; } 36 | .vex.vex-theme-wireframe .vex-close { 37 | position: absolute; 38 | top: 0; 39 | right: 0; 40 | cursor: pointer; } 41 | .vex.vex-theme-wireframe .vex-close:before { 42 | position: absolute; 43 | content: "\00D7"; 44 | font-size: 40px; 45 | font-weight: normal; 46 | line-height: 80px; 47 | height: 80px; 48 | width: 80px; 49 | text-align: center; 50 | top: 3px; 51 | right: 3px; 52 | color: #000; } 53 | .vex.vex-theme-wireframe .vex-close:hover:before, .vex.vex-theme-wireframe .vex-close:active:before { 54 | color: #000; } 55 | .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-message { 56 | margin-bottom: .5em; } 57 | .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input { 58 | margin-bottom: 1em; } 59 | .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input select, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input textarea, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="date"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="datetime"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="datetime-local"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="email"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="month"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="number"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="password"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="search"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="tel"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="text"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="time"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="url"], .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="week"] { 60 | background: #fff; 61 | width: 100%; 62 | padding: .25em .67em; 63 | font-family: inherit; 64 | font-weight: inherit; 65 | font-size: inherit; 66 | min-height: 2.5em; 67 | margin: 0 0 .25em; 68 | border: 2px solid #000; } 69 | .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input select:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input textarea:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="date"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="datetime"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="datetime-local"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="email"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="month"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="number"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="password"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="search"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="tel"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="text"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="time"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="url"]:focus, .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-input input[type="week"]:focus { 70 | border-style: dashed; 71 | outline: none; } 72 | .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-buttons { 73 | *zoom: 1; } 74 | .vex.vex-theme-wireframe .vex-dialog-form .vex-dialog-buttons:after { 75 | content: ""; 76 | display: table; 77 | clear: both; } 78 | .vex.vex-theme-wireframe .vex-dialog-button { 79 | border-radius: 0; 80 | border: 0; 81 | float: right; 82 | margin: 0 0 0 .5em; 83 | font-family: inherit; 84 | text-transform: uppercase; 85 | letter-spacing: .1em; 86 | font-size: .8em; 87 | line-height: 1em; 88 | padding: .75em 2em; } 89 | .vex.vex-theme-wireframe .vex-dialog-button.vex-last { 90 | margin-left: 0; } 91 | .vex.vex-theme-wireframe .vex-dialog-button:focus { 92 | -webkit-animation: vex-pulse 1.1s infinite; 93 | animation: vex-pulse 1.1s infinite; 94 | outline: none; } 95 | @media (max-width: 568px) { 96 | .vex.vex-theme-wireframe .vex-dialog-button:focus { 97 | -webkit-animation: none; 98 | animation: none; } } 99 | .vex.vex-theme-wireframe .vex-dialog-button.vex-dialog-button-primary { 100 | background: #000; 101 | color: #fff; 102 | border: 2px solid transparent; } 103 | .vex.vex-theme-wireframe .vex-dialog-button.vex-dialog-button-secondary { 104 | background: #fff; 105 | color: #000; 106 | border: 2px solid #000; } 107 | 108 | .vex-loading-spinner.vex-theme-wireframe { 109 | height: 2.5em; 110 | width: 2.5em; } 111 | -------------------------------------------------------------------------------- /app/css/vex.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes vex-fadein { 2 | 0% { 3 | opacity: 0; } 4 | 100% { 5 | opacity: 1; } } 6 | 7 | @keyframes vex-fadein { 8 | 0% { 9 | opacity: 0; } 10 | 100% { 11 | opacity: 1; } } 12 | 13 | @-webkit-keyframes vex-fadeout { 14 | 0% { 15 | opacity: 1; } 16 | 100% { 17 | opacity: 0; } } 18 | 19 | @keyframes vex-fadeout { 20 | 0% { 21 | opacity: 1; } 22 | 100% { 23 | opacity: 0; } } 24 | 25 | @-webkit-keyframes vex-rotation { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); } 29 | 100% { 30 | -webkit-transform: rotate(359deg); 31 | transform: rotate(359deg); } } 32 | 33 | @keyframes vex-rotation { 34 | 0% { 35 | -webkit-transform: rotate(0deg); 36 | transform: rotate(0deg); } 37 | 100% { 38 | -webkit-transform: rotate(359deg); 39 | transform: rotate(359deg); } } 40 | 41 | .vex, .vex *, .vex *:before, .vex *:after { 42 | -moz-box-sizing: border-box; 43 | box-sizing: border-box; } 44 | 45 | .vex { 46 | position: fixed; 47 | overflow: auto; 48 | -webkit-overflow-scrolling: touch; 49 | z-index: 1111; 50 | top: 0; 51 | right: 0; 52 | bottom: 0; 53 | left: 0; } 54 | 55 | .vex-scrollbar-measure { 56 | position: absolute; 57 | top: -9999px; 58 | width: 50px; 59 | height: 50px; 60 | overflow: scroll; } 61 | 62 | .vex-overlay { 63 | -webkit-animation: vex-fadein .5s; 64 | animation: vex-fadein .5s; 65 | position: fixed; 66 | z-index: 1111; 67 | background: rgba(0, 0, 0, 0.4); 68 | top: 0; 69 | right: 0; 70 | bottom: 0; 71 | left: 0; } 72 | 73 | .vex-overlay.vex-closing { 74 | -webkit-animation: vex-fadeout .5s forwards; 75 | animation: vex-fadeout .5s forwards; } 76 | 77 | .vex-content { 78 | -webkit-animation: vex-fadein .5s; 79 | animation: vex-fadein .5s; 80 | background: #fff; } 81 | 82 | .vex.vex-closing .vex-content { 83 | -webkit-animation: vex-fadeout .5s forwards; 84 | animation: vex-fadeout .5s forwards; } 85 | 86 | .vex-close:before { 87 | font-family: Arial, sans-serif; 88 | content: "\00D7"; } 89 | 90 | .vex-dialog-form { 91 | margin: 0; } 92 | 93 | .vex-dialog-button { 94 | text-rendering: optimizeLegibility; 95 | -webkit-appearance: none; 96 | -moz-appearance: none; 97 | appearance: none; 98 | cursor: pointer; 99 | -webkit-tap-highlight-color: transparent; } 100 | 101 | .vex-loading-spinner { 102 | -webkit-animation: vex-rotation .7s linear infinite; 103 | animation: vex-rotation .7s linear infinite; 104 | box-shadow: 0 0 1em rgba(0, 0, 0, 0.1); 105 | position: fixed; 106 | z-index: 1112; 107 | margin: auto; 108 | top: 0; 109 | right: 0; 110 | bottom: 0; 111 | left: 0; 112 | height: 2em; 113 | width: 2em; 114 | background: #fff; } 115 | 116 | body.vex-open { 117 | overflow: hidden; } 118 | -------------------------------------------------------------------------------- /app/css/vistally.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-user-drag: none; /* disable drag and drop */ 3 | } 4 | 5 | /* used to animate app and settings windows */ 6 | @keyframes fadein { 7 | from { 8 | opacity: 0; 9 | } 10 | 11 | to { 12 | opacity: 1; 13 | } 14 | } 15 | 16 | 17 | 18 | .window { 19 | animation: fadein 0.5s; 20 | } 21 | 22 | 23 | ::selection { 24 | background: #ffb7b7; 25 | } 26 | 27 | .unsaved { 28 | font-weight: bold; 29 | } 30 | 31 | 32 | 33 | .list-group-item { 34 | padding: 2px; 35 | border-color: lightgrey; 36 | } 37 | 38 | .toolbar-header { 39 | border-bottom: 1px solid #c2c0c2; 40 | background-color:cadetblue; 41 | } 42 | 43 | .toolbar-header .title { 44 | margin-top: 1px; 45 | } 46 | 47 | .toolbar-footer { 48 | position: absolute; 49 | bottom: 0; 50 | left: 0; 51 | width: 100%; 52 | height: 40px; 53 | background-color: lightgrey; 54 | border-top: 1px solid #c2c0c2; 55 | } 56 | .toolbar-header { 57 | padding: 5px; 58 | } 59 | 60 | .btn-reg, .btn-reg-con { 61 | height: calc(13pt + 7px); 62 | line-height: calc(13pt + 2px); 63 | font-size: 13pt; 64 | } 65 | 66 | .btn-reg, .btn-reg:active { 67 | width: 15%; 68 | font-size: 13px; 69 | } 70 | 71 | /* Register values */ 72 | /*.btn-reg-con, .btn-reg-con:active { 73 | width: 85%; 74 | 75 | font-size: 13px; 76 | font-weight:600; 77 | cursor: text; 78 | }*/ 79 | 80 | .btn-flag, .btn-flag-con { 81 | font-size: 15px; 82 | } 83 | 84 | .btn-rep { 85 | background-color: white; 86 | font-size: 15px; 87 | } 88 | 89 | .btn-rep-enabled { 90 | background-color: darkgray; 91 | } 92 | 93 | .btn-view { 94 | width: 33.3%; 95 | } 96 | 97 | .clock { 98 | margin-left:20px; 99 | } 100 | 101 | .clock-symbol { 102 | font-size: 15px; 103 | padding-top:3px; 104 | padding-bottom:3px; 105 | padding-left: 5px; 106 | padding-right: 5px; 107 | } 108 | 109 | .clock-time { 110 | font-size:15px; 111 | padding-top:3px; 112 | padding-bottom:3px; 113 | } 114 | 115 | .dashboard { 116 | position: relative; 117 | overflow: hidden; 118 | } 119 | 120 | .editor { 121 | height: calc(100% - 26px); 122 | width: 100%; 123 | } 124 | 125 | .viewer { 126 | position: fixed; 127 | top: 76px; 128 | padding-top: 5px; 129 | left: calc( 100vw - var(--dashboard-width)); 130 | overflow-y: auto; 131 | height: calc( 100vh - 95px); 132 | background-color: lightgrey; 133 | padding-bottom: 30px; /* Allow scrolling slightly beyond the end */ 134 | } 135 | 136 | .invisible { 137 | display: none !important; 138 | } 139 | 140 | .btn-byte-active { 141 | background-color: darkgray; 142 | } 143 | 144 | .th-mem { 145 | background-color: darkgray; 146 | color: white; 147 | } 148 | 149 | 150 | .tabs-files { 151 | background-color: lightgray; 152 | width: 100%; 153 | height: 27px; 154 | overflow: hidden; 155 | } 156 | 157 | .tab-file { 158 | max-width: 200px; 159 | overflow: hidden; 160 | } 161 | 162 | .tab-file-name { 163 | width: 20px; 164 | text-overflow: ellipsis; 165 | } 166 | 167 | .settings-menu { 168 | max-width: 36em; 169 | display: inline-block; 170 | background-color: lightgrey; 171 | text-align: left; 172 | padding-left: 1.25em; 173 | overflow: auto; 174 | animation: fadein 0.5s; 175 | } 176 | 177 | .file-view-pane { 178 | text-align: center; 179 | height: 100%; 180 | overflow: hidden; 181 | background-color: black; 182 | } 183 | 184 | .monaco-editor { 185 | text-align: left; 186 | /*-webkit-font-smoothing: antialiased;*/ 187 | 188 | } 189 | 190 | 191 | .settings-select { 192 | max-width: 13em; 193 | font-size: 12px; 194 | border-width: 1px; 195 | border-color: grey; 196 | } 197 | .settings-input { 198 | font-size: 12px; 199 | text-indent: 0.75em; 200 | border-width: 1px; 201 | border-radius: 4px; 202 | border-color: grey; 203 | } 204 | 205 | 206 | .settings-label { 207 | margin-bottom: 0px; 208 | margin-top: 10px; 209 | } 210 | 211 | .editor-line-highlight { 212 | font-weight: bolder; 213 | background-color: rgba(56, 76, 141, 0.5) 214 | /*text-decoration: underline;*/ 215 | /* width: 5px !important; 216 | left: 3px; */ 217 | } 218 | 219 | .editor-line-highlight-next { 220 | font-weight: bolder; 221 | background-color: rgba(6, 41, 155, 0.25) 222 | /*text-decoration: underline;*/ 223 | /* width: 5px !important; 224 | left: 3px; */ 225 | } 226 | 227 | .editor-line-highlight-error { 228 | font-weight: bolder; 229 | background-color: rgba(180, 29, 79,0.5) 230 | /*text-decoration: underline;*/ 231 | /* width: 5px !important; 232 | left: 3px; */ 233 | } 234 | 235 | .disabled-click { 236 | pointer-events: none; 237 | } 238 | 239 | .darken-overlay { 240 | position: absolute; 241 | background-color: rgba(255, 255, 255, 0.1); 242 | top: 0px; 243 | left: 0px; 244 | width: 100%; 245 | height: 100%; 246 | z-index: 10; 247 | } 248 | 249 | .editor-line-error { 250 | border-bottom: 2px dotted red; 251 | } 252 | 253 | .editor-glyph-margin-error { 254 | color: red; 255 | 256 | text-align:right; 257 | font-weight:bolder; 258 | } 259 | 260 | .editor-glyph-margin-error:after { 261 | content: "\26a0"; 262 | } 263 | 264 | .editor-glyph-margin-arrow { 265 | color: darkgrey; 266 | text-align: right; 267 | } 268 | 269 | .editor-glyph-margin-arrow:after { 270 | content: "\2192" 271 | } 272 | 273 | .editor-glyph-margin-pointer { 274 | color: red; 275 | text-align: right; 276 | } 277 | 278 | .editor-glyph-margin-pointer:after { 279 | font-weight:bold; 280 | content: "\027ff" 281 | } 282 | 283 | .button-back:before { 284 | content: "\25c0" 285 | } 286 | 287 | .button-forward:after { 288 | content: "\25ba" 289 | } 290 | 291 | 292 | 293 | .status-bar { 294 | width: 200px; 295 | align-self: center; 296 | } 297 | 298 | .float-left { 299 | float: left; 300 | width:50% 301 | } 302 | 303 | div.after { 304 | clear: left; 305 | } 306 | 307 | 308 | 309 | 310 | /*-------------------------------------------------------------------------------------*/ 311 | /*---------------------------pretty CSS tooltips for info buttons----------------------*/ 312 | /*-based on tippy.js library https://github.com/atomiks/tippyjs/blob/master/README.md--*/ 313 | /*-------------------------------------------------------------------------------------*/ 314 | 315 | .tippy-popper[x-placement^=top] .tippy-tooltip.light-theme .tippy-arrow { 316 | border-top: 7px solid #fff; 317 | border-right: 7px solid transparent; 318 | border-left: 7px solid transparent 319 | } 320 | 321 | .tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme .tippy-arrow { 322 | border-bottom: 7px solid #fff; 323 | border-right: 7px solid transparent; 324 | border-left: 7px solid transparent 325 | } 326 | 327 | .tippy-popper[x-placement^=left] .tippy-tooltip.light-theme .tippy-arrow { 328 | border-left: 7px solid #fff; 329 | border-top: 7px solid transparent; 330 | border-bottom: 7px solid transparent 331 | } 332 | 333 | .tippy-popper[x-placement^=right] .tippy-tooltip.light-theme .tippy-arrow { 334 | border-right: 7px solid #fff; 335 | border-top: 7px solid transparent; 336 | border-bottom: 7px solid transparent 337 | } 338 | 339 | .tippy-tooltip.light-theme { 340 | color: #26323d; 341 | box-shadow: 0 0 20px 4px rgba(154,161,177,.15),0 4px 80px -8px rgba(36,40,47,.25),0 4px 4px -2px rgba(91,94,105,.15); 342 | background-color: #fff; 343 | border-style: solid; 344 | border-color: blue; 345 | } 346 | 347 | .tippy-tooltip.light-theme .tippy-backdrop { 348 | background-color: #fff 349 | } 350 | 351 | .tippy-tooltip.light-theme .tippy-roundarrow { 352 | fill: #fff 353 | } 354 | 355 | .tippy-tooltip.light-theme[data-animatefill] { 356 | background-color: transparent 357 | } 358 | 359 | .tippy-tooltip.dark-theme { 360 | border-style: solid; 361 | border-color: blue; 362 | } 363 | 364 | 365 | .tooltip-stack-regs-light-theme { 366 | margin-left: 2px; 367 | padding: 0px; 368 | color: blue; 369 | font-weight:bold; 370 | } 371 | 372 | .tooltip-stack-regs-dark-theme { 373 | margin-left: 2px; 374 | padding: 0px; 375 | color: lightblue; 376 | font-weight: bold; 377 | } 378 | 379 | .tootip-fixed { 380 | font-size: 12px; 381 | } 382 | 383 | .tooltip-shift-reg-box { 384 | stroke-width:0.2px; 385 | stroke:blue; 386 | fill: white; 387 | } 388 | 389 | .tooltip-shift-carry-box { 390 | stroke-width: 0.2px; 391 | stroke: red; 392 | fill: white; 393 | } 394 | .tooltip-shift-reg-txt { 395 | font-size:1.8px; 396 | fill: green; 397 | } 398 | 399 | .tooltip-shift-alu-txt { 400 | font-size: 5px; 401 | fill: blue; 402 | } 403 | 404 | -------------------------------------------------------------------------------- /app/fonts/fira-code.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/fonts/fira-code.eot -------------------------------------------------------------------------------- /app/fonts/fira-code.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/fonts/fira-code.ttf -------------------------------------------------------------------------------- /app/fonts/fira-code.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/fonts/fira-code.woff -------------------------------------------------------------------------------- /app/fonts/material-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/fonts/material-icons.woff2 -------------------------------------------------------------------------------- /app/fonts/photon-entypo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/fonts/photon-entypo.eot -------------------------------------------------------------------------------- /app/fonts/photon-entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/fonts/photon-entypo.ttf -------------------------------------------------------------------------------- /app/fonts/photon-entypo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/fonts/photon-entypo.woff -------------------------------------------------------------------------------- /app/hovers/testhover.md: -------------------------------------------------------------------------------- 1 | # Test 0 2 | 3 | [testhover1.md](testhover1.md) 4 | -------------------------------------------------------------------------------- /app/hovers/testhover1.md: -------------------------------------------------------------------------------- 1 | # Test 1 2 | 3 | [testhover.md](testhover.md) 4 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | VisUAL2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/resources/errortest.html: -------------------------------------------------------------------------------- 1 |

HTML test file

-------------------------------------------------------------------------------- /app/resources/visual.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/app/resources/visual.ico -------------------------------------------------------------------------------- /app/test-data/ALLOWEDdp2ShiftsAll.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------dp2Shifts:2909---------------- 3 | Visual2 cannot parse test assembler 4 | 5 | Register Input Actual Out Model Out 6 | R0 2147483647 0 2147483647 7 | R1 2147483649 0 2147483649 8 | R2 4294967292 0 4294967292 9 | R3 4294967294 0 4294967294 10 | R4 2147483646 0 2147483646 11 | R5 4 0 4 12 | R6 4294967292 0 4294967292 13 | R7 2147483644 0 2147483644 14 | R8 3 0 3 15 | R9 2147483646 0 2147483646 16 | R10 1 0 1 17 | R11 2147483647 0 2147483647 18 | R12 2147483644 0 2147483644 19 | R13 4 4278190080 4 20 | R14 2147483647 0 2147483647 21 | Flag Before After Model 22 | N 0 0 1 23 | Z 1 0 24 | C 0 0 25 | V 1 0 1 26 | 27 | ---------ASM---------- 28 | TEQ R3 , R7 ,LSL #32 29 | ---------------------------------- 30 | 31 | 32 | 33 | --------------dp2Shifts:985---------------- 34 | Visual2 cannot parse test assembler 35 | 36 | Register Input Actual Out Model Out 37 | R0 4294967294 0 4294967294 38 | R1 4 0 4 39 | R2 2147483647 0 2147483647 40 | R3 4 0 4 41 | R4 3 0 3 42 | R5 2147483651 0 2147483651 43 | R6 1 0 1 44 | R7 4294967293 0 4294967293 45 | R8 4294967294 0 4294967294 46 | R9 4294967294 0 4294967294 47 | R10 2147483649 0 2147483649 48 | R11 4 0 49 | R12 0 0 50 | R13 1 4278190080 1 51 | R14 2 0 2 52 | Flag Before After Model 53 | N 0 0 54 | Z 0 0 1 55 | C 0 0 1 56 | V 1 0 1 57 | 58 | ---------ASM---------- 59 | MVNS R11, R10 , ASR #32 60 | ---------------------------------- 61 | 62 | 63 | 64 | --------------dp2Shifts:24---------------- 65 | Visual2 cannot parse test assembler 66 | 67 | Register Input Actual Out Model Out 68 | R0 4 0 4 69 | R1 2147483644 0 2147483644 70 | R2 1 0 1 71 | R3 2147483652 0 2147483652 72 | R4 2147483652 0 2147483652 73 | R5 2147483645 0 2147483645 74 | R6 2147483646 0 2147483646 75 | R7 4294967295 0 4294967295 76 | R8 4294967295 0 4294967295 77 | R9 2147483645 0 2147483645 78 | R10 2 0 2 79 | R11 2 0 2 80 | R12 2147483647 0 81 | R13 2147483648 4278190080 2147483648 82 | R14 2147483646 0 2147483646 83 | Flag Before After Model 84 | N 0 0 85 | Z 1 0 1 86 | C 0 0 87 | V 0 0 88 | 89 | ---------ASM---------- 90 | MOV R12 , R3 , LSL #32 91 | ---------------------------------- 92 | 93 | 94 | 95 | --------------dp2Shifts:246---------------- 96 | Flags: 97 | {FN = true; 98 | FZ = false; 99 | FC = false; 100 | FV = true} 101 | do not match model flags 102 | {FN = true; 103 | FZ = false; 104 | FC = true; 105 | FV = true} 106 | 107 | Register Input Actual Out Model Out 108 | R0 32 32 109 | R1 2147483649 2147483649 110 | R2 2147483644 2147483644 111 | R3 3 3 112 | R4 2147483651 2147483651 113 | R5 3 3 114 | R6 2147483646 2147483646 115 | R7 2147483647 4294967292 116 | R8 2147483646 2147483646 117 | R9 1 1 118 | R10 2147483652 2147483652 119 | R11 2147483651 2147483651 120 | R12 4294967294 4294967294 121 | R13 2147483646 2147483646 122 | R14 2147483651 2147483651 123 | Flag Before After Model 124 | N 0 1 125 | Z 0 0 126 | C 1 0 1 127 | V 1 1 128 | 129 | ---------ASM---------- 130 | MVNS R7 ,R3 , ROR R0 131 | ---------------------------------- 132 | 133 | -------------------------------------------------------------------------------- /app/test-data/ALLOWEDdp3ShiftsAll.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------dp3Shifts:2615---------------- 3 | Visual2 cannot parse test assembler 4 | 5 | Register Input Actual Out Model Out 6 | R0 4294967293 0 4294967293 7 | R1 2147483650 0 2147483650 8 | R2 2147483646 0 2147483646 9 | R3 4294967294 0 4294967294 10 | R4 2147483649 0 4294967293 11 | R5 2147483647 0 2147483647 12 | R6 1 0 1 13 | R7 3 0 3 14 | R8 2147483650 0 2147483650 15 | R9 3 0 3 16 | R10 2147483645 0 2147483645 17 | R11 2147483645 0 2147483645 18 | R12 4294967292 0 4294967292 19 | R13 4294967293 4278190080 4294967293 20 | R14 2147483648 0 2147483648 21 | Flag Before After Model 22 | N 0 0 23 | Z 1 0 1 24 | C 1 0 1 25 | V 0 0 26 | 27 | ---------ASM---------- 28 | ADD R4 ,R0 ,R6 , LSR #32 29 | ---------------------------------- 30 | 31 | 32 | 33 | --------------dp3Shifts:2729---------------- 34 | Visual2 cannot parse test assembler 35 | 36 | Register Input Actual Out Model Out 37 | R0 4294967295 0 4294967295 38 | R1 4294967292 0 4294967292 39 | R2 1 0 1 40 | R3 2147483649 0 2147483649 41 | R4 4 0 4 42 | R5 4294967293 0 4294967293 43 | R6 2147483649 0 2147483649 44 | R7 3 0 3 45 | R8 2147483651 0 2147483651 46 | R9 2 0 2 47 | R10 4294967294 0 4294967294 48 | R11 2147483651 0 2147483651 49 | R12 1 0 50 | R13 2147483646 4278190080 2147483646 51 | R14 2147483645 0 2147483645 52 | Flag Before After Model 53 | N 1 0 1 54 | Z 0 0 55 | C 0 0 56 | V 1 0 1 57 | 58 | ---------ASM---------- 59 | SBC R12 ,R12,R10 , LSL #32 60 | ---------------------------------- 61 | 62 | 63 | 64 | --------------dp3Shifts:1833---------------- 65 | Visual2 cannot parse test assembler 66 | 67 | Register Input Actual Out Model Out 68 | R0 2147483644 0 2147483644 69 | R1 2147483648 0 2147483648 70 | R2 2147483651 0 2147483651 71 | R3 4294967295 0 2147483653 72 | R4 3 0 3 73 | R5 4294967294 0 4294967294 74 | R6 4 0 4 75 | R7 4294967293 0 4294967293 76 | R8 2147483650 0 2147483650 77 | R9 4294967292 0 4294967292 78 | R10 4294967293 0 4294967293 79 | R11 4294967292 0 4294967292 80 | R12 4294967293 0 4294967293 81 | R13 2147483644 4278190080 2147483644 82 | R14 2147483648 0 2147483648 83 | Flag Before After Model 84 | N 0 0 1 85 | Z 1 0 86 | C 1 0 87 | V 1 0 88 | 89 | ---------ASM---------- 90 | RSCS R3 ,R12,R8 ,ROR #32 91 | ---------------------------------- 92 | 93 | 94 | 95 | --------------dp3Shifts:1322---------------- 96 | Visual2 cannot parse test assembler 97 | 98 | Register Input Actual Out Model Out 99 | R0 2147483649 0 2147483649 100 | R1 2147483647 0 2147483647 101 | R2 4294967293 0 4294967293 102 | R3 4294967293 0 4294967293 103 | R4 4294967295 0 4294967295 104 | R5 2 0 2 105 | R6 2147483649 0 2147483649 106 | R7 4 0 4 107 | R8 2147483650 0 2147483650 108 | R9 2147483651 0 2147483651 109 | R10 2147483650 0 2147483650 110 | R11 3 0 3 111 | R12 2147483650 0 2147483650 112 | R13 2147483648 4278190080 2147483648 113 | R14 2 0 2 114 | Flag Before After Model 115 | N 0 0 116 | Z 0 0 117 | C 1 0 1 118 | V 0 0 119 | 120 | ---------ASM---------- 121 | ADD R2 ,R3 ,R6 ,LSL #32 122 | ---------------------------------- 123 | 124 | 125 | 126 | --------------dp3Shifts:637---------------- 127 | Visual2 cannot parse test assembler 128 | 129 | Register Input Actual Out Model Out 130 | R0 2147483645 0 2147483645 131 | R1 2147483652 0 2147483652 132 | R2 2147483648 0 2147483648 133 | R3 2147483650 0 2147483644 134 | R4 2147483647 0 2147483647 135 | R5 3 0 3 136 | R6 2147483648 0 2147483648 137 | R7 2147483652 0 2147483652 138 | R8 2147483652 0 2147483652 139 | R9 2147483644 0 2147483644 140 | R10 2147483648 0 2147483648 141 | R11 4 0 4 142 | R12 2 0 2 143 | R13 2147483648 4278190080 2147483648 144 | R14 0 0 145 | Flag Before After Model 146 | N 0 0 147 | Z 1 0 148 | C 0 0 149 | V 1 0 1 150 | 151 | ---------ASM---------- 152 | BICS R3,R9, R3 ,LSL #32 153 | ---------------------------------- 154 | 155 | 156 | 157 | --------------dp3Shifts:931---------------- 158 | Visual2 cannot parse test assembler 159 | 160 | Register Input Actual Out Model Out 161 | R0 2147483645 0 2147483645 162 | R1 2147483647 0 2147483647 163 | R2 2147483645 0 2147483645 164 | R3 3 0 3 165 | R4 2147483650 0 2147483650 166 | R5 0 0 167 | R6 2147483645 0 2 168 | R7 2147483652 0 2147483652 169 | R8 2147483652 0 2147483652 170 | R9 2 0 2 171 | R10 2147483647 0 2147483647 172 | R11 2147483644 0 2147483644 173 | R12 4294967293 0 4294967293 174 | R13 0 4278190080 0 175 | R14 2 0 2 176 | Flag Before After Model 177 | N 0 0 178 | Z 1 0 1 179 | C 1 0 1 180 | V 1 0 1 181 | 182 | ---------ASM---------- 183 | EOR R6,R1 ,R0 , ROR #32 184 | ---------------------------------- 185 | 186 | -------------------------------------------------------------------------------- /app/test-data/ComputedBranchesAll.txt: -------------------------------------------------------------------------------- 1 | ComputedBranches:0 2 | Regs 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 3 | NZCV 0 0 0 0 4 | ... 5 | MOV R0, #0 6 | ADR R1, TARGET 7 | ADR R2, TARGETADDR 8 | MOV PC, R1 9 | ADD R0, R0, #1 10 | ADD R0, R0, #1 11 | TARGET ADD R0, R0, #1 12 | ADD R0, R0, #1 13 | ADD R0, R0, #1 14 | LDR R3, [R2] 15 | TARGETADDR DCD TARGET 16 | 17 | ... 18 | Regs 0x3 0x18 0x200 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 19 | NZCV 0 0 0 0 20 | 21 | ComputedBranches:7 22 | Regs 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 23 | NZCV 0 0 0 0 24 | ... 25 | MOV R0, #0 26 | ADR R1, TARGET 27 | ADR R2, TARGETADDR 28 | MOV R1, PC 29 | ADD R0, R0, #1 30 | ADD R0, R0, #1 31 | TARGET ADD R0, R0, #1 32 | ADD R0, R0, #1 33 | ADD R0, R0, #1 34 | LDR R3, [R2] 35 | TARGETADDR DCD TARGET 36 | 37 | ... 38 | Regs 0x5 0x14 0x200 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 39 | NZCV 0 0 0 0 40 | 41 | ComputedBranches:14 42 | Regs 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 43 | NZCV 0 0 0 0 44 | ... 45 | MOV R0, #0 46 | ADR R1, TARGET 47 | ADR R2, TARGETADDR 48 | LDR PC, [R2] 49 | ADD R0, R0, #1 50 | ADD R0, R0, #1 51 | TARGET ADD R0, R0, #1 52 | ADD R0, R0, #1 53 | ADD R0, R0, #1 54 | LDR R3, [R2] 55 | TARGETADDR DCD TARGET 56 | 57 | ... 58 | Regs 0x3 0x18 0x200 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 59 | NZCV 0 0 0 0 60 | 61 | ComputedBranches:21 62 | Regs 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 63 | NZCV 0 0 0 0 64 | ... 65 | MOV R0, #0 66 | ADR R1, TARGET 67 | ADR R2, TARGETADDR 68 | STR PC, [R2] 69 | ADD R0, R0, #1 70 | ADD R0, R0, #1 71 | TARGET ADD R0, R0, #1 72 | ADD R0, R0, #1 73 | ADD R0, R0, #1 74 | LDR R3, [R2] 75 | TARGETADDR DCD TARGET 76 | 77 | ... 78 | Regs 0x5 0x18 0x200 0x14 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 79 | NZCV 0 0 0 0 80 | 81 | ComputedBranches:28 82 | Regs 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 83 | NZCV 0 0 0 0 84 | ... 85 | MOV R0, #0 86 | ADR R1, TARGET 87 | ADR R2, TARGETADDR 88 | BL TARGET 89 | ADD R0, R0, #1 90 | ADD R0, R0, #1 91 | TARGET ADD R0, R0, #1 92 | ADD R0, R0, #1 93 | ADD R0, R0, #1 94 | LDR R3, [R2] 95 | TARGETADDR DCD TARGET 96 | 97 | ... 98 | Regs 0x3 0x18 0x200 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x10 99 | NZCV 0 0 0 0 100 | 101 | ComputedBranches:35 102 | Regs 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 103 | NZCV 0 0 0 0 104 | ... 105 | MOV R0, #0 106 | ADR R1, TARGET 107 | ADR R2, TARGETADDR 108 | LDR R4, =TARGET 109 | ADD R0, R0, #1 110 | ADD R0, R0, #1 111 | TARGET ADD R0, R0, #1 112 | ADD R0, R0, #1 113 | ADD R0, R0, #1 114 | LDR R3, [R2] 115 | TARGETADDR DCD TARGET 116 | 117 | ... 118 | Regs 0x5 0x18 0x200 0x18 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0xff000000 0x0 119 | NZCV 0 0 0 0 120 | 121 | -------------------------------------------------------------------------------- /app/test-data/MiscInstrAll.txt: -------------------------------------------------------------------------------- 1 | MiscInstr:0 2 | Regs 0xc024988f 0x78df0399 0x7da72974 0x38781155 0xfb7e320d 0xa3eb489 0xc1128f3b 0x8291f43a 0x9ceaec4a 0xd4577bf4 0x6b40616a 0xeecbec3c 0x530d8f5 0xc77bfbc5 0xc13841f 3 | NZCV 1 0 0 1 4 | ... 5 | ADR R0, DAT 6 | LDMIA R0, {R1-R6} 7 | LDR R7, =TESTEQU 8 | DAT DCD 0x12345678 9 | DAT1 DCB 3,4,5,6 10 | DAT2 DCB 12,13,14,15,16,17,18,19 11 | FILL 4 12 | DAT4 DCD 111 13 | TESTEQU EQU DAT+3 14 | 15 | ... 16 | Regs 0x200 0x12345678 0x6050403 0xf0e0d0c 0x13121110 0x0 0x6f 0x203 0x9ceaec4a 0xd4577bf4 0x6b40616a 0xeecbec3c 0x530d8f5 0xc77bfbc5 0xc13841f 17 | NZCV 1 0 0 1 18 | 19 | -------------------------------------------------------------------------------- /app/test-results/BETTERsMemLoadsAll.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------MemLoads:479---------------- 3 | Visual2 runs when VisuAL gives an error? 4 | 5 | Error in model 6 | 7 | ---------ASM---------- 8 | ADR R7,DAT3 9 | LDR R8 , [R7 ] ! 10 | DAT1 DCD 3903273698, 4284496457 , 306311911 ,1918985881 ,4085875476,4291926900 , 2983300192 , 2864149368 , 504412359, 3397904698 , 4268198127 ,1832337063 , 2513551886 ,1190878507 ,3162465754 ,4169910742 11 | DAT2 DCD 2089993674 ,1053652447 ,2071577171, 1111845843 ,467073668 , 2008014362 , 1326458183, 1487078627 ,2633889794 ,31061921,3345259356 , 1455447991 , 3450519736 ,2759282738,2884310325, 2853801390 12 | DAT3 DCD 2324248059 ,518188039 ,1301492952, 4160707516 , 1988189876, 3445883875 ,289443612, 4019679370 ,1768571416 , 3224290428,1677787370 ,41083189, 1862917909 , 2822027969 ,501019155,3219654304 13 | DAT4 DCD 1349184000 , 1402018069, 107244700 , 3075434533 , 239133 , 2166319280 ,3455603421 , 1316437646,3508548589 , 3871828434 ,1426515357 ,699238814 , 864632236, 2096983677, 2359508285 , 1038124142 14 | ---------------------------------- 15 | 16 | 17 | 18 | --------------MemLoads:400---------------- 19 | Visual2 runs when VisuAL gives an error? 20 | 21 | Error in model 22 | 23 | ---------ASM---------- 24 | ADR R7 , DAT3 25 | LDRB R8 ,[ R7 ] ! 26 | DAT1 DCD 3903273698 , 4284496457 ,306311911, 1918985881 , 4085875476,4291926900,2983300192, 2864149368, 504412359 , 3397904698 ,4268198127,1832337063 ,2513551886 , 1190878507 , 3162465754 ,4169910742 27 | DAT2 DCD 2089993674, 1053652447, 2071577171 , 1111845843 , 467073668, 2008014362 , 1326458183 , 1487078627 , 2633889794,31061921 , 3345259356, 1455447991 ,3450519736 , 2759282738 ,2884310325 , 2853801390 28 | DAT3 DCD 2324248059 , 518188039 , 1301492952 , 4160707516, 1988189876 ,3445883875 , 289443612, 4019679370 , 1768571416 , 3224290428 ,1677787370 ,41083189 ,1862917909 , 2822027969,501019155, 3219654304 29 | DAT4 DCD 1349184000 , 1402018069 , 107244700 , 3075434533 , 239133 ,2166319280 , 3455603421 , 1316437646, 3508548589 , 3871828434 , 1426515357 ,699238814 ,864632236 ,2096983677, 2359508285 , 1038124142 30 | ---------------------------------- 31 | 32 | 33 | 34 | --------------MemLoads:243---------------- 35 | Visual2 runs when VisuAL gives an error? 36 | 37 | Error in model 38 | 39 | ---------ASM---------- 40 | ADR R7, DAT3 41 | LDRB R8 , [R7 ] ! 42 | DAT1 DCD 3903273698 ,4284496457 ,306311911 ,1918985881, 4085875476, 4291926900, 2983300192 , 2864149368 , 504412359, 3397904698 ,4268198127 ,1832337063 , 2513551886 ,1190878507 ,3162465754, 4169910742 43 | DAT2 DCD 2089993674, 1053652447 , 2071577171, 1111845843,467073668 , 2008014362 ,1326458183 ,1487078627 , 2633889794 , 31061921 , 3345259356, 1455447991 , 3450519736, 2759282738 , 2884310325,2853801390 44 | DAT3 DCD 2324248059 ,518188039 , 1301492952, 4160707516 , 1988189876, 3445883875 ,289443612,4019679370 , 1768571416, 3224290428 , 1677787370 ,41083189, 1862917909 , 2822027969 , 501019155 ,3219654304 45 | DAT4 DCD 1349184000 ,1402018069, 107244700, 3075434533,239133 , 2166319280, 3455603421 , 1316437646, 3508548589 ,3871828434 , 1426515357 , 699238814 , 864632236 , 2096983677,2359508285,1038124142 46 | ---------------------------------- 47 | 48 | 49 | 50 | --------------MemLoads:321---------------- 51 | Visual2 runs when VisuAL gives an error? 52 | 53 | Error in model 54 | 55 | ---------ASM---------- 56 | ADR R7 ,DAT3 57 | LDR R8 ,[R7] ! 58 | DAT1 DCD 3903273698 ,4284496457 , 306311911 , 1918985881 , 4085875476, 4291926900,2983300192 , 2864149368,504412359 ,3397904698 ,4268198127 , 1832337063, 2513551886 ,1190878507 , 3162465754, 4169910742 59 | DAT2 DCD 2089993674 , 1053652447,2071577171 ,1111845843 ,467073668, 2008014362, 1326458183,1487078627, 2633889794, 31061921, 3345259356,1455447991 , 3450519736 , 2759282738 ,2884310325 , 2853801390 60 | DAT3 DCD 2324248059 , 518188039 , 1301492952 , 4160707516 ,1988189876, 3445883875,289443612 , 4019679370 , 1768571416 , 3224290428, 1677787370 , 41083189 , 1862917909, 2822027969 ,501019155 ,3219654304 61 | DAT4 DCD 1349184000,1402018069 , 107244700 , 3075434533 , 239133, 2166319280,3455603421 , 1316437646, 3508548589,3871828434 , 1426515357 , 699238814 , 864632236,2096983677 , 2359508285, 1038124142 62 | ---------------------------------- 63 | 64 | 65 | 66 | --------------MemLoads:164---------------- 67 | Visual2 runs when VisuAL gives an error? 68 | 69 | Error in model 70 | 71 | ---------ASM---------- 72 | ADR R7 , DAT3 73 | LDR R8,[ R7 ] ! 74 | DAT1 DCD 3903273698 ,4284496457, 306311911, 1918985881 ,4085875476, 4291926900, 2983300192 , 2864149368 , 504412359 , 3397904698 , 4268198127 ,1832337063 , 2513551886, 1190878507 ,3162465754, 4169910742 75 | DAT2 DCD 2089993674, 1053652447 , 2071577171 ,1111845843 ,467073668 , 2008014362,1326458183 , 1487078627 , 2633889794, 31061921,3345259356 , 1455447991 , 3450519736 , 2759282738,2884310325, 2853801390 76 | DAT3 DCD 2324248059 , 518188039 , 1301492952 , 4160707516 , 1988189876 , 3445883875 ,289443612, 4019679370 , 1768571416 ,3224290428,1677787370 , 41083189, 1862917909 ,2822027969 ,501019155 , 3219654304 77 | DAT4 DCD 1349184000, 1402018069,107244700 , 3075434533 ,239133,2166319280,3455603421 , 1316437646, 3508548589 , 3871828434, 1426515357 , 699238814 , 864632236 , 2096983677 , 2359508285 , 1038124142 78 | ---------------------------------- 79 | 80 | 81 | 82 | --------------MemLoads:85---------------- 83 | Visual2 runs when VisuAL gives an error? 84 | 85 | Error in model 86 | 87 | ---------ASM---------- 88 | ADR R7 ,DAT3 89 | LDRB R8 ,[ R7] ! 90 | DAT1 DCD 3903273698 ,4284496457 , 306311911 , 1918985881 , 4085875476 ,4291926900 , 2983300192 , 2864149368 , 504412359 ,3397904698, 4268198127 , 1832337063 , 2513551886 , 1190878507 , 3162465754 , 4169910742 91 | DAT2 DCD 2089993674 , 1053652447 , 2071577171 , 1111845843 , 467073668 ,2008014362 , 1326458183 , 1487078627 , 2633889794, 31061921 ,3345259356 , 1455447991 , 3450519736, 2759282738 ,2884310325,2853801390 92 | DAT3 DCD 2324248059, 518188039, 1301492952 ,4160707516,1988189876, 3445883875, 289443612 , 4019679370, 1768571416 , 3224290428 , 1677787370, 41083189 , 1862917909, 2822027969 , 501019155 , 3219654304 93 | DAT4 DCD 1349184000 , 1402018069, 107244700 , 3075434533,239133 ,2166319280 , 3455603421 , 1316437646, 3508548589 , 3871828434,1426515357 , 699238814,864632236, 2096983677 , 2359508285 , 1038124142 94 | ---------------------------------- 95 | 96 | 97 | 98 | --------------MemLoads:6---------------- 99 | Visual2 runs when VisuAL gives an error? 100 | 101 | Error in model 102 | 103 | ---------ASM---------- 104 | ADR R7, DAT3 105 | LDR R8,[ R7 ] ! 106 | DAT1 DCD 3903273698 ,4284496457 , 306311911 ,1918985881 , 4085875476,4291926900, 2983300192 ,2864149368 ,504412359 ,3397904698 , 4268198127 , 1832337063 ,2513551886 , 1190878507 ,3162465754 ,4169910742 107 | DAT2 DCD 2089993674, 1053652447 , 2071577171 ,1111845843 ,467073668, 2008014362,1326458183, 1487078627 , 2633889794 , 31061921 , 3345259356, 1455447991, 3450519736 , 2759282738,2884310325 , 2853801390 108 | DAT3 DCD 2324248059, 518188039 , 1301492952 , 4160707516 ,1988189876,3445883875 ,289443612,4019679370 , 1768571416 , 3224290428,1677787370 , 41083189 , 1862917909, 2822027969 ,501019155 , 3219654304 109 | DAT4 DCD 1349184000 ,1402018069 ,107244700 ,3075434533 , 239133, 2166319280 ,3455603421 , 1316437646 , 3508548589, 3871828434, 1426515357 ,699238814, 864632236 , 2096983677 ,2359508285 , 1038124142 110 | ---------------------------------- 111 | 112 | -------------------------------------------------------------------------------- /app/test-results/BETTERsMemStoresAll.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------MemStores:479---------------- 3 | Visual2 runs when VisuAL gives an error? 4 | 5 | Error in model 6 | 7 | ---------ASM---------- 8 | ADR R11 , DAT3 9 | STR R9 , [ R11] ! 10 | ; **** CheckSum in R1 *** 11 | ADR R3, DAT1+0x100 12 | MOV R1, #0 13 | CHECKLOOP LDR R12, [R3,#-4]! 14 | ADD R1, R1, R12 15 | ADR R12, DAT1 16 | CMP R3,R12 17 | BNE CHECKLOOP 18 | DAT1 DCD 1780874446, 2328385545 , 3296312804 , 2143984065 , 322772012 ,2426300838 ,3919636974 ,189486613, 2979621581 ,3226716658,3851208888 ,4020193489, 3682714309 , 1748827312 , 3387164468 , 2674075447 19 | DAT2 DCD 50657950, 3385321977 ,3741973757 , 555969480 ,164927943, 711942353, 3722388221 , 1402754033, 2032355510 ,355092652,1726771607,4042695021,221135350 , 2089222580, 1437041433,3487370249 20 | DAT3 DCD 2093508966 ,1721954050, 539369809 , 1997255836 , 1235833994 , 3223210948, 2655555278 , 1794291844 ,1864897610 ,2207088942 ,4060698295 ,3226177900 , 161949786 , 3704331539, 2155159407 , 371295930 21 | DAT4 DCD 3387498086, 3825759353, 3160040602,868898769, 3517603982, 4278325857 , 2977539377 , 52723296 , 3607413763 , 2458599772 , 4287319727 , 436151824 , 2837108022,3847944140, 1149688312 , 874981946 22 | ---------------------------------- 23 | 24 | 25 | 26 | --------------MemStores:400---------------- 27 | Visual2 runs when VisuAL gives an error? 28 | 29 | Error in model 30 | 31 | ---------ASM---------- 32 | ADR R11, DAT3 33 | STRB R9 , [R11] ! 34 | ; **** CheckSum in R1 *** 35 | ADR R3, DAT1+0x100 36 | MOV R1, #0 37 | CHECKLOOP LDR R12, [R3,#-4]! 38 | ADD R1, R1, R12 39 | ADR R12, DAT1 40 | CMP R3,R12 41 | BNE CHECKLOOP 42 | DAT1 DCD 1780874446 , 2328385545 ,3296312804 , 2143984065 , 322772012 , 2426300838 , 3919636974 ,189486613 , 2979621581 ,3226716658, 3851208888 , 4020193489, 3682714309, 1748827312 , 3387164468 , 2674075447 43 | DAT2 DCD 50657950 , 3385321977 , 3741973757 , 555969480 , 164927943, 711942353 , 3722388221, 1402754033 , 2032355510 , 355092652, 1726771607, 4042695021 ,221135350 , 2089222580 , 1437041433 , 3487370249 44 | DAT3 DCD 2093508966 , 1721954050 , 539369809 , 1997255836 , 1235833994, 3223210948, 2655555278 , 1794291844 , 1864897610 , 2207088942, 4060698295 , 3226177900 , 161949786,3704331539 , 2155159407 , 371295930 45 | DAT4 DCD 3387498086 , 3825759353 , 3160040602, 868898769 , 3517603982, 4278325857, 2977539377 , 52723296 ,3607413763 , 2458599772 ,4287319727 ,436151824, 2837108022 ,3847944140 ,1149688312, 874981946 46 | ---------------------------------- 47 | 48 | 49 | 50 | --------------MemStores:243---------------- 51 | Visual2 runs when VisuAL gives an error? 52 | 53 | Error in model 54 | 55 | ---------ASM---------- 56 | ADR R11,DAT3 57 | STRB R9 , [R11 ]! 58 | ; **** CheckSum in R1 *** 59 | ADR R3, DAT1+0x100 60 | MOV R1, #0 61 | CHECKLOOP LDR R12, [R3,#-4]! 62 | ADD R1, R1, R12 63 | ADR R12, DAT1 64 | CMP R3,R12 65 | BNE CHECKLOOP 66 | DAT1 DCD 1780874446 , 2328385545 , 3296312804 , 2143984065,322772012 , 2426300838 ,3919636974 , 189486613, 2979621581 , 3226716658, 3851208888, 4020193489 , 3682714309 , 1748827312, 3387164468, 2674075447 67 | DAT2 DCD 50657950 ,3385321977, 3741973757 , 555969480 , 164927943 ,711942353 , 3722388221 , 1402754033 , 2032355510,355092652, 1726771607, 4042695021, 221135350 , 2089222580,1437041433 , 3487370249 68 | DAT3 DCD 2093508966 ,1721954050 ,539369809 , 1997255836 , 1235833994 ,3223210948 , 2655555278 ,1794291844 ,1864897610,2207088942 , 4060698295 , 3226177900 ,161949786 ,3704331539 , 2155159407,371295930 69 | DAT4 DCD 3387498086, 3825759353, 3160040602, 868898769, 3517603982 , 4278325857 , 2977539377, 52723296 , 3607413763,2458599772 , 4287319727 ,436151824,2837108022 , 3847944140 , 1149688312, 874981946 70 | ---------------------------------- 71 | 72 | 73 | 74 | --------------MemStores:321---------------- 75 | Visual2 runs when VisuAL gives an error? 76 | 77 | Error in model 78 | 79 | ---------ASM---------- 80 | ADR R11 , DAT3 81 | STR R9,[ R11]! 82 | ; **** CheckSum in R1 *** 83 | ADR R3, DAT1+0x100 84 | MOV R1, #0 85 | CHECKLOOP LDR R12, [R3,#-4]! 86 | ADD R1, R1, R12 87 | ADR R12, DAT1 88 | CMP R3,R12 89 | BNE CHECKLOOP 90 | DAT1 DCD 1780874446 , 2328385545, 3296312804 ,2143984065 , 322772012 , 2426300838 ,3919636974, 189486613, 2979621581,3226716658 ,3851208888,4020193489,3682714309,1748827312 , 3387164468 , 2674075447 91 | DAT2 DCD 50657950 , 3385321977 , 3741973757 , 555969480, 164927943 , 711942353, 3722388221 , 1402754033, 2032355510 , 355092652 , 1726771607 ,4042695021 , 221135350 , 2089222580 , 1437041433 , 3487370249 92 | DAT3 DCD 2093508966 , 1721954050 ,539369809 , 1997255836 , 1235833994,3223210948, 2655555278 , 1794291844 , 1864897610 ,2207088942 , 4060698295,3226177900 , 161949786 , 3704331539 , 2155159407, 371295930 93 | DAT4 DCD 3387498086, 3825759353 , 3160040602, 868898769, 3517603982 , 4278325857, 2977539377 , 52723296 ,3607413763 , 2458599772, 4287319727 ,436151824 , 2837108022 ,3847944140 , 1149688312 , 874981946 94 | ---------------------------------- 95 | 96 | 97 | 98 | --------------MemStores:164---------------- 99 | Visual2 runs when VisuAL gives an error? 100 | 101 | Error in model 102 | 103 | ---------ASM---------- 104 | ADR R11 , DAT3 105 | STR R9 ,[ R11 ] ! 106 | ; **** CheckSum in R1 *** 107 | ADR R3, DAT1+0x100 108 | MOV R1, #0 109 | CHECKLOOP LDR R12, [R3,#-4]! 110 | ADD R1, R1, R12 111 | ADR R12, DAT1 112 | CMP R3,R12 113 | BNE CHECKLOOP 114 | DAT1 DCD 1780874446, 2328385545, 3296312804, 2143984065 , 322772012 , 2426300838, 3919636974, 189486613 , 2979621581 , 3226716658 , 3851208888 , 4020193489 , 3682714309 , 1748827312 , 3387164468, 2674075447 115 | DAT2 DCD 50657950 ,3385321977 , 3741973757 ,555969480,164927943, 711942353 ,3722388221 , 1402754033, 2032355510, 355092652 , 1726771607 ,4042695021,221135350 ,2089222580 , 1437041433,3487370249 116 | DAT3 DCD 2093508966, 1721954050,539369809 ,1997255836 ,1235833994 , 3223210948, 2655555278, 1794291844, 1864897610 ,2207088942, 4060698295 , 3226177900, 161949786 , 3704331539 , 2155159407 ,371295930 117 | DAT4 DCD 3387498086 ,3825759353, 3160040602, 868898769, 3517603982,4278325857,2977539377 ,52723296 ,3607413763 , 2458599772 ,4287319727 , 436151824 , 2837108022 , 3847944140 , 1149688312 , 874981946 118 | ---------------------------------- 119 | 120 | 121 | 122 | --------------MemStores:85---------------- 123 | Visual2 runs when VisuAL gives an error? 124 | 125 | Error in model 126 | 127 | ---------ASM---------- 128 | ADR R11 ,DAT3 129 | STRB R9,[ R11 ] ! 130 | ; **** CheckSum in R1 *** 131 | ADR R3, DAT1+0x100 132 | MOV R1, #0 133 | CHECKLOOP LDR R12, [R3,#-4]! 134 | ADD R1, R1, R12 135 | ADR R12, DAT1 136 | CMP R3,R12 137 | BNE CHECKLOOP 138 | DAT1 DCD 1780874446, 2328385545 , 3296312804 ,2143984065 , 322772012,2426300838 , 3919636974 ,189486613,2979621581 ,3226716658 ,3851208888 ,4020193489 , 3682714309 , 1748827312, 3387164468 , 2674075447 139 | DAT2 DCD 50657950 , 3385321977 ,3741973757 , 555969480 ,164927943,711942353 ,3722388221 ,1402754033 , 2032355510 , 355092652 , 1726771607 , 4042695021, 221135350 ,2089222580, 1437041433,3487370249 140 | DAT3 DCD 2093508966, 1721954050, 539369809 ,1997255836 , 1235833994 , 3223210948 , 2655555278 , 1794291844 ,1864897610,2207088942 , 4060698295 ,3226177900 , 161949786 , 3704331539 , 2155159407, 371295930 141 | DAT4 DCD 3387498086 , 3825759353 ,3160040602,868898769, 3517603982 ,4278325857 , 2977539377 , 52723296 ,3607413763,2458599772 , 4287319727 ,436151824 , 2837108022 , 3847944140 , 1149688312,874981946 142 | ---------------------------------- 143 | 144 | 145 | 146 | --------------MemStores:6---------------- 147 | Visual2 runs when VisuAL gives an error? 148 | 149 | Error in model 150 | 151 | ---------ASM---------- 152 | ADR R11 , DAT3 153 | STR R9 , [ R11 ] ! 154 | ; **** CheckSum in R1 *** 155 | ADR R3, DAT1+0x100 156 | MOV R1, #0 157 | CHECKLOOP LDR R12, [R3,#-4]! 158 | ADD R1, R1, R12 159 | ADR R12, DAT1 160 | CMP R3,R12 161 | BNE CHECKLOOP 162 | DAT1 DCD 1780874446 ,2328385545 , 3296312804,2143984065 , 322772012 ,2426300838, 3919636974, 189486613 , 2979621581 , 3226716658, 3851208888 ,4020193489, 3682714309 , 1748827312 , 3387164468 , 2674075447 163 | DAT2 DCD 50657950 , 3385321977 ,3741973757 ,555969480, 164927943 ,711942353, 3722388221 , 1402754033,2032355510 ,355092652, 1726771607, 4042695021 ,221135350, 2089222580 ,1437041433 ,3487370249 164 | DAT3 DCD 2093508966 , 1721954050 ,539369809 , 1997255836 , 1235833994 , 3223210948 , 2655555278 ,1794291844 , 1864897610 ,2207088942 , 4060698295 ,3226177900 , 161949786 ,3704331539 , 2155159407 , 371295930 165 | DAT4 DCD 3387498086, 3825759353 ,3160040602, 868898769 , 3517603982 ,4278325857 , 2977539377 , 52723296 , 3607413763 ,2458599772, 4287319727 ,436151824, 2837108022 , 3847944140 , 1149688312,874981946 166 | ---------------------------------- 167 | 168 | -------------------------------------------------------------------------------- /app/test-results/ERRORsMemLoadsAll.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------MemLoads:388---------------- 3 | Visual2 cannot parse test assembler 4 | 5 | Register Input Actual Out Model Out 6 | R0 1209282684 0 1209282684 7 | R1 393019475 0 393019475 8 | R2 2682578044 0 2682578044 9 | R3 2407440921 0 2407440921 10 | R4 2 0 2 11 | R5 283353208 0 283353208 12 | R6 4235107966 0 4235107966 13 | R7 2097705640 0 643 14 | R8 1349770796 0 2324248059 15 | R9 2025503319 0 2025503319 16 | R10 3024480132 0 3024480132 17 | R11 4039134891 0 4039134891 18 | R12 2443241327 0 2443241327 19 | R13 156803353 4278190080 156803353 20 | R14 1291646335 0 1291646335 21 | Flag Before After Model 22 | N 1 0 1 23 | Z 0 0 24 | C 1 0 1 25 | V 0 0 26 | 27 | ---------ASM---------- 28 | ADR R7, DAT3 29 | LDR R8,[ R7 ] , #0x3 30 | DAT1 DCD 3903273698 , 4284496457, 306311911,1918985881,4085875476,4291926900,2983300192 , 2864149368 , 504412359 , 3397904698 , 4268198127 ,1832337063 , 2513551886 , 1190878507, 3162465754, 4169910742 31 | DAT2 DCD 2089993674 ,1053652447 , 2071577171 ,1111845843 , 467073668 , 2008014362 , 1326458183 ,1487078627 , 2633889794 ,31061921 , 3345259356, 1455447991 ,3450519736, 2759282738 , 2884310325, 2853801390 32 | DAT3 DCD 2324248059 ,518188039, 1301492952 , 4160707516,1988189876 , 3445883875 , 289443612, 4019679370, 1768571416 , 3224290428 ,1677787370 , 41083189,1862917909,2822027969 , 501019155 , 3219654304 33 | DAT4 DCD 1349184000 , 1402018069 , 107244700, 3075434533 , 239133, 2166319280 , 3455603421 , 1316437646, 3508548589, 3871828434 , 1426515357 ,699238814 , 864632236 ,2096983677 ,2359508285, 1038124142 34 | ---------------------------------- 35 | 36 | -------------------------------------------------------------------------------- /app/test-results/ERRORsMemStoresAll.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------MemStores:230---------------- 3 | Visual2 cannot parse test assembler 4 | 5 | Register Input Actual Out Model Out 6 | R0 4234037955 0 4234037955 7 | R1 473375332 0 748880547 8 | R2 926055158 0 926055158 9 | R3 2237691589 0 512 10 | R4 3829487160 0 3829487160 11 | R5 2252902908 0 2252902908 12 | R6 395102362 0 395102362 13 | R7 911580877 0 911580877 14 | R8 795843196 0 795843196 15 | R9 3185205050 0 3185205050 16 | R10 2 0 2 17 | R11 2473632534 0 639 18 | R12 945023029 0 512 19 | R13 960437613 4278190080 960437613 20 | R14 3971472291 0 3971472291 21 | Flag Before After Model 22 | N 0 0 23 | Z 0 0 1 24 | C 0 0 1 25 | V 0 0 26 | 27 | ---------ASM---------- 28 | ADR R11 , DAT3 29 | STR R9 , [R11 ] , #0xffffffff 30 | ; **** CheckSum in R1 *** 31 | ADR R3, DAT1+0x100 32 | MOV R1, #0 33 | CHECKLOOP LDR R12, [R3,#-4]! 34 | ADD R1, R1, R12 35 | ADR R12, DAT1 36 | CMP R3,R12 37 | BNE CHECKLOOP 38 | DAT1 DCD 1780874446 , 2328385545,3296312804 , 2143984065 , 322772012 , 2426300838 , 3919636974 ,189486613 , 2979621581 , 3226716658 ,3851208888 ,4020193489,3682714309, 1748827312 , 3387164468,2674075447 39 | DAT2 DCD 50657950 ,3385321977 , 3741973757 ,555969480 ,164927943, 711942353 ,3722388221 ,1402754033, 2032355510, 355092652 , 1726771607, 4042695021 ,221135350 , 2089222580 ,1437041433 , 3487370249 40 | DAT3 DCD 2093508966 ,1721954050,539369809 ,1997255836 , 1235833994 , 3223210948 , 2655555278,1794291844 , 1864897610,2207088942 , 4060698295 , 3226177900 ,161949786, 3704331539, 2155159407 , 371295930 41 | DAT4 DCD 3387498086 , 3825759353 , 3160040602, 868898769 , 3517603982 ,4278325857 , 2977539377 ,52723296 , 3607413763, 2458599772 , 4287319727, 436151824, 2837108022 ,3847944140, 1149688312 , 874981946 42 | ---------------------------------- 43 | 44 | 45 | 46 | --------------MemStores:72---------------- 47 | Visual2 cannot parse test assembler 48 | 49 | Register Input Actual Out Model Out 50 | R0 2963348631 0 2963348631 51 | R1 4102862870 0 3284582859 52 | R2 360149278 0 360149278 53 | R3 4270874826 0 512 54 | R4 553611658 0 553611658 55 | R5 1874279578 0 1874279578 56 | R6 3862897032 0 3862897032 57 | R7 975347107 0 975347107 58 | R8 195976084 0 195976084 59 | R9 1425940066 0 1425940066 60 | R10 2 0 2 61 | R11 1028231749 0 635 62 | R12 1733850849 0 512 63 | R13 4282202758 4278190080 4282202758 64 | R14 2188650617 0 2188650617 65 | Flag Before After Model 66 | N 0 0 67 | Z 1 0 1 68 | C 1 0 1 69 | V 0 0 70 | 71 | ---------ASM---------- 72 | ADR R11 , DAT3 73 | STR R9 , [ R11 ] , #0xfffffffb 74 | ; **** CheckSum in R1 *** 75 | ADR R3, DAT1+0x100 76 | MOV R1, #0 77 | CHECKLOOP LDR R12, [R3,#-4]! 78 | ADD R1, R1, R12 79 | ADR R12, DAT1 80 | CMP R3,R12 81 | BNE CHECKLOOP 82 | DAT1 DCD 1780874446, 2328385545,3296312804 , 2143984065 , 322772012 , 2426300838 , 3919636974 , 189486613, 2979621581, 3226716658 , 3851208888 ,4020193489 ,3682714309,1748827312 ,3387164468 , 2674075447 83 | DAT2 DCD 50657950 , 3385321977,3741973757 , 555969480,164927943 ,711942353 , 3722388221,1402754033 ,2032355510 , 355092652 ,1726771607, 4042695021 , 221135350 ,2089222580 ,1437041433,3487370249 84 | DAT3 DCD 2093508966 , 1721954050 , 539369809, 1997255836, 1235833994 , 3223210948,2655555278 , 1794291844, 1864897610 , 2207088942 , 4060698295 , 3226177900 , 161949786,3704331539 , 2155159407 ,371295930 85 | DAT4 DCD 3387498086,3825759353 ,3160040602, 868898769 , 3517603982 , 4278325857 , 2977539377 , 52723296 ,3607413763, 2458599772, 4287319727, 436151824 ,2837108022 , 3847944140, 1149688312 , 874981946 86 | ---------------------------------- 87 | 88 | -------------------------------------------------------------------------------- /app/test-results/ERRORsdp2ImmAll.txt: -------------------------------------------------------------------------------- 1 | 2 | --------------dp2Imm:545---------------- 3 | Visual2 cannot parse test assembler 4 | 5 | Register Input Actual Out Model Out 6 | R0 2147483644 0 2147483644 7 | R1 3 0 3 8 | R2 4294967292 0 4294967292 9 | R3 2147483647 0 2147483647 10 | R4 2 0 2 11 | R5 4 0 4 12 | R6 4294967292 0 4294967292 13 | R7 4294967295 0 4294967295 14 | R8 2147483651 0 1073741802 15 | R9 2147483644 0 2147483644 16 | R10 4294967295 0 4294967295 17 | R11 4294967292 0 4294967292 18 | R12 3 0 3 19 | R13 2147483648 4278190080 2147483648 20 | R14 2147483647 0 2147483647 21 | Flag Before After Model 22 | N 1 0 23 | Z 0 0 24 | C 1 0 1 25 | V 0 0 26 | 27 | ---------ASM---------- 28 | MVNS R8, #-1073741803 29 | ---------------------------------- 30 | 31 | 32 | 33 | --------------dp2Imm:418---------------- 34 | Flags: 35 | {FN = true; 36 | FZ = false; 37 | FC = false; 38 | FV = false} 39 | do not match model flags 40 | {FN = true; 41 | FZ = false; 42 | FC = true; 43 | FV = false} 44 | 45 | Register Input Actual Out Model Out 46 | R0 2 2 47 | R1 0 0 48 | R2 2147483647 2147483647 49 | R3 2147483651 2147483651 50 | R4 4 4 51 | R5 2147483650 2147483650 52 | R6 2147483652 2147483652 53 | R7 4294967293 4294773759 54 | R8 4294967295 4294967295 55 | R9 3 3 56 | R10 2147483649 2147483649 57 | R11 4 4 58 | R12 2 2 59 | R13 1 1 60 | R14 2147483652 2147483652 61 | Flag Before After Model 62 | N 0 1 63 | Z 0 0 64 | C 1 0 1 65 | V 0 0 66 | 67 | ---------ASM---------- 68 | MVNS R7, #193536 69 | ---------------------------------- 70 | 71 | 72 | 73 | --------------dp2Imm:303---------------- 74 | Visual2 cannot parse test assembler 75 | 76 | Register Input Actual Out Model Out 77 | R0 4294967294 0 4294967294 78 | R1 2147483645 0 2147483645 79 | R2 4294967294 0 4294967294 80 | R3 2147483647 0 2147483647 81 | R4 2147483644 0 2147483644 82 | R5 3 0 1073741788 83 | R6 0 0 84 | R7 3 0 3 85 | R8 2 0 2 86 | R9 2 0 2 87 | R10 4 0 4 88 | R11 4294967295 0 4294967295 89 | R12 2147483644 0 2147483644 90 | R13 2147483648 4278190080 2147483648 91 | R14 2147483649 0 2147483649 92 | Flag Before After Model 93 | N 0 0 94 | Z 0 0 95 | C 0 0 96 | V 0 0 97 | 98 | ---------ASM---------- 99 | MVN R5 ,#-1073741789 100 | ---------------------------------- 101 | 102 | 103 | 104 | --------------dp2Imm:333---------------- 105 | Flags: 106 | {FN = true; 107 | FZ = false; 108 | FC = false; 109 | FV = true} 110 | do not match model flags 111 | {FN = true; 112 | FZ = false; 113 | FC = true; 114 | FV = true} 115 | 116 | Register Input Actual Out Model Out 117 | R0 4 4 118 | R1 4 4 119 | R2 3 3 120 | R3 4294967292 4294967292 121 | R4 2147483646 4294964543 122 | R5 0 0 123 | R6 2147483651 2147483651 124 | R7 4 4 125 | R8 2147483646 2147483646 126 | R9 4294967292 4294967292 127 | R10 1 1 128 | R11 1 1 129 | R12 4294967294 4294967294 130 | R13 4294967294 4294967294 131 | R14 2147483650 2147483650 132 | Flag Before After Model 133 | N 0 1 134 | Z 0 0 135 | C 1 0 1 136 | V 1 1 137 | 138 | ---------ASM---------- 139 | MVNS R4 ,#2752 140 | ---------------------------------- 141 | 142 | 143 | 144 | --------------dp2Imm:375---------------- 145 | Flags: 146 | {FN = true; 147 | FZ = false; 148 | FC = false; 149 | FV = false} 150 | do not match model flags 151 | {FN = true; 152 | FZ = false; 153 | FC = true; 154 | FV = false} 155 | 156 | Register Input Actual Out Model Out 157 | R0 2147483652 4289724415 158 | R1 2147483651 2147483651 159 | R2 2147483645 2147483645 160 | R3 4294967293 4294967293 161 | R4 0 0 162 | R5 4294967292 4294967292 163 | R6 2147483652 2147483652 164 | R7 0 0 165 | R8 4294967292 4294967292 166 | R9 4294967294 4294967294 167 | R10 4 4 168 | R11 2147483644 2147483644 169 | R12 2147483650 2147483650 170 | R13 2147483650 2147483650 171 | R14 4294967294 4294967294 172 | Flag Before After Model 173 | N 0 1 174 | Z 1 0 175 | C 1 0 1 176 | V 0 0 177 | 178 | ---------ASM---------- 179 | MVNS R0, #5242880 180 | ---------------------------------- 181 | 182 | 183 | 184 | --------------dp2Imm:260---------------- 185 | Visual2 cannot parse test assembler 186 | 187 | Register Input Actual Out Model Out 188 | R0 3 0 3 189 | R1 2147483646 0 1073741810 190 | R2 1 0 1 191 | R3 0 0 192 | R4 2147483650 0 2147483650 193 | R5 2147483647 0 2147483647 194 | R6 2 0 2 195 | R7 2147483652 0 2147483652 196 | R8 2147483647 0 2147483647 197 | R9 2147483645 0 2147483645 198 | R10 4294967292 0 4294967292 199 | R11 4294967293 0 4294967293 200 | R12 2147483649 0 2147483649 201 | R13 2147483645 4278190080 2147483645 202 | R14 4294967292 0 4294967292 203 | Flag Before After Model 204 | N 0 0 205 | Z 0 0 206 | C 0 0 207 | V 1 0 1 208 | 209 | ---------ASM---------- 210 | MVN R1 , #-1073741811 211 | ---------------------------------- 212 | 213 | 214 | 215 | --------------dp2Imm:272---------------- 216 | Visual2 cannot parse test assembler 217 | 218 | Register Input Actual Out Model Out 219 | R0 2147483647 0 2147483647 220 | R1 2147483651 0 2147483651 221 | R2 4294967295 0 4294967295 222 | R3 2147483652 0 2147483652 223 | R4 2147483649 0 2147483649 224 | R5 1 0 1 225 | R6 2147483650 0 2147483650 226 | R7 4294967294 0 4294967294 227 | R8 2147483648 0 2147483648 228 | R9 2147483647 0 2147483647 229 | R10 2147483651 0 2147483651 230 | R11 4294967292 0 4294967292 231 | R12 3 0 3 232 | R13 2147483652 4278190080 2147483652 233 | R14 4294967292 0 4294967292 234 | Flag Before After Model 235 | N 0 0 1 236 | Z 0 0 237 | C 0 0 238 | V 1 0 1 239 | 240 | ---------ASM---------- 241 | TEQ R0 , #-1073741779 242 | ---------------------------------- 243 | 244 | 245 | 246 | --------------dp2Imm:290---------------- 247 | Flags: 248 | {FN = true; 249 | FZ = false; 250 | FC = false; 251 | FV = true} 252 | do not match model flags 253 | {FN = true; 254 | FZ = false; 255 | FC = true; 256 | FV = true} 257 | 258 | Register Input Actual Out Model Out 259 | R0 4294967294 4294967294 260 | R1 2147483651 2147483651 261 | R2 4294967295 4294967295 262 | R3 2147483649 4294955519 263 | R4 1 1 264 | R5 2147483646 2147483646 265 | R6 2147483649 2147483649 266 | R7 2147483652 2147483652 267 | R8 2147483644 2147483644 268 | R9 2147483651 2147483651 269 | R10 2147483652 2147483652 270 | R11 2147483644 2147483644 271 | R12 3 3 272 | R13 2147483650 2147483650 273 | R14 2147483652 2147483652 274 | Flag Before After Model 275 | N 1 1 276 | Z 0 0 277 | C 1 0 1 278 | V 1 1 279 | 280 | ---------ASM---------- 281 | MVNS R3 , #11776 282 | ---------------------------------- 283 | 284 | 285 | 286 | --------------dp2Imm:115---------------- 287 | Flags: 288 | {FN = false; 289 | FZ = false; 290 | FC = false; 291 | FV = true} 292 | do not match model flags 293 | {FN = false; 294 | FZ = false; 295 | FC = true; 296 | FV = true} 297 | 298 | Register Input Actual Out Model Out 299 | R0 4294967295 4294967295 300 | R1 4294967294 4294967294 301 | R2 2147483648 2147483648 302 | R3 4294967295 4294967295 303 | R4 2147483648 2147483648 304 | R5 2147483645 720896 305 | R6 1 1 306 | R7 2147483647 2147483647 307 | R8 4 4 308 | R9 2147483646 2147483646 309 | R10 2147483647 2147483647 310 | R11 2147483652 2147483652 311 | R12 2147483649 2147483649 312 | R13 4294967295 4294967295 313 | R14 2147483652 2147483652 314 | Flag Before After Model 315 | N 1 0 316 | Z 0 0 317 | C 1 0 1 318 | V 1 1 319 | 320 | ---------ASM---------- 321 | MOVS R5 ,#720896 322 | ---------------------------------- 323 | 324 | 325 | 326 | --------------dp2Imm:78---------------- 327 | Flags: 328 | {FN = false; 329 | FZ = false; 330 | FC = false; 331 | FV = true} 332 | do not match model flags 333 | {FN = false; 334 | FZ = false; 335 | FC = true; 336 | FV = true} 337 | 338 | Register Input Actual Out Model Out 339 | R0 4294967293 4294967293 340 | R1 0 0 341 | R2 4294967293 4294967293 342 | R3 4294967292 4294967292 343 | R4 2147483650 2147483650 344 | R5 2147483647 2147483647 345 | R6 2147483651 2147483651 346 | R7 4294967295 4294967295 347 | R8 2 2 348 | R9 2147483649 2147483649 349 | R10 2147483648 2147483648 350 | R11 4294967294 4294967294 351 | R12 2147483652 2147483652 352 | R13 4294967295 4294967295 353 | R14 4 56320 354 | Flag Before After Model 355 | N 0 0 356 | Z 0 0 357 | C 1 0 1 358 | V 1 1 359 | 360 | ---------ASM---------- 361 | MVNS R14 , #-56321 362 | ---------------------------------- 363 | 364 | -------------------------------------------------------------------------------- /build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/build/icon.icns -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/build/icon.ico -------------------------------------------------------------------------------- /docs/visual-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scc416/Visual2/9ebdcd84935acd724658c506acb4073c965ad9a5/docs/visual-screen.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "visual", 3 | "productName": "VisUAL2", 4 | "main": "main.js", 5 | "description" : "F# written ARM assembler and simulator with elmish, React Monaco Editor, Electron & Fable", 6 | "author" : "Dr. Tom Clarke, 2018 3rd year HLP students at EEE ICL, Sally Chan", 7 | "version" : "1.07.0", 8 | "scripts": { 9 | "start": "cd src/Main && dotnet fable webpack -w --port free -- -w --config webpack.config.js -w --mode production", 10 | "build": "cd src/Main && dotnet fable webpack --port free -- --config webpack.config.js --mode production", 11 | "pack": "electron-builder --dir", 12 | "dist": "electron-builder", 13 | "pack-win": "electron-builder --windows", 14 | "pack-linux": "electron-builder --linux", 15 | "pack-osx": "electron-builder --macos", 16 | "pack-all": "yarn pack-osx && yarn pack-linux && yarn pack-win", 17 | "launch": "electron . -w", 18 | "launch-debug": "electron . -w --debug" 19 | }, 20 | "dependencies": { 21 | "@babel/core": "^7.0.0", 22 | "@babel/plugin-transform-runtime": "^7.0.0", 23 | "@babel/preset-react": "^7.0.0", 24 | "@babel/runtime-corejs2": "^7.0.0", 25 | "@tippy.js/react": "^2.2.0", 26 | "copyfiles": "^2.1.0", 27 | "cross-zip": "^2.1.5", 28 | "css-loader": "^2.1.1", 29 | "electron-context-menu": "^0.9.1", 30 | "electron-settings": "^3.2.0", 31 | "electron-tabs": "^0.9.1", 32 | "fable-compiler": "^2.3.10", 33 | "lodash": ">=4.17.11", 34 | "monaco-editor": "0.16.2", 35 | "monaco-editor-webpack-plugin": "^1.7.0", 36 | "node-sass": "^4.12.0", 37 | "react": "^16.8.6", 38 | "react-dom": "^16.4.2", 39 | "react-monaco-editor": "^0.25.1", 40 | "react-resize-detector": "^4.1.3", 41 | "requirejs": "^2.3.5", 42 | "sass-loader": "^7.1.0", 43 | "style-loader": "^0.23.1", 44 | "tippy.js": "^2.5.4", 45 | "vex-dialog": "^1.1.0", 46 | "vex-js": "^4.1.0" 47 | }, 48 | "devDependencies": { 49 | "@babel/core": "^7.0.0", 50 | "@babel/plugin-proposal-class-properties": "^7.4.4", 51 | "@babel/preset-env": "^7.0.0", 52 | "@babel/standalone": "^7.0.0", 53 | "@babel/template": "^7.0.0", 54 | "babel-loader": "^8.0.0", 55 | "cloc": "^2.3.3", 56 | "copy-webpack-plugin": "^4.5.1", 57 | "cross-zip-cli": "^1.0.0", 58 | "electron": "4.1.5", 59 | "electron-builder": "^20.43.0", 60 | "electron-installer-dmg": "^1.0.0", 61 | "fable-loader": "^2.1.6", 62 | "loglevel": "^1.4.1", 63 | "uglifyjs-webpack-plugin": "^1.2.5", 64 | "webpack": "^4.30.0", 65 | "webpack-cli": "^3.3.1" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/build/FAKE/[Content_Types].xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /paket.dependencies: -------------------------------------------------------------------------------- 1 | source https://nuget.org/api/v2 2 | storage:none 3 | 4 | clitool dotnet-fable 5 | nuget Fable.Core 6 | nuget Fable.Import.Browser 7 | nuget Fable.Import.Electron 8 | nuget Fable.Import.Node 9 | nuget Fable.React 10 | nuget FSharp.Core 11 | nuget Fable.Elmish 12 | nuget Fable.Elmish.React 13 | nuget Fable.Elmish.Browser 14 | nuget Fable.Elmish.Debugger 15 | nuget Fable.Elmish.HMR 16 | nuget Fable.PowerPack 17 | github fable-compiler/ts2fable-exports:dev Monaco.fs 18 | 19 | group Build 20 | source https://nuget.org/api/v2 21 | 22 | nuget FAKE -------------------------------------------------------------------------------- /setup.bat: -------------------------------------------------------------------------------- 1 | .paket\paket.exe install 2 | git submodule update --init --recursive 3 | git submodule update --recursive --remote 4 | :: .paket\paket.bootstrapper.exe 5 | :: .paket\paket.exe install 6 | :: .paket\paket.exe update 7 | dotnet nuget locals all --clear 8 | dotnet restore src\Main\Main.fsproj 9 | dotnet restore src\Renderer\Renderer.fsproj 10 | dotnet restore src\Emulator\Emulator.fsproj 11 | yarn install 12 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | paket install 2 | git submodule update --init --recursive 3 | git submodule update --recursive --remote 4 | dotnet nuget locals all --clear 5 | dotnet restore src/Main/Main.fsproj 6 | dotnet restore src/Renderer/Renderer.fsproj 7 | dotnet restore src/Emulator/Emulator.fsproj 8 | yarn install 9 | -------------------------------------------------------------------------------- /src/Emulator/Branch.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Emulator.Branch 5 | Description: Implement ARM branch instructions 6 | *) 7 | 8 | /// emulate ARM branch instructions 9 | module Branch 10 | open CommonData 11 | open CommonLex 12 | open Expressions 13 | open Errors 14 | open Helpers 15 | 16 | type Instr = 17 | | B of uint32 18 | | BL of uint32 19 | | END 20 | 21 | let branchTarget = function | B t | BL t -> [ t ] | END -> [] 22 | 23 | // Branch instructions have no suffixes 24 | let branchSpec = { 25 | InstrC = BRANCH 26 | Roots = [ "B"; "BL"; "END" ] 27 | Suffixes = [ "" ] 28 | } 29 | 30 | /// map of all possible opcodes recognised 31 | let opCodes = opCodeExpand branchSpec 32 | 33 | let parse (ls : LineData) : Parse option = 34 | let parse' (_iClass, (root, suffix, cond)) = 35 | let (WA la) = ls.LoadAddr // address this instruction is loaded into memory 36 | let target = parseEvalNumericExpression ls.SymTab ls.Operands 37 | match root, target with 38 | | "B", Ok t -> B t |> Ok 39 | | "BL", Ok t -> BL t |> Ok 40 | | "B", Error t 41 | | "BL", Error t -> Error t 42 | | "END", _ when ls.Operands = "" -> Ok END 43 | | "END", _ -> makeParseError "END (no operands)" ls.Operands "list#pseudo-instructions-and-directives" 44 | | _ -> failwithf "What? Unexpected root in Branch.parse'%s'" root 45 | |> fun ins -> 46 | copyParse ls ins cond 47 | |> (fun pa -> { pa with PStall = match root with | "B" | "BL" -> 2 | _ -> 0 }) 48 | let OPC = ls.OpCode.ToUpper() 49 | if Map.containsKey OPC opCodes // lookup opcode to see if it is known 50 | then parse' opCodes.[OPC] |> Some 51 | else None 52 | 53 | /// Parse Active Pattern used by top-level code 54 | let (|IMatch|_|) = parse 55 | 56 | 57 | /// Execute a Branch instruction 58 | let executeBranch ins cpuData = 59 | let nxt = getPC cpuData + 4u // Address of the next instruction 60 | match ins with 61 | | B addr -> 62 | cpuData 63 | |> setReg R15 addr 64 | |> Ok 65 | | BL addr -> 66 | cpuData 67 | |> setReg R15 addr 68 | |> setReg R14 nxt 69 | |> Ok 70 | | END -> 71 | EXIT |> Error 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/Emulator/CommonData.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Emulator.CommonData 5 | Description: Low-level data structures used throughout the emulator 6 | *) 7 | 8 | /// Common data types and code for emulator 9 | module CommonData 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////// 12 | // Common types and code used by all modules 13 | ////////////////////////////////////////////////////////////////////////////////////// 14 | 15 | /// ARM Status bits 16 | type Flags = { N : bool; C : bool; Z : bool; V : bool } 17 | 18 | 19 | ////////////////////////ARM register names and operations///////////////////////////// 20 | 21 | 22 | /// ARM register names 23 | /// NB R15 is the program counter as read 24 | 25 | type RName = | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 26 | | R8 | R9 | R10 | R11 | R12 | R13 | R14 | R15 27 | 28 | 29 | 30 | /// Map used to convert strings into RName values, 31 | /// includes register aliasses PC, LR, SP 32 | let regNames = 33 | Map.ofList [ 34 | "R0", R0; "R1", R1; "R2", R2; "R3", R3; "R4", R4; "R5", R5 35 | "R6", R6; "R7", R7; "R8", R8; "R9", R9; "R10", R10; "R11", R11; 36 | "R12", R12; "R13", R13; "R14", R14; "R15", R15; 37 | "PC", R15; "LR", R14; "SP", R13 38 | ] 39 | 40 | // various functions used to convert between string, RName, and register number 41 | 42 | /// Inverse of regNames, used to convert RName values to strings 43 | /// NB The string chosen will always be the register (not alias) 44 | let regStrings = 45 | regNames 46 | |> Map.toList 47 | |> List.map (fun (s, rn) -> (rn, s)) 48 | |> List.filter (fun (_, s : string) -> s.StartsWith "R") 49 | |> Map.ofList 50 | 51 | /// Map converts RName into register number (no aliasses) 52 | let regNums = Map.map (fun _ (s : string) -> int (s.[1..])) regStrings 53 | 54 | /// Map converts register number into RName (no aliasses) 55 | let inverseRegNums = 56 | regNums |> Map.toList 57 | |> List.map (fun (rn, n) -> (n, rn)) |> Map.ofList 58 | 59 | /// Property on RName to return register number, for convenience 60 | /// Aliasses not included, since they are not RNames 61 | type RName with 62 | /// Return the number of a register as an integer 63 | member r.RegNum = regNums.[r] 64 | 65 | /// Return a register name from an integer 66 | let register n = 67 | if 0 <= n && n < 16 68 | then inverseRegNums.[n] 69 | else (failwithf "Register %d does not exist!" n) 70 | 71 | /// Type to represent the contents of one memory location 72 | /// 'INS is a parameter set to the type of an instruction 73 | /// needed because instruction type is only defined 74 | /// at top level. 75 | type MemLoc<'INS> = 76 | | DataLoc of uint32 77 | | Code of 'INS 78 | 79 | /// type to represent a (word) address 80 | /// there is some ambiguity. Does this contain the real address 81 | /// which is always divisible by 4 82 | /// or does it contain the word number (real address dvided by 4) 83 | /// either way multiply/divide by 4 will cause problems! 84 | /// document this well and be consistent. 85 | type WAddr = WA of uint32 86 | 87 | /// type to represent memory 88 | type CodeMemory<'INS> = Map 89 | 90 | type Data = | Dat of uint32 | CodeSpace 91 | 92 | type DataMemory = Map 93 | 94 | /// ARM state as values of all registers and status bits 95 | /// NB PC can be found as R15 - 8. (Pipelining) 96 | type DataPath = { 97 | Fl : Flags; // Flags 98 | Regs : Map // map representing registers. 99 | // Must be correctly initialised 100 | MM : DataMemory // map showing the contents of all memory 101 | } 102 | -------------------------------------------------------------------------------- /src/Emulator/CommonLex.fs: -------------------------------------------------------------------------------- 1 |  2 | (* 3 | VisUAL2 @ Imperial College London 4 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 5 | Module: Emulator.CommonLex 6 | Description: Perform common part of parsing and define parse types 7 | *) 8 | 9 | /// functions and types for initial assembly parse 10 | module CommonLex 11 | 12 | open CommonData 13 | open Expressions 14 | open Errors 15 | 16 | /// ARM execution conditions 17 | type Condition = 18 | 19 | | Ceq 20 | | Cne 21 | | Cmi 22 | | Cpl 23 | | Chi 24 | | Chs 25 | | Clo 26 | | Cls 27 | | Cge 28 | | Cgt 29 | | Cle 30 | | Clt 31 | | Cvs 32 | | Cvc 33 | | Cnv // the "never executed" condition NV - not often used! 34 | | Cal // the "always executed condition "AL". Used by default on no condition 35 | 36 | /// classes of instructions (example, add/change this is needed) 37 | type InstrClass = | DP | MEM | MISC | BRANCH | PSEUDO 38 | 39 | /// specification of set of instructions 40 | type OpSpec = { 41 | InstrC : InstrClass 42 | Roots : string list 43 | Suffixes : string list 44 | } 45 | 46 | 47 | 48 | 49 | /// result returned from instruction-specific module parsing 50 | /// an instruction class. If symbol definitions are found in a 51 | /// symbol table then a complete parse will be output 52 | /// otherwise some fields will be None 53 | type Parse<'INS> = { 54 | /// value representing instruction. NB type varies with instruction class 55 | PInstr : Result<'INS, Errors.ParseError> 56 | /// name and value of `label defined on this line, if one is. 57 | PLabel : (string * Resolvable) option 58 | /// number of bytes in instruction memory area taken up by this instruction 59 | ISize : uint32 60 | /// number of bytes in data memory area taken up by this instruction, if it needs this 61 | DSize : uint32 option 62 | /// execution condition for instruction 63 | PCond : Condition 64 | /// opcode: same as LineData.OpCode 65 | POpCode : string 66 | /// Number of cycles extra if instruction is executed 67 | PStall : int 68 | } 69 | 70 | /// data given to instruction-specific parse function 71 | type LineData = { 72 | /// memory address this instruction is loaded. Must be word address 73 | LoadAddr : WAddr 74 | /// name of label defined on this line, if one exists 75 | Label : string option 76 | /// table of symbols with defined values: see SymbolTable type for info 77 | SymTab : SymbolTable 78 | /// opcode string: this is the whole opcode including suffix and condition if present 79 | OpCode : string 80 | /// string of all the operands 81 | Operands : string 82 | } 83 | 84 | let copyParse ld ins cond = 85 | let la = match ld.LoadAddr with | WA la -> la 86 | { 87 | PInstr = ins 88 | PLabel = ld.Label |> Option.map (fun lab -> (lab, la |> Ok)) 89 | ISize = 4u 90 | DSize = Some 0u 91 | PCond = cond 92 | POpCode = ld.OpCode 93 | PStall = 0 94 | } 95 | 96 | let copyDefault (ld : LineData) cond = 97 | copyParse ld (``Unimplemented parse`` |> Error) cond 98 | 99 | 100 | 101 | /// Strings with corresponding execution condition 102 | /// Note some conditions have multiple strings 103 | /// Note "" is a valid condition string (always execute condition) 104 | let condMap = [ "EQ", Ceq; "NE", Cne; "MI", Cmi; "PL", Cpl; "HI", Chi; 105 | "HS", Chs; "LO", Clo; "LS", Cls; "GE", Cge; "GT", Cgt; 106 | "LE", Cle; "LT", Clt; "VS", Cvs; "VC", Cvc; "CC", Clo; "CS", Chs 107 | "NV", Cnv; "AL", Cal; "", Cal ] |> Map.ofList 108 | 109 | /// list of all strings representing execution conditions 110 | /// includes "" 111 | let condStrings = 112 | condMap 113 | |> Map.toList 114 | |> List.map fst 115 | |> List.distinct 116 | 117 | /// generate all possible opcode strings for given specification 118 | /// each string is paired with info about instruction 119 | /// and the three parts of the opcode 120 | let opCodeExpand (spec : OpSpec) 121 | : // opcode class root suffix instr cond 122 | Map = 123 | spec.Roots 124 | |> List.collect (fun r -> 125 | spec.Suffixes 126 | |> List.collect (fun s -> 127 | condStrings 128 | |> List.map (fun c -> r + s + c, (spec.InstrC, (r, s, condMap.[c]))))) 129 | |> Map.ofList 130 | 131 | 132 | let stripCondition (opc : string) = 133 | let n = opc.Length 134 | if n > 2 then 135 | match List.tryFind ((=) opc.[n - 2..n - 1]) condStrings with 136 | | None -> opc, None 137 | | Some cond -> opc.[0..n - 2], Some opc.[n - 2..n - 1] 138 | else opc, None 139 | -------------------------------------------------------------------------------- /src/Emulator/Emulator.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Emulator/Errors.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Emulator.Errors 5 | Description: Handle Errors 6 | *) 7 | 8 | 9 | // WARNING - this code is out of date and needs TLC when errors are properly defined 10 | 11 | /// Error handling for parse and simulator 12 | module Errors 13 | 14 | open CommonData 15 | 16 | 17 | /// Failure message for impossible match cases 18 | let alwaysMatchesFM = "Should never happen! Match statement always matches." 19 | 20 | let noErrorsFM = "Should never happen! No errors at this stage." 21 | 22 | // ************************************************************************* 23 | // Error messages for instruction parsing 24 | // ************************************************************************* 25 | 26 | /// Error message for `Invalid register` 27 | let notValidRegEM = " is not a valid register." 28 | 29 | /// Error message for `Invalid offset` 30 | let notValidOffsetEM = " is not a valid offset." 31 | 32 | /// Error message for `Invalid instruction` 33 | let notValidFormatEM = " is not a valid instruction format." 34 | 35 | /// Error message for `Invalid literal` 36 | let notValidLiteralEM = " is not a valid literal." 37 | 38 | /// Error message for `Invalid shift` or `Invalid second operand` 39 | let notValidRegLitEM = " is not a valid literal or register." 40 | 41 | /// Error message for `Invalid flexible second operand` 42 | let notValidFlexOp2EM = " is an invalid flexible second operand" 43 | 44 | /// Error message for `Invalid suffix` 45 | let notValidSuffixEM = " is not a valid suffix for this instruction." 46 | 47 | let notImplementedInsEM = " is not a recognised instruction." 48 | // ************************************************************************* 49 | // Error messages for instruction execution 50 | // ************************************************************************* 51 | 52 | type ErrCode = 53 | | ``Invalid syntax`` of wanted : string * found : string * page : string 54 | | ``Invalid format`` of error : string * found : string * page : string 55 | | ``Invalid instruction`` of reason : string 56 | | ``Invalid Label`` of label: string 57 | | ``Label required`` of reason : string 58 | | ``Unimplemented parse`` 59 | | ``Undefined symbol`` of symList : (string * string) list 60 | | ``Invalid opCode`` of root : string option * condition : string option * suffix : string 61 | | ``Unimplemented instruction`` of opCode : string 62 | | ``Duplicate symbol`` of sym : string * lines : int list 63 | | ``Literal more than 32 bits`` of literal : string 64 | | ``Literal is not a valid number`` of literal : string 65 | 66 | type ParseError = ErrCode 67 | 68 | /// The thing that stopped the simulation: EXIT means a normal program END. 69 | type ExecuteError = 70 | | NotInstrMem of uint32 // Trying to fetch from address where there is no instruction 71 | | ``Run time error`` of uint32 * string // a memory access error at given address (with error message) 72 | | ``Unknown symbol runtime error`` of string list // this should never happen, since symbols are resolved by parse 73 | | EXIT 74 | | TBEXIT 75 | 76 | let makeParseError wanted found page = ``Invalid syntax`` (wanted = wanted, found = found, page = page) |> Error 77 | 78 | let makeFormatError wanted found page = ``Invalid format`` (error = wanted, found = found, page = page) |> Error 79 | 80 | let makeInstructionError str = ``Invalid instruction`` str |> Error 81 | 82 | /// A function to combine results or forward errors. 83 | let combineError (res1 : Result<'T1, 'E>) (res2 : Result<'T2, 'E>) : Result<'T1 * 'T2, 'E> = 84 | match res1, res2 with 85 | | Error e1, _ -> Error e1 86 | | _, Error e2 -> Error e2 87 | | Ok rt1, Ok rt2 -> Ok(rt1, rt2) 88 | 89 | /// A function that combines two results by applying a function on them as a pair, or forwards errors. 90 | let combineErrorMapResult (res1 : Result<'T1, 'E>) (res2 : Result<'T2, 'E>) (mapf : 'T1 -> 'T2 -> 'T3) : Result<'T3, 'E> = 91 | combineError res1 res2 92 | |> Result.map (fun (r1, r2) -> mapf r1 r2) 93 | 94 | /// A function that applies a possibly erroneous function to a possibly erroneous argument, or forwards errors. 95 | let applyResultMapError (res : Result<'T1 -> 'T2, 'E>) (arg : Result<'T1, 'E>) = 96 | match arg, res with 97 | | Ok arg', Ok res' -> res' arg' |> Ok 98 | | _, Error e -> e |> Error 99 | | Error e, _ -> e |> Error 100 | 101 | let mapErrorApplyResult (arg : Result<'T1, 'E>) (res : Result<'T1 -> 'T2, 'E>) = 102 | match arg, res with 103 | | Ok arg', Ok res' -> res' arg' |> Ok 104 | | _, Error e -> e |> Error 105 | | Error e, _ -> e |> Error 106 | 107 | let condenseResultList transform (lst : Result<'a, 'b> list) : Result<'a list, 'b> = 108 | let rec condenser' inlst outlst = 109 | match inlst with 110 | | head :: tail -> 111 | match head with 112 | | Ok res -> condenser' tail ((transform res) :: outlst) 113 | | Error e -> e |> Error 114 | | [] -> List.rev outlst |> Ok 115 | condenser' lst [] 116 | -------------------------------------------------------------------------------- /src/Emulator/Expressions.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Emulator.Expressions 5 | Description: Parse expressions with constants, symbols, and arithmetic 6 | *) 7 | 8 | 9 | /// Assembler code expressions (symbols, operators, and constants) 10 | module Expressions 11 | open System.Text.RegularExpressions 12 | open Errors 13 | open EEExtensions 14 | 15 | 16 | /// Match the start of txt with pat 17 | /// Return a tuple of the matched text and the rest 18 | let (|RegexPrefix|_|) pat txt = 19 | // Match from start, ignore whitespace 20 | let m = Regex.Match(txt, "^[\\s]*" + pat + "[\\s]*") 21 | match m.Success with 22 | | true -> (m.Value, txt.Substring(m.Value.Length)) |> Some 23 | | false -> None 24 | 25 | 26 | /// Remove all whitespace from a matched string 27 | let removeWs txt = Regex.Replace(txt, "[\\s]*", "") 28 | 29 | /// Active pattern for matching labels 30 | /// Also removes any whitespace from around the label 31 | let (|LabelExpr|_|) txt = 32 | match txt with 33 | | RegexPrefix "[a-zA-Z][a-zA-Z0-9_]+" (var, rst) -> 34 | (// Remove whitespace from the label 35 | removeWs var, rst) |> Some 36 | | _ -> None 37 | 38 | 39 | 40 | type SymbolTable = Map 41 | 42 | // [] 43 | type Expression = 44 | | BinOp of (uint32 -> uint32 -> uint32) * Expression * Expression 45 | | Label of string 46 | | Literal of uint32 47 | // override _x.Equals (_y) = false 48 | 49 | type Resolvable = Result 50 | 51 | 52 | /// Evaluate exp against the symbol table syms 53 | /// Returns a list of all errors or the result 54 | let rec eval (syms : Map) exp : Result = 55 | let joinErrors a b = 56 | match a, b with 57 | | ``Undefined symbol`` a', ``Undefined symbol`` b' -> 58 | ``Undefined symbol`` (a' @ b') |> Error 59 | | ``Undefined symbol`` _, a' 60 | | a', _ -> a' |> Error 61 | let doBinary op x y = 62 | match (eval syms x), (eval syms y) with 63 | | Ok resX, Ok resY -> ((op resX resY) >>> 0) |> Ok 64 | | Error a, Error b -> joinErrors a b 65 | | Error a, _ -> a |> Error 66 | | _, Error b -> b |> Error 67 | let getSymError x = 68 | let x' = String.toUpper x 69 | let symLst = syms |> Map.toList |> List.map fst 70 | match List.tryFind (fun sym -> x' = String.toUpper sym) symLst with 71 | | Some sym -> x, sprintf "'%s' which has different case from label '%s'" x sym 72 | | None -> x, sprintf "'%s' which is not defined as a label" x 73 | match exp with 74 | | BinOp(op, x, y) -> doBinary op x y 75 | | Literal x -> x |> Ok 76 | | Label x -> 77 | match (Map.containsKey x syms) with 78 | | true -> syms.[x] |> Ok 79 | | false -> 80 | ``Undefined symbol`` [ getSymError x ] |> Error 81 | 82 | 83 | let to32BitLiteral chars = 84 | try 85 | chars 86 | |> int64 87 | |> function 88 | | n when n > (1L <<< 32) || n < (-1L <<< 31) -> Error(``Literal more than 32 bits`` chars) 89 | | n -> Ok(uint32 n) 90 | with 91 | | e -> Error(``Literal is not a valid number`` chars) 92 | 93 | 94 | 95 | 96 | /// Active pattern for matching expressions 97 | /// Returns an Expression AST 98 | let rec (|Expr|_|) expTxt = 99 | 100 | let (|Minus|_|) (txt : string) = 101 | match txt.Length > 0 && txt.[0] = '-' with 102 | | true -> Some txt.[1..] 103 | | false -> None 104 | 105 | let (|PosLiteralExpr|_|) txt = 106 | match txt with 107 | | RegexPrefix "0[xX][0-9a-fA-F][0-9a-fA-F_]*" (num, rst) 108 | | RegexPrefix "0[bB][0-1][0-1_]*" (num, rst) 109 | | RegexPrefix "[0-9][0-9_]*" (num, rst) -> 110 | try 111 | let litNum = 112 | num 113 | |> String.replace "_" "" 114 | |> String.toLower 115 | |> int64 116 | |> function // check that literal constants are within 32 bit range under FABLE 117 | | n when n > ((1L <<< 32) - 1L) -> 118 | failwithf "Literal more than 32 bits" 119 | | n -> uint32 n 120 | |> Literal 121 | (litNum, rst) |> Some 122 | with 123 | | _ -> 124 | printfn "Exception in Expr: uint32(%A)" num 125 | None 126 | | RegexPrefix "&[0-9a-fA-F]+" (num, rst) -> 127 | ("0x" + (removeWs num).[1..] |> uint32 |> Literal, rst) |> Some 128 | | _ -> None 129 | 130 | let (|LiteralExpr|_|) (expTxt : string) = 131 | match expTxt with 132 | | PosLiteralExpr(num, txt) -> Some(num, txt) 133 | | Minus(PosLiteralExpr(num, txt)) -> Some(BinOp((-), Literal 0u, num), txt) 134 | | _ -> None 135 | 136 | /// Active pattern matching either labels, literals 137 | /// or a bracketed expression (recursively defined) 138 | let (|PrimExpr|_|) txt = 139 | match txt with 140 | | LabelExpr(lab, rst) -> (Label lab, rst) |> Some 141 | | LiteralExpr x -> Some x 142 | | RegexPrefix "\(" (_, Expr(exp, RegexPrefix "\)" (_, rst))) -> (exp, rst) |> Some 143 | | _ -> None 144 | 145 | /// Higher order active patterns to match lists of the form 146 | /// x op x op x ... to capture left associativity correctly. 147 | let rec (|LBinExprList|_|) (|NextExpr|_|) reg op lVal txt = 148 | match txt with 149 | | RegexPrefix reg (_, NextExpr(rVal, rst)) -> 150 | match rst with 151 | | LBinExprList (|NextExpr|_|) reg op (BinOp(op, lVal, rVal)) (exp, rst') 152 | -> Some(exp, rst') 153 | | _ -> Some(BinOp(op, lVal, rVal), rst) 154 | | _ -> None 155 | 156 | /// Higher order active pattern for defining binary operators 157 | /// NextExpr is the active pattern of the operator with the next 158 | /// highest precedence. reg is the regex which matches this operator 159 | /// op is the operation it performs 160 | let (|LBinExpr|_|) (|NextExpr|_|) reg op txt = 161 | match txt with 162 | | NextExpr(lVal, rhs) -> 163 | match rhs with 164 | | LBinExprList (|NextExpr|_|) reg op lVal x 165 | -> Some x 166 | // Can't nest this AP because its the 167 | // "pass-through" to the next operator 168 | | _ -> (lVal, rhs) |> Some 169 | | _ -> None 170 | 171 | // Define active patterns for the binary operators 172 | // Order of precedence: Add, Sub, Mul 173 | let (|MulExpr|_|) = (|LBinExpr|_|) (|PrimExpr|_|) "\*" (*) 174 | let (|SubExpr|_|) = (|LBinExpr|_|) (|MulExpr|_|) "\-" (-) 175 | let (|AddExpr|_|) = (|LBinExpr|_|) (|SubExpr|_|) "\+" (+) 176 | 177 | match expTxt with 178 | | AddExpr x -> Some x 179 | | _ -> None 180 | 181 | 182 | let printUintRes r = 183 | match r with 184 | | Ok u -> printfn "OK %d" u; r 185 | | Error(code, eTxt, eMess) -> printfn "Error:<%s><%s>" eTxt eMess; r 186 | 187 | let parseEvalNumericExpression syms op = 188 | match removeWs op with 189 | | Expr(ast, _) -> eval syms ast 190 | | _ when String.contains "#" op -> makeParseError "Numeric expression (without #)" op "" 191 | | _ -> makeParseError "Numeric expression" op "" 192 | 193 | let parse syms op = 194 | match removeWs op with 195 | | Expr(ast, txt) -> Result.map (fun e -> e, txt) (eval syms ast) 196 | | _ when String.contains "#" op -> makeParseError "Numeric expression (without #)" op "" 197 | | _ -> makeParseError "Numeric expression" op "" 198 | 199 | 200 | type PartsOfASM = | ALabel | AOpCode | AOperand of int 201 | 202 | /// Code to implement accurate error reporting 203 | /// Malformed lines will be best effort parsed into parts 204 | /// Each part will be returned with its position in the original line 205 | let getASMPart symTab isOpCode (part : PartsOfASM) (line : string) = 206 | let isSymbol s = Map.containsKey s symTab 207 | let pack (thing : string) (restOfLine : string) = 208 | let n = line.Length 209 | let r = restOfLine.Length 210 | let ePos = n - r + 1 211 | let sPos = ePos - thing.Length 212 | thing, sPos, ePos 213 | match part, line with 214 | | ALabel, LabelExpr(lab, rst) when isOpCode lab |> not -> pack lab rst 215 | | _ -> failwithf "Not implemented" 216 | 217 | -------------------------------------------------------------------------------- /src/Emulator/Misc.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Emulator.Misc 5 | Description: Implement ARM miscellaneous instructions 6 | *) 7 | 8 | /// emulate DCD, DCB, FILL, EQU, ADR instructions 9 | module Misc 10 | open EEExtensions 11 | open CommonData 12 | open CommonLex 13 | open Expressions 14 | open Helpers 15 | open Errors 16 | open DP 17 | 18 | 19 | type FILLInstr = { NumBytes : uint32; FillValue : uint32 } 20 | 21 | type ADRInstr = { AReg : RName; AVal : uint32 } 22 | 23 | type Instr = 24 | | DCD of uint32 list 25 | | DCB of uint32 list 26 | | FILL of FILLInstr 27 | | EQU of uint32 28 | | ADR of ADRInstr 29 | 30 | let miscRoots = [ "DCD"; "DCB"; "FILL"; "EQU"; "ADR" ] 31 | 32 | 33 | /// Errors which can occur during parsing 34 | // type ErrInstr = 35 | // | InvalidExp of string 36 | // | InvalidExpList of string 37 | // | InvalidFill of string 38 | // | LabelRequired 39 | /// Error types for parsing. 40 | 41 | let commaSplit (x : string) = 42 | x.Split([| ',' |]) 43 | |> Array.toList 44 | |> List.map String.trim 45 | 46 | let mergeResults (lst : Result<'T, 'E> list) = 47 | let folder (st : Result<'T list, 'E>) (r : Result<'T, 'E>) = 48 | match st with 49 | | Error st -> Error st 50 | | Ok st -> Result.map (fun r -> r :: st) r 51 | List.fold folder (Ok []) lst 52 | |> Result.map List.rev 53 | 54 | 55 | let parseNumExpr ls s = 56 | Ok((), s) 57 | |> ResExpr(fun _ e -> e) 58 | |> ResCheckDone 59 | |> Result.bind (fun exp -> 60 | eval ls.SymTab exp) 61 | 62 | let parseExprList symTab lst = 63 | List.map (parseNumExpr symTab) lst 64 | |> mergeResults 65 | 66 | 67 | 68 | let parse (ls : LineData) : Parse = 69 | let (WA la) = ls.LoadAddr // address this instruction is loaded into memory 70 | let opLst = commaSplit ls.Operands 71 | let resolvedOpLst = parseExprList ls opLst 72 | let (|PARSE|_|) op = parseNumExpr ls op |> Some 73 | let (|RESOLVEALL|_|) lst = match parseExprList ls lst with | Ok ops -> Some ops | _ -> None 74 | let opCode = ls.OpCode 75 | let offsetError wb b1 b2 ofs = 76 | let msg = sprintf "Valid %s offset in range %d..%d. Use 'LDR Rx, =SYMBOL' when offset is larger than this" wb b1 b2 77 | makeParseError msg (sprintf "Offset of %d" ofs) "" 78 | let checkAddrOffset (ofs : int) = 79 | match ofs - 8 with 80 | | x when x % 4 <> 0 && (x > 264 || x < -248) -> offsetError "byte" -248 264 (ofs - 8) 81 | | x when (x > 1032 || x < -1016) -> offsetError "word" -1016 1032 (ofs - 8) 82 | | x -> Ok() 83 | 84 | let labelBinder f = 85 | match ls.Label with 86 | | Some lab -> f lab 87 | | None -> ``Label required`` ("'" + ls.Operands + "' requires a label.") 88 | 89 | 90 | let makeDataInstr dataInstrCode = Result.map dataInstrCode resolvedOpLst 91 | 92 | let makeDataDirective dSizeOpt dataInstr = 93 | { copyDefault ls Cal with 94 | PInstr = dataInstr 95 | ISize = 0u 96 | DSize = dSizeOpt 97 | } 98 | 99 | 100 | 101 | let opNum = List.length opLst |> uint32 102 | 103 | let makeFILL ops = 104 | match resolvedOpLst with 105 | | Ok [ nBytes ] when nBytes % 4u = 0u -> 106 | makeDataDirective (Some nBytes) (FILL { NumBytes = nBytes; FillValue = 0u } |> Ok) 107 | | Ok [ nBytes; fillVal ] when nBytes % 4u = 0u -> 108 | makeDataDirective (Some nBytes) (FILL { NumBytes = nBytes; FillValue = fillVal } |> Ok) 109 | | Ok [ nBytes ] 110 | | Ok [ nBytes; _ ] -> 111 | let msg = sprintf "%d FILL bytes is invalid. Fill must have a number of bytes divisible by 4" nBytes 112 | makeDataDirective (Some 0u) (makeInstructionError msg) 113 | 114 | | _ -> makeDataDirective (Some 0u) <| 115 | makeInstructionError ("Invalid operands '" + ls.Operands + "'. Fill must have 1 or 2 operands") 116 | 117 | let makeEQU (op : Resolvable) = 118 | match op with 119 | | Ok addr -> makeDataDirective (Some 0u) (EQU addr |> Ok) 120 | | Error e -> makeDataDirective (Some 0u) (Error e) 121 | |> fun pa -> { pa with PLabel = Option.map (fun lab -> lab, op) ls.Label } 122 | 123 | let pa = copyDefault ls Cal 124 | match opCode.ToUpper(), opLst with 125 | | "DCD", RESOLVEALL ops -> makeDataDirective (Some(opNum * 4u)) (makeDataInstr DCD) 126 | | "DCB", RESOLVEALL ops when ops.Length % 4 = 0 -> makeDataDirective (Some opNum) (makeDataInstr DCB) 127 | | "DCB", _ -> 128 | let msg = "Invalid operands: '" + ls.Operands + "'. DCB must have a number of parameters divisible by 4" 129 | makeInstructionError msg 130 | |> makeDataDirective (Some 0u) 131 | | "FILL", RESOLVEALL [ op ] -> makeFILL [ op, 0u ] 132 | | "FILL", _ -> makeDataDirective None <| makeInstructionError ("Invalid operands for FILL: unresolved symbols") 133 | | "ADR", RegMatch(Ok rn) :: [ PARSE(Ok addr) ] -> 134 | match checkAddrOffset (int addr - int la) with 135 | | Ok _ -> { pa with PInstr = ADR { AReg = rn; AVal = addr } |> Ok; PStall = (if rn = R15 then 2 else 0) } 136 | | Error e -> { pa with PInstr = Error e } 137 | | "ADR", _ops -> 138 | let msg = "Invalid operands: '" + ls.Operands + 139 | "'. ADR must have a register followed by a numeric expression operand." 140 | { pa with PInstr = makeInstructionError msg } 141 | | "EQU", [ PARSE op ] when opLst <> [] -> makeEQU op 142 | | "EQU", x -> { pa with PInstr = makeInstructionError (sprintf "'%A' is an invalid expression for EQU" x) } 143 | | _, ops -> makeInstructionError ("Invalid instruction: '" + ls.OpCode + " " + ls.Operands + "'") 144 | |> makeDataDirective (Some 0u) 145 | | _ -> failwithf "What? unrecognised Misc opcode %s" opCode 146 | 147 | 148 | 149 | /// Parse Active Pattern used by top-level code 150 | let (|IMatch|_|) (ls : LineData) = 151 | if List.contains ls.OpCode miscRoots 152 | then 153 | //printfn "IMISC Parsing '%s'" ls.OpCode 154 | parse ls |> Some 155 | else 156 | //printfn "IMISC Not parsing '%s'" ls.OpCode 157 | None 158 | 159 | -------------------------------------------------------------------------------- /src/Emulator/ParseTop.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Emulator.ParseTop 5 | Description: Top-level code to parse instructions 6 | *) 7 | 8 | /// Top-level code implementing assembler parsing 9 | module ParseTop 10 | open CommonLex 11 | open CommonData 12 | 13 | open Errors 14 | open Expressions 15 | 16 | /// allows different modules to return different instruction types 17 | type Instr = 18 | | IMEM of Memory.Instr 19 | | IDP of DP.Instr 20 | | IMISC of Misc.Instr 21 | | IBRANCH of Branch.Instr 22 | | EMPTY 23 | 24 | 25 | 26 | let Blank lab = { 27 | PCond = Cal 28 | PInstr = Ok EMPTY 29 | PLabel = lab 30 | ISize = 0u 31 | DSize = Some 0u 32 | POpCode = "" 33 | PStall = 0 34 | } 35 | 36 | /// Split line on whitespace into an list 37 | let splitIntoWords (line : string) = 38 | line.Split(([| ' '; '\t'; '\f'; '\r'; '\n'; '\b' |] : char array), 39 | System.StringSplitOptions.RemoveEmptyEntries) 40 | |> Array.collect (function | "" -> [||] | s -> [| s |]) 41 | |> Array.map (fun s -> s.Trim()) 42 | |> Array.toList 43 | 44 | /// Note that Instr in Mem and DP modules is NOT same as Instr in this module 45 | /// Instr here is all possible isntruction values combines with a D.U. 46 | /// that tags the Instruction class 47 | /// Similarly ErrParse 48 | /// Similarly IMatch here is combination of module IMatches 49 | let IMatch(ld : LineData) : Parse option = 50 | let copy cons pa = 51 | { // NB need this copy by fields because types do not match 52 | 53 | PCond = pa.PCond 54 | PInstr = Result.map cons pa.PInstr 55 | PLabel = pa.PLabel 56 | POpCode = pa.POpCode 57 | ISize = pa.ISize 58 | DSize = pa.DSize 59 | PStall = pa.PStall 60 | } |> Some 61 | 62 | 63 | match ld with 64 | | Memory.IMatch pa -> copy IMEM pa 65 | | DP.IMatch pa -> copy IDP pa 66 | | Misc.IMatch pa -> copy IMISC pa 67 | | Branch.IMatch pa -> copy IBRANCH pa 68 | | _ -> None 69 | 70 | 71 | 72 | type CondInstr = { 73 | Cond : Condition 74 | InsExec : Instr 75 | InsOpCode : string 76 | Cycles : int64 77 | } 78 | 79 | let makeParse labOpt la ins = 80 | { 81 | PInstr = ins 82 | PLabel = labOpt |> Option.map (fun lab -> lab, la) 83 | ISize = 0u 84 | DSize = Some 0u 85 | PCond = Cal 86 | POpCode = "" 87 | PStall = 0 88 | } 89 | 90 | 91 | 92 | 93 | let parseLine (symtab : SymbolTable) (loadI : uint32, loadD : uint32) (asmLine : string) = 94 | let isDataOp (op : string) = List.contains (op.ToUpper()) [ "DCD"; "DCB"; "FILL" ] 95 | 96 | let isLabel (str : string) = 97 | let isIdentifierChar ch = System.Char.IsLetterOrDigit ch || ch = '_' 98 | str.Length > 1 && System.Char.IsLetter str.[0] && Seq.forall isIdentifierChar str 99 | 100 | /// put parameters into a LineData record and parse 101 | let (|TRYPARSE|_|) (words : string list) = 102 | match words with 103 | | label :: opcode :: operands when label = "" || isLabel label -> 104 | { 105 | OpCode = opcode.ToUpper() 106 | Operands = (String.concat " " operands).Trim() 107 | Label = match label with | "" -> None | _ -> Some label 108 | LoadAddr = (if isDataOp opcode then loadD else loadI) |> WA 109 | SymTab = symtab 110 | } |> IMatch 111 | | _ -> None 112 | 113 | /// remove comments from string 114 | let removeComment (txt : string) = 115 | txt.Split ';' 116 | |> function 117 | | [| x |] -> x 118 | | [||] -> "" 119 | | lineWithComment -> lineWithComment.[0] 120 | /// try to parse 1st word, or 2nd word, as opcode 121 | /// If 2nd word is opcode 1st word must be label 122 | let parseLine' words = 123 | let defParse lab = makeParse lab (Ok loadI) 124 | match [ "" ] @ words @ [ "" ] with 125 | | "" :: TRYPARSE pa -> pa 126 | | TRYPARSE pa -> pa 127 | | [ ""; label; "" ] -> 128 | if isLabel label 129 | then defParse (Some label) (EMPTY |> Ok) 130 | else defParse None (``Invalid Label`` label |> Error) 131 | | [ ""; "" ] -> defParse None (EMPTY |> Ok) 132 | | "" :: opc :: _ -> 133 | defParse None (``Unimplemented instruction`` opc |> Error) 134 | | _ -> failwithf "What: should not be possible!" 135 | asmLine 136 | |> removeComment 137 | |> splitIntoWords 138 | |> parseLine' 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /src/Emulator/paket.references: -------------------------------------------------------------------------------- 1 | dotnet-fable 2 | Fable.Core 3 | Fable.Import.Browser 4 | Fable.React -------------------------------------------------------------------------------- /src/Main/Main.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Main.Main 5 | Description: Electron Main Process 6 | *) 7 | 8 | /// This single module is compiled to JS to make the electron main process that runs node directly on teh host PC and starts up the app. 9 | /// This process is also used for any native resource access (files etc) via electron IPC calls 10 | module Main 11 | 12 | 13 | 14 | open Fable.Core 15 | open Fable.Core.JsInterop 16 | open Fable.Import 17 | open Fable.Import.Electron 18 | open Node.Exports 19 | open System.Diagnostics 20 | 21 | let printHelpMessage() = 22 | printfn """ 23 | Visual2 command line options 24 | ---------------------------- 25 | -h, --help - print this help message 26 | -d, --debug - run with browser dev tools initially open, for startup debug info logged to console 27 | - to open or close dev tools after startup 28 | """ 29 | 30 | let args = 31 | Fable.Import.Node.Globals.``process``.argv 32 | |> Seq.toList 33 | |> List.map (fun s -> s.ToLower()) 34 | /// returns true if any of flags are present as command line argument 35 | let argFlagIsOn (flags:string list) = 36 | let fl = List.map (fun (s:string) -> s.ToLower()) flags 37 | List.exists (fun flag -> List.contains flag args) fl 38 | 39 | /// returns true if fl is recognised as valid? 40 | let isValidFlag fl = 41 | List.contains fl ["-h";"--help";"-d";"--debug";"-w";".";] 42 | 43 | /// returns true if we need to disable startup and print help message 44 | let hasHelpArgs() = 45 | argFlagIsOn ["--help";"-h"] || List.exists (fun arg -> not (isValidFlag arg)) (List.tail args) 46 | 47 | if hasHelpArgs() && not (argFlagIsOn ["--help";"-h"]) then 48 | printfn "Bad arguments: %A" args 49 | 50 | /// returns true if we need to add debugging info and printout 51 | let hasDebugArgs() = argFlagIsOn ["--debug";"-d"] 52 | 53 | // Keep a global reference of the window object, if you don't, the window will 54 | // be closed automatically when the JavaScript object is garbage collected. 55 | let mutable mainWindow: BrowserWindow option = Option.None 56 | 57 | /// ensure that if app is started again the first instance is focussed and the second quits 58 | //let shouldQuit = electron.app.makeSingleInstance( fun _ _ -> 59 | //// Someone tried to run a second instance, we should focus our window. 60 | //match mainWindow with 61 | //| Some win -> 62 | // if (win.isMinimized()) then 63 | // win.restore(); 64 | // win.focus(); 65 | //| Core.Option.None -> ()) 66 | 67 | //if (shouldQuit) then 68 | //electron.app.quit() 69 | 70 | 71 | // Used for right-click context menu 72 | [] 73 | let contextMenu () = jsNative 74 | 75 | let settings:obj = importDefault "electron-settings" 76 | 77 | let dTrace fmt s = if hasDebugArgs() then printfn fmt s 78 | 79 | dTrace "settings=%A" (settings?get "editor-theme") 80 | 81 | let enableHotReload (window:BrowserWindow) = 82 | printfn "Enabling development hot reload..." 83 | fs.watch(path.join(Node.Globals.__dirname, "/main.js"), fun _ _ -> 84 | window.webContents.reloadIgnoringCache() 85 | ) |> ignore 86 | fs.watch(path.join(Node.Globals.__dirname, "/app/js"), fun _ _ -> 87 | window.webContents.reloadIgnoringCache() 88 | ) |> ignore 89 | fs.watch(path.join(Node.Globals.__dirname, "/app/css"), fun _ _ -> 90 | window.webContents.reloadIgnoringCache() 91 | ) |> ignore 92 | fs.watch(path.join(Node.Globals.__dirname, "/app/index.html"), fun _ _ -> 93 | window.webContents.reloadIgnoringCache() 94 | ) |> ignore 95 | 96 | 97 | /// create main renderer window of app 98 | let createMainWindow () = 99 | if hasHelpArgs() then printHelpMessage() 100 | else 101 | if hasDebugArgs() then printfn "Starting to create app window..." 102 | let options = createEmpty 103 | // Complete list of window options 104 | // https://electronjs.org/docs/api/browser-window#new-browserwindowoptions 105 | options.width <- Some 1200. 106 | options.height <- Some 800. 107 | options.show <- Some false 108 | let prefs = createEmpty 109 | prefs.devTools <- Some (argFlagIsOn ["-w"; "-d"; "--debug"]) 110 | options.webPreferences <- Some prefs 111 | 112 | options.frame <- Some true 113 | options.hasShadow <- Some true 114 | options.backgroundColor <- Some "#5F9EA0" 115 | options.icon <- Some (U2.Case2 "app/visual.ico") 116 | 117 | let window = electron.BrowserWindow.Create(options) 118 | if hasDebugArgs() then window.webContents.openDevTools(); 119 | // Load the index.html of the app. 120 | let opts = createEmpty> 121 | opts.pathname <- Some <| path.join(Node.Globals.__dirname, "/app/index.html") 122 | opts.protocol <- Some "file:" 123 | dTrace "Loading HTML: %A" opts.pathname 124 | window.loadURL(url.format(opts)) 125 | dTrace "%s" "load complete" 126 | let mutable closeAfterSave = false 127 | window.on("close", 128 | unbox (fun e -> 129 | if not closeAfterSave then 130 | dTrace "%s" "Close event received!" 131 | e?preventDefault () |> ignore 132 | window.webContents.send "closingWindow" 133 | )) |> ignore 134 | // Emitted when the window is closed. 135 | window.on("closed", unbox(fun () -> 136 | // Dereference the window object, usually you would store windows 137 | // in an array if your app supports multi windows, this is the time 138 | // when you should delete the corresponding element. 139 | mainWindow <- Option.None 140 | )) |> ignore 141 | 142 | window.on("resize", 143 | unbox ( fun _ -> 144 | window.webContents.send "resizeWindow")) |> ignore 145 | 146 | window.webContents.on("new-window", (fun e x -> 147 | printfn "Opening new window! %A %A" e x 148 | e?preventDefault(); 149 | electron.shell.openExternal x |> ignore 150 | )) |> ignore 151 | 152 | electron.ipcMain?on ("doClose", unbox (fun () -> 153 | closeAfterSave <- true 154 | dTrace "%s" "Closing window NOW!" 155 | window?close() 156 | )) |> ignore 157 | 158 | 159 | // Maximize the window 160 | //window.maximize() 161 | 162 | // Clear the menuBar, this is overwritten by the renderer process 163 | //let template = ResizeArray [ 164 | // createEmpty 165 | // ] 166 | //electron.Menu.setApplicationMenu(electron.Menu.buildFromTemplate(template)) 167 | 168 | window.on("ready-to-show", (fun () -> 169 | window.show() 170 | options.backgroundColor <- Some "#F0F0F0" 171 | window.focus() 172 | dTrace "%s" "Window on!" 173 | if argFlagIsOn ["-w"] then enableHotReload window) 174 | ) |> ignore 175 | 176 | mainWindow <- Some window 177 | 178 | // This method will be called when Electron has finished 179 | // initialization and is ready to create browser windows. 180 | electron.app.on("ready", unbox createMainWindow) |> ignore 181 | 182 | // Quit when all windows are closed. 183 | electron.app.on("window-all-closed", unbox(fun () -> 184 | // On OS X it is common for applications and their menu bar 185 | // to stay active until the user quits explicitly with Cmd + Q 186 | // if Node.Globals.``process``.platform <> Node.Base.NodeJS.Darwin then 187 | electron.app.quit() 188 | )) |> ignore 189 | 190 | electron.app.on("activate", unbox(fun () -> 191 | // On OS X it's common to re-create a window in the app when the 192 | // dock icon is clicked and there are no other windows open. 193 | if mainWindow.IsNone then 194 | createMainWindow() 195 | )) |> ignore 196 | -------------------------------------------------------------------------------- /src/Main/Main.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Main/paket.references: -------------------------------------------------------------------------------- 1 | dotnet-fable 2 | Fable.Core 3 | Fable.Import.Browser 4 | Fable.Import.Electron 5 | Fable.Import.Node -------------------------------------------------------------------------------- /src/Renderer/ErrorDocs.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Renderer.ErrorDocs 5 | Description: create markdown for assembler hover message hints 6 | *) 7 | module ErrorDocs 8 | 9 | open EEExtensions 10 | open Refs 11 | open Fable.PowerPack 12 | 13 | 14 | let opCodeData = [ 15 | "ADD","dest := op1 + op2", DP3 16 | "SUB","dest := op1 - op2", DP3 17 | "RSB","dest := op2 - op1", DP3 18 | "ADC","dest := op1 + op2 + C", DP3 19 | "SBC","dest := op1 - op2 + C", DP3 20 | "RSC","dest := op2 - op1 + C - 1", DP3 21 | "MOV","dest := op2", DP2 22 | "MVN","dest := NOT op2", DP2 23 | "CMP","set NZCV on op1 - op2", CMP 24 | "CMN","set NZCV on op1 + op2", CMP 25 | "TST","set NZ on op1 bitwise AND op2", CMP 26 | "TEQ","set NZ on op1 bitwise XOR op2", CMP 27 | "LDR","load memory word or byte at address 'EA' into Rd. Optionally update Rb.", LDRSTR 28 | "STR","load memory word or byte at address 'EA' into Rd. Optionally update Rb.", LDRSTR 29 | "LDM","load multiple registers from memory", LDMSTM 30 | "STM","store multiple registers to memory", LDMSTM 31 | "FILL", "allocate op1 data bytes. Op1 must be divisible by 4. Fill words with 0.", MISC 32 | "DCD","allocate data words as specified by op1,...opn",MISC 33 | "DCB","allocate data bytes as specified by op1,...,opn. The number of operand must be divisible by 4",MISC 34 | "EQU","define label on this line to equal op1. Op1 may contain: labels,numbers, +,-,*,/", EQU 35 | ] 36 | 37 | /// match opcode with opcode list returning root instruction (without suffixes or conditions) 38 | /// return "unimplemented" on no match. 39 | let getRoot (opc:string) = 40 | opCodeData 41 | |> List.collect (fun (root,legend,opType) -> 42 | if String.startsWith (root.ToUpper()) (opc.ToUpper()) then 43 | [root,legend, opType] 44 | else []) 45 | |> function 46 | | [ spec] -> spec 47 | | _ -> "unimplemented", "",UNIMPLEMENTED 48 | 49 | /// Add extra diagnostic info for bad shift instructions 50 | let makeShiftModes (isShift, isRRX, isBadShift) = 51 | match isShift,isRRX,isBadShift with 52 | | None, None, None -> " #-1" 53 | | Some sft,_, _ -> sprintf " R2, %s #5" sft 54 | | _, Some _, _ -> " R10, RRX" 55 | | _, _, Some bad -> sprintf " R6, LSR #1**\n\n*Note: * **%s** *is not a valid shift, did you mean* **LSR** , **ASR** , **LSL** , **ROR** , **RRX** *?* **" (String.trim bad) 56 | 57 | 58 | 59 | let makeDPHover2 (opc,sfts) func = 60 | sprintf """ 61 | *%s dest, op2; %s* 62 | 63 | **%s R0, R1** 64 | 65 | **%s R5, #101** 66 | 67 | **%s R10, #0x5a** 68 | 69 | **%s R7, %s** 70 | 71 | """ opc func opc opc opc opc (makeShiftModes sfts) 72 | 73 | let makeCMPHover (opc,sfts) func = 74 | sprintf """ 75 | *%s op1, op2; %s* 76 | 77 | **%s R0, R1** 78 | 79 | **%s R5, #101** 80 | 81 | **%s R10, #0x5a** 82 | 83 | **%s R7, %s** 84 | """ opc func opc opc opc opc (makeShiftModes sfts) 85 | 86 | let makeLDRSTRHover opc func = 87 | sprintf """ 88 | *%s Rd, EA; %s* 89 | 90 | **%s R0, [R10]** 91 | 92 | **%s R5, [R9,#100]** 93 | 94 | **%s R1, [R1], #0x5a** 95 | 96 | **%s R8, [R13, #-32]!** 97 | 98 | **%s R3, [R4, R5]** 99 | 100 | **%s R3, [R4, R5, LSL #2]!** 101 | """ opc func opc opc opc opc opc opc 102 | 103 | let makeLDMSTMHover opc func = 104 | sprintf """ 105 | *%s Rs[!], {register-list}; %s* 106 | 107 | **LDMFD R0!, {R1}** 108 | 109 | **STMFD R10!, {R2,R14}** 110 | 111 | **LDMIB R10, {R2-R9,R11}** 112 | """ opc func 113 | 114 | let makeMISCHover opc func = 115 | let initLine = 116 | match opc with 117 | | "DCD" | "DCB" | "dcd" | "dcb" -> "op1, ..., opn; " 118 | | "FILL" | "fill" -> "op1 ; " 119 | | _ -> failwithf "%s is not a MISC opcode" opc 120 | sprintf """ 121 | *%s %s %s* 122 | 123 | **DCD op1, ..., opn** 124 | 125 | **DCB op1, ..., opn** 126 | 127 | **FILL N** 128 | """ opc initLine func 129 | 130 | let makeEQUHover opc func = 131 | sprintf """ 132 | *%s op1; %s* 133 | 134 | **X1 EQU 44** 135 | 136 | **MULTDATA EQU DATA1 + 0x100** 137 | 138 | **PTR EQU (X1 - 12) * 4 + X2** 139 | """ opc func 140 | 141 | let makeDPHover3 (opc,sfts) func = 142 | sprintf """ 143 | *%s dest, op1, op2; %s* 144 | 145 | **%s R0, R1, R2** 146 | 147 | **%s R5, R5, #101** 148 | 149 | **%s R10, R0, #0x5a** 150 | 151 | **%s R7, R10, %s** 152 | 153 | """ opc func opc opc opc opc (makeShiftModes sfts) 154 | 155 | let unimplementedHover opc = 156 | sprintf " '%s': There is a problem with this instruction" opc 157 | 158 | 159 | let getOpcHover mess opc line = 160 | //printfn "getting hover: opc='%s' line='%s'" opc line 161 | let uLine = 162 | String.toUpper (line + " ") 163 | |> String.replaceChar ',' ' ' 164 | |> String.replaceChar '#' ' ' 165 | if opc = "" then failwithf "can't get hover for '' opcode" 166 | let lineContains lst = List.tryFind (fun sft -> String.contains sft uLine) lst 167 | let isShift = lineContains [" LSL";" LSR";" ASR";" ROR"] 168 | let isRRX = lineContains [" RRX"] 169 | let isBadShift = lineContains [" ASL ";" ROL "; " RRL "] 170 | let _, legend,typ = getRoot opc 171 | let opc' = opc,(isShift,isRRX,isBadShift) 172 | let hoverText = 173 | match typ with 174 | | DP3 -> mess + makeDPHover3 opc' legend 175 | | DP2 -> mess + makeDPHover2 opc' legend 176 | | CMP -> mess + makeCMPHover opc' legend 177 | | MISC -> mess + makeMISCHover opc legend 178 | | LDRSTR -> mess + makeLDRSTRHover opc legend 179 | | LDMSTM -> mess + makeLDMSTMHover opc legend 180 | | EQU -> mess + makeEQUHover opc legend 181 | | UNIMPLEMENTED -> unimplementedHover opc 182 | |> (fun s -> [s]) 183 | let stripComment line = 184 | match String.split [|';'|] line |> Array.toList with 185 | | ins :: _ -> ins 186 | | _ -> failwithf "What? split should return at least one item!" 187 | let oLen = opc.Length 188 | let splitLine = 189 | " " + (stripComment line) + " " 190 | |> String.splitString [|opc|] 191 | |> Array.toList 192 | |> List.rev 193 | let oStart = 194 | match splitLine with 195 | | _afterPart :: before -> List.sumBy String.length before + 1 196 | | x -> failwithf "What? Unexpected split '%A' can't happen. line = '%s', opc = '%s'." x line opc 197 | let lineText = sprintf "```\n%s\n```\n" (stripComment line) 198 | if oStart + oLen - 1 >= line.Length then 199 | ([lineText] @ hoverText), (1, lineText.Length) 200 | else ([lineText] @ hoverText), (oStart, oStart + oLen - 1) 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /src/Renderer/Files.fs: -------------------------------------------------------------------------------- 1 | module Files 2 | 3 | open EEExtensions 4 | open Fable.Core.JsInterop 5 | open Fable.Import 6 | open Fable.Import.Electron 7 | open Node.Exports 8 | open Refs 9 | open Elmish 10 | 11 | let writeToFile str path = 12 | let errorHandler _err = // TODO: figure out how to handle errors which can occur 13 | () 14 | fs.writeFile (path, str, errorHandler) 15 | 16 | /// merge 2 maps into 1 17 | /// if key repeated, the ones in the old map are kept 18 | let mapMerge newMap = 19 | newMap 20 | |> Map.fold (fun map key value -> 21 | Map.add key value map) 22 | 23 | /// return the file name from the file path 24 | let fileName path = 25 | path 26 | |> String.toList 27 | |> List.rev 28 | |> List.takeWhile (fun x -> x <> '/') 29 | |> List.rev 30 | |> List.toString 31 | 32 | /// return file path without file name 33 | let filePathSetting path = 34 | path 35 | |> String.toList 36 | |> List.rev 37 | |> List.skipWhile (fun x -> x <> '/') 38 | |> List.rev 39 | |> List.toString 40 | 41 | /// format the list of files into a list of Editors 42 | let openLstOfFiles (fLst : string list) : Editor List = 43 | let readFile (path:string) = 44 | Node.Exports.fs.readFileSync (path, "utf8") 45 | fLst 46 | |> List.map (fun x -> 47 | { DefaultValue = readFile x 48 | FilePath = Some x 49 | FileName = x |> fileName |> Some 50 | IEditor = Option.None 51 | Saved = true }) 52 | 53 | let fileFilterOpts = 54 | ResizeArray [ 55 | createObj [ 56 | "name" ==> "Assembly Code" 57 | "extensions" ==> ResizeArray [ "s" ] 58 | ] 59 | ] |> Some 60 | 61 | /// open file dialog 62 | let openFile currentFilePath (dispatch : Msg -> Unit) = 63 | let options = createEmpty 64 | options.properties <- ResizeArray([ "openFile"; "multiSelections" ]) |> Some 65 | options.filters <- fileFilterOpts 66 | options.defaultPath <- Some currentFilePath 67 | // path of the opened files 68 | let seq = electron.remote.dialog.showOpenDialog (options) /// open dialog 69 | let fileLst = 70 | match isUndefined seq with 71 | | true -> /// the dialog is cancelled, so seq is undefined 72 | [] 73 | | false -> 74 | seq 75 | |> Seq.toList 76 | |> openLstOfFiles 77 | OpenFile fileLst |> dispatch 78 | 79 | /// save file dialog 80 | let saveFileAs filePathSetting (editor : Editor) dispatch : (unit) = 81 | let options = createEmpty 82 | options.filters <- fileFilterOpts 83 | let savedFilePath = 84 | match editor.FilePath with 85 | | Some x -> x 86 | | _ -> filePathSetting 87 | options.defaultPath <- Some savedFilePath 88 | /// path of the saved file 89 | let result = electron.remote.dialog.showSaveDialog (options) ///open the save file dialog 90 | match isUndefined result with 91 | | true -> 92 | SaveAsFile Option.None |> dispatch 93 | | false -> 94 | writeToFile (editor.IEditor?getValue ()) result 95 | let fileInfo = result, fileName result 96 | fileInfo |> Some |> SaveAsFile |> dispatch 97 | 98 | /// top-level function for saving file 99 | /// open the save dialog when necessary 100 | let saveFileUpdate info settingTabs = 101 | match info.TabId, settingTabs with 102 | | -1, _ -> 103 | info, Cmd.none 104 | | id, Some x when x = id -> 105 | info, Cmd.ofMsg SaveSettingsOnly 106 | | id, _ -> 107 | let filePath = info.Editors.[id].FilePath 108 | match filePath with 109 | | Option.None -> 110 | info, 111 | SaveAsDl 112 | |> UpdateDialogBox 113 | |> Cmd.ofMsg /// open the dialog 114 | | Some fPath -> 115 | let currentEditor = info.Editors.[id] 116 | writeToFile (currentEditor.IEditor?getValue ()) fPath 117 | let newEditors = 118 | Map.add id 119 | { currentEditor with Saved = true } 120 | info.Editors 121 | { Editors = newEditors 122 | TabId = info.TabId }, 123 | Cmd.none 124 | 125 | /// top-level function for save file as 126 | /// open the save file dialog when necessary 127 | let saveAsFileDialogUpdate = 128 | function 129 | | -1, _ -> Cmd.none /// make sure sure no other dialog is opened and there is at least one tab 130 | | x, Some y when x = y -> Cmd.ofMsg SaveSettingsOnly 131 | | _ -> SaveAsDl |> UpdateDialogBox |> Cmd.ofMsg 132 | 133 | /// top-level function for opening up the open file dialog 134 | let saveAsFileUpdate (info, filePathSettingStr) 135 | fileInfo = 136 | match fileInfo with 137 | | Option.None -> 138 | info, filePathSettingStr 139 | | Some (filePath, fileName) -> 140 | let newEditor = 141 | { info.Editors.[info.TabId] with FilePath = Some filePath 142 | FileName = Some fileName 143 | Saved = true } 144 | let newEditors = 145 | info.Editors 146 | |> Map.add info.TabId 147 | newEditor 148 | |> Map.filter (fun key value -> 149 | key = info.TabId || 150 | value.FilePath <> newEditor.FilePath) 151 | let newFilePathSettings = filePathSetting filePath 152 | { info with Editors = newEditors }, newFilePathSettings 153 | 154 | /// top-level function for opening file 155 | let openFileUpdate (info, filePath) 156 | editor = 157 | let newId = uniqueTabId info.Editors 158 | let length = List.length editor 159 | match length with 160 | | 0 -> // no file is selected to be opened 161 | filePath, info 162 | | _ -> 163 | let newEditors = 164 | editor 165 | // zip it with number so it can be convert into map 166 | // number start at the unique tab id to avoid replacement 167 | |> List.zip [newId .. newId + length - 1] 168 | |> List.filter (fun (_, x) -> 169 | // check if the files are already opened 170 | info.Editors 171 | |> Map.forall (fun _ value -> 172 | value.FilePath <> x.FilePath)) 173 | |> Map.ofList 174 | let mergedEditors = mapMerge newEditors info.Editors 175 | let currentEditor = List.head editor // find the first opened file 176 | let newId = // make the first file as current tab 177 | mergedEditors 178 | |> Map.findKey (fun _ value -> 179 | value.FilePath = currentEditor.FilePath) 180 | mergedEditors.[newId].FilePath.Value 181 | |> filePathSetting, 182 | { TabId = newId 183 | Editors = mergedEditors } -------------------------------------------------------------------------------- /src/Renderer/MenuBar.fs: -------------------------------------------------------------------------------- 1 | module MenuBar 2 | 3 | open EEExtensions 4 | open Fable.Core 5 | open Fable.Core.JsInterop 6 | open Fable.Import 7 | open Fable.Import.Electron 8 | open Node.Base 9 | open Refs 10 | open Views 11 | open Elmish 12 | open Integration 13 | open Tests 14 | open Testbench 15 | 16 | let runExtPage url () = 17 | electron.shell.openExternal url |> ignore 18 | 19 | let display runMode = 20 | match runMode with 21 | | ExecutionTop.ResetMode -> "ResetMode" 22 | | ExecutionTop.FinishedMode _ -> "FinishedMode" 23 | | ExecutionTop.ActiveMode _ -> "ActiveMode" 24 | | ExecutionTop.ParseErrorMode -> "ParseErrorMode" 25 | | ExecutionTop.RunErrorMode _ -> "RunErrorMode" 26 | 27 | /// Wrap an action so that it can only happen if simulator is stopped. 28 | /// Converts unit -> unit into obj. Must be called as fun () -> interlock actionName action. 29 | /// Suitable for use as JS callback. 30 | let interlock (actionName : string) debugLevel runMode dispatch msg = 31 | let action = fun _ -> msg |> dispatch 32 | if debugLevel > 0 then printf "Interlock : runMode=%A" (display runMode) 33 | match runMode with 34 | | ExecutionTop.ResetMode 35 | | ExecutionTop.ParseErrorMode -> 36 | action () 37 | | _ -> 38 | ((sprintf "Can't %s while simulator is running

Reset and %s
" actionName actionName), msg) 39 | |> ResetEmulatorDl 40 | |> UpdateDialogBox 41 | |> dispatch 42 | 43 | /// Wrap an action so that it can only happen if simulator is stopped. 44 | /// Operates on (Unit->Unit) to make (Unit->Unit). 45 | /// Suitable for use as action in menu. 46 | let interlockAction (actionName : string) debugLevel runMode dispatch msg = (fun () -> 47 | interlock actionName debugLevel runMode dispatch msg|> ignore 48 | ) 49 | 50 | (**************************************************************************************************** 51 | * 52 | * MENU OPERATIONS 53 | * 54 | ****************************************************************************************************) 55 | 56 | let loadDemo (editors : Map) = 57 | let sampleFileName = Tests.sampleDir + "karatsuba.s" 58 | let txt = 59 | Node.Exports.fs.readFileSync (sampleFileName, "utf8") 60 | let newEditor = 61 | { DefaultValue = txt 62 | FileName = Option.None 63 | FilePath = Option.None 64 | IEditor = Option.None 65 | Saved = true } 66 | let newId = Refs.uniqueTabId editors 67 | let newEditors= Map.add newId newEditor editors 68 | { Editors = newEditors 69 | TabId = newId } 70 | 71 | (**************************************************************************************************** 72 | * 73 | * MENU HELPER FUNCTIONS 74 | * 75 | ****************************************************************************************************) 76 | 77 | 78 | let menuSeparator = 79 | let sep = createEmpty 80 | sep.``type`` <- Some Separator 81 | sep 82 | 83 | /// Make action menu item from name, opt key to trigger, and action. 84 | let makeItem (label : string) (accelerator : string option) (iAction : unit -> unit) = 85 | let handlerCaster f = System.Func f |> Some 86 | let item = createEmpty 87 | item.label <- Some label 88 | item.accelerator <- accelerator 89 | item.click <- handlerCaster (fun _ _ -> iAction()) 90 | item 91 | 92 | /// Make role menu from name, opt key to trigger, and action. 93 | let makeRoleItem label accelerator role = 94 | let item = makeItem label accelerator id 95 | item.role <- U2.Case1 role |> Some 96 | item 97 | 98 | /// make conditional menu item from condition, name, opt key to trigger, and action 99 | let makeCondItem cond label accelerator action = 100 | let item = makeItem label accelerator action 101 | item.visible <- Some cond 102 | item 103 | 104 | /// Make a new menu from a a list of menu items 105 | let makeMenu (name : string) (table : MenuItemOptions list) = 106 | let subMenu = createEmpty 107 | subMenu.label <- Some name 108 | subMenu.submenu <- 109 | table 110 | |> ResizeArray 111 | |> U2.Case2 |> Some 112 | subMenu 113 | 114 | 115 | (**************************************************************************************************** 116 | * 117 | * MENUS 118 | * 119 | ****************************************************************************************************) 120 | let fileMenu (dispatch : (Msg -> Unit)) id debugLevel runMode = 121 | makeMenu "File" [ 122 | makeItem "New" (Some "CmdOrCtrl+N") (interlockAction "make new file tab" debugLevel runMode dispatch NewFile) 123 | menuSeparator 124 | makeItem "Save" (Some "CmdOrCtrl+S") (interlockAction "save file" debugLevel runMode dispatch SaveFile) 125 | makeItem "Save As" (Some "CmdOrCtrl+Shift+S") (interlockAction "save file" debugLevel runMode dispatch SaveAsFileDialog) 126 | makeItem "Open" (Some "CmdOrCtrl+O") (interlockAction "open file" debugLevel runMode dispatch OpenFileDialog) 127 | menuSeparator 128 | makeItem "Close" (Some "CmdOrCtrl+W") (interlockAction "close file" debugLevel runMode dispatch (AttemptToDeleteTab id)) 129 | menuSeparator 130 | makeItem "Quit" (Some "CmdOrCtrl+Q") (interlockAction "quit" debugLevel runMode dispatch AttemptToExit) 131 | ] 132 | 133 | let editMenu (dispatch : (Msg -> Unit)) debugLevel runMode = 134 | makeMenu "Edit" [ 135 | makeItem "Undo" (Some "CmdOrCtrl+Z") (fun _ -> UndoEditor |> dispatch ) 136 | makeItem "Redo" (Some "CmdOrCtrl+Shift+Z") (fun _ -> RedoEditor |> dispatch ) 137 | menuSeparator 138 | makeRoleItem "Cut" (Some "CmdOrCtrl+X") MenuItemRole.Cut 139 | makeRoleItem "Copy" (Some "CmdOrCtrl+C") MenuItemRole.Copy 140 | makeRoleItem "Paste" (Some "CmdOrCtrl+V") MenuItemRole.Paste 141 | menuSeparator 142 | makeItem "Select All" (Some "CmdOrCtrl+A") (fun _ -> SelectAllEditor |> dispatch ) 143 | menuSeparator 144 | makeItem "Find" (Some "CmdOrCtrl+F") (fun _ -> FindEditor |> dispatch) 145 | makeItem "Replace" (Some "CmdOrCtrl+H") (fun _ -> FindAndReplaceEditor |> dispatch) 146 | menuSeparator 147 | makeItem "Increase Font Size" (Some "CmdOrCtrl+.") (fun _ -> IncreaseFontSize |> dispatch ) 148 | makeItem "Decrease Font Size" (Some "CmdOrCtrl+,") (fun _ -> DecreaseFontSize |> dispatch ) 149 | makeItem "Preferences" Core.Option.None (interlockAction "show preferences tab" debugLevel runMode dispatch SelectSettingsTab) 150 | ] 151 | 152 | let viewMenu debugLevel = 153 | let devToolsKey = if Node.Globals.``process``.platform = NodeJS.Platform.Darwin then "Alt+Command+I" else "Ctrl+Shift+I" 154 | makeMenu "View" [ 155 | makeRoleItem "Toggle Fullscreen" (Some "F11") MenuItemRole.Togglefullscreen 156 | menuSeparator 157 | makeRoleItem "Zoom In" (Some "CmdOrCtrl+Plus") MenuItemRole.Zoomin 158 | makeRoleItem "Zoom Out" (Some "CmdOrCtrl+-") MenuItemRole.Zoomout 159 | makeRoleItem "Reset Zoom" (Some "CmdOrCtrl+0") MenuItemRole.Resetzoom 160 | menuSeparator 161 | makeCondItem (debugLevel > 0) "Toggle Dev Tools" (Some devToolsKey) (electron.remote.getCurrentWebContents()).toggleDevTools 162 | ] 163 | 164 | let popupMenu (items) = 165 | let menu = electron.remote.Menu.Create() 166 | items 167 | |> List.map electron.remote.MenuItem.Create 168 | |> List.iter menu.append 169 | menu.popup (electron.remote.getCurrentWindow()) 170 | () 171 | 172 | let runSingleTest editors (disptach : Msg -> unit) = 173 | let decorations, cmd, testLst = getTestList editors 174 | match testLst with 175 | | [] -> 176 | "Can't find any tests. Have you loaded a valid testbench?" 177 | |> Alert 178 | |> UpdateDialogBox 179 | | lst -> 180 | let testLst = 181 | List.map (fun (test : ExecutionTop.Test) -> 182 | let name = sprintf "Step code with initial data from Test %d" test.TNum 183 | let actFun = fun () -> test |> StartTest |> disptach 184 | makeItem name Core.None actFun) lst 185 | testLst 186 | |> PopupMenu 187 | 188 | let testMenu (dispatch : (Msg -> Unit)) debugLevel runMode editors = 189 | let runToBranch() = () 190 | let menu = electron.remote.Menu.Create() 191 | let runTo cond = (cond, System.Int64.MaxValue) |> RunEditorTab |> dispatch 192 | makeMenu "Test" [ 193 | makeItem "Step <-" (Some "F3") (fun () -> StepCodeBackBy 1L |> dispatch) 194 | makeItem "Step ->" (Some "F4") (fun () -> StepCode |> dispatch ) 195 | makeItem "Step to next call" (Some "F5") (fun () -> runTo ExecutionTop.ToSubroutine ) 196 | makeItem "Step to next return" (Some "F6") (fun () -> runTo ExecutionTop.ToReturn ) 197 | makeItem "Step forward by" Core.Option.None (fun () -> UpdateDialogBox StepDl |> dispatch ) 198 | makeItem "Step back by" Core.Option.None (fun () -> UpdateDialogBox StepBackDl |> dispatch ) 199 | menuSeparator 200 | makeItem "Step into test" Core.Option.None (fun () -> dispatch |> runSingleTest editors |> dispatch ) 201 | makeItem "Run all tests" Core.Option.None (interlockAction "Testbench" debugLevel runMode dispatch RunTestBenchOnCode) 202 | ] 203 | 204 | let helpMenu dispatch debugLevel runMode = 205 | let newDialogBox = Alert (sprintf "

VisUAL2 ARM Simulator v%s

" Refs.appVersion + 206 | "(c) 2018, Imperial College
Acknowledgements: Salman Arif (VisUAL), HLP 2018 class" + 207 | " (F# reimplementation), with special mention to Thomas Carrotti," + 208 | " Lorenzo Silvestri, and HLP Team 10") 209 | makeMenu "Help" ( 210 | [ 211 | makeItem "UAL instruction guide" Core.Option.None (runExtPage <| visualDocsPage "guide#content") 212 | makeItem "VisUAL2 web pages" Core.Option.None (runExtPage <| visualDocsPage "") 213 | makeItem "Testbenches" Core.Option.None (runExtPage <| visualDocsPage "testbench") 214 | makeItem "Official ARM documentation" Core.Option.None (runExtPage "http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0234b/i1010871.html") 215 | menuSeparator 216 | makeItem "Load complex demo code" Core.Option.None (interlockAction "load code" debugLevel runMode dispatch LoadDemoCode) 217 | makeCondItem (debugLevel > 0) "Run dev tools FABLE checks" Core.Option.None (interlockAction "FABLE checks" debugLevel runMode dispatch RunTestBench) 218 | makeCondItem (debugLevel > 0) "Run Emulator Tests" Core.Option.None (interlockAction "run tests" debugLevel runMode dispatch RunAllEmulatorTests) 219 | menuSeparator 220 | makeItem "About" Core.option.None (fun _ -> (newDialogBox |> UpdateDialogBox |> dispatch )) 221 | ]) 222 | 223 | 224 | /// Make all app menus 225 | let mainMenu info 226 | debugLevel 227 | runMode 228 | (dispatch : (Msg -> Unit))= 229 | let template = 230 | ResizeArray [ 231 | fileMenu dispatch info.TabId debugLevel runMode 232 | editMenu dispatch debugLevel runMode 233 | viewMenu debugLevel 234 | helpMenu dispatch debugLevel runMode 235 | testMenu dispatch debugLevel runMode info.Editors 236 | ] 237 | template 238 | |> electron.remote.Menu.buildFromTemplate 239 | |> electron.remote.Menu.setApplicationMenu 240 | -------------------------------------------------------------------------------- /src/Renderer/Renderer.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | True 8 | paket-files/Monaco.fs 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Renderer/Settings.fs: -------------------------------------------------------------------------------- 1 | module Settings 2 | 3 | open Fable.Import.Browser 4 | open Refs 5 | open Fable.Import.React 6 | open Fable.Helpers.React 7 | open Fable.Helpers.React.Props 8 | open Fable.Core.JsInterop 9 | open Fable.Import 10 | open Tabs 11 | open CommonData 12 | open Fable.Core 13 | open Node.Exports 14 | 15 | /// A reference to the settings for the app 16 | /// persistent using electron-settings 17 | let settings : obj = electron.remote.require "electron-settings" 18 | 19 | let checkPath (p : string) = 20 | let p' = path.dirname p 21 | try 22 | let stat' = fs.statSync (U2.Case1 p') 23 | let stat = fs.statSync (U2.Case1 p) 24 | match (stat.isDirectory(), stat'.isDirectory()) with 25 | | true, _ -> p 26 | | false, true -> p' 27 | | _ -> os.homedir() 28 | with 29 | | e -> os.homedir() 30 | 31 | let setJSONSettings setting = 32 | let setSetting (name : string) (value : string) = 33 | printf "Saving JSON: %A" value 34 | settings?set (name, value) |> ignore 35 | printfn "Saving settings to this PC: %A" setting 36 | setSetting "JSON" (Fable.Import.JS.JSON.stringify setting) 37 | 38 | 39 | let getJSONSettings initSettings = 40 | let json = settings?get ("JSON", "undefined") 41 | printfn "Getting settings" 42 | match json = "undefined" with 43 | | true -> 44 | printfn "No JSON settings found on this PC" 45 | setJSONSettings() 46 | initSettings 47 | | false -> 48 | try 49 | let vs = (Fable.Import.JS.JSON.parse json) :?> VSettings 50 | vs 51 | with 52 | | e -> 53 | printfn "Parse failed: using default settings" 54 | initSettings 55 | 56 | 57 | let checkSettings (vs : VSettings) vso = 58 | try 59 | let checkNum (n : string) (min : int64) (max : int64) (def : string) = 60 | match int64 n with 61 | | x when x > max -> def 62 | | x when x < min -> def 63 | | x -> x.ToString() 64 | { 65 | vs with 66 | EditorTheme = 67 | match List.tryFind (fun (th, _) -> (th = vs.EditorTheme)) themes with 68 | | Some _ -> vs.EditorTheme 69 | | _ -> printfn "Setting theme to default" 70 | vso.EditorTheme 71 | SimulatorMaxSteps = 72 | checkNum vs.SimulatorMaxSteps 0L System.Int64.MaxValue vso.SimulatorMaxSteps 73 | EditorFontSize = 74 | checkNum vs.EditorFontSize minFontSize maxFontSize vso.EditorFontSize 75 | CurrentFilePath = checkPath vs.CurrentFilePath 76 | } 77 | with 78 | | _ -> printf "Error parsing stored settings: %A" vs 79 | vs 80 | 81 | 82 | /// string for the id, to obtain the value in input 83 | let editorFontSize = "editor-font-size" 84 | let simulatorMaxSteps = "simulator-max-steps" 85 | let editorTheme = "editor-theme" 86 | let editorWordWrap = "editor-word-wrap" 87 | let editorRenderWhitespace = "editor-render-whitespace" 88 | 89 | let getIntSetting mini maxi (defi : string) setting = 90 | let (|INT|_|) (n : string) = 91 | try 92 | Some(int64 n) 93 | with 94 | | e -> Some(defi |> int64) 95 | match setting with 96 | | INT n when n >= mini && n <= maxi -> n |> string 97 | | INT n when n < mini -> mini |> string 98 | | INT n when n > maxi -> maxi |> string 99 | | _ -> defi 100 | 101 | 102 | /// examine, save (onto user's computer) and return the new settings 103 | let getFormSettings (settings : VSettings) = 104 | let getS (name : string) = 105 | let input = document.getElementById (name) :?> HTMLInputElement 106 | input.value 107 | /// for checked box 108 | let getT (name : string) = 109 | let input = document.getElementById (name) :?> HTMLInputElement 110 | input.``checked`` 111 | let vs = { 112 | SimulatorMaxSteps = getIntSetting 0L 1000000000L settings.SimulatorMaxSteps (getS simulatorMaxSteps) 113 | EditorFontSize = getIntSetting 6L 100L settings.EditorFontSize (getS editorFontSize) 114 | EditorTheme = getS editorTheme 115 | EditorWordWrap = getT editorWordWrap 116 | EditorRenderWhitespace = getT editorRenderWhitespace 117 | CurrentFilePath = settings.CurrentFilePath 118 | RegisteredKey = settings.RegisteredKey 119 | OnlineFetchText = settings.OnlineFetchText 120 | } 121 | let newSettings = checkSettings vs settings 122 | setJSONSettings newSettings 123 | newSettings 124 | 125 | /// React description for the settings menu 126 | let settingsMenu dispatch (settings : VSettings) saved: ReactElement = 127 | let onChange = 128 | OnChange (fun x -> 129 | match saved with 130 | | true -> EditorTextChange |> dispatch 131 | | false -> () ) 132 | form [ Class "settings-menu editor" ] 133 | [ div [ Class "float-left" ] 134 | [ h4 [] 135 | [ str "Editor" ] 136 | div [ Class "form-group" ] 137 | [ label [ Class "settings-label" ] 138 | [ str "Font Size" ] 139 | br [ ] 140 | input [ Type "number" 141 | Id "editor-font-size" 142 | Class "settings-input" 143 | DefaultValue settings.EditorFontSize 144 | Min 6 145 | Max 60 146 | Step 2 147 | onChange ]] 148 | div [ Class "form-group" ] 149 | [ label [ Class "settings-label" ] 150 | [ str "Theme" ] 151 | br [ ] 152 | select [ Class "form-control settings-select" 153 | Id "editor-theme" 154 | DefaultValue settings.EditorTheme 155 | onChange ] 156 | //[ option [ Value "vs" ] 157 | // [ str "vs" ] 158 | //option [ Value "vs-dark" ] 159 | // [ str "vs-dark" ] 160 | //option [ Value "hc-black" ] 161 | //[ str "hc-black" ] ] ] 162 | [ option [ Value "one-dark-pro" ] 163 | [ str "One Dark Pro" ] 164 | option [ Value "one-light-pro" ] 165 | [ str "One Light Pro" ] 166 | option [ Value "solarised-dark" ] 167 | [ str "Solarised Dark" ] 168 | option [ Value "solarised-light" ] 169 | [ str "Solarised Light" ] ] ] 170 | div [ Class "form-group" ] 171 | [ label [ Class "settings-label" ] 172 | [ str "Word Wrap" ] 173 | br [] 174 | input [ Type "checkbox" 175 | Id "editor-word-wrap" 176 | DefaultChecked settings.EditorWordWrap 177 | onChange ] ] 178 | div [ Class "form-group" ] 179 | [ label [ Class "settings-label" ] 180 | [ str "Render Whitespace Characters" ] 181 | br [ ] 182 | input [ Type "checkbox" 183 | Id "editor-render-whitespace" 184 | DefaultChecked settings.EditorRenderWhitespace 185 | onChange ] ] ] 186 | div [] 187 | [ h4 [] 188 | [ str "Simulator" ] 189 | div [ Class "form-group" ] 190 | [ label [ Class "settings-label" ] 191 | [ str "Max Steps" 192 | br [ ] 193 | str "(0 for no max)" ] 194 | br [ ] 195 | input [ Type "number" 196 | Id "simulator-max-steps" 197 | Class "settings-input" 198 | Min 0 199 | Max 10000000 200 | Step 100 201 | DefaultValue settings.SimulatorMaxSteps 202 | onChange ] ] ] 203 | div [ Class "after" ] 204 | [] 205 | div [ DOMAttr.OnClick (fun _ -> SaveSettings |> dispatch)] 206 | [ div [ Class "btn btn-default" ] 207 | [ str "Save and Close Settings" ] ] ] 208 | 209 | /// create new setting tab and return new editors map & tab id 210 | let createSettingsTab editors = 211 | let id = uniqueTabId editors 212 | let newSettingTab = 213 | { DefaultValue = "" 214 | FileName = Some " Settings" 215 | FilePath = None 216 | IEditor = None 217 | Saved = true } 218 | let newEditors = 219 | Map.add id newSettingTab editors 220 | { Editors = newEditors 221 | TabId = id } 222 | 223 | /// top-level function to select the settings tab 224 | /// create a setting tab when necessary 225 | let selectSettingsTabUpdate (settingsTab, editors) = 226 | match settingsTab with 227 | | None -> 228 | createSettingsTab editors 229 | // setting tab already exists 230 | | Some x -> 231 | { Editors = editors 232 | TabId = x } 233 | 234 | /// top-level function to save settings 235 | let saveSettingsUpdate (settings, editors, settingsTab, iExports) = 236 | let newSettings = 237 | getFormSettings settings 238 | // close and remove the setting tab after settings are saved 239 | let newEditors = Map.remove settingsTab editors 240 | let newId = 241 | match Map.isEmpty newEditors with 242 | | true -> -1 243 | | _ -> selectLastTabId newEditors 244 | match newSettings.EditorTheme = settings.EditorTheme with 245 | | false -> iExports?editor?setTheme newSettings.EditorTheme 246 | | true -> () 247 | newSettings, 248 | { Editors = newEditors 249 | TabId = newId } 250 | 251 | /// top-level function to save settings 252 | let saveSettingsOnlyUpdate (settings, iExports, settingsTab : int, editors : Map) = 253 | let newSettings = 254 | getFormSettings settings 255 | let newEditors = 256 | Map.add 257 | settingsTab 258 | { editors.[settingsTab] with Saved = true } 259 | editors 260 | match newSettings.EditorTheme = settings.EditorTheme with 261 | | false -> iExports?editor?setTheme (newSettings.EditorTheme) 262 | | true -> () 263 | newSettings, newEditors -------------------------------------------------------------------------------- /src/Renderer/Stats.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Renderer.Stats 5 | Description: Collect locally and post to the web usage statistics. Also allow some control over updates etc. 6 | *) 7 | 8 | module Stats 9 | 10 | open Fable.Core.JsInterop 11 | open Fable.Import 12 | open Fable.Import.Browser 13 | open Fable.Core 14 | open EEExtensions 15 | open Node.Exports 16 | open Refs 17 | open Fable.PowerPack 18 | open Fable.PowerPack.Fetch 19 | open System 20 | open Settings 21 | open Elmish 22 | 23 | let logFileName = "Visual2eventLog.txt" 24 | 25 | let time() = System.DateTime.Now.Ticks 26 | let mutable activity: bool = true 27 | let mutable sleeping: bool = false 28 | 29 | 30 | let dirOfSettings() = 31 | let settingsF = settings?file() 32 | printfn "SettingsF=%s" settingsF 33 | let m = String.regexMatchGroups @"(.*[\\\/])([^\\\/]*$)" settingsF 34 | match m with 35 | | Some [ dir ; _ ; _] -> dir 36 | | _ -> failwithf "Error finding directory of string: '%s'" settingsF 37 | 38 | 39 | 40 | let appendLog item = 41 | let logHeader = sprintf "%s %s %s\n" Refs.appVersion (os.homedir()) (os.hostname()) 42 | let logName = dirOfSettings() + "//" + logFileName 43 | match fs.existsSync (U2.Case1 logName) with 44 | | true -> fs.writeFileSync (logHeader + logName, item) 45 | | false -> fs.appendFile(logName, item, fun _e -> ()) 46 | 47 | 48 | 49 | let logMessage (mess:LogMessage): Unit = failwithf "Not yet implemented" 50 | 51 | 52 | let activityStats = { 53 | new EventListenerObject with 54 | member x.handleEvent _event = 55 | if sleeping then 56 | logMessage {LogT=Wake;Time=time()} 57 | sleeping <- false 58 | activity <- true 59 | } 60 | 61 | 62 | 63 | 64 | let pushLogFile() = 65 | () 66 | 67 | let checkActivity() = 68 | if not activity then 69 | if not sleeping then 70 | logMessage {LogT=Sleep;Time=time()} 71 | sleeping <- true 72 | else 73 | logMessage {LogT=Wake;Time=time()} 74 | activity <- false 75 | pushLogFile() 76 | 77 | 78 | //document.addEventListener("mousemove", U2.Case2 activityStats) 79 | //document.addEventListener("keypress", U2.Case2 activityStats) 80 | 81 | 82 | let (|MatchDate|_|) txt = 83 | let parse = System.DateTime.TryParse 84 | match String.regexMatchGroups "([^\-]+)-([^\-]+)" txt with 85 | | Some [d1 ; d2; _] -> 86 | // if debugLevel > 1 then printfn "Parsed %A, %A" d1 d2 87 | match parse d1, parse d2 with 88 | | (true, dp1), (true, dp2) -> 89 | //printf "Parsedgood: %A %A" dp1 dp2 90 | Some (dp1.Date, dp1.TimeOfDay, dp2.TimeOfDay) 91 | | s -> None 92 | | Some s -> None 93 | | None -> None 94 | 95 | 96 | let infoBox (mess:string) = 97 | ("

Information


" + mess + "

") 98 | |> Alert 99 | |> UpdateDialogBox 100 | |> Cmd.ofMsg 101 | 102 | 103 | let (|MatchVersion|_|) txt = 104 | let parseVer txt = String.regexMatchGroups @"([0-9]+)\.([0-9]+)\.([0-9]+)" txt 105 | let appVer = parseVer Refs.appVersion 106 | let (|ToI|_|) txt = try Some (int txt) with | _exc -> (printfn "Can't convert %s to integer" txt ; None) 107 | match appVer, parseVer txt with 108 | | None,_ -> failwithf "What? Can't parse app version= %s!" Refs.appVersion 109 | | Some [ToI aMajor; ToI aMinor; ToI aDebug;_], Some [ToI major ; ToI minor; ToI debug;_] -> 110 | printfn "Web latest version = %d.%d.%d" major minor debug 111 | match major > aMajor, minor > aMinor, debug > aDebug with 112 | | true, _, _ -> (infoBox <| sprintf "There is a new major release of Visual2 (%s) with additional features, you may wish to upgrade." txt) |> Some 113 | | _, true, _ when major = aMajor -> 114 | (infoBox <| sprintf "There is a new minor release of Visual2 (%s) with new features, you should upgrade." txt) |> Some 115 | | _, false, true when major = aMajor && minor = aMinor -> 116 | (infoBox <| sprintf "There is a new release of Visual2 (%s) with bug fixes, you may wish to upgrade." txt) |> Some 117 | | _ -> None 118 | | _, None -> None 119 | | _, x -> None 120 | 121 | let remindNewVersion txt = 122 | printfn "Remind new version if needed!" 123 | txt 124 | |> String.splitRemoveEmptyEntries [|'\n';'\r'|] 125 | |> Array.iter ( 126 | function 127 | | MatchVersion _ -> () 128 | | _ -> () 129 | ) 130 | 131 | let remindInExams txt (lastRemindTime : System.TimeSpan option ) = 132 | printfn "Remind in exams every 5 min!" 133 | let mutable newRemindTime = lastRemindTime 134 | let mutable cmd = Cmd.none 135 | let cmd1, remind = 136 | infoBox ("WARNING: an assessed Test is scheduled now." + 137 | "If you are currently doing this you are not allowed to use Visual2. " + 138 | "Please exit Visual2 immediately"), 139 | Some DateTime.Now.TimeOfDay 140 | txt 141 | |> String.splitRemoveEmptyEntries [|'\n';'\r'|] 142 | |> Array.iter ( 143 | function 144 | | MatchDate (date, t1, t2) -> 145 | let tim = DateTime.Now 146 | let inExam = tim.TimeOfDay > t1 && tim.TimeOfDay < t2 && tim.Date = date.Date 147 | match inExam, lastRemindTime with 148 | | true, None -> 149 | newRemindTime <- remind 150 | cmd <- cmd1 151 | | true, Some tt when tt.Add (TimeSpan.FromMinutes 5.) < tim.TimeOfDay -> 152 | newRemindTime <- remind 153 | cmd <- cmd1 154 | | _ -> () 155 | | _ -> () 156 | ) 157 | newRemindTime, cmd 158 | 159 | 160 | let doIfHoursLaterThan hours (tim:System.DateTime) = 161 | System.DateTime.Now > tim.Add (System.TimeSpan.FromHours hours) 162 | 163 | 164 | let checkActions txt ve lastRemindTime = 165 | match ve with 166 | | Startup -> remindNewVersion txt 167 | | RunningCode -> () 168 | remindInExams txt lastRemindTime 169 | 170 | let doFetch (onlineFetchText, ve, lastRemindTime, debugLevel) = 171 | //new IHttpRequestHeaders 172 | //hdrs?append("pragma","no-cache") |> ignore 173 | //hdrs?append("cache-control","no-cache") |> ignore 174 | fetch ("http://intranet.ee.ic.ac.uk/t.clarke/tom/info.txt?" + DateTime.Now.Ticks.ToString()) [ 175 | Cache RequestCache.Nostore 176 | ] 177 | |> Promise.map ( 178 | fun res -> 179 | if res.Ok 180 | then 181 | Ok res 182 | else 183 | if debugLevel > 0 then printfn "can't read internet data" 184 | let newLastOnlineFetchTime = Error System.DateTime.Now 185 | let newLastRemindTime, cmd = checkActions onlineFetchText ve lastRemindTime 186 | let newOnlineFetchText = onlineFetchText 187 | Error "can't read internet data" 188 | ) 189 | |> Promise.bindResult (fun res -> res.text()) 190 | |> Promise.mapResult (fun txt -> 191 | //if debugLevel > 0 then printf "----%s----%s----" txt vSettings.OnlineFetchText 192 | let newLastOnlineFetchTime = Ok System.DateTime.Now 193 | let newLastRemindTime, cmd = checkActions txt ve lastRemindTime 194 | let newOnlineFetchText = txt 195 | if onlineFetchText <> txt 196 | then 197 | setJSONSettings() 198 | printfn "-----updating online text to-----\n%s\n------------------------" txt 199 | txt 200 | ) 201 | 202 | let readOnlineInfo (ve: VisualEvent) info onlineFetchText = 203 | let doFetchBl = 204 | match info.LastOnlineFetchTime with 205 | | Error tim -> doIfHoursLaterThan (if ve = Startup then 0. else 0.1) tim 206 | | Ok tim -> doIfHoursLaterThan (if info.DebugLevel > 0 then 0.001 else 24.) tim 207 | match doFetchBl with 208 | | true -> 209 | Cmd.ofPromise doFetch 210 | (onlineFetchText, ve, info.LastRemindTime, info.DebugLevel) 211 | (fun x -> 212 | match x with 213 | | Ok x -> (x, ve) |> ReadOnlineInfoSuccess 214 | | _ -> ReadOnlineInfoFail ve) 215 | (fun _ -> ReadOnlineInfoFail ve) 216 | | false -> 217 | Cmd.none 218 | 219 | let readOnlineInfoResultUpdate onlineFetchText ve lastRemindTime success = 220 | let newLastOnlineFetchTime = 221 | match success with 222 | | true -> Ok System.DateTime.Now 223 | | false -> Error System.DateTime.Now 224 | let newLastRemindTime, cmd = checkActions onlineFetchText ve lastRemindTime 225 | newLastOnlineFetchTime, newLastRemindTime, cmd -------------------------------------------------------------------------------- /src/Renderer/Tabs.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Renderer.Tabs 5 | Description: handle editor tabs: each can contain a distinct assembly file 6 | *) 7 | 8 | /// implement Monaco editor file tabs 9 | 10 | module Tabs 11 | open Fable.Core.JsInterop 12 | open Fable.Import 13 | open Fable.Import.Browser 14 | open Fable.Core 15 | open EEExtensions 16 | open CommonData 17 | open Refs 18 | open Elmish 19 | open Fable.Core.JsInterop 20 | 21 | /// return the id of the last editor in the map of editors 22 | let selectLastTabId editors = 23 | editors 24 | |> Map.toList 25 | |> List.rev 26 | |> List.head 27 | |> fst 28 | 29 | /// Editor value of a blank tab 30 | let blankTab = 31 | { DefaultValue = "" 32 | FileName = None 33 | FilePath = None 34 | IEditor = None 35 | Saved = true } 36 | 37 | /// top-level function to delete tab 38 | let deleteTabUpdate (info, settingsTab) = 39 | let newEditors = Map.remove info.TabId info.Editors 40 | let newTabId = 41 | match Map.isEmpty newEditors with 42 | | true -> -1 43 | | false -> selectLastTabId newEditors 44 | let newSettingsTab = 45 | match settingsTab with 46 | | Some x when x = info.TabId -> None 47 | | x -> 48 | match x = Some info.TabId with 49 | | true -> 50 | info.Editors.[info.TabId].IEditor?dispose () |> ignore 51 | | _ -> () 52 | x 53 | { TabId = newTabId 54 | Editors = newEditors }, newSettingsTab 55 | 56 | /// top-level function to select file tab 57 | let selectFileTabUpdate id editors = 58 | match Map.isEmpty editors with 59 | | true -> -1 60 | | _ -> 61 | match Map.containsKey id editors with 62 | | true -> id 63 | | _ -> selectLastTabId editors 64 | 65 | /// top-level function for opening new tab 66 | let newFileUpdate editors = 67 | let newTabId = uniqueTabId editors 68 | let newEditors = Map.add newTabId blankTab editors 69 | { TabId = newTabId 70 | Editors = newEditors } 71 | 72 | let attemptToDeleteTabUpdate (info, dialogBox) 73 | id = 74 | match id with 75 | | -1 -> Cmd.none 76 | | _ -> 77 | match id = info.TabId, info.Editors.[id].Saved with 78 | | true, true -> Cmd.ofMsg DeleteTab 79 | | true, false -> UnsavedFileDl |> UpdateDialogBox |> Cmd.ofMsg 80 | | _ -> Cmd.none -------------------------------------------------------------------------------- /src/Renderer/Testbench.fs: -------------------------------------------------------------------------------- 1 | (* 2 | VisUAL2 @ Imperial College London 3 | Project: A user-friendly ARM emulator in F# and Web Technologies ( Github Electron & Fable Compiler ) 4 | Module: Renderer.Testbench 5 | Description: File for GUI interface and higher-level automation in testing of assembly programs with 6 | special testbench files containing sets of tests. 7 | *) 8 | 9 | module Testbench 10 | 11 | open Fable.Core.JsInterop 12 | open Refs 13 | open EEExtensions 14 | open Helpers 15 | open CommonData 16 | open ExecutionTop 17 | open TestLib 18 | open Elmish 19 | 20 | let getTBWithTab (editors: Map) = 21 | editors 22 | |> Map.map (fun _ value -> value.IEditor?getValue ()) 23 | |> Map.filter (fun _ value -> value |> String.trim |> String.startsWith "##TESTBENCH") 24 | |> Map.toList 25 | |> function | [ tab, tb ] -> Ok(tab, tb) 26 | | [] -> Error "No testbench is loaded" 27 | | _ -> Error "More than one testbench is loaded" 28 | 29 | let getTB editors = 30 | getTBWithTab editors 31 | |> Result.map snd 32 | 33 | let currentTabIsTB tabId (editors : Map) = 34 | match tabId with 35 | | -1 -> false 36 | | tab -> editors.[tab].IEditor?getValue () 37 | |> String.trim |> String.startsWith "##TESTBENCH" 38 | 39 | /// Top-level testbench parse. Locate loaded testbench, generate pair of testbench tab ID 40 | /// and Test list, or Error message. If testbench lines contain errors these are highlighted in buffer. 41 | /// Previous error highlights are removed from buffer. 42 | let getParsedTests dStart (editors : Map) = 43 | let mutable decorations = [] 44 | let mutable cmd = [] 45 | let processParseErrors (eLst : Result list) = 46 | let highlightErrors tab = 47 | List.iter (fun (lNum, mess) -> 48 | printfn "Testbench error %d %s." lNum mess 49 | decorations <- 50 | Editors.highlightLine editors.[tab].IEditor lNum "editor-line-error" decorations ) 51 | match getTBWithTab editors with 52 | | Error mess -> Error mess 53 | | Ok(tab, _) -> 54 | // delete decorations 55 | List.iter (Result.mapError (highlightErrors tab) >> ignore) eLst 56 | match List.errorList eLst with 57 | | [] -> 58 | List.okList eLst |> Ok 59 | | x -> 60 | printfn "%A" x 61 | cmd <- cmd @ [ tab |> SelectFileTab |> Cmd.ofMsg ] 62 | Error "Parse errors in testbench" 63 | 64 | let initStack = 0xFF000000u 65 | getTBWithTab editors 66 | |> Result.bind ( 67 | fun (tab, tb) -> 68 | String.toUpper tb 69 | |> String.splitString [| "\n" |] 70 | |> Array.toList 71 | |> parseTests initStack dStart 72 | |> processParseErrors 73 | |> Result.map (fun x -> tab, x)), 74 | cmd, 75 | decorations 76 | 77 | let getTestRunInfo (test : Test list) = 78 | function 79 | | Some(lim, _) -> 80 | let dp = initTestDP (lim.Mem, lim.SymInf.SymTab) test.[0] 81 | match dp with 82 | | Ok dp -> Some false, getRunInfoFromImageWithInits NoBreak lim dp.Regs dp.Fl Map.empty dp.MM |> Ok |> Some 83 | | Error e -> Some false, Error e |> Some 84 | | None -> None, None 85 | 86 | let runTests tests = 87 | match tests with 88 | | test :: _ -> 89 | printfn "Running tests" 90 | (true, 0L, NoBreak, Some tests) |> TryParseAndIndentCode |> Cmd.ofMsg 91 | | [] -> 92 | Cmd.none 93 | 94 | let getTestRunInfoMatch startTest tests = 95 | function 96 | | Some(Ok ri) -> 97 | let ri' = { ri with TestState = if startTest then NoTest else Testing tests } 98 | let steps = 99 | if startTest then 1L else System.Int64.MaxValue 100 | ActiveMode(RunState.Running, ri') |> Some, 101 | (NoBreak, steps, ri') 102 | |> AsmStepDisplay 103 | |> Cmd.ofMsg 104 | | Some(Error eMess) -> 105 | None, 106 | eMess 107 | |> Alert 108 | |> UpdateDialogBox 109 | |> Cmd.ofMsg 110 | | _ -> 111 | None, 112 | "Can't run tests: current tab must have valid assembler" 113 | |> Alert 114 | |> UpdateDialogBox 115 | |> Cmd.ofMsg 116 | 117 | /// Write test Checklines to the buffer containing the testbench file 118 | let writeTest (test : Test) editors = 119 | editors 120 | |> getTBWithTab 121 | |> Result.map (fun (tabId, dat) -> 122 | dat 123 | |> String.splitString [| "\n" |] 124 | |> Array.toList 125 | |> List.map String.trim 126 | |> List.chunkAt (String.trim >> String.startsWith "#TEST") 127 | |> List.collect (fun chunk -> 128 | let testLst = String.splitOnWhitespace (List.head chunk) |> Array.toList 129 | let testData = List.filter (String.trim >> String.startsWith ">>" >> not) (chunk |> List.tail) 130 | match testLst with 131 | | "#TEST" :: LITERALNUMB(n, "") :: _ when int n = test.TNum -> 132 | (sprintf "#TEST %d" n) :: testData @ test.CheckLines 133 | | _ -> chunk) // no change 134 | |> List.filter ((<>) "") 135 | |> String.concat "\n" 136 | |> fun r -> tabId, r) 137 | |> function | Ok(tabId, txt) -> 138 | let editor = editors.[tabId].IEditor 139 | editor?setValue txt 140 | Cmd.none 141 | | Error _ -> 142 | "Error! What? can't find testbench to write results!" 143 | |> Alert 144 | |> UpdateDialogBox 145 | |> Cmd.ofMsg 146 | 147 | /// Generate one Test of result messages and add them to the testbench buffer. 148 | /// If no errors mark the Test as Passed. 149 | /// test: test to add (one of those in the testbench). 150 | /// dp: DataPath after test simulation ends. 151 | /// Returns true if test has passed. 152 | let addResultsToTestbench (test : Test) (dp : DataPath) editors = 153 | let goodParse, resultLines = computeTestResults test dp 154 | writeTest { test with CheckLines = resultLines } editors, 155 | goodParse 156 | 157 | let getTestList editors = 158 | let result, cmd1, decorations = 159 | getParsedTests 0x10000000u editors 160 | let cmd2, testLst = 161 | result 162 | |> function 163 | | Error e -> 164 | e 165 | |> Alert 166 | |> UpdateDialogBox 167 | |> Cmd.ofMsg, 168 | [] 169 | | Ok(_, tests) -> 170 | Cmd.none, 171 | tests 172 | let allCmd = Cmd.batch (cmd1 @ [ cmd2 ]) 173 | decorations, allCmd, testLst 174 | -------------------------------------------------------------------------------- /src/Renderer/paket.references: -------------------------------------------------------------------------------- 1 | dotnet-fable 2 | Fable.Core 3 | Fable.Import.Browser 4 | Fable.Import.Electron 5 | Fable.Elmish 6 | Fable.Elmish.React 7 | Fable.Elmish.Browser 8 | Fable.Elmish.Debugger 9 | Fable.Elmish.HMR 10 | Fable.PowerPack 11 | File: Monaco.fs -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var webpack = require("webpack"); 3 | var MonacoWebpackPlugin = require("monaco-editor-webpack-plugin"); 4 | 5 | function resolve(filePath) { 6 | return path.join(__dirname, filePath) 7 | } 8 | 9 | var babelOptions = { 10 | presets: ["@babel/preset-react"], 11 | plugins: ['@babel/plugin-proposal-class-properties'] 12 | }; 13 | 14 | var isProduction = process.argv.indexOf("-w") < 0; 15 | console.log("Bundling for " + (isProduction ? "production" : "development") + "..."); 16 | 17 | var basicConfig = { 18 | node: { 19 | __dirname: false, 20 | __filename: false 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.fs(x|proj)?$/, 26 | use: { 27 | loader: "fable-loader", 28 | options: { 29 | babel: babelOptions, 30 | define: isProduction ? ["DEBUG"] : ["DEBUG", "WATCH"] 31 | } 32 | } 33 | }, 34 | { 35 | test: /\.js$/, 36 | exclude: /node_modules/, 37 | use: { 38 | loader: 'babel-loader', 39 | options: babelOptions 40 | }, 41 | }, 42 | { 43 | test: /\.css$/, 44 | use: ['style-loader', 'css-loader' ] 45 | } 46 | ] 47 | } 48 | }; 49 | 50 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 51 | //const UglifyJSPlugin = require('uglifyjs-webpack-plugin') 52 | 53 | var mainConfig = Object.assign({ 54 | target: "electron-main", 55 | entry: resolve("src/Main/Main.fsproj"), 56 | output: { 57 | path: resolve("."), 58 | filename: "main.js" 59 | }, 60 | }, basicConfig); 61 | 62 | var rendererConfig = Object.assign({ 63 | plugins: [ 64 | 65 | //new UglifyJSPlugin(), 66 | new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }), 67 | new MonacoWebpackPlugin({ 68 | // languages:["javascript","css","html","json"], 69 | features:['accessibilityHelp', 'bracketMatching', 'caretOperations', 'clipboard', 'codeAction', 'codelens', 'colorDetector', 'comment', 'contextmenu', 'coreCommands', 'cursorUndo', 'dnd', 'find', 'folding', 'fontZoom', 'format', 'goToDefinitionCommands', 'goToDefinitionMouse', 'gotoError', 'gotoLine', 'hover', 'inPlaceReplace', 'inspectTokens', 'iPadShowKeyboard', 'linesOperations', 'multicursor', 'parameterHints', 'quickCommand', 'quickOutline', 'referenceSearch', 'rename', 'smartSelect', 'snippets', 'toggleHighContrast', 'toggleTabFocusMode', 'transpose', 'wordHighlighter', 'wordOperations', 'wordPartOperations'] 70 | // ["accessibilityHelp", "bracketMatching", "caretOperations", "clipboard", "codeAction", "codelens", "colorDetector", "comment", "contextmenu", "coreCommands", "cursorUndo", "dnd", "find", "folding", "fontZoom", "format", "goToDefinitionCommands", "goToDefinitionMouse", "gotoError", "gotoLine", "hover", "inPlaceReplace", "inspectTokens", "iPadShowKeyboard", "linesOperations", "links", "multicursor", "parameterHints", "quickCommand", "quickOutline", "referenceSearch", "rename", "smartSelect", "snippets", "suggest", "toggleHighContrast", "toggleTabFocusMode", "transpose", "wordHighlighter", "wordOperations", "wordPartOperations"] 71 | }) 72 | ], 73 | target: "electron-renderer", 74 | devtool: "source-map", 75 | entry: resolve("src/Renderer/Renderer.fsproj"), 76 | output: { 77 | path: resolve("app/js"), 78 | filename: "renderer.js" 79 | }, 80 | externals: { 81 | "monaco": "var monaco", 82 | "editor": "var editor", 83 | "fable-repl": "var Fable", 84 | } 85 | }, basicConfig); 86 | 87 | module.exports = [mainConfig, rendererConfig] 88 | --------------------------------------------------------------------------------