├── .gitattributes ├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── BuildAndRunAllTests.bat ├── BuildAndRunAllTests.sh ├── LICENSE ├── OS Project └── nuget.config ├── Sample Programs ├── idle-n.txt ├── idle.txt ├── prog1.txt ├── prog2.txt ├── prog3.txt ├── readme.txt ├── scott1.txt ├── scott10.txt ├── scott11.txt ├── scott12.txt ├── scott13.txt ├── scott2.txt ├── scott3.txt ├── scott4.txt ├── scott5.txt ├── scott6.txt ├── scott7.txt ├── scott8.txt ├── scott9.txt ├── testAll.bat ├── testAll.sh ├── testAllocAndFree.bat ├── testCalls.bat ├── testEvents.bat ├── testJumps.bat ├── testLocks.bat ├── testMemoryProtection.bat ├── testMulti.bat ├── testMultiSuper.bat ├── testRegisters.bat ├── testSharedMem.bat └── testStack.bat ├── TinyOS.sln ├── azure-pipelines.yml ├── originalassignment.md ├── readme.md └── src └── TinyOSCore ├── CPU.cs ├── EntryPoint.cs ├── Instruction.cs ├── InstructionCollection.cs ├── MemoryManager.cs ├── OS.cs ├── Process.cs ├── ProcessCollection.cs ├── Program.cs ├── TinyOSCore.csproj ├── appsettings.json └── publish.bat /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | # http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ 3 | * text=lf 4 | 5 | *.cs diff=csharp -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '33 7 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'csharp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/csharp 3 | 4 | ### Csharp ### 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 9 | 10 | # User-specific files 11 | *.suo 12 | *.user 13 | *.userosscache 14 | *.sln.docstates 15 | 16 | # profram specific debug dumps 17 | page*.xml 18 | 19 | # User-specific files (MonoDevelop/Xamarin Studio) 20 | *.userprefs 21 | 22 | # Build results 23 | [Dd]ebug/ 24 | [Dd]ebugPublic/ 25 | [Rr]elease/ 26 | [Rr]eleases/ 27 | x64/ 28 | x86/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | notlinked/ 34 | linked/ 35 | out.txt 36 | 37 | # Visual Studio 2015 cache/options directory 38 | .vs/ 39 | # Uncomment if you have tasks that create the project's static files in wwwroot 40 | #wwwroot/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUNIT 47 | *.VisualState.xml 48 | TestResult.xml 49 | 50 | # Build Results of an ATL Project 51 | [Dd]ebugPS/ 52 | [Rr]eleasePS/ 53 | dlldata.c 54 | 55 | # .NET Core 56 | project.lock.json 57 | project.fragment.lock.json 58 | artifacts/ 59 | **/Properties/launchSettings.json 60 | 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.pch 68 | *.pdb 69 | *.pgc 70 | *.pgd 71 | *.rsp 72 | *.sbr 73 | *.tlb 74 | *.tli 75 | *.tlh 76 | *.tmp 77 | *.tmp_proj 78 | *.log 79 | *.vspscc 80 | *.vssscc 81 | .builds 82 | *.pidb 83 | *.svclog 84 | *.scc 85 | 86 | # Chutzpah Test files 87 | _Chutzpah* 88 | 89 | # Visual C++ cache files 90 | ipch/ 91 | *.aps 92 | *.ncb 93 | *.opendb 94 | *.opensdf 95 | *.sdf 96 | *.cachefile 97 | *.VC.db 98 | *.VC.VC.opendb 99 | 100 | # Visual Studio profiler 101 | *.psess 102 | *.vsp 103 | *.vspx 104 | *.sap 105 | 106 | # TFS 2012 Local Workspace 107 | $tf/ 108 | 109 | # Guidance Automation Toolkit 110 | *.gpState 111 | 112 | # ReSharper is a .NET coding add-in 113 | _ReSharper*/ 114 | *.[Rr]e[Ss]harper 115 | *.DotSettings.user 116 | 117 | # JustCode is a .NET coding add-in 118 | .JustCode 119 | 120 | # TeamCity is a build add-in 121 | _TeamCity* 122 | 123 | # DotCover is a Code Coverage Tool 124 | *.dotCover 125 | 126 | # Visual Studio code coverage results 127 | *.coverage 128 | *.coveragexml 129 | 130 | # NCrunch 131 | _NCrunch_* 132 | .*crunch*.local.xml 133 | nCrunchTemp_* 134 | 135 | # MightyMoose 136 | *.mm.* 137 | AutoTest.Net/ 138 | 139 | # Web workbench (sass) 140 | .sass-cache/ 141 | 142 | # Installshield output folder 143 | [Ee]xpress/ 144 | 145 | # DocProject is a documentation generator add-in 146 | DocProject/buildhelp/ 147 | DocProject/Help/*.HxT 148 | DocProject/Help/*.HxC 149 | DocProject/Help/*.hhc 150 | DocProject/Help/*.hhk 151 | DocProject/Help/*.hhp 152 | DocProject/Help/Html2 153 | DocProject/Help/html 154 | 155 | # Click-Once directory 156 | publish/ 157 | 158 | # Publish Web Output 159 | *.[Pp]ublish.xml 160 | *.azurePubxml 161 | # TODO: Comment the next line if you want to checkin your web deploy settings 162 | # but database connection strings (with potential passwords) will be unencrypted 163 | *.pubxml 164 | *.publishproj 165 | 166 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 167 | # checkin your Azure Web App publish settings, but sensitive information contained 168 | # in these scripts will be unencrypted 169 | PublishScripts/ 170 | 171 | # NuGet Packages 172 | *.nupkg 173 | # The packages folder can be ignored because of Package Restore 174 | **/packages/* 175 | # except build/, which is used as an MSBuild target. 176 | !**/packages/build/ 177 | # Uncomment if necessary however generally it will be regenerated when needed 178 | #!**/packages/repositories.config 179 | # NuGet v3's project.json files produces more ignorable files 180 | *.nuget.props 181 | *.nuget.targets 182 | 183 | # Microsoft Azure Build Output 184 | csx/ 185 | *.build.csdef 186 | 187 | # Microsoft Azure Emulator 188 | ecf/ 189 | rcf/ 190 | 191 | # Windows Store app package directories and files 192 | AppPackages/ 193 | BundleArtifacts/ 194 | Package.StoreAssociation.xml 195 | _pkginfo.txt 196 | 197 | # Visual Studio cache files 198 | # files ending in .cache can be ignored 199 | *.[Cc]ache 200 | # but keep track of directories ending in .cache 201 | !*.[Cc]ache/ 202 | 203 | # Others 204 | ClientBin/ 205 | ~$* 206 | *~ 207 | *.dbmdl 208 | *.dbproj.schemaview 209 | *.jfm 210 | *.pfx 211 | *.publishsettings 212 | orleans.codegen.cs 213 | 214 | # Since there are multiple workflows, uncomment next line to ignore bower_components 215 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 216 | #bower_components/ 217 | 218 | # RIA/Silverlight projects 219 | Generated_Code/ 220 | 221 | # Backup & report files from converting an old project file 222 | # to a newer Visual Studio version. Backup files are not needed, 223 | # because we have git ;-) 224 | _UpgradeReport_Files/ 225 | Backup*/ 226 | UpgradeLog*.XML 227 | UpgradeLog*.htm 228 | 229 | # SQL Server files 230 | *.mdf 231 | *.ldf 232 | *.ndf 233 | 234 | # Business Intelligence projects 235 | *.rdl.data 236 | *.bim.layout 237 | *.bim_*.settings 238 | 239 | # Microsoft Fakes 240 | FakesAssemblies/ 241 | 242 | # GhostDoc plugin setting file 243 | *.GhostDoc.xml 244 | 245 | # Node.js Tools for Visual Studio 246 | .ntvs_analysis.dat 247 | node_modules/ 248 | 249 | # Typescript v1 declaration files 250 | typings/ 251 | 252 | # Visual Studio 6 build log 253 | *.plg 254 | 255 | # Visual Studio 6 workspace options file 256 | *.opt 257 | 258 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 259 | *.vbw 260 | 261 | # Visual Studio LightSwitch build output 262 | **/*.HTMLClient/GeneratedArtifacts 263 | **/*.DesktopClient/GeneratedArtifacts 264 | **/*.DesktopClient/ModelManifest.xml 265 | **/*.Server/GeneratedArtifacts 266 | **/*.Server/ModelManifest.xml 267 | _Pvt_Extensions 268 | 269 | # Paket dependency manager 270 | .paket/paket.exe 271 | paket-files/ 272 | 273 | # FAKE - F# Make 274 | .fake/ 275 | 276 | # JetBrains Rider 277 | .idea/ 278 | *.sln.iml 279 | 280 | # CodeRush 281 | .cr/ 282 | 283 | # Python Tools for Visual Studio (PTVS) 284 | __pycache__/ 285 | *.pyc 286 | 287 | # Cake - Uncomment if you are using it 288 | # tools/** 289 | # !tools/packages.config 290 | 291 | # Telerik's JustMock configuration file 292 | *.jmconfig 293 | 294 | # BizTalk build output 295 | *.btp.cs 296 | *.btm.cs 297 | *.odx.cs 298 | *.xsd.cs 299 | 300 | # End of https://www.gitignore.io/api/csharp 301 | AnalysisReport.sarif 302 | upgrade-assistant.clef 303 | -------------------------------------------------------------------------------- /BuildAndRunAllTests.bat: -------------------------------------------------------------------------------- 1 | pushd . 2 | cd "src\TinyOSCore" 3 | dotnet publish -r win-x64 --self-contained -p:PublishSingleFile=true -p:SuppressTrimAnalysisWarnings=true -p:EnableCompressionInSingleFile=true 4 | copy "..\..\Sample Programs\*" bin\Debug\net6.0\win-x64\publish 5 | pushd . 6 | cd bin\Debug\net6.0\win-x64\publish 7 | call testAll.bat 8 | popd 9 | popd 10 | -------------------------------------------------------------------------------- /BuildAndRunAllTests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -v 3 | pushd . 4 | cd src/TinyOSCore 5 | dotnet publish -r linux-x64 --self-contained -p:PublishSingleFile=true -p:SuppressTrimAnalysisWarnings=true -p:EnableCompressionInSingleFile=true 6 | cp ../../Sample\ Programs/* bin/Debug/net6.0/linux-x64/publish 7 | pushd . 8 | cd bin/Debug/net6.0/linux-x64/publish 9 | ./testAll.sh 10 | popd 11 | popd 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017, Scott Hanselman 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /OS Project/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample Programs/idle-n.txt: -------------------------------------------------------------------------------- 1 | 6 r5, $100 ;move 100 into r5 (how many times we'll run) 2 | 6 r4, $0 ;move 0 into r4 3 | 6 r6, $14 ;how many bytes to jump forward to exit 4 | 26 r4 ;lower our priority TO 0 5 | 6 r1, $20 ;move 20 into r1 6 | 11 r1 ;print the number 20 7 | 1 r3 ;incr r3 (our counter) 8 | 15 r3, r5 ;compare r3 and r5 9 | 18 r6 ;if r3 and r5 equal, jump r6 10 | 6 r2, $-38 ;back up the ip 38 11 | 13 r2 ;loop forever (jump back 38) 12 | 27 ;exit - this program is the same idle loop, but only is idle for r5 clock cycles -------------------------------------------------------------------------------- /Sample Programs/idle.txt: -------------------------------------------------------------------------------- 1 | 6 r4, $0 ;move 0 into r4 2 | 26 r4 ;lower our priority TO 0 3 | 6 r1, $20 ;move 20 into r1 4 | 11 r1 ;print the number 20 5 | 6 r2, $-19 ;back up the ip 19 6 | 13 r2 ;loop forever (jump back 19) 7 | -------------------------------------------------------------------------------- /Sample Programs/prog1.txt: -------------------------------------------------------------------------------- 1 | 11 r8 ;Print r8 2 | 6 r1 $10 ;Move 10 into r1 3 | 6 r2 $11 ;Move 11 into r2 4 | 6 r3 $0 ;Move 0 into r3 5 | 23 r1 ;Acquire lock in r1 (currently lock 10) 6 | 11 r2 ;Print r2 7 | 25 r3 ;Sleep r3 (current 0, will sleep forever) 8 | 11 r3 ;Print r3 9 | 24 r1 ;Release r1 10 | 27 ;Exit -------------------------------------------------------------------------------- /Sample Programs/prog2.txt: -------------------------------------------------------------------------------- 1 | 11 r8 ;Print r8 2 | 6 r1 $10 ;Move 10 into r1 3 | 6 r2 $6 ;Move 6 into r2 4 | 6 r3 $25 ;Move 25 intno r3 5 | 23 r1 ;Acquire lock in r1 (currently 10) 6 | 11 r3 ;Print r3 (currently 25) 7 | 24 r1 ;Release r4 (currently 10) 8 | 25 r3 ;Sleep r3 (currently 25) 9 | 11 r3 ;Print r3 (currently 25) 10 | 27 ;Exit -------------------------------------------------------------------------------- /Sample Programs/prog3.txt: -------------------------------------------------------------------------------- 1 | 11 r8 ;Print r8 2 | 6 r1 $10 ;Move 10 into r1 3 | 23 r1 ;Acquire Lock in r1 (currently 10) 4 | 2 r1 $1 ;Addi 1 to r1 5 | 25 r1 ;Sleep r1 (currently 25) 6 | 23 r1 ;Acquire r1 (currently 11, INVALID -> NOOP) 7 | 2 r1 $1 ;Addi 1 to r1 8 | 25 r1 ;Sleep r1 (currently 12) 9 | 23 r1 ;Acquire r1 (currently 12, INVALUD -> NOOP) 10 | 11 r1 ;Print r1 (currently 12) 11 | 6 r2 $100 ;Move 100 into r2 12 | 25 r2 ;Sleep r2 (currently 100) 13 | 11 r2 ;Print r2 14 | 27 ;Exit -------------------------------------------------------------------------------- /Sample Programs/readme.txt: -------------------------------------------------------------------------------- 1 | Sample Programs 2 | ----------------- 3 | * I usually keep these in the ..\bin\Debug\net6.0 dir for ease of execution 4 | 5 | * If you want to debug in VS.NET go to the Properties Dialog of the current Project. Go to "Configuration Properties|Debugging" under Command Line Arguments and add the same args you'd add on the command line. 6 | 7 | So, you might put 8 | 9 | 1024 prog3.txt idle-n.txt 10 | 11 | to have 1024 bytes of addressable memory and run prog3.txt and idle-n.txt when debugging. 12 | 13 | 14 | - Scott -------------------------------------------------------------------------------- /Sample Programs/scott1.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $3276834 ;move a big number into r1 2 | 7 r2, r1 ;move r1 to r2 3 | 11 r2 ;print r2 4 | 2 r2, $5 ;increment r2 by 5 5 | 2 r2, $5 ;increment r2 by 5 6 | 2 r2, $5 ;increment r2 by 5 7 | 2 r2, $5 ;increment r2 by 5 8 | 2 r2, $5 ;increment r2 by 5 9 | 2 r2, $5 ;increment r2 by 5 10 | 2 r2, $5 ;increment r2 by 5 11 | 11 r2 ;print r2 12 | 27 ;exit. -------------------------------------------------------------------------------- /Sample Programs/scott10.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $1 ;move 1 into r1 2 | 31 r1 ;wait on r1 3 | 6 r1, $1 ;move 1 into r1 4 | 6 r2, $22 ;move 22 into r2 5 | 6 r3, $33 ;move 33 into r3 6 | 6 r4, $44 ;move 44 into r4 7 | 6 r5, $55 ;move 55 into r5 8 | 6 r6, $66 ;move 66 into r6 9 | 27 -------------------------------------------------------------------------------- /Sample Programs/scott11.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $1 ;move 1 into r1 2 | 29 r1, r2 ;map shared mem region #r1, return addr inr2 3 | 11 r2 ;print r2 (the memory address) 4 | 7 r3, r2 ;copy the memory address into r3 (we might need it) 5 | 6 r4, $1 ;lock 1 6 | 23 r4 ;lock r4 (lock #1) 7 | 6 r3, $99 ;put 99 in r3 8 | 9 r2, r3 ;put r3 at memory r2 9 | 2 r2, $4 ;add 4 10 | 9 r2, r3 ;put r3 at memory r2 11 | 2 r2, $4 ;add 4 12 | 9 r2, r3 ;put r3 at memory r2 13 | 2 r2, $4 ;add 4 14 | 9 r2, r3 ;put r3 at memory r2 15 | 2 r2, $4 ;add 4 16 | 24 r4 ;release 1 17 | 6 r5, $1 ;event 1 18 | 30 r5 ;signal 1 19 | 27 -------------------------------------------------------------------------------- /Sample Programs/scott12.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $1 ;move 1 into r1 2 | 29 r1, r2 ;map shared mem region #r1, return addr inr2 3 | 11 r2 ;print r2 4 | 6 r5, $1 ;event 1 5 | 31 r5 ;wait on 1 6 | 12 r2 ;print out shared mem 7 | 2 r2, $4 ;add 4 8 | 12 r2 9 | 2 r2, $4 ;add 4 10 | 12 r2 11 | 2 r2, $4 ;add 4 12 | 12 r2 13 | 2 r2, $4 ;add 4 14 | 27 -------------------------------------------------------------------------------- /Sample Programs/scott13.txt: -------------------------------------------------------------------------------- 1 | 6 r4, $4 ;we'll need 4 bytes 2 | 22 r4, r5 ;ask for 4 bytes 3 | 7 r2, r5 ;save address in r2 4 | 6 r4, $33 ;we'll need 12 bytes 5 | 22 r4, r5 ;ask for 12 bytes 6 | 7 r1, r5 ;save address in r1 7 | 28 r2 ;release 8 | 6 r6, $11 ;put 11 in r6 9 | 9 r5, r6 ;put 11 in the new memory 10 | 2 r5, $4 11 | 9 r5, r6 ;put 11 in the new memory 12 | 2 r5, $4 13 | 9 r5, r6 ;put 11 in the new memory 14 | 6 r4, $17 ;we'll need 17 bytes 15 | 22 r4, r5 ;ask for 17 bytes 16 | 7 r3, r5 ;save address in r3 17 | 28 r1 18 | 28 r3 19 | 27 ; this is exit. -------------------------------------------------------------------------------- /Sample Programs/scott2.txt: -------------------------------------------------------------------------------- 1 | 1 r1 ;incr r1 2 | 2 r6, $16 ;add $16 to r6 3 | 26 r6 ;set priority to 26 4 | 2 r2, $5 ;increment r2 by 5 5 | 3 r1, r2 ;add 1 and 2 and the result goes in 1 6 | 2 r2, $5 ;increment r2 by 5 7 | 6 r3, $99 ;move 99 into r3 8 | 7 r4, r3 ;move r3 into r4 9 | 11 r4 ;print r4 10 | 27 ;exit -------------------------------------------------------------------------------- /Sample Programs/scott3.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $99 ;move 99 into r1 2 | 4 r1 ;push r1 onto the stack 3 | 6 r1, $11 ;move 11 into r1 4 | 4 r1 ;push r1 onto the stack 5 | 1 r1 ;incr r1 6 | 35 r1 ;pop off the stack into r1 7 | 6 r3, $252 ;move 252 into r3 8 | 12 r3 ;print memory at r3 9 | 6 r3, $150 ;put 150 into r3 10 | 36 r3 ;pop off the stack into memory at r3 11 | 12 r3 ;print memory at r3 12 | 5 $88 ;push 88 onto the stack 13 | 5 $77 ;push 77 onto the stack 14 | 5 $66 ;push 66 onto the stack 15 | 35 r2 ;pop off the stack into r2 16 | 11 r2 ;print r2 17 | 35 r2 ;pop off the stack into r2 18 | 11 r2 ;print r2 19 | 35 r2 ;pop off the stack into r2 20 | 11 r2 ;print r2 21 | 27 ;exit -------------------------------------------------------------------------------- /Sample Programs/scott4.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $99 2 | 4 r1 3 | 6 r1, $11 4 | 4 r1 5 | 1 r1 6 | 35 r1 7 | 6 r3, $252 8 | 12 r3 9 | 6 r3, $150 10 | 36 r3 11 | 12 r3 12 | 5 $88 13 | 5 $77 14 | 5 $66 15 | 35 r2 16 | 11 r2 17 | 35 r2 18 | 11 r2 19 | 35 r2 20 | 11 r2 21 | 27 ; this is exit. -------------------------------------------------------------------------------- /Sample Programs/scott5.txt: -------------------------------------------------------------------------------- 1 | 6 r2, $255 ;move 255 into r2 2 | 6 r1, $244 ;move 244 into r1 3 | 9 r1, r2 ;move contents of r2 into memory pointed to by r1 (now address 244) 4 | 12 r1 ;print memory pointed to by r1 5 | 10 r2, r1 ;move memory pointed to by r1 into memory pointed to by r2 6 | 12 r2 ;print memory pointed to by r2 7 | 8 r3, r2 ;move memory pointed to by r2 into contents of r3 8 | 11 r3 ;print r3 9 | 6 r4, $4 ;move 4 into r4 10 | 33 r2, r4 ;clear memory at r2 for length r4 11 | 6 r6, $12 ;move 12 into r6 12 | 14 r6, $14 ;compare r6 and 14 13 | 14 r6, $11 ;compare r6 and 11 14 | 14 r6, $12 ;compare r6 and 12 15 | 6 r7, $1 ;jump over this exit 16 | 13 r7 17 | 27 ; this is exit. 18 | 11 r1 19 | 6 r6, $12 ;move 12 into r6 20 | 14 r6, $14 ;compare r6 and 14 21 | 16 r7 ; jlt over the exit 22 | 27 23 | 11 r1 24 | 6 r6, $19 ;move 12 into r6 25 | 14 r6, $14 ;compare r6 and 18 26 | 17 r7 ; jgt over the exit 27 | 27 28 | 11 r1 29 | 6 r6, $14 ;move 12 into r6 30 | 14 r6, $14 ;compare r6 and 18 31 | 18 r7 ; je over the exit 32 | 27 33 | 11 r1 34 | 27 -------------------------------------------------------------------------------- /Sample Programs/scott6.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $1 ;move 1 into r2 2 | 11 r1 3 | 1 r1 4 | 11 r1 5 | 1 r1 6 | 11 r1 7 | 1 r1 8 | 11 r1 9 | 6 r2, $43 ;jump 43 bytes forward 10 | 19 r2 11 | 1 r1 12 | 11 r1 13 | 6 r3, $150 ;move 150 into r3 14 | 6 r4, $11 ;move 11 into r4 15 | 9 r3, r4 ;move r4 into memory at r3 16 | 20 r3 17 | 27 ;ext 18 | 6 r1, $55 ;move 55 into r2 19 | 21 ;ret 20 | 11 r1 21 | 21 -------------------------------------------------------------------------------- /Sample Programs/scott7.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $1 ;move 1 into r2 2 | 6 r5, $11 ;move 11 into r5 3 | 25 r5 ;sleep 11 - because we sleep, this program must be launch with another app like idle to take up those sleep cycles 4 | 11 r1 5 | 1 r1 6 | 11 r1 7 | 1 r1 8 | 11 r1 9 | 1 r1 10 | 11 r1 11 | 6 r2, $43 ;jump 43 bytes forward 12 | 19 r2 13 | 1 r1 14 | 11 r1 15 | 6 r3, $150 ;move 150 into r3 16 | 6 r4, $11 ;move 11 into r4 17 | 9 r3, r4 ;move r4 into memory at r3 18 | 20 r3 19 | 27 ;ext 20 | 6 r1, $55 ;move 55 into r2 21 | 21 ;ret 22 | 11 r1 23 | 21 -------------------------------------------------------------------------------- /Sample Programs/scott8.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $1 ;move 1 into r1 2 | 23 r1 ;acquire lock #1 3 | 6 r2, $22 ;move 22 into r2 4 | 6 r3, $33 ;move 33 into r3 5 | 6 r4, $44 ;move 44 into r4 6 | 6 r5, $55 ;move 55 into r5 7 | 6 r6, $66 ;move 66 into r6 8 | 6 r2, $22 ;move 22 into r2 9 | 6 r3, $33 ;move 33 into r3 10 | 6 r4, $44 ;move 44 into r4 11 | 6 r5, $55 ;move 55 into r5 12 | 6 r6, $66 ;move 66 into r6 13 | 6 r2, $22 ;move 22 into r2 14 | 6 r3, $33 ;move 33 into r3 15 | 6 r4, $44 ;move 44 into r4 16 | 6 r5, $55 ;move 55 into r5 17 | 6 r6, $66 ;move 66 into r6 18 | 24 r1 19 | 27 -------------------------------------------------------------------------------- /Sample Programs/scott9.txt: -------------------------------------------------------------------------------- 1 | 6 r1, $1 ;move 1 into r1 2 | 6 r2, $22 ;move 22 into r2 3 | 6 r3, $33 ;move 33 into r3 4 | 6 r4, $44 ;move 44 into r4 5 | 6 r5, $55 ;move 55 into r5 6 | 6 r6, $66 ;move 66 into r6 7 | 6 r1, $1 ;move 1 into r1 8 | 30 r1 ;signal event #1 9 | 27 -------------------------------------------------------------------------------- /Sample Programs/testAll.bat: -------------------------------------------------------------------------------- 1 | call testAllocAndFree.bat 2 | call testCalls.bat 3 | call testEvents.bat 4 | call testJumps.bat 5 | call testLocks.bat 6 | call testMemoryProtection.bat 7 | call testRegisters.bat 8 | call testSharedMem.bat 9 | call testStack.bat 10 | call testMulti.bat 11 | -------------------------------------------------------------------------------- /Sample Programs/testAll.sh: -------------------------------------------------------------------------------- 1 | chmod +x *.bat 2 | /bin/bash testAllocAndFree.bat 3 | /bin/bash testCalls.bat 4 | /bin/bash testEvents.bat 5 | /bin/bash testJumps.bat 6 | /bin/bash testLocks.bat 7 | /bin/bash testMemoryProtection.bat 8 | /bin/bash testRegisters.bat 9 | /bin/bash testSharedMem.bat 10 | /bin/bash testStack.bat 11 | /bin/bash testMulti.bat 12 | -------------------------------------------------------------------------------- /Sample Programs/testAllocAndFree.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 512 scott13.txt -------------------------------------------------------------------------------- /Sample Programs/testCalls.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 512 scott6.txt 2 | -------------------------------------------------------------------------------- /Sample Programs/testEvents.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 1024 scott9.txt scott10.txt -------------------------------------------------------------------------------- /Sample Programs/testJumps.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 512 scott5.txt 2 | -------------------------------------------------------------------------------- /Sample Programs/testLocks.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 1568 scott8.txt scott8.txt scott8.txt -------------------------------------------------------------------------------- /Sample Programs/testMemoryProtection.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 512 scott4.txt 2 | -------------------------------------------------------------------------------- /Sample Programs/testMulti.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 5760 scott1.txt scott2.txt scott3.txt scott4.txt scott5.txt scott6.txt scott7.txt scott8.txt scott11.txt scott13.txt -------------------------------------------------------------------------------- /Sample Programs/testMultiSuper.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 7000 scott1.txt scott2.txt scott1.txt scott2.txt scott1.txt scott2.txt scott1.txt scott2.txt scott1.txt scott2.txt scott1.txt scott2.txt scott1.txt scott2.txt scott1.txt scott2.txt -------------------------------------------------------------------------------- /Sample Programs/testRegisters.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 1024 scott1.txt scott3.txt 2 | -------------------------------------------------------------------------------- /Sample Programs/testSharedMem.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 1024 scott11.txt scott12.txt -------------------------------------------------------------------------------- /Sample Programs/testStack.bat: -------------------------------------------------------------------------------- 1 | TinyOSCore.exe 512 scott3.txt 2 | -------------------------------------------------------------------------------- /TinyOS.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26621.2 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1C4F21C7-9F73-44AB-BABA-37B63FD55C88}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TinyOSCore", "src\TinyOSCore\TinyOSCore.csproj", "{47BD5898-A552-42BC-86C3-231E04FB84DD}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7C405F39-2520-4BEE-90BC-FDBD4FFD46B7}" 11 | ProjectSection(SolutionItems) = preProject 12 | BuildAndRunAllTests.bat = BuildAndRunAllTests.bat 13 | BuildAndRunAllTests.sh = BuildAndRunAllTests.sh 14 | LICENSE = LICENSE 15 | originalassignment.md = originalassignment.md 16 | readme.md = readme.md 17 | EndProjectSection 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sample Programs", "Sample Programs", "{0B333DF1-4A80-4442-BBF7-78AD4BA25AC3}" 20 | ProjectSection(SolutionItems) = preProject 21 | Sample Programs\idle-n.txt = Sample Programs\idle-n.txt 22 | Sample Programs\idle.txt = Sample Programs\idle.txt 23 | Sample Programs\prog1.txt = Sample Programs\prog1.txt 24 | Sample Programs\prog2.txt = Sample Programs\prog2.txt 25 | Sample Programs\prog3.txt = Sample Programs\prog3.txt 26 | Sample Programs\readme.txt = Sample Programs\readme.txt 27 | Sample Programs\scott1.txt = Sample Programs\scott1.txt 28 | Sample Programs\scott10.txt = Sample Programs\scott10.txt 29 | Sample Programs\scott11.txt = Sample Programs\scott11.txt 30 | Sample Programs\scott12.txt = Sample Programs\scott12.txt 31 | Sample Programs\scott13.txt = Sample Programs\scott13.txt 32 | Sample Programs\scott2.txt = Sample Programs\scott2.txt 33 | Sample Programs\scott3.txt = Sample Programs\scott3.txt 34 | Sample Programs\scott4.txt = Sample Programs\scott4.txt 35 | Sample Programs\scott5.txt = Sample Programs\scott5.txt 36 | Sample Programs\scott6.txt = Sample Programs\scott6.txt 37 | Sample Programs\scott7.txt = Sample Programs\scott7.txt 38 | Sample Programs\scott8.txt = Sample Programs\scott8.txt 39 | Sample Programs\scott9.txt = Sample Programs\scott9.txt 40 | Sample Programs\testAll.bat = Sample Programs\testAll.bat 41 | Sample Programs\testAll.sh = Sample Programs\testAll.sh 42 | Sample Programs\testAllocAndFree.bat = Sample Programs\testAllocAndFree.bat 43 | Sample Programs\testCalls.bat = Sample Programs\testCalls.bat 44 | Sample Programs\testEvents.bat = Sample Programs\testEvents.bat 45 | Sample Programs\testJumps.bat = Sample Programs\testJumps.bat 46 | Sample Programs\testLocks.bat = Sample Programs\testLocks.bat 47 | Sample Programs\testMemoryProtection.bat = Sample Programs\testMemoryProtection.bat 48 | Sample Programs\testMulti.bat = Sample Programs\testMulti.bat 49 | Sample Programs\testMultiSuper.bat = Sample Programs\testMultiSuper.bat 50 | Sample Programs\testRegisters.bat = Sample Programs\testRegisters.bat 51 | Sample Programs\testSharedMem.bat = Sample Programs\testSharedMem.bat 52 | Sample Programs\testStack.bat = Sample Programs\testStack.bat 53 | EndProjectSection 54 | EndProject 55 | Global 56 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 57 | Debug|Any CPU = Debug|Any CPU 58 | Release|Any CPU = Release|Any CPU 59 | EndGlobalSection 60 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 61 | {47BD5898-A552-42BC-86C3-231E04FB84DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 62 | {47BD5898-A552-42BC-86C3-231E04FB84DD}.Debug|Any CPU.Build.0 = Debug|Any CPU 63 | {47BD5898-A552-42BC-86C3-231E04FB84DD}.Release|Any CPU.ActiveCfg = Release|Any CPU 64 | {47BD5898-A552-42BC-86C3-231E04FB84DD}.Release|Any CPU.Build.0 = Release|Any CPU 65 | EndGlobalSection 66 | GlobalSection(SolutionProperties) = preSolution 67 | HideSolutionNode = FALSE 68 | EndGlobalSection 69 | GlobalSection(NestedProjects) = preSolution 70 | {47BD5898-A552-42BC-86C3-231E04FB84DD} = {1C4F21C7-9F73-44AB-BABA-37B63FD55C88} 71 | EndGlobalSection 72 | GlobalSection(ExtensibilityGlobals) = postSolution 73 | SolutionGuid = {EC60F6D1-76C5-4C77-9BA8-D10F577809EC} 74 | EndGlobalSection 75 | EndGlobal 76 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # ASP.NET Core 2 | # Build and test ASP.NET Core web applications targeting .NET Core. 3 | # Add steps that run tests, create a NuGet package, deploy, and more: 4 | # https://docs.microsoft.com/vsts/pipelines/languages/dotnet-core 5 | 6 | pool: 7 | vmImage: 'Ubuntu 16.04' 8 | 9 | variables: 10 | buildConfiguration: 'Release' 11 | 12 | steps: 13 | - script: dotnet build --configuration $(buildConfiguration) 14 | displayName: 'dotnet build $(buildConfiguration)' 15 | -------------------------------------------------------------------------------- /originalassignment.md: -------------------------------------------------------------------------------- 1 | # CST 352 Operating systems final project spec 2 | 3 | The goal of this project is to write a virtual operating system for an abstract machine to provide the following services. The details of the abstract machine will be provided below. 4 | 5 | - Load and unload programs. 6 | - Allocate and deallocate virtual memory. 7 | - Provide I/O services. 8 | - These will just be standard I/o input. 9 | - Provide services for scheduling processes. 10 | - Based on priority. 11 | - Based on time cycles expiring. 12 | - Based on resources. 13 | - Provide services for mutual exclusion and synchronization. 14 | - Semaphores. 15 | - Locks( mutexes ). 16 | - Events. 17 | 18 | ## Changes made on 4/8/2002 19 | 20 | The following features are mandatory. Mandatory implies these features must be implemented and fully functional. If some or all of the features are not working as specified, the grade is left to the instructor's subjective decisions. This feature set is called the BASE FEATURE SET in this document. 21 | 22 | - Process scheduling based on priority. 23 | - Process scheduling based on time quantum expiration is optional. 24 | - This implies that the current running process continues to run until it exits or tries to acquire a resource that is currently held by another process. 25 | - The functionality for Sleep is mandatory. 26 | - Provide output services. (Print. This is used to verify the functionality of the program ). 27 | - Provide mutual exclusion facilities. Minimally locks must be implemented. 28 | - An idle process is required. This process continues to run until time elapses for another process to wake up. 29 | - On a process exit. 30 | - All the memory that still belongs to the process MUST be clean deallocated and MUST be made available for other processes. 31 | - All internal OS structures used for the process(PCB..) must be released as well. 32 | - If the process holds locks when it exits, the lock MUST be marked as not acquired. 33 | - This implies any process waiting for this lock MUST now be made eligible to run. 34 | - These features, if implemented completely, account for 65% of the total grade for the class. 35 | 36 | ## Changes made on 05/06/2002 37 | 38 | The following features may be implemented, in addition to the above, for an additional 35% grade. This implies that if the above mandatory features and these features are implemented completely and verified to be functionally complete, the student SHALL receive the full grade of 100% for the class. The mandatory features are the minimum set of features needed. Students are strongly advised to get their mandatory features working before even venturing into these features. Students MUST clearly indicate at the time of submission what features they implemented. This feature set is KNOWN AS THE EXTENDED FEATURE SET in this document. 39 | 40 | - Implement dynamic memory allocation features. 41 | - Alloc and FreeMemory MUST be implemented. 42 | - Implement virtual memory using dynamic paging. 43 | - Each process's memory is now classified as virtual memory. 44 | - Each process has its own set of page tables that map its virtual memory to physical memory. 45 | - A process may incur page faults when it tries to access memory it currently does not own or does not have in memory. 46 | - Page size for the page tables can be set to 4 bytes or taken as an input to the OS command line arguments. 47 | - Normal data files may be used to store the unused state of a process. 48 | - Each process may have its own file for paging or may share a file. 49 | - OS code must service page faults and handle them properly. 50 | - Page tables can either grow in size or be restricted to a fixed size. 51 | - The former is preferable although both will be considered as good. 52 | 53 | The following are the list of opcodes that are minimally needed for the above features. The instructor SHALL use only these opcodes in his sample programs in order to test students' projects. It is left up to the students to choose additional opcodes to implement if they find them interesting. 54 | 55 | ## Opcodes 56 | 57 | | Opcode | BASE FEATURE SET | EXTENDED FEATURE SET | 58 | | --- | --- | --- | 59 | | Incr | x | x | 60 | | Addi | x | x | 61 | | movmr | x | x | 62 | | movmm | x | x | 63 | | movrm | x | x | 64 | | printr | x | x | 65 | | printm | x | x | 66 | | AcquireLock | x | x | 67 | | ReleaseLock | x | x | 68 | | Alloc | | x | 69 | | FreeMemory | | x | 70 | | Sleep | x | x | 71 | | MemoryClear | | x | 72 | | Exit | x | x | 73 | | movi | x | x | 74 | | movr | x | x | 75 | 76 | The project will implement a virtual operating system. The term virtual in this context implies an operating system that will run on top of a standard platform. 77 | 78 | - Either a standard PC with Windows or Linux platform is sufficient. 79 | - Any standard C/C++/Java compiler may be used to implement the operating system. 80 | - Since there is no real hardware here, the operating system provides the above services + executes the programs themselves. 81 | - In this sense, the operating system is both the system and the hardware , all in one. It interprets the programs by itself( similar to the Java virtual machine). 82 | 83 | ## Definition of the abstract machine. 84 | 85 | The machine used for this project will be an abstract one. Abstract implies there is no real hardware (CPU+ chipset + hardwired logic) needed to implement this. Instead, it will be emulated in software. The machine has the following details. The abstract machine is a 32-bit machine which implies all addresses are 32-bits and registers are 32-bits as well. 86 | 87 | - It has 10 general purpose registers. 88 | - Each register is 32-bits wide and can store any information. 89 | - They are addressed as 1 through 10 in the opcodes for this machine. 90 | - Register 10 is also the stack pointer register. 91 | - Always contains the top of the stack. 92 | - Grows towards lower addresses. 93 | - Pushing decrements stack pointer. Popping increments it. 94 | - Only 32-bit quantities may be pushed or popped. 95 | - Only the full-registers may be addressed. 96 | - This is unlike x86 where a 32-bit register may be addressed by its full 32-bit , 16-bit or 8-bit portions. 97 | - The abstract machine has 2 bit flag registers. 98 | - SF is the sign flag. This is set when any comparison of 2 quantities results in a sign extension. 99 | - ZF is the sign flag. This is set when any comparison of 2 quantities results in a zero( both quantities are equal ). 100 | - The instruction pointer register is special and is 32-bits wide. 101 | - Not accessible to the programmer. 102 | - Modified when the program executes. 103 | - Must be saved by the operating system on function calls and context switches. 104 | - Also known as eip in this document. 105 | - The abstract machine has the following opcodes. Since the intent of this project is to teach Operating system design and implementation, the machine is not complete in the sense that it does not provide a full repertoire of instructions (similar to x86 or other architectures). Each opcode is exactly 1 byte long and is of the following format. 106 | - <opcode> <argument 1> <argument 2> .. 107 | - All instructions are multiples of bytes. 108 | - All instructions take exactly one clock cycle to execute, independent of the actual operation of the instruction. 109 | - Context-switches only happen on instruction boundaries. 110 | - Constants are indicated by the operator $ in front of them. 111 | - Registers are indicated by r1 … r10. 112 | - The stack pointer (register 10) has another name for it which is sp. 113 | 114 | | Opcode | Value(decimal) | Format | 115 | | --- | --- | --- | 116 | | Incr | 1 | incr r1(increment value of register 1 by 1 ). | 117 | | Addi | 2 | addi r1,$1 is the same as incr r1 | 118 | | addr | 3 | Addr r1, r2( r1 <= r1 + r2 ). | 119 | | Pushr | 4 | Pushr rx (pushes contents of register x onto stack. Decrements sp by 4 ). | 120 | | Pushi | 5 | Pushi $x . pushes the constant x onto stack. Sp is decremented by 4 after push. | 121 | | Movi | 6 | Movi rx, $y. rx <= y | 122 | | Movr | 7 | Movr rx, ry ; rx <= ry | 123 | | Movmr | 8 | Movmr rx, ry ; rx <= [ry] | 124 | | Movrm | 9 | Movrm rx,ry; [rx] <= ry | 125 | | Movmm | 10 | Movmm rx, ry [rx] <= [ry] | 126 | | Printr | 11 | Printr r1 ; displays contents of register 1 | 127 | | Printm | 12 | Printm r1; displays contents of memory whose address is in register 1. | 128 | | Jmp | 13 | Jmp r1; control transfers to the instruction whose address is r1 bytes relative to the current instruction. R1 may be negative. | 129 | | Cmpi | 14 | Cmpi rx, $y; subtract y from register rx. If rx < y, set sign flag. If rx > y, clear sign flag. If rx == y , set zero flag. | 130 | | Cmpr | 15 | The same as cmpi except now both operands are registers. | 131 | | Jlt | 16 | Jlt rx; if the sign flag is set, jump to the instruction whose offset is rx bytes from the current instruction. | 132 | | Jgt | 17 | Jgt rx; if the sign flag is clear, jump to the instruction whose offset is rx bytes from the current instruction | 133 | | Je | 18 | Je rx; if the zero flag is clear, jump to the instruction whose offset is rx bytes from the current instruction. | 134 | | Call | 19 | Call r1; call the procedure at offset r1 bytes from the current instruction. The address of the next instruction to execute after a return is pushed on the stack. | 135 | | Callm | 20 | Callm r1; call the procedure at offset [r1] bytes from the current instruction. The address of the next instruction to execute after a return is pushed on the stack. | 136 | | Ret | 21 | Pop the return address from the stack and transfer control to this instruction. | 137 | | Alloc | 22 | Alloc r1, r2; allocate memory of size equal to r1 bytes and return the address of the new memory in r2. If failed, r2 is cleared to 0. | 138 | | AcquireLock | 23 | AcquireLock r1; Acquire the operating system lock whose # is provided in the register r1. If the lock is invalid, the instruction is a no-op. | 139 | | ReleaseLock | 24 | Releaselock r1; release the operating system lock whose # is provided in the register r1; if the lock is not held by the current process, the instruction is a no-op. | 140 | | Sleep | 25 | Sleep r1; Sleep the # of clock cycles as indicated in r1. Another process or the idle process must be scheduled at this point. If the time to sleep is 0, the process sleeps infinitely. | 141 | | SetPriority | 26 | SetPriority r1; Set the priority of the current process to the value in register r1; See priorities discussion in Operating system design | 142 | | Exit | 27 | Exit. This opcode is executed by a process to exit and be unloaded. Another process or the idle process must now be scheduled. | 143 | | FreeMemory | 28 | FreeMemory r1; Free the memory allocated whose address is in r1. | 144 | | MapSharedMem | 29 | MapSharedMem r1, r2; Map the shared memory region identified by r1 and return the start address in r2. | 145 | | SignalEvent | 30 | SignalEvent r1; Signal the event indicated by the value in register r1. | 146 | | WaitEvent | 31 | WaitEvent r1; Wait for the event in register r1 to be triggered. This results in context-switches happening. | 147 | | Input | 32 | Input r1; read the next 32-bit value into register r1. | 148 | | MemoryClear | 33 | MemoryClear r1, r2; set the bytes starting at address r1 of length r2 bytes to zero. | 149 | | TerminateProcess | 34 | TerminateProcess r1; terminate the process whose id is in the register r1. | 150 | | Popr | 35 | pop the contents at the top of the stack into register rx which is the operand. Stack pointer is decremented by 4. | 151 | | popm | 36 | pop the contents at the top of the stack into the memory operand whose address is in the register which is the operand. Stack pointer is decremented by 4. | 152 | 153 | ## Operating system design goals 154 | 155 | The operating system designed in this project must provide the following services to programs written for this operating system. 156 | 157 | - Provide virtual memory services. 158 | - All processes will have page tables allocated by the operating system. 159 | - OS will detect invalid memory accesses and terminate the processes. 160 | - Terminating processes means the operating system will display an error message on the console and choose the next process to execute. 161 | - Processes can allocate any amount of memory subject to the resources available. 162 | - Processes only manipulate virtual addresses. 163 | - Provide inter-process synchronization mechanisms. 164 | - OS provides mutexes for a process to lock out other processes while manipulating critical shared structures. 165 | - For this project, the OS comes with (or is preconfigured with) 10 locks, each identified by the numbers 1 through 10. 166 | - The OS does not provide any services for processes to allocate their own critical sections. 167 | - The instructions AcquireLock and ReleaseLock allow a process to acquire and release the OS provided locks. 168 | - The locks provided by the OS are meant for use by application processes to protect themselves while manipulating shared-critical structures. 169 | - Provide scheduling services. 170 | - Each process is scheduled independently. 171 | - Processes are single-threaded. 172 | - Only one process is running at a time. 173 | - A process once scheduled(means it starts running) continues to run until the following happens. 174 | - It exits( by executing opcode Exit ). 175 | - It sleeps for some time( by executing opcode Sleep ). 176 | - It acquires a lock already acquired by someone else. 177 | - It accesses an address which requires a page fault and there is not enough memory available. Once another process frees up some memory, this process is scheduled again. 178 | - Waits on an event to be signaled by another process. 179 | - Its time quantum runs out. 180 | - Each process has a time quantum. A time quantum is the # of clock cycles it is allowed to run before it is scheduled out. 181 | - Provide memory-mapping services. 182 | - This OS provides built-in or preconfigured shared memory regions of size 10000 bytes each for a total of 10 memory regions, each indexed by the number 1 thru 10 respectively. 183 | - Processes may map any of them into their address spaces by using the opcode MapSharedMem and passing the # of the shared memory region. 184 | - Processes may use this facility to share memory and perform inter-process communication. 185 | - Provide I/O services. 186 | - Processes may use these I/O services to print out values to the console. 187 | - Processes may use input services to read values from the console as well. 188 | 189 | ## Project requirements 190 | 191 | Where the word MUST is used, the features are required in order for the student to receive full grade for the project. The word OS is used to describe the implementation of this operating system. Where the word MAY is used, the feature is optional. 192 | 193 | - Students MAY use C/C++ or Java to write the operating system. 194 | - If C/C++, students MUST use Visual C++ 5.0 or 6.0. 195 | - If Java, the code must be compilable using Sun's JDK 2.0 or greater. 196 | - The OS must be compilable without any errors. 197 | - Any errors in compilation results in 0 grade. 198 | - The students are responsible for providing any readme or any other documentation to the instruction in order to evaluate the project. 199 | - The program must be compilable on windows platforms. 200 | - Warnings MUST be minimized. 201 | - If the operating system code crashes, the grade provided is based on the instructor's subjective decisions. 202 | - The instructor will evaluate the project using sample files that he will provide later in the class. 203 | - The team ( of 2 students ) is graded as a whole for the project. 204 | - Any differences between the team members( if any ) must be resolved by the members themselves. 205 | - It is strongly advised that students team up for this project. 206 | 207 | ## Project features 208 | 209 | - The OS must contain an interpreter that understands the above opcodes. 210 | - The OS must be invoked as follows. 211 | - OS <# of bytes> <program1.txt> <program2.txt> ….. 212 | - Each programx.txt contains the code for the programs to be loaded and executed. 213 | - The number of bytes for all programs that can be loaded(including code, data, heap and stack) must be provided in the first parameter. 214 | - This # does not include the # of bytes the OS will itself need to keep track of information about each process such as process blocks. 215 | - The OS will provide the following services. 216 | - Loader to load programs of the above type. 217 | - The students may assume that the instructor will provide programs with correct opcodes. 218 | - This is the not the same as rogue programs. 219 | - Scheduler for scheduling programs. 220 | - Maintain process context(using process context blocks or otherwise ). 221 | - The time quantum a process is limited to running before it is scheduled out is 10 clock cycles. 222 | - All process context (including all registers, page tables) MUST be stored in the process context block. 223 | - An idle process must be provided that runs if no other process is eligible to run. 224 | - The idle process will be provided in a separate file called idle.txt. 225 | - The idle process just sits in a tight loop printing out the value 20. 226 | - The idle process only has a quantum of 5 clock cycles. 227 | - The idle process never exits. 228 | - The scheduler always schedules the highest-priority process eligible to run. 229 | - There are 32-priorities in the OS. 230 | - Processes with higher priorities run until they give up control, exit or are terminated. 231 | - The bigger the priority #, the higher the priority for the process. 232 | - A process may adjust its own priority by invoking the opcode SetPriority. 233 | - In addition to these queues, the scheduler MUST implement queues for blocking & other types of processes. 234 | - Virtual memory manager. 235 | - Each process MUST only access virtual addresses. 236 | - When a process is loaded, the memory manager MUST construct its page tables in the appropriate fashion. 237 | - Every memory access by each process goes through page tables and accesses the real memory. 238 | - This is true for all addresses(code, data, stack and heap). 239 | - The details of breaking down a virtual address to a physical address using page tables will be provided in the class. 240 | - If a process accesses an address it does not own, the OS must print an error message with the values of the registers of the process at the time the problem occurred, terminate the process and schedule another one. 241 | - Processes sharing memory. 242 | - A process may map the OS provided shared memory region into its own address space using the MapSharedMem opcode. 243 | - This allows 2 or more processes to share memory. 244 | - The exact usage of these memory regions is left to the processes themselves. 245 | - Process virtual memory. 246 | - A process's memory map is divided into 4 regions. 247 | - Code. This is the region containing the instructions with some combination of the above opcodes. 248 | - Stack. This is the region where the program may store temporary variables. When a function is called, the interpreter stores the return address here as well. 249 | - When a program is loaded, it is provided a stack of 4k bytes. 250 | - The stack grows and shrinks depending on usage. 251 | - Global data. 252 | - When a program is loaded, it is provided a memory region called global data of size 4k bytes. The contents are initialized to 0. Please see "process initial state" for more information. 253 | - Heap. 254 | - Heap is the portion of the address space that the process can allocate dynamically using the Alloc and FreeMemory opcodes. 255 | - Process initial state. 256 | - A program becomes a process when it is loaded by the operating system. 257 | - When a process is created, its registers have the following state. 258 | - It is the responsibility of the operating system to set it up this way. 259 | - R1 – r7 are undefined. 260 | - Register r8 contains the id of the process. 261 | - R9 contains the virtual address of the global data region( of length 4k bytes ). 262 | - R10 (sp) is set to the top of the stack. 263 | - Growing the stack implies it grows towards lower addresses. 264 | - The instruction pointer(eip) contains the value 0 essentially translating(via page tables) to the first instruction in the program to be executed. 265 | - Process exiting. 266 | - A process may exit due to any of the following reasons. 267 | - It invokes the Exit opcode. 268 | - It performs an illegal operation(it access a memory location it does not own). 269 | - Another process kills this process using the TerminateProcess opcode. 270 | - It is left to the individual processes to find the id of the other processes. 271 | - Admittedly, the security is very weak(allowing any process to terminate any other process). 272 | - When a process exits for whatever reason, your OS must perform the following. 273 | - Display the # of page faults, the # of context switches it went through, the # of clock cycles it consumed. 274 | - Process synchronization. 275 | - The OS provides 10 mutexes or locks. 276 | - The locks are numbered through 1 to 10. 277 | - A process acquires the lock using AcquireLock. 278 | - If another process already owns the lock, the current process is put to sleep on the wait queue. 279 | - If a process X tries to acquire the same lock Y two or more times, it is a no-operation. In short, the process MUST not deadlock against itself. 280 | - A processes releases a lock it is currently holding via ReleaseLock. 281 | - This MUST make only one process(the highest priority process currently waiting) eligible to be scheduled. 282 | - This implies that other processes also blocking for this lock will not be scheduled. Only the highest priority process will be scheduled(if any). 283 | - The process releasing the lock might be scheduled out because the process now eligible to run may have a higher priority than the one releasing the lock. 284 | - The OS must take into account priority inversion. 285 | - It is possible that a higher-priority process is blocked for a resource that is currently owned by a lower-priority process. 286 | - In this case, the OS must bump up the priority of the lower priority process to that of the blocked process and keep it this way until the lower-priority process releases the resources. 287 | - If a process holding a lock exits or is terminated for whatever reason, 288 | - The lock MUST be considered not held and another process waiting(if any) should be made eligible for scheduling. 289 | - Events. 290 | - Events, unlike locks, are provided for process synchronization. 291 | - They allow one process to notify another process the occurrence of an event. 292 | - The OS provides built-in events for a total of 10. They are numbered 1 to 10. 293 | - Any event is in one of 2 states. 294 | - Signaled. This implies any process waiting on it is eligible to run now. 295 | - An event is set to signaled when a process invokes the SignalEvent opcode. 296 | - Non-signaled. 297 | - This is the initial state of all events when the OS boots up(so to speak). 298 | - When a process that is waiting on it becomes eligible to run, the event becomes non-signaled allowing another process to wait on it. 299 | - There is no concept of ownership of an event. 300 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Scott Hanselman's Tiny Virtual Operating System and Abstract Machine in C# 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/vb8k3n8e7y77kijw?svg=true)](https://ci.appveyor.com/project/ScottHanselman/tinyos) 4 | 5 | ## What is this? 6 | 7 | This was the final project for my CST352-Operating Systems class at [OIT](http://www.oit.edu) (Oregon Institute of Technology). The requirements, exactly as they were given to me by the teacher, are in [originalassignment.md](originalassignment.md). The goal of this project was to write a small _virtual_ operating system for an _abstract_ machine that provides a number of basic OS-like services like: 8 | 9 | - Virtual Memory, Demand Paging 10 | - Input/Output 11 | - Memory Protection, Shared Memory 12 | - Registers, Stack, Data, Heap, etc 13 | - Jump instructions for calling "Functions" 14 | - And so on… 15 | 16 | This is a cute, fun, interesting and _completely useless thing_. So, don't get your hopes up that you'll get actual work done with it. ­ 17 | 18 | It's neat however, as it is a study on how I solved a particular problem (this assignment) given a 10 week semester. I was the only student to use C#, and I finished it in 4 weeks, leaving 6 weeks to chill and watch the other students using Java and C++ do their thing. 19 | 20 | It's also ironic because I used a high-level OO language like C# to deal with a minute concept like an "Operating System" the might have 256 bytes (bytes, not Kbytes) of memory. 21 | 22 | During this process I exercised a good and interesting chunk of the C# language and the .NET Framework. There are some very silly things like the OS's implementation of virtual memory swapping out memory pages as XML. I might take an array of 4 bytes and make an XML file to help them. I hope the irony isn't lost on you. I also commented all the C# with XML and built an [ndoc](http://ndoc.sf.net) MSDN style help file. So, you might just use this as a learning tool and a pile of sample code. 23 | 24 | One Note: I'm an ok programmer, but understand that I whipped this out in several 3am coding sessions, as well as during lectures in class. This is NOT fabulous code, and should be looked upon as interesting, not gospel. I'm sure I've done some very clever things in it, and for each clever thing, there's _n_ stupid things. I'll leave the repair of these stupid things as an exercise to the reader. 25 | 26 | Of course, you'll need the .NET Framework to run this, but to really have fun debugging it and stepping through the code you'll need VS.NET. Go read the code and final\_project.doc and enjoy! 27 | 28 | Scott Hanselman 29 | 30 | [scott@hanselman.com](mailto:scott@hanselman.com) 31 | 32 | May 2002 33 | 34 | ## What's the jist? 35 | 36 | I started out with some basic OO constructs, a static CPU object, an OS object, objects for Processes, Instructions, etc. A lot of this information is in the Help (CHM) File. Basically it's setup like this: 37 | 38 | - *CPU Object* – responsible for physical memory (which may be smaller than addressable memory) holding CPU registers and fetching program opcodes and translating them into SystemCalls in the OS, etc. 39 | - *OS Object* – Most of the work is here. It has a MemoryManager object who is responsible for the translations between Addressable (Virtual) memory, Process memory and Physical Memory. All Processes access memory from _their_ point of view…they never talk to "physical memory" (Which is just an array of bytes in the CPU object) 40 | The scheduler is in the OS object as well as locks, events, and all that good stuff. Each of the 36 opcodes are implemented here and treated as C# delegates…well, now I'm telling you all the good stuff…read the code! 41 | - *Program Object* - represents a collection of instructions. Responsible for parsing the files off disk and holding them. 42 | - *Process Object* – different than Program as it's an actual running process in the TinyOS. There can be more than one instance of a Process for each Program. (You can run the same program twice, etc) It has a ProcessControlBlock containing Process specific registers, etc. 43 | - *EntryPoint Class* – Contains main() and "bootstraps" the whole thing. 44 | 45 | The OS is made up, the CPU is made up, the opCodes are made up. This is an exercise to learn about Operating System concepts, and it's not meant to look or act like any specific OS or system. 46 | 47 | ## What does a Program look like? 48 | 49 | Here's an example program, specifically the "idle" loop. The idle loop is a process that never ends, it just prints out "20" over and over. I use it to keep the clock running when all the other processes are sleeping. 50 | ``` 51 | 6 r4, $0 ;move 0 into r4 52 | 26 r4 ;lower our priority TO 0 53 | 6 r1, $20 ;move 20 into r1 54 | 11 r1 ;print the number 20 55 | 6 r2, $-19 ;back up the ip 19 bytes 56 | 13 r2 ;loop forever (jump back 19) 57 | ``` 58 | Programs consist of: 59 | 60 | ``` 61 | Opcode, [optional param], [other optional param] ;optional comment 62 | ``` 63 | 64 | So, if we look at: 65 | 66 | ``` 67 | 6 r4, $0 ;move 0 into r4 68 | ``` 69 | 70 | We see that it's operation 6, which is Movi or "Move Immediate." It moves a constant value into one of our 10 registers. The first param is r4, indicating register 4. The second param is $0. The "$" indicates a constant. So we are the value 0 into register #4. Just like x86 assembly – only not at all.  71 | 72 | So if you look at the comments for this app you can see that it loops forever. 73 | 74 | ## How do run Program(s) 75 | 76 | Usage: 77 | ``` 78 | OS membytes [files] 79 | ``` 80 | For example: 81 | ``` 82 | OS 1568 prog1.txt prog2.txt prog3.txt prog1.txt idle.txt 83 | ``` 84 | This command line would run the OS with 1568 bytes of virtual (addressable) memory and start up 5 processes. Note that Prog1.txt is specified twice. That means it will have two separate and independent running processes. We also specified the forever running idle.txt. Use CTRL-C to break. The OS has operations for shared memory, locks, and events, so you can setup rudimentary inter-module communication. 85 | 86 | ## Why should I care? 87 | 88 | There are 13 other sample apps you can play with. The OS is most interesting when you run it with multiple apps. You can mess with OS.config to setup the amount of memory available to each process, the whole system's physical memory, memory page size etc. 89 | 90 | It's interesting from an OS theory point of view if you think about the kinds of experiments you can do like lowering physical memory to something ridiculous like 32 bytes. That will increase page faults and virtual memory swapping. So, the OS can be tuned with the config file. 91 | 92 | ## What are the options in OS.config? 93 | 94 | It is certainly possible to give the OS a bad config, like more physical memory than addressable, or a page size that is the same size as physical memory. But, use common sense and play. I've setup it up with reasonable defaults. 95 | 96 | Here's a sample OS.config file. The Config has to be in the same directory as the OS.exe. Take a look at the included OS.config, as it has additional XML comments explaining each option. 97 | ``` 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | ``` 116 | Of note are the Dumpxxx options. With all of these options set to false, the OS only outputs the bare minimum debug information. With them on (I like to have the all on) you'll be able to see the results of each instruction and how they affect registers, physical memory, etc. You'll see physical memory pages swap to disk, memory fragmentation, the instruction pointer increment, and processes take turns on the CPU. 117 | 118 | Be sure to turn up the size of screen buffer (usually under "Layout" in the Properties Dialog of your command prompt) to something like 3000 or 9999. This way you'll be able to scroll back and look at the details of your run. 119 | ``` 120 | OS 512 prog1.txt > output.txt 121 | ``` 122 | You might also try something like this to create a log file, or modify the source to include logging! 123 | 124 | ## What are the available OpCodes? 125 | 126 | These are also printed and explain in the Help File as well as Final\_Project.doc. When writing a program you use the value, not the text name of the opcode. So, you'd say `2 r1, $1` and **NOT** `addi r1, $1`. 127 | 128 | | Opcode | Value(decimal) | Format | 129 | | --- | --- | --- | 130 | | Incr | 1 | incr r1(increment value of register 1 by 1 ). | 131 | | Addi | 2 | addi r1,$1 is the same as incr r1 | 132 | | addr | 3 | Addr r1, r2( r1 <= r1 + r2 ). | 133 | | Pushr | 4 | Pushr rx (pushes contents of register x onto stack. Decrements sp by 4 ). | 134 | | Pushi | 5 | Pushi $x . pushes the constant x onto stack. Sp is decremented by 4 after push. | 135 | | Movi | 6 | Movi rx, $y. rx <= y | 136 | | Movr | 7 | Movr rx, ry ; rx <= ry | 137 | | Movmr | 8 | Movmr rx, ry ; rx <= [ry] | 138 | | Movrm | 9 | Movrm rx,ry; [rx] <= ry | 139 | | Movmm | 10 | Movmm rx, ry [rx] <= [ry] | 140 | | Printr | 11 | Printr r1 ; displays contents of register 1 | 141 | | Printm | 12 | Printm r1; displays contents of memory whose address is in register 1. | 142 | | Jmp | 13 | Jmp r1; control transfers to the instruction whose address is r1 bytes relative to the current instruction. R1 may be negative. | 143 | | Cmpi | 14 | Cmpi rx, $y; subtract y from register rx. If rx < y, set sign flag. If rx > y, clear sign flag. If rx == y , set zero flag. | 144 | | Cmpr | 15 | The same as cmpi except now both operands are registers. | 145 | | Jlt | 16 | Jlt rx; if the sign flag is set, jump to the instruction whose offset is rx bytes from the current instruction. | 146 | | Jgt | 17 | Jgt rx; if the sign flag is clear, jump to the instruction whose offset is rx bytes from the current instruction | 147 | | Je | 18 | Je rx; if the zero flag is clear, jump to the instruction whose offset is rx bytes from the current instruction. | 148 | | Call | 19 | Call r1; call the procedure at offset r1 bytes from the current instruction. The address of the next instruction to execute after a return is pushed on the stack. | 149 | | Callm | 20 | Callm r1; call the procedure at offset [r1] bytes from the current instruction. The address of the next instruction to execute after a return is pushed on the stack. | 150 | | Ret | 21 | Pop the return address from the stack and transfer control to this instruction. | 151 | | Alloc | 22 | Alloc r1, r2; allocate memory of size equal to r1 bytes and return the address of the new memory in r2. If failed, r2 is cleared to 0. | 152 | | AcquireLock | 23 | AcquireLock r1; Acquire the operating system lock whose # is provided in the register r1. If the lock is invalid, the instruction is a no-op. | 153 | | ReleaseLock | 24 | Releaselock r1; release the operating system lock whose # is provided in the register r1; if the lock is not held by the current process, the instruction is a no-op. | 154 | | Sleep | 25 | Sleep r1; Sleep the # of clock cycles as indicated in r1. Another process or the idle process must be scheduled at this point. If the time to sleep is 0, the process sleeps infinitely. | 155 | | SetPriority | 26 | SetPriority r1; Set the priority of the current process to the value in register r1; See priorities discussion in Operating system design | 156 | | Exit | 27 | Exit. This opcode is executed by a process to exit and be unloaded. Another process or the idle process must now be scheduled. | 157 | | FreeMemory | 28 | FreeMemory r1; Free the memory allocated whose address is in r1. | 158 | | MapSharedMem | 29 | MapSharedMem r1, r2; Map the shared memory region identified by r1 and return the start address in r2. | 159 | | SignalEvent | 30 | SignalEvent r1; Signal the event indicated by the value in register r1. | 160 | | WaitEvent | 31 | WaitEvent r1; Wait for the event in register r1 to be triggered. This results in context-switches happening. | 161 | | Input | 32 | Input r1; read the next 32-bit value into register r1. | 162 | | MemoryClear | 33 | MemoryClear r1, r2; set the bytes starting at address r1 of length r2 bytes to zero. | 163 | | TerminateProcess | 34 | TerminateProcess r1; terminate the process whose id is in the register r1. | 164 | | Popr | 35 | pop the contents at the top of the stack into register rx which is the operand. Stack pointer is decremented by 4. | 165 | | popm | 36 | pop the contents at the top of the stack into the memory operand whose address is in the register which is the operand. Stack pointer is decremented by 4. | 166 | 167 | ## Known Issues/Things to Know 168 | 169 | - The OS will look in the current directory for files if no directory is specified. 170 | - Processes will be loaded and executed in the order they are specified on the command line. 171 | - There are two idle processes included. idle.txt will run with lowest priority and will print out 20. It will run forever. idle-n.txt will run for n loops (not cycles), specified in the code. As shipped, idle-n will run for 100 loops. 172 | - Redirecting OS output to a file is convenient: OS 1024 prog1.txt prog2.txt prog3.txt > output.txt 173 | - OS.config contains many debug flags that can be included to provide insight into non-debug program execution. 174 | - OS.config contains many options for configuration of memory. It IS possible to feed invalid values into this config file. For example, it's not valid to have a physical memory size larger than addressable memory, or a page size larger than addressable memory, etc. This behavior is appropriate, and is by design. 175 | - Setting DumpInstruction=true in OS.config will output the a debug print of the executing instruction and the current process id. 176 | - If an idle process (idle.txt, etc) isn't included, and all running processes sleep or block on a lock, the OS will spin forever looking for an eligible process to run, and will find none. CTRL-C will exit at this point. This behavior is per spec and by design. 177 | - The OS will create XML swap files in the current for each memory page swapped. These are cleaned up at startup, rather than shutdown, for purposes of exploration. 178 | - Batch files for testing purposes are included in this directory. 179 | -------------------------------------------------------------------------------- /src/TinyOSCore/CPU.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | using System; 35 | using System.Collections; 36 | using System.Configuration; 37 | using System.Diagnostics; 38 | 39 | namespace Hanselman.CST352 40 | { 41 | /// 42 | /// CPU is never instanciated, but is "always" there...like a real CPU. :) It holds 43 | /// and the . It also provides a mapping from s to SystemCalls in 44 | /// the . 45 | /// 46 | public abstract class CPU 47 | { 48 | /// 49 | /// The size of a memory page for this system. This should be a multiple of 4. Small sizes (like 4) will 50 | /// cause the system to thrash and page often. 16 is a nice compromise for such a small system. 51 | /// 64 might also work well. This probably won't change, but it is nice to be able to. 52 | /// This is loaded from Configuration on a call to 53 | /// 54 | public static uint pageSize = 0; 55 | 56 | /// 57 | /// The clock for the system. This increments as we execute each . 58 | /// 59 | public static uint clock = 0; 60 | 61 | /// 62 | /// The CPU's reference to the . This is set by the . 63 | /// 64 | public static OS theOS = null; 65 | 66 | /// 67 | /// Initialized our array that represents physical memory. Should only be called once. 68 | /// 69 | /// The size of physical memory 70 | public static void initPhysicalMemory(uint memorySize) 71 | { 72 | pageSize = uint.Parse(EntryPoint.Configuration["MemoryPageSize"]); 73 | 74 | uint newMemorySize = UtilRoundToBoundary(memorySize, CPU.pageSize); 75 | 76 | // Initalize Physical Memory 77 | physicalMemory = new byte[newMemorySize]; 78 | 79 | if (newMemorySize != memorySize) 80 | Console.WriteLine("CPU: Memory was expanded from {0} bytes to {1} bytes to a page boundary." + System.Environment.NewLine,memorySize, newMemorySize); 81 | } 82 | 83 | /// 84 | /// Here is the actual array of bytes that contains the physical memory for this CPU. 85 | /// 86 | internal static byte[] physicalMemory; 87 | 88 | /// 89 | /// We have 10 registers. R11 is the , and we don't use R0. R10 is the . So, that's 1 to 10, and 11. 90 | /// 91 | internal static uint[] registers = new uint[12]; //0 to 11 92 | 93 | /// 94 | /// We have a Sign Flag and a Zero Flag in a 95 | /// 96 | private static BitArray bitFlagRegisters = new BitArray(2,false); 97 | 98 | #region Public Accessors 99 | /// 100 | /// Public get/set accessor for the Sign Flag 101 | /// 102 | public static bool sf 103 | { 104 | get { return bitFlagRegisters[0]; } 105 | set { bitFlagRegisters[0] = value; } 106 | } 107 | 108 | /// 109 | /// Public get/set accessor for the Zero Flag 110 | /// 111 | public static bool zf 112 | { 113 | get { return bitFlagRegisters[1]; } 114 | set { bitFlagRegisters[1] = value; } 115 | } 116 | 117 | /// 118 | /// Public get/set accessor for Stack Pointer 119 | /// 120 | public static uint sp 121 | { 122 | get { return CPU.registers[10]; } 123 | set { CPU.registers[10] = value; } 124 | } 125 | 126 | /// 127 | /// Public get/set access for the CPU's Instruction Pointer 128 | /// 129 | public static uint ip 130 | { 131 | get { return CPU.registers[11]; } 132 | set { CPU.registers[11] = value; } 133 | } 134 | #endregion 135 | 136 | 137 | /// 138 | /// Takes the process id from the and the CPU's and 139 | /// gets the next from memory. The translates 140 | /// via an array of s and retrives a from 141 | /// and calls it. 142 | /// 143 | public static void executeNextOpCode() 144 | { 145 | // The opCode still is pointed to by CPU.ip, but the memory access is protected 146 | opCodeToSysCall((InstructionType)theOS.memoryMgr[theOS.currentProcess.PCB.pid,CPU.ip]); 147 | CPU.clock++; 148 | } 149 | 150 | /// 151 | /// The translates via an array of s and 152 | /// retrives a and calls it. 153 | /// 154 | /// An enum that maps to a 155 | public static void opCodeToSysCall(InstructionType opCode) 156 | { 157 | #region System Calls Map 158 | SystemCall[] sysCalls = 159 | { 160 | new SystemCall(theOS.Noop), //0 161 | 162 | new SystemCall(theOS.Incr), //1 163 | new SystemCall(theOS.Addi), //2 164 | new SystemCall(theOS.Addr), //3 165 | new SystemCall(theOS.Pushr), //4 166 | new SystemCall(theOS.Pushi), //5 167 | 168 | new SystemCall(theOS.Movi), //6 169 | new SystemCall(theOS.Movr), //7 170 | new SystemCall(theOS.Movmr), //8 171 | new SystemCall(theOS.Movrm), //9 172 | new SystemCall(theOS.Movmm), //10 173 | 174 | new SystemCall(theOS.Printr), //11 175 | new SystemCall(theOS.Printm), //12 176 | new SystemCall(theOS.Jmp), //13 177 | new SystemCall(theOS.Cmpi), //14 178 | new SystemCall(theOS.Cmpr), //15 179 | 180 | new SystemCall(theOS.Jlt), //16 181 | new SystemCall(theOS.Jgt), //17 182 | new SystemCall(theOS.Je), //18 183 | new SystemCall(theOS.Call), //19 184 | new SystemCall(theOS.Callm), //20 185 | 186 | new SystemCall(theOS.Ret), //21 187 | new SystemCall(theOS.Alloc), //22 188 | new SystemCall(theOS.AcquireLock), //23 189 | new SystemCall(theOS.ReleaseLock), //24 190 | new SystemCall(theOS.Sleep), //25 191 | 192 | new SystemCall(theOS.SetPriority), //26 193 | new SystemCall(theOS.Exit), //27 194 | new SystemCall(theOS.FreeMemory), //28 195 | new SystemCall(theOS.MapSharedMem), //29 196 | new SystemCall(theOS.SignalEvent), //30 197 | 198 | new SystemCall(theOS.WaitEvent), //31 199 | new SystemCall(theOS.Input), //32 200 | new SystemCall(theOS.MemoryClear), //33 201 | new SystemCall(theOS.TerminateProcess), //34 202 | new SystemCall(theOS.Popr), //35 203 | 204 | new SystemCall(theOS.Popm) //36 205 | }; 206 | #endregion 207 | 208 | Debug.Assert(opCode >= InstructionType.Incr && opCode <= InstructionType.Popm); 209 | 210 | SystemCall call = sysCalls[(int)opCode]; 211 | call(); 212 | } 213 | 214 | 215 | #region Dump Functions for debugging 216 | /// 217 | /// Dumps the values of as the currently sees it. 218 | /// 219 | public static void DumpRegisters() 220 | { 221 | if (bool.Parse(EntryPoint.Configuration["DumpRegisters"]) == false) 222 | return; 223 | 224 | Console.WriteLine("CPU Registers: r1 {0,-8:G} r6 {1,-8:G}",registers[1],registers[6]); 225 | Console.WriteLine(" r2 {0,-8:G} r7 {1,-8:G}",registers[2],registers[7]); 226 | Console.WriteLine(" r3 {0,-8:G} (pid) r8 {1,-8:G}",registers[3],registers[8]); 227 | Console.WriteLine(" r4 {0,-8:G} (data) r9 {1,-8:G}",registers[4],registers[9]); 228 | Console.WriteLine(" r5 {0,-8:G} (sp) r10 {1}",registers[5],registers[10]); 229 | Console.WriteLine(" sf {0,-8:G} ip {1}",CPU.sf,CPU.ip); 230 | Console.WriteLine(" zf {0,-8:G} ",CPU.zf); 231 | } 232 | 233 | /// 234 | /// Dumps the current for the current process at the current 235 | /// 236 | public static void DumpInstruction() 237 | { 238 | if (bool.Parse(EntryPoint.Configuration["DumpInstruction"]) == false) 239 | return; 240 | 241 | Console.WriteLine(" Pid:{0} {1} {2}",CPU.registers[8],(InstructionType)theOS.memoryMgr[theOS.currentProcess.PCB.pid,CPU.ip],(uint)theOS.memoryMgr[theOS.currentProcess.PCB.pid,CPU.ip]); 242 | } 243 | 244 | /// 245 | /// Dumps the content of the CPU's array. 246 | /// 247 | public static void DumpPhysicalMemory() 248 | { 249 | if (bool.Parse(EntryPoint.Configuration["DumpPhysicalMemory"]) == false) 250 | return; 251 | 252 | int address = 0; 253 | foreach (byte b in physicalMemory) 254 | { 255 | if (address == 0 || address%16==0) 256 | Console.Write(System.Environment.NewLine + "{0,-4:000} ", address); 257 | address++; 258 | if (b == 0) 259 | Console.Write("{0,3}","-"); 260 | else 261 | Console.Write("{0,3}",(int)b); 262 | if (address%4==0 && address%16!=0) Console.Write(" :"); 263 | } 264 | Console.WriteLine(); 265 | } 266 | #endregion 267 | 268 | #region Type Conversion and Utility Functions 269 | 270 | /// 271 | /// Pins down a section of memory and converts an array of bytes into an unsigned int () 272 | /// 273 | /// array of bytes to convert 274 | /// value of bytes as a uint 275 | public unsafe static uint BytesToUInt(byte[] BytesIn) 276 | { 277 | fixed(byte* otherbytes = BytesIn) 278 | { 279 | uint newUint = 0; 280 | uint* ut = (uint*)&otherbytes[0]; 281 | newUint = *ut; 282 | return newUint; 283 | } 284 | } 285 | 286 | /// 287 | /// Pins down a section of memory and converts an unsigned int into an array of ()s 288 | /// 289 | /// the uint to convert 290 | /// uint containing the value of the uint 291 | public unsafe static byte[] UIntToBytes(uint UIntIn) 292 | { 293 | //turn a uint into 4 bytes 294 | byte[] fourBytes = new byte[4]; 295 | uint* pt = &UIntIn; 296 | byte* bt = (byte*)&pt[0]; 297 | fourBytes[0] = *bt++; 298 | fourBytes[1] = *bt++; 299 | fourBytes[2] = *bt++; 300 | fourBytes[3] = *bt++; 301 | return fourBytes; 302 | } 303 | 304 | /// 305 | /// Utility function to round any number to any arbirary boundary 306 | /// 307 | /// number to be rounded 308 | /// boundary multiplier 309 | /// new rounded number 310 | public static uint UtilRoundToBoundary(uint number, uint boundary) 311 | { 312 | uint newNumber = (uint)(boundary * ((number / boundary) + ((number % boundary > 0) ? 1: 0))); 313 | return newNumber; 314 | } 315 | #endregion 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/TinyOSCore/EntryPoint.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | using System; 35 | using System.IO; 36 | using System.Text.RegularExpressions; 37 | using System.Configuration; 38 | using Microsoft.Extensions.Configuration; 39 | using Microsoft.Extensions.DependencyInjection; 40 | 41 | namespace Hanselman.CST352 42 | { 43 | /// 44 | /// "Bootstraps" the system by creating an , setting the size of the 's memory, 45 | /// and loading each into memory. Then, for each we create a 46 | /// . Then we start everything by calling 47 | /// 48 | class EntryPoint 49 | { 50 | public static IConfigurationRoot Configuration { get; set; } 51 | 52 | /// 53 | /// The entry point for the virtual OS 54 | /// 55 | [STAThread] 56 | static void Main(string[] args) 57 | { 58 | var builder = new ConfigurationBuilder() 59 | .AddJsonFile("appsettings.json"); 60 | Configuration = builder.Build(); 61 | 62 | OS theOS = null; 63 | uint bytesOfVirtualMemory = 0; 64 | uint bytesOfPhysicalMemory = 0; 65 | 66 | PrintHeader(); 67 | 68 | if (args.Length < 2) 69 | PrintInstructions(); 70 | else 71 | { 72 | //try 73 | { 74 | // Total addressable (virtual) memory taken from the command line 75 | bytesOfVirtualMemory = uint.Parse(args[0]); 76 | 77 | bytesOfPhysicalMemory = uint.Parse(Configuration["PhysicalMemory"]); 78 | 79 | // Setup static physical memory 80 | CPU.initPhysicalMemory(bytesOfPhysicalMemory); 81 | 82 | // Create the OS and Memory Manager with Virtual Memory 83 | theOS = new OS(bytesOfVirtualMemory); 84 | 85 | // Let the CPU know about the OS 86 | CPU.theOS = theOS; 87 | 88 | Console.WriteLine("CPU has {0} bytes of physical memory",CPU.physicalMemory.Length); 89 | Console.WriteLine("OS has {0} bytes of virtual (addressable) memory",theOS.memoryMgr.virtualMemSize); 90 | 91 | // For each file on the command line, load the program and create a process 92 | for (int i = 1; i < args.Length; i++) 93 | { 94 | if (File.Exists(args[i])) 95 | { 96 | Program p = Program.LoadProgram(args[i]); 97 | Process rp = theOS.createProcess(p, uint.Parse(Configuration["ProcessMemory"])); 98 | Console.WriteLine("Process id {0} has {1} bytes of process memory and {2} bytes of heap",rp.PCB.pid,Configuration["ProcessMemory"],rp.PCB.heapAddrEnd-rp.PCB.heapAddrStart); 99 | p.DumpProgram(); 100 | } 101 | } 102 | 103 | // Start executing! 104 | theOS.execute(); 105 | } 106 | //catch (Exception e) 107 | { 108 | //PrintInstructions(); 109 | //Console.WriteLine(e.ToString()); 110 | } 111 | 112 | // Pause 113 | Console.WriteLine("OS execution complete. Press Enter to continue..."); 114 | Console.ReadLine(); 115 | } 116 | } 117 | 118 | /// 119 | /// Prints the static instructions on how to invoke from the command line 120 | /// 121 | private static void PrintInstructions() 122 | { 123 | Console.WriteLine(""); 124 | Console.WriteLine("usage: OS membytes [files]"); 125 | } 126 | 127 | /// 128 | /// Prints the static informatonal header 129 | /// 130 | private static void PrintHeader() 131 | { 132 | Console.WriteLine("Scott's CST352 Virtual Operating System"); 133 | Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().FullName); 134 | Console.WriteLine("Copyright (C) Scott Hanselman 2002. All rights reserved." + System.Environment.NewLine); 135 | 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/TinyOSCore/Instruction.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | using System; 35 | using System.Text.RegularExpressions; 36 | 37 | namespace Hanselman.CST352 38 | { 39 | /// 40 | /// Represents a single line in a program, consisting of an 41 | /// and one or two optional parameters. An instruction can parse a raw instruction from a test file. 42 | /// Tge instruction is then loaded into an which is a member of 43 | /// . The is translated into bytes that are 44 | /// loaded into the processes memory space. It's never used again, but it's a neat overly object oriented 45 | /// construct that simplified the coding of the creation of a and complicated the 46 | /// running of the whole system. It was worth it though. 47 | /// 48 | public class Instruction 49 | { 50 | 51 | /// 52 | /// Overridden method for pretty printing of Instructions 53 | /// 54 | /// A formatted string representing an Instruction 55 | public override string ToString() 56 | { 57 | return String.Format("OpCode: {0,-2:G} {1,-12:G} Param1: {2,4:G} Param2: {3,4:G}", (byte)this.OpCode, this.OpCode, this.Param1 == uint.MaxValue? "" :this.Param1.ToString(),this.Param2 == uint.MaxValue ? "" :this.Param2.ToString()); 58 | } 59 | 60 | /// 61 | /// The OpCode for this Instruction 62 | /// 63 | public InstructionType OpCode; 64 | 65 | /// 66 | /// The first parameter to the opCode. May be a Constant or a Register value, or not used at all 67 | /// 68 | public uint Param1 = uint.MaxValue; 69 | 70 | /// 71 | /// The second parameter to the opCode. May be a Constant or a Register value, or not used at all 72 | /// 73 | public uint Param2 = uint.MaxValue; 74 | 75 | /// 76 | /// Public constructor for an Instruction 77 | /// 78 | /// A raw string from a Program File. 79 | /// Any one of the following lines is a valid rawInstruction 80 | ///
 81 | 		///  1   r1          ; incr r1
 82 | 		///  2   r6, $16     ; add 16 to r6
 83 | 		///  26  r6          ; setPriority to r6
 84 | 		///  2   r2, $5      ; increment r2 by 5
 85 | 		///  3   r1, r2      ; add 1 and 2 and the result goes in 1
 86 | 		///  2   r2, $5      ; increment r2 by 5
 87 | 		///  6   r3, $99     ; move 99 into r3
 88 | 		///  7   r4, r3      ; move r3 into r4
 89 | 		///  11  r4          ; print r4
 90 | 		///  27              ; this is exit.
 91 | 		/// 
