[-]*\\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
--------------------------------------------------------------------------------