92 | ///
93 | public Instruction(string rawInstruction) 94 | { 95 | Regex r = new Regex("(?:;.+)|\\A(?\\d+){1}|\\sr(?[-]*\\d)|\\$(?[-]*\\d+)"); 96 | 97 | MatchCollection matchcol = r.Matches(rawInstruction); 98 | foreach(Match m in matchcol) 99 | { 100 | GroupCollection g = m.Groups; 101 | 102 | for (int i = 1; i < g.Count ; i++) 103 | { 104 | if (g[i].Value.Length != 0 ) 105 | { 106 | if (r.GroupNameFromNumber(i) == "opcode") 107 | { 108 | this.OpCode = (InstructionType)byte.Parse(g[i].Value); 109 | } 110 | 111 | if (r.GroupNameFromNumber(i) == "param" || r.GroupNameFromNumber(i) == "const") 112 | { 113 | //Yank them as ints (to preserve signed-ness) 114 | // Treat them as uints for storage 115 | // This will only affect negative numbers, and 116 | // VERY large unsigned numbers 117 | if (uint.MaxValue == this.Param1) 118 | this.Param1 = uint.Parse(g[i].Value); 119 | else if (uint.MaxValue == this.Param2) 120 | { 121 | if (g[i].Value[0] == '-') 122 | this.Param2 = (uint)int.Parse(g[i].Value); 123 | else 124 | this.Param2 = uint.Parse(g[i].Value); 125 | 126 | } 127 | } 128 | 129 | } 130 | } 131 | } 132 | } 133 | } 134 | 135 | /// 136 | /// This enum provides an easy conversion between numerical opCodes like "2" and text 137 | /// and easy to remember consts like "Addi" 138 | /// 139 | public enum InstructionType 140 | { 141 | /// 142 | /// No op 143 | /// 144 | Noop = 0, 145 | 146 | /// 147 | /// Increments register 148 | ///
149 | 		/// 1 r1
150 | 		/// 
151 | ///
152 | Incr, 153 | 154 | /// 155 | /// Adds constant 1 to register 1 156 | ///
157 | 		/// 2 r1, $1
158 | 		/// 
159 | ///
160 | Addi, 161 | 162 | /// 163 | /// Adds r2 to r1 and stores the value in r1 164 | ///
165 | 		/// 3 r1, r2
166 | 		/// 
167 | ///
168 | Addr, 169 | 170 | /// 171 | /// Pushes contents of register 1 onto stack 172 | ///
173 | 		/// 4 r1
174 | 		/// 
175 | ///
176 | Pushr, 177 | 178 | /// 179 | /// Pushes constant 1 onto stack 180 | ///
181 | 		/// 5 $1
182 | 		/// 
183 | ///
184 | Pushi, 185 | 186 | /// 187 | /// Moves constant 1 into register 1 188 | ///
189 | 		/// 6 r1, $1
190 | 		/// 
191 | ///
192 | Movi, 193 | 194 | /// 195 | /// Moves contents of register2 into register 1 196 | ///
197 | 		/// 7 r1, r2
198 | 		/// 
199 | ///
200 | Movr, 201 | 202 | /// 203 | /// Moves contents of memory pointed to register 2 into register 1 204 | ///
205 | 		/// 8 r1, r2
206 | 		/// 
207 | ///
208 | Movmr, 209 | 210 | /// 211 | /// Moves contents of register 2 into memory pointed to by register 1 212 | ///
213 | 		/// 9 r1, r2
214 | 		/// 
215 | ///
216 | Movrm, 217 | 218 | /// 219 | /// Moves contents of memory pointed to by register 2 into memory pointed to by register 1 220 | ///
221 | 		/// 10 r1, r2
222 | 		/// 
223 | ///
224 | Movmm, 225 | 226 | /// 227 | /// Prints out contents of register 1 228 | ///
229 | 		/// 11 r1
230 | 		/// 
231 | ///
232 | Printr, 233 | 234 | /// 235 | /// Prints out contents of memory pointed to by register 1 236 | ///
237 | 		/// 12 r1
238 | 		/// 
239 | ///
240 | Printm, 241 | 242 | /// 243 | /// Control transfers to the instruction whose address is r1 bytes relative to the current instruction. 244 | /// r1 may be negative. 245 | ///
246 | 		/// 13 r1
247 | 		/// 
248 | ///
249 | Jmp, 250 | 251 | /// 252 | /// Compare contents of r1 with 1. If r1 < 9 set sign flag. If r1 > 9 clear sign flag. 253 | /// If r1 == 9 set zero flag. 254 | ///
255 | 		/// 14 r1, $9
256 | 		/// 
257 | ///
258 | Cmpi, 259 | 260 | 261 | /// 262 | /// Compare contents of r1 with r2. If r1 < r2 set sign flag. If r1 > r2 clear sign flag. 263 | /// If r1 == r2 set zero flag. 264 | ///
265 | 		/// 15 r1, r2
266 | 		/// 
267 | ///
268 | Cmpr, 269 | 270 | 271 | /// 272 | /// If the sign flag is set, jump to the instruction that is offset r1 bytes from the current instruction 273 | ///
274 | 		/// 16 r1
275 | 		/// 
276 | ///
277 | Jlt, 278 | 279 | /// 280 | /// If the sign flag is clear, jump to the instruction that is offset r1 bytes from the current instruction 281 | ///
282 | 		/// 17 r1
283 | 		/// 
284 | ///
285 | Jgt, 286 | 287 | /// 288 | /// If the zero flag is set, jump to the instruction that is offset r1 bytes from the current instruction 289 | ///
290 | 		/// 18 r1
291 | 		/// 
292 | ///
293 | Je, 294 | 295 | /// 296 | /// Call the procedure at offset r1 bytes from the current instrucion. 297 | /// The address of the next instruction to excetute after a return is pushed on the stack 298 | ///
299 | 		/// 19 r1
300 | 		/// 
301 | ///
302 | Call, 303 | 304 | /// 305 | /// Call the procedure at offset of the bytes in memory pointed by r1 from the current instrucion. 306 | /// The address of the next instruction to excetute after a return is pushed on the stack 307 | ///
308 | 		/// 20 r1
309 | 		/// 
310 | ///
311 | Callm, 312 | 313 | /// 314 | /// Pop the return address from the stack and transfer control to this instruction 315 | ///
316 | 		/// 21
317 | 		/// 
318 | ///
319 | Ret, 320 | 321 | /// 322 | /// Allocate memory of the size equal to r1 bytes and return the address of the new memory in r2. 323 | /// If failed, r2 is cleared to 0. 324 | ///
325 | 		/// 22 r1, r2
326 | 		/// 
327 | ///
328 | Alloc, 329 | 330 | /// 331 | /// Acquire the OS lock whose # is provided in register r1. 332 | /// Icf the lock is not held by the current process 333 | /// the operation is a no-op 334 | ///
335 | 		/// 23 r1
336 | 		/// 
337 | ///
338 | AcquireLock, 339 | 340 | /// 341 | /// Release the OS lock whose # is provided in register r1. 342 | /// Another process or the idle process 343 | /// must be scheduled at this point. 344 | /// if the lock is not held by the current process, 345 | /// the instruction is a no-op 346 | ///
347 | 		/// 24 r1
348 | 		/// 
349 | ///
350 | ReleaseLock, 351 | 352 | /// 353 | /// Sleep the # of clock cycles as indicated in r1. 354 | /// Another process or the idle process 355 | /// must be scheduled at this point. 356 | /// If the time to sleep is 0, the process sleeps infinitely 357 | ///
358 | 		/// 25 r1
359 | 		/// 
360 | ///
361 | Sleep, 362 | 363 | /// 364 | /// Set the priority of the current process to the value 365 | /// in register r1 366 | ///
367 | 		/// 26 r1
368 | 		/// 
369 | ///
370 | SetPriority, 371 | 372 | /// 373 | /// This opcode causes an exit and the process's memory to be unloaded. 374 | /// Another process or the idle process must now be scheduled 375 | ///
376 | 		/// 27
377 | 		/// 
378 | ///
379 | Exit, 380 | 381 | /// 382 | /// Free the memory allocated whose address is in r1 383 | ///
384 | 		/// 28 r1
385 | 		/// 
386 | ///
387 | FreeMemory, 388 | 389 | /// 390 | /// Map the shared memory region identified by r1 and return the start address in r2 391 | ///
392 | 		/// 29 r1, r2
393 | 		/// 
394 | ///
395 | MapSharedMem, 396 | 397 | /// 398 | /// Signal the event indicated by the value in register r1 399 | ///
400 | 		/// 30 r1
401 | 		/// 
402 | ///
403 | SignalEvent, 404 | 405 | /// 406 | /// Wait for the event in register r1 to be triggered resulting in a context-switch 407 | ///
408 | 		/// 31 r1
409 | 		/// 
410 | ///
411 | WaitEvent, 412 | 413 | /// 414 | /// Read the next 32-bit value into register r1 415 | ///
416 | 		/// 32 r1
417 | 		/// 
418 | ///
419 | Input, 420 | 421 | /// 422 | /// set the bytes starting at address r1 of length r2 to zero 423 | ///
424 | 		/// 33 r1, r2
425 | 		/// 
426 | ///
427 | MemoryClear, 428 | 429 | /// 430 | /// Terminate the process whose id is in the register r1 431 | ///
432 | 		/// 34 r1
433 | 		/// 
434 | ///
435 | TerminateProcess, 436 | 437 | /// 438 | /// Pop the contents at the top of the stack into register r1 439 | ///
440 | 		/// 35 r1
441 | 		/// 
442 | ///
443 | Popr, 444 | 445 | /// 446 | /// Pop the contents at the top of the stack into the memory pointed to by register r1 447 | ///
448 | 		/// 36 r1
449 | 		/// 
450 | ///
451 | Popm 452 | }; 453 | 454 | } 455 | -------------------------------------------------------------------------------- /src/TinyOSCore/InstructionCollection.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | namespace Hanselman.CST352 35 | { 36 | using System; 37 | using System.Collections; 38 | 39 | 40 | /// 41 | /// A collection that stores objects. 42 | /// 43 | /// 44 | [Serializable()] 45 | public class InstructionCollection : CollectionBase { 46 | 47 | /// 48 | /// Initializes a new instance of . 49 | /// 50 | public InstructionCollection() { 51 | } 52 | 53 | /// 54 | /// Initializes a new instance of based on another . 55 | /// 56 | /// 57 | /// A from which the contents are copied 58 | /// 59 | public InstructionCollection(InstructionCollection value) { 60 | this.AddRange(value); 61 | } 62 | 63 | /// 64 | /// Initializes a new instance of containing any array of objects. 65 | /// 66 | /// 67 | /// A array of objects with which to intialize the collection 68 | /// 69 | public InstructionCollection(Instruction[] value) { 70 | this.AddRange(value); 71 | } 72 | 73 | /// 74 | /// Represents the entry at the specified index of the . 75 | /// 76 | /// The zero-based index of the entry to locate in the collection. 77 | /// 78 | /// The entry at the specified index of the collection. 79 | /// 80 | /// is outside the valid range of indexes for the collection. 81 | public Instruction this[int index] { 82 | get { 83 | return ((Instruction)(List[index])); 84 | } 85 | set { 86 | List[index] = value; 87 | } 88 | } 89 | 90 | /// 91 | /// Adds a with the specified value to the 92 | /// . 93 | /// 94 | /// The to add. 95 | /// 96 | /// The index at which the new element was inserted. 97 | /// 98 | /// 99 | public int Add(Instruction value) { 100 | return List.Add(value); 101 | } 102 | 103 | /// 104 | /// Copies the elements of an array to the end of the . 105 | /// 106 | /// 107 | /// An array of type containing the objects to add to the collection. 108 | /// 109 | /// 110 | /// None. 111 | /// 112 | /// 113 | public void AddRange(Instruction[] value) { 114 | for (int i = 0; (i < value.Length); i = (i + 1)) { 115 | this.Add(value[i]); 116 | } 117 | } 118 | 119 | /// 120 | /// 121 | /// Adds the contents of another to the end of the collection. 122 | /// 123 | /// 124 | /// 125 | /// A containing the objects to add to the collection. 126 | /// 127 | /// 128 | /// None. 129 | /// 130 | /// 131 | public void AddRange(InstructionCollection value) { 132 | for (int i = 0; (i < value.Count); i = (i + 1)) { 133 | this.Add(value[i]); 134 | } 135 | } 136 | 137 | /// 138 | /// Gets a value indicating whether the 139 | /// contains the specified . 140 | /// 141 | /// The to locate. 142 | /// 143 | /// if the is contained in the collection; 144 | /// otherwise, . 145 | /// 146 | /// 147 | public bool Contains(Instruction value) { 148 | return List.Contains(value); 149 | } 150 | 151 | /// 152 | /// Copies the values to a one-dimensional instance at the 153 | /// specified index. 154 | /// 155 | /// The one-dimensional that is the destination of the values copied from . 156 | /// The index in where copying begins. 157 | /// 158 | /// None. 159 | /// 160 | /// is multidimensional. -or- The number of elements in the is greater than the available space between and the end of . 161 | /// is . 162 | /// is less than 's lowbound. 163 | /// 164 | public void CopyTo(Instruction[] array, int index) { 165 | List.CopyTo(array, index); 166 | } 167 | 168 | /// 169 | /// Returns the index of a in 170 | /// the . 171 | /// 172 | /// The to locate. 173 | /// 174 | /// The index of the of in the 175 | /// , if found; otherwise, -1. 176 | /// 177 | /// 178 | public int IndexOf(Instruction value) { 179 | return List.IndexOf(value); 180 | } 181 | 182 | /// 183 | /// Inserts a into the at the specified index. 184 | /// 185 | /// The zero-based index where should be inserted. 186 | /// The to insert. 187 | /// None. 188 | /// 189 | public void Insert(int index, Instruction value) { 190 | List.Insert(index, value); 191 | } 192 | 193 | /// 194 | /// Returns an enumerator that can iterate through 195 | /// the . 196 | /// 197 | /// None. 198 | /// 199 | public new InstructionEnumerator GetEnumerator() { 200 | return new InstructionEnumerator(this); 201 | } 202 | 203 | /// 204 | /// Removes a specific from the 205 | /// . 206 | /// 207 | /// The to remove from the . 208 | /// None. 209 | /// is not found in the Collection. 210 | public void Remove(Instruction value) { 211 | List.Remove(value); 212 | } 213 | 214 | /// 215 | /// Provided for "foreach" support with this collection 216 | /// 217 | public class InstructionEnumerator : object, IEnumerator { 218 | 219 | private IEnumerator baseEnumerator; 220 | 221 | private IEnumerable temp; 222 | 223 | /// 224 | /// Public constructor for an InstructionEnumerator 225 | /// 226 | /// The we are going to iterate over 227 | public InstructionEnumerator(InstructionCollection mappings) { 228 | this.temp = ((IEnumerable)(mappings)); 229 | this.baseEnumerator = temp.GetEnumerator(); 230 | } 231 | 232 | /// 233 | /// The current 234 | /// 235 | public Instruction Current { 236 | get { 237 | return ((Instruction)(baseEnumerator.Current)); 238 | } 239 | } 240 | 241 | /// 242 | /// The current IEnumerator interface 243 | /// 244 | object IEnumerator.Current { 245 | get { 246 | return baseEnumerator.Current; 247 | } 248 | } 249 | 250 | /// 251 | /// Move to the next Instruction 252 | /// 253 | /// true or false based on success 254 | public bool MoveNext() { 255 | return baseEnumerator.MoveNext(); 256 | } 257 | 258 | /// 259 | /// Move to the next Instruction 260 | /// 261 | /// true or false based on success 262 | bool IEnumerator.MoveNext() 263 | { 264 | return baseEnumerator.MoveNext(); 265 | } 266 | 267 | /// 268 | /// Reset the cursor 269 | /// 270 | public void Reset() 271 | { 272 | baseEnumerator.Reset(); 273 | } 274 | 275 | /// 276 | /// Reset the cursor 277 | /// 278 | void IEnumerator.Reset() 279 | { 280 | baseEnumerator.Reset(); 281 | } 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /src/TinyOSCore/MemoryManager.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | using System; 35 | using System.Collections; 36 | using System.IO; 37 | using System.Runtime.Serialization; 38 | using System.Xml; 39 | using System.Xml.Serialization; 40 | using System.Diagnostics; 41 | using System.Threading; 42 | using System.Text; 43 | using System.Configuration; 44 | using System.Runtime.Serialization.Formatters.Binary; 45 | 46 | namespace Hanselman.CST352 47 | { 48 | /// 49 | /// The MemoryManager for the . All memory accesses by a 50 | /// go through this class. 51 | /// 52 | /// 53 | /// theOS.memoryMgr[processId, 5]; //accesses memory at address 5 54 | /// 55 | public class MemoryManager 56 | { 57 | private ArrayList _pageTable; 58 | 59 | //BitArray freePhysicalPages = new BitArray((int)(CPU.physicalMemory.Length/CPU.pageSize), true); 60 | private bool[] freePhysicalPages = new bool[(int)(CPU.physicalMemory.Length/CPU.pageSize)]; 61 | 62 | /// 63 | /// Total ammount of addressable memory. This is set in the Constructor. 64 | /// Once set, it is readonly 65 | /// 66 | public readonly uint virtualMemSize = 0; 67 | 68 | /// 69 | /// 70 | /// 71 | /// 72 | public MemoryManager(uint virtualMemSizeIn) 73 | { 74 | // 75 | // Find a size for addressableMemory that is on a page boundary 76 | // 77 | virtualMemSize = CPU.UtilRoundToBoundary(virtualMemSizeIn, CPU.pageSize); 78 | 79 | // 80 | // Size of memory must be a factor of CPU.pageSize 81 | // This was asserted when the CPU initialized memory 82 | // 83 | uint physicalpages = (uint)(CPU.physicalMemory.Length/CPU.pageSize); 84 | uint addressablepages = (uint)(virtualMemSize/CPU.pageSize); 85 | 86 | _pageTable = new ArrayList((int)addressablepages); 87 | 88 | // Delete all our Swap Files 89 | foreach (string f in Directory.GetFiles(".","*.xml")) 90 | File.Delete(f); 91 | 92 | // For all off addressable memory... 93 | // Make the pages in physical and the pages that aren't in physical 94 | for (uint i = 0;i < virtualMemSize; i+=CPU.pageSize) 95 | { 96 | // Mark the Pages that are in physical memory as "false" or "not free" 97 | MemoryPage p; 98 | if (i < CPU.physicalMemory.Length) 99 | { 100 | p = new MemoryPage(i, true); 101 | freePhysicalPages[(int)(i/CPU.pageSize)] = false; 102 | } 103 | else p = new MemoryPage(i, false); 104 | 105 | _pageTable.Add(p); 106 | } 107 | 108 | // 109 | // Cordon off some shared memory regions...these are setting the AppSettings 110 | // 111 | uint SharedRegionsSize = uint.Parse(EntryPoint.Configuration["SharedMemoryRegionSize"]); 112 | uint SharedRegions = uint.Parse(EntryPoint.Configuration["NumOfSharedMemoryRegions"]); 113 | if (SharedRegions > 0 && SharedRegionsSize > 0) 114 | { 115 | uint TotalPagesNeeded = (uint)(SharedRegions*SharedRegionsSize/CPU.pageSize); 116 | uint pagesPerRegion = TotalPagesNeeded/SharedRegions; 117 | 118 | // ForExample: 119 | // I need 2 regions 120 | // 64 bytes needed for each 121 | // 4 pages each 122 | // 8 total pages needed 123 | 124 | // Because I pre-allocate shared memory I'll have the luxury of contigous pages of memory. 125 | // I'll exploit this hack in MapSharedMemoryToProcess 126 | foreach (MemoryPage page in _pageTable) 127 | { 128 | // Do we still need pages? 129 | if (TotalPagesNeeded > 0) 130 | { 131 | // If this page is assigned to the OS, take it 132 | if (page.SharedMemoryRegion == 0) 133 | { 134 | // Now assign it to us 135 | page.SharedMemoryRegion = SharedRegions; 136 | TotalPagesNeeded--; 137 | if (TotalPagesNeeded % pagesPerRegion == 0) 138 | SharedRegions--; 139 | } 140 | } 141 | else //We have all we need 142 | break; 143 | } 144 | } 145 | } 146 | 147 | 148 | /// 149 | /// 150 | /// 151 | /// The Process 152 | /// The number of bytes requested. Will be rounded up to the nearest page 153 | /// The Start Address of the Alloc'ed memory 154 | public uint ProcessHeapAlloc(Process p, uint bytesRequested) 155 | { 156 | // Round up to the nearest page boundary 157 | uint pagesRequested = MemoryManager.BytesToPages(bytesRequested); 158 | uint addrStart = 0; 159 | 160 | // 161 | // Finds n *Contiguous* Pages 162 | // 163 | 164 | // Start with a list of potentialPages... 165 | ArrayList potentialPages = new ArrayList(); 166 | 167 | // Look through all the pages in our heap 168 | for (int i = 0; i < p.PCB.heapPageTable.Count; i++) 169 | { 170 | // The pages must be contiguous 171 | bool bContiguous = true; 172 | 173 | //From this start page, check for contiguous free pages nearby 174 | MemoryPage startPage = (MemoryPage)p.PCB.heapPageTable[i]; 175 | 176 | //Is this page, and x ahead of it free? 177 | if (startPage.heapAllocationAddr == 0) 178 | { 179 | potentialPages.Clear(); 180 | potentialPages.Add(startPage); 181 | 182 | //Is this page, and x ahead of it free? 183 | for (int j = 1; j < pagesRequested;j++) 184 | { 185 | // Have we walked past the end of the heap? 186 | if ((i+j) >= p.PCB.heapPageTable.Count) 187 | throw new HeapException(p.PCB.pid, pagesRequested*CPU.pageSize); 188 | 189 | MemoryPage nextPage = (MemoryPage)p.PCB.heapPageTable[i+j]; 190 | if (nextPage.heapAllocationAddr == 0) 191 | potentialPages.Add(nextPage); 192 | else 193 | bContiguous = false; 194 | } 195 | // If we make it here, we've found enough contiguous pages, break and continue 196 | if (bContiguous == true) 197 | break; 198 | } 199 | } 200 | 201 | // Did we not find enough pages? 202 | if (potentialPages.Count != pagesRequested) 203 | throw new HeapException(p.PCB.pid, pagesRequested*CPU.pageSize); 204 | 205 | // Mark each page with the address of the original alloc 206 | // so we can Free them later 207 | addrStart = ((MemoryPage)potentialPages[0]).addrProcessIndex; 208 | foreach (MemoryPage page in potentialPages) 209 | page.heapAllocationAddr = addrStart; 210 | 211 | return addrStart; 212 | } 213 | 214 | 215 | /// 216 | /// For debugging only. The value used to "zero out" memory when doing a FreeMemory. 217 | /// 218 | private static int memoryClearInt; 219 | 220 | /// 221 | /// Releases pages that were Alloc'ed from the Process's Heap 222 | /// 223 | /// The Processes 224 | /// The Process address that the allocation began at 225 | /// 226 | public uint ProcessHeapFree(Process p, uint startAddr) 227 | { 228 | uint pageCount = 0; 229 | foreach (MemoryPage page in p.PCB.heapPageTable) 230 | { 231 | if (page.heapAllocationAddr == startAddr) 232 | { 233 | page.heapAllocationAddr = 0; 234 | pageCount++; 235 | } 236 | } 237 | 238 | // 239 | // For Heap Debugging, uncomment this line, 240 | // this incrementing value will be used to 241 | // clear memory out when releasing heap blocks 242 | // 243 | //memoryClearInt++; 244 | 245 | memoryClearInt = 0; 246 | SetMemoryOfProcess(p.PCB.pid, startAddr, pageCount*CPU.pageSize, (byte)memoryClearInt); 247 | return 0; 248 | 249 | } 250 | 251 | /// 252 | /// Adds all the pages allocated to a Process's heap to a PCB specific table of memory pages 253 | /// 254 | /// The Process 255 | public void CreateHeapTableForProcess(Process p) 256 | { 257 | foreach (MemoryPage page in _pageTable) 258 | { 259 | if (page.pidOwner == p.PCB.pid) 260 | { 261 | if (page.addrProcessIndex >= p.PCB.heapAddrStart && page.addrProcessIndex < p.PCB.heapAddrEnd) 262 | { 263 | p.PCB.heapPageTable.Add(page); 264 | } 265 | } 266 | } 267 | } 268 | 269 | 270 | /// 271 | /// Gets a 4 byte unsigned integer (typically an opCode param) from memory 272 | /// 273 | /// The calling processid 274 | /// The address in memory from the Process's point of view 275 | /// 276 | public uint getUIntFrom(uint processid, uint processIndex) 277 | { 278 | return CPU.BytesToUInt(getBytesFrom(processid, processIndex, 4)); 279 | } 280 | 281 | /// 282 | /// Sets a 4 byte unsigned integer (typically an opCode param) to memory 283 | /// 284 | /// The calling processid 285 | /// The address in memory from the Process's point of view 286 | /// The new value 287 | public void setUIntAt(uint processid, uint processIndex, uint avalue) 288 | { 289 | setBytesAt(processid, processIndex, CPU.UIntToBytes(avalue)); 290 | } 291 | 292 | /// 293 | /// Gets an array of "length" bytes from a specific process's memory address 294 | /// 295 | /// The calling process's id 296 | /// The address in memory from the Process's point of view 297 | /// how many bytes 298 | /// an initialized byte array containing the contents of memory 299 | public byte[] getBytesFrom(uint processid, uint processIndex, uint length) 300 | { 301 | byte[] bytes = new byte[length]; 302 | for (uint i = 0; i < length; i++) 303 | { 304 | bytes[i] = this[processid, processIndex + i]; 305 | } 306 | return bytes; 307 | } 308 | 309 | /// 310 | /// Sets an array of bytes to a specific process's memory address 311 | /// 312 | /// The calling processid 313 | /// The address in memory from the Process's point of view 314 | /// The source array of bytes 315 | public void setBytesAt(uint processid, uint processIndex, byte[] pageValue) 316 | { 317 | for (uint i = 0; i < pageValue.Length; i++) 318 | { 319 | this[processid, processIndex+i] = pageValue[i]; 320 | } 321 | } 322 | 323 | 324 | 325 | /// 326 | /// Translates a Process's address space into physical address space 327 | /// 328 | /// The calling process's id 329 | /// The address in memory from the Process's point of view 330 | /// Whether we mark this as dirty or not 331 | /// The physical address of the memory we requested 332 | /// This process has accessed memory outside it's Process address space 333 | public uint ProcessAddrToPhysicalAddr(uint processid, uint processMemoryIndex, bool dirtyFlag) 334 | { 335 | foreach(MemoryPage page in _pageTable) 336 | { 337 | // If this process owns this page 338 | if (page.pidOwner == processid) 339 | { 340 | // If this page is responsible for the memory addresses we are interested in 341 | if((processMemoryIndex >= page.addrProcessIndex) && (processMemoryIndex < page.addrProcessIndex+CPU.pageSize)) 342 | { 343 | // Get the page offset 344 | uint pageOffset = processMemoryIndex - page.addrProcessIndex; 345 | return ProcessAddrToPhysicalAddrHelper(page, dirtyFlag, pageOffset); 346 | } 347 | } 348 | 349 | // Maybe this is a shared region? 350 | if (page.SharedMemoryRegion != 0) 351 | { 352 | // Go through the list of owners and see if we are one... 353 | for (int i = 0; i <= page.pidSharedOwnerList.Count-1; i++) 354 | { 355 | // Do we own this page? 356 | if ((uint)page.pidSharedOwnerList[i] == processid) 357 | { 358 | // Does this page handle this address? 359 | if (processMemoryIndex >= (uint)page.pidSharedProcessIndex[i] && processMemoryIndex < (uint)page.pidSharedProcessIndex[i]+CPU.pageSize) 360 | { 361 | uint pageOffset = processMemoryIndex - (uint)page.pidSharedProcessIndex[i]; 362 | return ProcessAddrToPhysicalAddrHelper(page, dirtyFlag, pageOffset); 363 | } 364 | } 365 | } 366 | } 367 | } 368 | 369 | // If we make it here, this process has accessed memory that doesn't exist in the page table 370 | // We'll catch this exception and terminate the process for accessing memory that it doesn't own 371 | throw(new MemoryException(processid, processMemoryIndex)); 372 | } 373 | 374 | private uint ProcessAddrToPhysicalAddrHelper(MemoryPage page, bool dirtyFlag, uint pageOffset) 375 | { 376 | // Get the page offset 377 | uint virtualIndex = page.addrVirtual+pageOffset; 378 | 379 | // Update Flags for this process 380 | page.isDirty = dirtyFlag || page.isDirty; 381 | page.accessCount++; 382 | page.lastAccessed = DateTime.Now; 383 | 384 | // Take this new "virtual" address (relative to all addressable memory) 385 | // and translate it to physical ram. Page Faults may occur inside this next call. 386 | uint physicalIndex = VirtualAddrToPhysical(page,virtualIndex); 387 | return physicalIndex; 388 | } 389 | 390 | 391 | /// 392 | /// Resets a memory page to defaults, deletes that page's swap file and 393 | /// may mark the page as free in physical memory 394 | /// 395 | /// The to reset 396 | public void ResetPage(MemoryPage page) 397 | { 398 | if (page.isValid == true) 399 | { 400 | // Make this page as availble in physical memory 401 | uint i = page.addrPhysical / CPU.pageSize; 402 | Debug.Assert(i < freePhysicalPages.Length); //has to be 403 | freePhysicalPages[(int)i] = true; 404 | } 405 | 406 | //Reset to reasonable defaults 407 | page.isDirty = false; 408 | page.addrPhysical = 0; 409 | page.pidOwner = 0; 410 | page.pageFaults = 0; 411 | page.accessCount = 0; 412 | page.lastAccessed = DateTime.Now; 413 | page.addrProcessIndex = 0; 414 | page.heapAllocationAddr = 0; 415 | 416 | // Delete this page's swap file 417 | string filename = System.Environment.CurrentDirectory + "/page" + page.pageNumber + "." + page.addrVirtual + ".xml"; 418 | File.Delete(filename); 419 | } 420 | 421 | /// 422 | /// 423 | /// 424 | /// 425 | /// 426 | /// 427 | public uint VirtualAddrToPhysical(MemoryPage page, uint virtualIndex) 428 | { 429 | if (page.isValid == false) 430 | { 431 | int i = 0; 432 | for (; i < freePhysicalPages.Length; i++) 433 | { 434 | if (freePhysicalPages[i] == true) 435 | { 436 | // Found a free physical page! 437 | freePhysicalPages[i] = false; 438 | break; 439 | } 440 | } 441 | 442 | // If we have reach the end of the freePhysicalPages 443 | // without finding a free page - we are out of physical memory, therefore 444 | // we PageFault and start looking for victim pages to swap out 445 | if (i == freePhysicalPages.Length) 446 | { 447 | MemoryPage currentVictim = null; 448 | foreach (MemoryPage possibleVictim in _pageTable) 449 | { 450 | if (!page.Equals(possibleVictim) && possibleVictim.isValid == true) 451 | { 452 | if (currentVictim == null) currentVictim = possibleVictim; 453 | 454 | // If this is the least accessed Memory Page we've found so far 455 | if (possibleVictim.lastAccessed < currentVictim.lastAccessed) 456 | currentVictim = possibleVictim; 457 | } 458 | } 459 | // Did we find no victims? That's a HUGE problem, and shouldn't ever happen 460 | Debug.Assert(currentVictim != null); 461 | 462 | SwapOut(currentVictim); 463 | 464 | // Take the physical address of this page 465 | page.addrPhysical = currentVictim.addrPhysical; 466 | 467 | SwapIn(page); 468 | } 469 | else // no page fault 470 | { 471 | // Map this page to free physical page "i" 472 | page.addrPhysical = (uint)(i*CPU.pageSize); 473 | SwapIn(page); 474 | } 475 | 476 | } 477 | 478 | // Adjust the physical address with pageOffset from a page boundary 479 | uint pageOffset = virtualIndex % CPU.pageSize; 480 | uint physicalIndex = page.addrPhysical+pageOffset; 481 | return physicalIndex; 482 | } 483 | 484 | /// 485 | /// Public accessor method to make Virtual Memory look like an array 486 | /// 487 | /// 488 | /// theOS.memoryMgr[processId, 5]; //accesses memory at address 5 489 | /// 490 | public byte this[uint processid, uint processMemoryIndex] 491 | { 492 | get 493 | { 494 | uint physicalIndex = ProcessAddrToPhysicalAddr(processid, processMemoryIndex, false); 495 | return CPU.physicalMemory[physicalIndex]; 496 | } 497 | set 498 | { 499 | uint physicalIndex = ProcessAddrToPhysicalAddr(processid, processMemoryIndex, true); 500 | CPU.physicalMemory[physicalIndex] = value; 501 | } 502 | } 503 | 504 | /// 505 | /// Helper method to translate # of bytes to # of Memory Pages 506 | /// 507 | /// bytes to translate 508 | /// number of pages 509 | public static uint BytesToPages(uint bytes) 510 | { 511 | return (CPU.UtilRoundToBoundary(bytes, CPU.pageSize)/CPU.pageSize); 512 | //return ((uint)(bytes / CPU.pageSize) + (uint)(bytes % CPU.pageSize)); 513 | } 514 | 515 | /// 516 | /// Takes a Process's ID and releases all MemoryPages assigned to it, zeroing and reseting them 517 | /// 518 | /// Process ID 519 | public void ReleaseMemoryOfProcess(uint pid) 520 | { 521 | foreach (MemoryPage page in _pageTable) 522 | { 523 | if (page.pidOwner == pid) 524 | { 525 | if (page.isValid == true) 526 | { 527 | SetMemoryOfProcess(pid,page.addrProcessIndex,CPU.pageSize,0); 528 | } 529 | ResetPage(page); 530 | } 531 | 532 | if (page.SharedMemoryRegion != 0) 533 | { 534 | for (int i = 0; i <= page.pidSharedOwnerList.Count-1; i++) 535 | { 536 | // Do we own this page? 537 | if ((uint)page.pidSharedOwnerList[i] == pid) 538 | { 539 | page.pidSharedOwnerList.RemoveAt(i); 540 | page.pidSharedProcessIndex.RemoveAt(i); 541 | break; 542 | } 543 | } 544 | } 545 | } 546 | } 547 | 548 | /// 549 | /// Zeros out memory belonging to a Process from start until length 550 | /// 551 | /// Process ID 552 | /// start memory address 553 | /// length in bytes 554 | /// the new value of the byte 555 | public void SetMemoryOfProcess(uint pid, uint start, uint length, byte newvalue) 556 | { 557 | for (uint i = start; i < (start+length);i++) 558 | this[pid,i] = newvalue; 559 | } 560 | 561 | /// 562 | /// Maps the shared memory region to the process passed in 563 | /// 564 | /// the number of the shared region to map 565 | /// Process ID 566 | /// the index in process memory of the shared region 567 | public uint MapSharedMemoryToProcess(uint memoryRegion, uint pid) 568 | { 569 | uint SharedRegionsSize = uint.Parse(EntryPoint.Configuration["SharedMemoryRegionSize"]); 570 | uint PagesNeeded = (uint)(SharedRegionsSize/CPU.pageSize); 571 | 572 | uint startAddrProcessIndex; 573 | uint addrProcessIndex = 0; 574 | 575 | //Find the max address used by this process (a free place to map this memory to) 576 | foreach (MemoryPage page in _pageTable) 577 | { 578 | if (page.pidOwner == pid) 579 | addrProcessIndex = Math.Max(page.addrProcessIndex,addrProcessIndex); 580 | } 581 | //Add one more page, to get the address of where to map the Shared Memory Region 582 | addrProcessIndex += CPU.pageSize; 583 | startAddrProcessIndex = addrProcessIndex; 584 | 585 | // Very inefficient: 586 | // Now, find the Shared Memory pages and and map them to this process 587 | foreach (MemoryPage page in _pageTable) 588 | { 589 | if (PagesNeeded > 0) 590 | { 591 | if (page.SharedMemoryRegion == memoryRegion) 592 | { 593 | page.pidSharedOwnerList.Add(pid); 594 | page.pidSharedProcessIndex.Add(addrProcessIndex); 595 | addrProcessIndex += CPU.pageSize; 596 | PagesNeeded--; 597 | } 598 | } 599 | else 600 | // We've got enough pages... 601 | break; 602 | } 603 | return startAddrProcessIndex; 604 | } 605 | 606 | 607 | /// 608 | /// Takes a number of bytes and a process id and assigns MemoryPages in the pageTable to the Process 609 | /// 610 | /// # of bytes to assign 611 | /// Process ID 612 | public void MapMemoryToProcess(uint bytes, uint pid) 613 | { 614 | uint pagesNeeded = BytesToPages(bytes); 615 | uint addrProcessIndex = 0; 616 | 617 | foreach (MemoryPage page in _pageTable) 618 | { 619 | if (pagesNeeded > 0) 620 | { 621 | // If this page is assigned to the OS, 622 | // and not a SharedMemoryRegion and take it 623 | if (page.pidOwner == 0 && page.SharedMemoryRegion == 0) 624 | { 625 | // Now assign it to us 626 | page.pidOwner = pid; 627 | page.addrProcessIndex = addrProcessIndex; 628 | addrProcessIndex += CPU.pageSize; 629 | pagesNeeded--; 630 | } 631 | } 632 | else 633 | // We've got enough pages... 634 | break; 635 | } 636 | 637 | // Did we go through the whole pageTable and not have enough memory? 638 | if (pagesNeeded > 0) 639 | { 640 | Console.WriteLine("OUT OF MEMORY: Process {0} requested {1} more bytes than were available!",pid,pagesNeeded*CPU.pageSize); 641 | System.Environment.Exit(1); 642 | } 643 | } 644 | 645 | /// 646 | /// Represents an entry in the Page Table. MemoryPages (or "Page Table Entries") 647 | /// are created once and never destroyed, their values are just reassigned 648 | /// 649 | public class MemoryPage 650 | { 651 | /// 652 | /// The number of the shared memory region this MemoryPage is mapped to 653 | /// 654 | public uint SharedMemoryRegion = 0; 655 | 656 | /// 657 | /// One of two parallel arrays, one of shared owners of this page, one of shared process indexes of this page 658 | /// 659 | public ArrayList pidSharedOwnerList = new ArrayList(); 660 | 661 | /// 662 | /// One of two parallel arrayz, one of shared owners of this page, one of shared process indexes of this page 663 | /// 664 | public ArrayList pidSharedProcessIndex = new ArrayList(); 665 | 666 | /// 667 | /// The number this page is in addressable Memory. Set once and immutable 668 | /// 669 | public readonly uint pageNumber = 0; 670 | 671 | /// 672 | /// The address in addressable space this page is responsbile for 673 | /// 674 | public readonly uint addrVirtual = 0; 675 | 676 | /// 677 | /// The address in Process space this page is responsible for 678 | /// 679 | public uint addrProcessIndex = 0; 680 | 681 | /// 682 | /// The process address that originally allocated this page. Kept so we can free that page(s) later. 683 | /// 684 | public uint heapAllocationAddr = 0; 685 | 686 | /// 687 | /// The process that is currently using this apge 688 | /// 689 | public uint pidOwner = 0; 690 | 691 | /// 692 | /// This is only valid when 693 | /// pidOwner != 0 and isValid == true 694 | /// meaning the page is actually mapped and present 695 | /// 696 | public uint addrPhysical = 0; 697 | 698 | /// 699 | /// Is the page in memory now? 700 | /// 701 | public bool isValid; 702 | 703 | /// 704 | /// Has the page been changes since it was last swapped in from Disk? 705 | /// 706 | public bool isDirty = false; 707 | 708 | /// 709 | /// For statistics: How many times has this page been involved in a pageFault? 710 | /// 711 | public uint pageFaults = 0; 712 | 713 | /// 714 | /// For aging and swapping: How many times has this page's address range been accessed? 715 | /// 716 | public uint accessCount = 0; 717 | 718 | /// 719 | /// For aging and swapping: When was this page last accessed? 720 | /// 721 | public DateTime lastAccessed = DateTime.Now; 722 | 723 | /// 724 | /// Only public constructor for a Memory Page and is only called once 725 | /// in the constructor 726 | /// 727 | /// The address in addressable memory this page is responsible for 728 | /// Is this page in memory right now? 729 | public MemoryPage(uint initAddrVirtual, bool isValidFlag) 730 | { 731 | isValid = isValidFlag; 732 | if (isValid) 733 | addrPhysical = initAddrVirtual; 734 | addrVirtual = initAddrVirtual; 735 | pageNumber = (addrVirtual)/CPU.pageSize; 736 | } 737 | } 738 | 739 | /// 740 | /// Represents the actual values in memory that a MemoryPage points to. 741 | /// MemoryPageValue is serialized to disk, currently as XML, in . 742 | /// 743 | [Serializable] public class MemoryPageValue 744 | { 745 | /// 746 | /// The array of bytes holding the value of memory for this page 747 | /// 748 | [XmlArray(ElementName = "byte", Namespace = "http://www.hanselman.com")] 749 | public byte[] memory = new byte[CPU.pageSize]; 750 | 751 | /// 752 | /// For aging and swapping: How many times has this page's address range been accessed? 753 | /// 754 | public uint accessCount = 0; 755 | 756 | /// 757 | /// For aging and swapping: When was this page last accessed? 758 | /// 759 | public DateTime lastAccessed = DateTime.Now; 760 | } 761 | 762 | /// 763 | /// Swaps the specified to disk. Currently implemented as XML for fun. 764 | /// 765 | /// The to be swapped 766 | public void SwapOut(MemoryPage victim) 767 | { 768 | if (victim.isDirty) 769 | { 770 | 771 | // Generate a filename based on address and page number 772 | string filename = System.Environment.CurrentDirectory + "/page" + victim.pageNumber + "-" + victim.addrVirtual + ".xml"; 773 | 774 | // IFormatter ser = new BinaryFormatter(); 775 | // Stream writer = new FileStream(filename, FileMode.Create); 776 | 777 | XmlSerializer ser = new XmlSerializer(typeof(MemoryPageValue)); 778 | Stream fs = new FileStream(filename, FileMode.Create); 779 | XmlWriter writer = new XmlTextWriter(fs, new UTF8Encoding()); 780 | 781 | MemoryPageValue pageValue = new MemoryPageValue(); 782 | 783 | // Copy the bytes from Physical Memory so we don't pageFault in a Fault Hander 784 | byte[] bytes = new byte[CPU.pageSize]; 785 | for (int i = 0; i < CPU.pageSize; i++) 786 | bytes[i] = CPU.physicalMemory[victim.addrPhysical+i]; 787 | 788 | // Copy details from the MemoryPage to the MemoryPageValue 789 | pageValue.memory = bytes; 790 | pageValue.accessCount = victim.accessCount; 791 | pageValue.lastAccessed = victim.lastAccessed; 792 | 793 | //Console.WriteLine("Swapping out page {0} at physical memory {1}",victim.pageNumber, victim.addrPhysical); 794 | 795 | // Write the MemoryPageValue to disk! 796 | ser.Serialize(writer,pageValue); 797 | 798 | //writer.Flush(); 799 | //writer.Close(); 800 | fs.Close(); 801 | } 802 | victim.isValid = false; 803 | } 804 | 805 | /// 806 | /// Swaps in the specified from disk. Currently implemented as XML for fun. 807 | /// 808 | /// The that is being swapped in 809 | public void SwapIn(MemoryPage winner) 810 | { 811 | // Generate a filename based on address and page number 812 | string filename = System.Environment.CurrentDirectory + "/page" + winner.pageNumber + "-" + winner.addrVirtual + ".xml"; 813 | if (File.Exists(filename) && winner.isValid == false) 814 | { 815 | //BinaryFormatter ser = new BinaryFormatter(); 816 | //Stream reader = new FileStream(filename, FileMode.Open); 817 | 818 | XmlSerializer ser = new XmlSerializer(typeof(MemoryPageValue)); 819 | Stream fs = new FileStream(filename, FileMode.Open); 820 | XmlReader reader = new XmlTextReader(fs); 821 | 822 | // Load the MemoryPageValue in from Disk! 823 | MemoryPageValue pageValue = (MemoryPageValue)ser.Deserialize(reader); 824 | 825 | // Copy the bytes from Physical Memory so we don't pageFault in a Fault Hander 826 | for (int i = 0; i < CPU.pageSize; i++) 827 | CPU.physicalMemory[winner.addrPhysical+i] = pageValue.memory[i]; 828 | 829 | //Console.WriteLine("Swapping in page {0} at physical memory {1}",winner.pageNumber, winner.addrPhysical); 830 | 831 | winner.accessCount = pageValue.accessCount; 832 | winner.lastAccessed = pageValue.lastAccessed; 833 | 834 | pageValue = null; 835 | 836 | reader.Close(); 837 | fs.Close(); 838 | File.Delete(filename); 839 | } 840 | else //no swap file, do nothing 841 | { 842 | //Console.WriteLine(filename + " doesn't exist"); 843 | } 844 | 845 | // We are now in memory and we were involved in Page Fault 846 | winner.isValid = true; 847 | winner.pageFaults++; 848 | } 849 | 850 | /// 851 | /// For statistical purposes only. 852 | /// Total up how many times this Process has been involved in a Page Fault 853 | /// 854 | /// The Process to total 855 | /// number of Page Faults 856 | public uint PageFaultsForProcess(Process p) 857 | { 858 | uint totalPageFaults = 0; 859 | foreach (MemoryPage page in _pageTable) 860 | { 861 | if (page.pidOwner == p.PCB.pid) 862 | { 863 | totalPageFaults += page.pageFaults; 864 | } 865 | } 866 | return totalPageFaults; 867 | } 868 | } 869 | 870 | /// 871 | /// Memory Protection: MemoryExceptions are constructed and thrown 872 | /// when a accessed memory that doesn't belong to it. 873 | /// 874 | public class MemoryException : Exception 875 | { 876 | /// 877 | /// Process ID 878 | /// 879 | public uint pid = 0; 880 | /// 881 | /// Process address in question 882 | /// 883 | public uint processAddress = 0; 884 | 885 | /// 886 | /// Public Constructor for a Memory Exception 887 | /// 888 | /// Process ID 889 | /// Process address 890 | public MemoryException(uint pidIn, uint addrIn) 891 | { 892 | pid = pidIn; 893 | processAddress = addrIn; 894 | } 895 | 896 | /// 897 | /// Pretty printing for MemoryExceptions 898 | /// 899 | /// Formatted string about the MemoryException 900 | public override string ToString() 901 | { 902 | return String.Format("Process {0} tried to access memory at address {1} and will be terminated! ",pid, processAddress); 903 | } 904 | } 905 | 906 | /// 907 | /// Memory Protection: MemoryExceptions are constructed and thrown 908 | /// when a accessed memory that doesn't belong to it. 909 | /// 910 | public class StackException : Exception 911 | { 912 | /// 913 | /// Process ID 914 | /// 915 | public uint pid = 0; 916 | /// 917 | /// Num of Bytes more than the stack could handle 918 | /// 919 | public uint tooManyBytes = 0; 920 | 921 | /// 922 | /// Public Constructor for a Memory Exception 923 | /// 924 | /// Process ID 925 | /// Process address 926 | public StackException(uint pidIn, uint tooManyBytesIn) 927 | { 928 | pid = pidIn; 929 | tooManyBytes = tooManyBytesIn; 930 | } 931 | 932 | /// 933 | /// Pretty printing for MemoryExceptions 934 | /// 935 | /// Formatted string about the MemoryException 936 | public override string ToString() 937 | { 938 | return String.Format("Process {0} tried to push {1} too many bytes on to the stack and will be terminated! ",pid, tooManyBytes); 939 | } 940 | } 941 | 942 | /// 943 | /// Memory Protection: MemoryExceptions are constructed and thrown 944 | /// when a accessed memory that doesn't belong to it. 945 | /// 946 | public class HeapException : Exception 947 | { 948 | /// 949 | /// Process ID 950 | /// 951 | public uint pid = 0; 952 | /// 953 | /// Num of Bytes more than the stack could handle 954 | /// 955 | public uint tooManyBytes = 0; 956 | 957 | /// 958 | /// Public Constructor for a Memory Exception 959 | /// 960 | /// Process ID 961 | /// Process address 962 | public HeapException(uint pidIn, uint tooManyBytesIn) 963 | { 964 | pid = pidIn; 965 | tooManyBytes = tooManyBytesIn; 966 | } 967 | 968 | /// 969 | /// Pretty printing for MemoryExceptions 970 | /// 971 | /// Formatted string about the MemoryException 972 | public override string ToString() 973 | { 974 | return String.Format("Process {0} tried to alloc {1} bytes more from the heap than were free and will be terminated! ",pid, tooManyBytes); 975 | } 976 | } 977 | 978 | 979 | } 980 | -------------------------------------------------------------------------------- /src/TinyOSCore/Process.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | using System; 35 | using System.Collections; 36 | 37 | namespace Hanselman.CST352 38 | { 39 | 40 | /// 41 | /// Represents a running Process in the table. Implements 42 | /// so two Processes can be compared with > and <. This will allow easy sorting of the runningProcesses table 43 | /// based on . 44 | /// 45 | public class Process : IComparable 46 | { 47 | /// 48 | /// Process Constructor 49 | /// 50 | /// the readonly unique id for this Process 51 | /// the ammount of memory this Process and address 52 | public Process(uint processId, uint memorySize) 53 | { 54 | PCB = new ProcessControlBlock(processId, memorySize); 55 | } 56 | 57 | /// 58 | /// 59 | /// 60 | public ProcessControlBlock PCB; 61 | 62 | 63 | /// 64 | /// Internal class to that represents a ProcessControlBlock. It isn't a struct so it can have 65 | /// instance field initializers. Maintains things like and for this 66 | /// Process. 67 | /// 68 | /// Global Data Region at R9 and SP at R10 are set in 69 | /// 70 | public class ProcessControlBlock 71 | { 72 | /// 73 | /// Constructor for a ProcessControlBlock 74 | /// 75 | /// the new readonly ProcessId. Set only once, readonly afterwards. 76 | /// 77 | public ProcessControlBlock(uint id, uint memorySize) 78 | { 79 | pid = id; 80 | registers[8] = (uint)pid; 81 | processMemorySize = memorySize; 82 | } 83 | #region Process Details 84 | 85 | /// 86 | /// The OS-wide unique Process ID. This is set in the constructor. 87 | /// 88 | public readonly uint pid; 89 | 90 | /// 91 | /// The length of the code segement for this Process relative to the 0. It points one byte after the code segment. 92 | /// 93 | public uint codeSize = 0; 94 | 95 | /// 96 | /// Maximum size of the stack for this Process 97 | /// 98 | public uint stackSize = 0; 99 | 100 | /// 101 | /// Size of the Data Segement for this Process 102 | /// 103 | public uint dataSize = 0; 104 | 105 | /// 106 | /// Start address of the Heap for this Process 107 | /// 108 | public uint heapAddrStart = 0; 109 | 110 | /// 111 | /// End Address of the Heap for this Process 112 | /// 113 | public uint heapAddrEnd = 0; 114 | 115 | /// 116 | /// ArrayList of MemoryPages that are associated with the Heap for this Process 117 | /// 118 | public ArrayList heapPageTable = new ArrayList(); 119 | 120 | /// 121 | /// The ammount of memory this Process is allowed to access. 122 | /// 123 | public uint processMemorySize = 0; 124 | #endregion 125 | 126 | #region Process State 127 | /// 128 | /// The states this Process can go through. Starts at NewProcess, changes to Running. 129 | /// 130 | public ProcessState state = ProcessState.NewProcess; 131 | 132 | /// 133 | /// We have 10 registers. R11 is the , and we don't use R0. R10 is the . So, that's 1 to 10, and 11. 134 | /// 135 | public uint[] registers = new uint[12]; 136 | 137 | /// 138 | /// We have a Sign Flag and a Zero Flag in a 139 | /// 140 | private BitArray bitFlagRegisters = new BitArray(2,false); 141 | 142 | /// 143 | /// This Process's current priority. Can be changed programmatically. 144 | /// 145 | public int priority = 1; 146 | 147 | /// 148 | /// The number of this can execute before being switched out. 149 | /// 150 | public int timeQuantum = 5; 151 | 152 | /// 153 | /// If we are waiting on a lock, we'll store it's value here 154 | /// 155 | public uint waitingLock = 0; 156 | 157 | /// 158 | /// If we are waiting on an event, we'll store it's value here 159 | /// 160 | public uint waitingEvent = 0; 161 | #endregion 162 | 163 | #region Counter Variables 164 | /// 165 | /// The number of clockCycles this has executed 166 | /// 167 | public int clockCycles = 0; 168 | 169 | /// 170 | /// The number of additional to sleep. 171 | /// If we are in a waiting state, and this is 0, we will sleep forever. 172 | /// If this is 1 (we are about to wake up) our state will change to ProcessState.Running 173 | /// 174 | public uint sleepCounter = 0; 175 | 176 | /// 177 | /// The number of times this application has been switched out 178 | /// 179 | public int contextSwitches = 0; 180 | 181 | /// 182 | /// The number of pageFaults this has experienced. 183 | /// 184 | public int pageFaults = 0; 185 | #endregion 186 | 187 | #region Accessors 188 | /// 189 | /// Public get/set accessor for the Sign Flag 190 | /// 191 | public bool sf //Sign Flag 192 | { 193 | get { return bitFlagRegisters[0]; } 194 | set { bitFlagRegisters[0] = value; } 195 | } 196 | 197 | /// 198 | /// Public get/set accessor for the Zero Flag 199 | /// 200 | public bool zf //Zero Flag 201 | { 202 | get { return bitFlagRegisters[1]; } 203 | set { bitFlagRegisters[1] = value; } 204 | } 205 | 206 | /// 207 | /// Public get/set accessor for the Stack Pointer 208 | /// 209 | public uint sp 210 | { 211 | get { return registers[10]; } 212 | set { registers[10] = value; } 213 | } 214 | 215 | /// 216 | /// Public get/set accessor for the Instruction Pointer 217 | /// 218 | public uint ip 219 | { 220 | get { return registers[11]; } 221 | set { registers[11] = value; } 222 | } 223 | #endregion 224 | } 225 | 226 | 227 | /// 228 | /// Needed to implement . Compares Processes based on . 229 | ///
230 | 		/// Value                  Meaning 
231 | 		/// --------------------------------------------------------
232 | 		///	Less than zero         This instance is less than obj
233 | 		/// Zero                   This instance is equal to obj 
234 | 		/// Greater than an zero   This instance is greater than obj
235 | 		/// 
236 | ///
237 | /// 238 | /// 239 | public int CompareTo(object obj) 240 | { 241 | if (obj is Process) 242 | { 243 | //We want to sort HIGHEST priority first (reverse of typical) 244 | // Meaning 9,8,7,6,5,4,3,2,1 245 | Process p = (Process)obj; 246 | if (this.PCB.priority < p.PCB.priority) return 1; 247 | if (this.PCB.priority > p.PCB.priority) return -1; 248 | if (this.PCB.priority == p.PCB.priority) 249 | { 250 | //Make sure potentially starved processes get a chance 251 | if (this.PCB.clockCycles < p.PCB.clockCycles) return 1; 252 | if (this.PCB.clockCycles > p.PCB.clockCycles) return -1; 253 | } 254 | return 0; 255 | } 256 | else 257 | throw new ArgumentException(); 258 | } 259 | } 260 | #region Process-specific enums 261 | 262 | /// 263 | /// All the states a can experience. 264 | /// 265 | public enum ProcessState 266 | { 267 | /// 268 | /// A initial state 269 | /// 270 | NewProcess = 0, 271 | /// 272 | /// The state of a ready to run 273 | /// 274 | Ready, 275 | /// 276 | /// The state of the currently running 277 | /// 278 | Running, 279 | /// 280 | /// The state of a waiting after a Sleep 281 | /// 282 | WaitingAsleep, 283 | /// 284 | /// The state of a waiting after an AcquireLock 285 | /// 286 | WaitingOnLock, 287 | /// 288 | /// The state of a waiting after a WaitEvent 289 | /// 290 | WaitingOnEvent, 291 | /// 292 | /// The state of a waiting to be removed from the Running 293 | /// 294 | Terminated 295 | } 296 | 297 | /// 298 | /// The Range of a can experience. 299 | /// 300 | public enum ProcessPriority 301 | { 302 | /// 303 | /// The lowest priority a can be 304 | /// 305 | LowPriority = 0, 306 | /// 307 | /// The Highest priority a can be 308 | /// 309 | MaxPriority = 31 310 | } 311 | #endregion 312 | } 313 | 314 | -------------------------------------------------------------------------------- /src/TinyOSCore/ProcessCollection.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | namespace Hanselman.CST352 35 | { 36 | using System; 37 | using System.Collections; 38 | 39 | 40 | /// 41 | /// 42 | /// A collection that stores objects. 43 | /// 44 | /// 45 | /// 46 | [Serializable()] 47 | public class ProcessCollection : CollectionBase, IComparer 48 | { 49 | 50 | /// 51 | /// 52 | /// Initializes a new instance of . 53 | /// 54 | /// 55 | public ProcessCollection() 56 | { 57 | } 58 | 59 | /// 60 | /// 61 | /// Initializes a new instance of based on another . 62 | /// 63 | /// 64 | /// 65 | /// A from which the contents are copied 66 | /// 67 | public ProcessCollection(ProcessCollection value) 68 | { 69 | this.AddRange(value); 70 | } 71 | 72 | /// 73 | /// 74 | /// Initializes a new instance of containing any array of objects. 75 | /// 76 | /// 77 | /// 78 | /// A array of objects with which to intialize the collection 79 | /// 80 | public ProcessCollection(Process[] value) 81 | { 82 | this.AddRange(value); 83 | } 84 | 85 | /// 86 | /// Represents the entry at the specified index of the . 87 | /// 88 | /// The zero-based index of the entry to locate in the collection. 89 | /// 90 | /// The entry at the specified index of the collection. 91 | /// 92 | /// is outside the valid range of indexes for the collection. 93 | public Process this[int index] 94 | { 95 | get 96 | { 97 | return ((Process)(List[index])); 98 | } 99 | set 100 | { 101 | List[index] = value; 102 | } 103 | } 104 | 105 | /// 106 | /// Adds a with the specified value to the 107 | /// . 108 | /// 109 | /// The to add. 110 | /// 111 | /// The index at which the new element was inserted. 112 | /// 113 | /// 114 | public int Add(Process value) 115 | { 116 | return List.Add(value); 117 | } 118 | 119 | /// 120 | /// Copies the elements of an array to the end of the . 121 | /// 122 | /// 123 | /// An array of type containing the objects to add to the collection. 124 | /// 125 | /// 126 | /// None. 127 | /// 128 | /// 129 | public void AddRange(Process[] value) 130 | { 131 | for (int i = 0; (i < value.Length); i = (i + 1)) 132 | { 133 | this.Add(value[i]); 134 | } 135 | } 136 | 137 | /// 138 | /// 139 | /// Adds the contents of another to the end of the collection. 140 | /// 141 | /// 142 | /// 143 | /// A containing the objects to add to the collection. 144 | /// 145 | /// 146 | /// None. 147 | /// 148 | /// 149 | public void AddRange(ProcessCollection value) 150 | { 151 | for (int i = 0; (i < value.Count); i = (i + 1)) 152 | { 153 | this.Add(value[i]); 154 | } 155 | } 156 | 157 | /// 158 | /// Gets a value indicating whether the 159 | /// contains the specified . 160 | /// 161 | /// The to locate. 162 | /// 163 | /// if the is contained in the collection; 164 | /// otherwise, . 165 | /// 166 | /// 167 | public bool Contains(Process value) 168 | { 169 | return List.Contains(value); 170 | } 171 | 172 | 173 | /// 174 | /// Implemented for IComparable. 175 | /// 176 | /// A Process object 177 | /// A Process object 178 | /// a comparison int from CompareTo 179 | public int Compare(object x, object y) 180 | { 181 | Process px = (Process)x; 182 | Process py = (Process)y; 183 | 184 | return px.CompareTo(py); 185 | } 186 | 187 | /// 188 | /// Sorts the list of based on 189 | /// 190 | public void Sort() 191 | { 192 | InnerList.Sort((IComparer)this); 193 | } 194 | 195 | /// 196 | /// Copies the values to a one-dimensional instance at the 197 | /// specified index. 198 | /// 199 | /// The one-dimensional that is the destination of the values copied from . 200 | /// The index in where copying begins. 201 | /// 202 | /// None. 203 | /// 204 | /// is multidimensional. -or- The number of elements in the is greater than the available space between and the end of . 205 | /// is . 206 | /// is less than 's lowbound. 207 | /// 208 | public void CopyTo(Process[] array, int index) { 209 | List.CopyTo(array, index); 210 | } 211 | 212 | /// 213 | /// Returns the index of a in 214 | /// the . 215 | /// 216 | /// The to locate. 217 | /// 218 | /// The index of the of in the 219 | /// , if found; otherwise, -1. 220 | /// 221 | /// 222 | public int IndexOf(Process value) { 223 | return List.IndexOf(value); 224 | } 225 | 226 | /// 227 | /// Inserts a into the at the specified index. 228 | /// 229 | /// The zero-based index where should be inserted. 230 | /// The to insert. 231 | /// None. 232 | /// 233 | public void Insert(int index, Process value) { 234 | List.Insert(index, value); 235 | } 236 | 237 | /// 238 | /// Returns an enumerator that can iterate through 239 | /// the . 240 | /// 241 | /// None. 242 | /// 243 | public new ProcessEnumerator GetEnumerator() { 244 | return new ProcessEnumerator(this); 245 | } 246 | 247 | /// 248 | /// Removes a specific from the 249 | /// . 250 | /// 251 | /// The to remove from the . 252 | /// None. 253 | /// is not found in the Collection. 254 | public void Remove(Process value) { 255 | List.Remove(value); 256 | } 257 | 258 | /// 259 | /// Provided for "foreach" support with this collection 260 | /// 261 | public class ProcessEnumerator : object, IEnumerator 262 | { 263 | 264 | private IEnumerator baseEnumerator; 265 | 266 | private IEnumerable temp; 267 | 268 | /// 269 | /// Public constructor for an ProcessEnumerator 270 | /// 271 | /// The we are going to iterate over 272 | public ProcessEnumerator(ProcessCollection mappings) 273 | { 274 | this.temp = ((IEnumerable)(mappings)); 275 | this.baseEnumerator = temp.GetEnumerator(); 276 | } 277 | 278 | /// 279 | /// The current 280 | /// 281 | public Process Current 282 | { 283 | get { 284 | return ((Process)(baseEnumerator.Current)); 285 | } 286 | } 287 | 288 | /// 289 | /// The current IEnumerator interface 290 | /// 291 | object IEnumerator.Current 292 | { 293 | get { 294 | return baseEnumerator.Current; 295 | } 296 | } 297 | 298 | /// 299 | /// Move to the next Process 300 | /// 301 | /// true or false based on success 302 | public bool MoveNext() 303 | { 304 | return baseEnumerator.MoveNext(); 305 | } 306 | 307 | /// 308 | /// Move to the next Process 309 | /// 310 | /// true or false based on success 311 | bool IEnumerator.MoveNext() 312 | { 313 | return baseEnumerator.MoveNext(); 314 | } 315 | 316 | /// 317 | /// Reset the cursor 318 | /// 319 | public void Reset() 320 | { 321 | baseEnumerator.Reset(); 322 | } 323 | 324 | /// 325 | /// Reset the cursor 326 | /// 327 | void IEnumerator.Reset() 328 | { 329 | baseEnumerator.Reset(); 330 | } 331 | } 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /src/TinyOSCore/Program.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // Copyright (c) Scott Hanselman. All Rights Reserved. 4 | // 5 | // ------------------------------------------------------------------------------ 6 | // 7 | // Scott Hanselman's Tiny Academic Virtual CPU and OS 8 | // Copyright (c) 2002, Scott Hanselman (scott@hanselman.com) 9 | // All rights reserved. 10 | // 11 | // A BSD License 12 | // Redistribution and use in source and binary forms, with or without modification, 13 | // are permitted provided that the following conditions are met: 14 | // 15 | // Redistributions of source code must retain the above copyright notice, 16 | // this list of conditions and the following disclaimer. 17 | // Redistributions in binary form must reproduce the above copyright notice, 18 | // this list of conditions and the following disclaimer in the documentation 19 | // and/or other materials provided with the distribution. 20 | // Neither the name of Scott Hanselman nor the names of its contributors 21 | // may be used to endorse or promote products derived from this software without 22 | // specific prior written permission. 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 27 | // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 | // THE POSSIBILITY OF SUCH DAMAGE. 33 | // 34 | using System; 35 | using System.Collections; 36 | using System.IO; 37 | using System.Configuration; 38 | 39 | namespace Hanselman.CST352 40 | { 41 | /// 42 | /// Represents a Program (not a ) on disk and the s it's comprised of. 43 | /// Used as a utility class to load a off disk. 44 | /// 45 | public class Program 46 | { 47 | private InstructionCollection instructions = null; 48 | 49 | /// 50 | /// Public constructor for a Program 51 | /// 52 | /// The collection of objects that make up this Program 53 | public Program(InstructionCollection instructionsParam) 54 | { 55 | instructions = new InstructionCollection(instructionsParam); 56 | } 57 | 58 | /// 59 | /// Spins through the and creates an array of bytes 60 | /// that is then copied into Memory by 61 | /// 62 | /// Array of bytes representing the in memory 63 | unsafe public byte[] GetMemoryImage() 64 | { 65 | ArrayList arrayListInstr = new ArrayList(); 66 | 67 | foreach (Instruction instr in instructions) 68 | { 69 | // Instructions are one byte 70 | arrayListInstr.Add((byte)instr.OpCode); 71 | 72 | // Params are Four Bytes 73 | if (instr.Param1 != uint.MaxValue) 74 | { 75 | byte[] paramBytes = CPU.UIntToBytes(instr.Param1); 76 | for (int i = 0; i < paramBytes.Length; i++) 77 | arrayListInstr.Add(paramBytes[i]); 78 | } 79 | 80 | if (instr.Param2 != uint.MaxValue) 81 | { 82 | byte[] paramBytes = CPU.UIntToBytes(instr.Param2); 83 | for (int i = 0; i < paramBytes.Length; i++) 84 | arrayListInstr.Add(paramBytes[i]); 85 | } 86 | } 87 | 88 | // Create and array of bytes and return the instructions in it 89 | arrayListInstr.TrimToSize(); 90 | byte[] arrayInstr = new byte[arrayListInstr.Count]; 91 | arrayListInstr.CopyTo(arrayInstr); 92 | return arrayInstr; 93 | } 94 | 95 | /// 96 | /// Loads a Program from a file on disk. For each line the Program, create an 97 | /// and pass the raw string to the Instructions's constructor. The resulting 98 | /// is the Program 99 | /// 100 | /// file with code to load 101 | /// a new loaded Program 102 | public static Program LoadProgram(string fileName) 103 | { 104 | using (TextReader t = File.OpenText(fileName)) 105 | { 106 | InstructionCollection instructions = new InstructionCollection(); 107 | string strRawInstruction = t.ReadLine(); 108 | while (strRawInstruction != null) 109 | { 110 | instructions.Add(new Instruction(strRawInstruction)); 111 | strRawInstruction = t.ReadLine(); 112 | } 113 | Program p = new Program(instructions); 114 | t.Close(); 115 | return p; 116 | } 117 | } 118 | 119 | /// 120 | /// For Debugging, pretty prints the Instructions that make up this Program 121 | /// 122 | public void DumpProgram() 123 | { 124 | if (bool.Parse(EntryPoint.Configuration["DumpProgram"]) == false) 125 | return; 126 | 127 | foreach (Instruction i in this.instructions) 128 | Console.WriteLine(i.ToString()); 129 | Console.WriteLine(); 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /src/TinyOSCore/TinyOSCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net6.0 5 | true 6 | true 7 | 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | all 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/TinyOSCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "PhysicalMemory": "128", 3 | "ProcessMemory": "384", 4 | "DumpPhysicalMemory": "true", 5 | "DumpInstruction": "true", 6 | "DumpRegisters": "true", 7 | "DumpProgram": "true", 8 | "DumpContextSwitch": "true", 9 | "PauseOnExit": "false", 10 | "SharedMemoryRegionSize": "16", 11 | "NumOfSharedMemoryRegions": "4", 12 | "MemoryPageSize": "16", 13 | "StackSize": "16", 14 | "DataSize": "16" 15 | } 16 | -------------------------------------------------------------------------------- /src/TinyOSCore/publish.bat: -------------------------------------------------------------------------------- 1 | dotnet publish -r win-x64 --self-contained -p:PublishSingleFile=true -p:SuppressTrimAnalysisWarnings=true -p:EnableCompressionInSingleFile=true --------------------------------------------------------------------------------