diff --git a/README.md b/README.md index d1e3befe..2632c436 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/MARIE-js/MARIE.js.svg?branch=master)](https://travis-ci.org/MARIE-js/MARIE.js) [![Gitter chat](https://badges.gitter.im/MARIE-js/gitter.png)](https://gitter.im/MARIE-js/Lobby) [![npm version](https://badge.fury.io/js/npm.svg)](https://badge.fury.io/js/npm) ============== -Current version: `0.9.2` +Current version: `0.9.3` MARIE.js is an implementation of a simulator for a 'Machine Architecture that is Really Intuitive and Easy' from [The Essentials of Computer Organization and Architecture](https://books.google.com.au/books/about/The_Essentials_of_Computer_Organization.html?id=3kQoAwAAQBAJ&redir_esc=y) (Linda Null, Julia Lobur) in JavaScript. diff --git a/package.json b/package.json index f86764e4..269a5577 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "MARIE.js", - "version": "0.9.2", + "version": "0.9.3", "description": "MARIE.js is an implementation of a simulator for a 'Machine Architecture that is Really Intuitive and Easy' from The Essentials of Computer Organization and Architecture (Linda Null, Julia Lobur) in JavaScript.", "main": "index.js", "scripts": { diff --git a/src/code/multiply.mas b/src/code/multiply.mas index 27190db9..8f398da4 100644 --- a/src/code/multiply.mas +++ b/src/code/multiply.mas @@ -24,4 +24,7 @@ loop, Load num / Output result to user then halt program Load num Output -Halt \ No newline at end of file +Halt + +X, DEC 0 +Y, DEC 0 \ No newline at end of file diff --git a/src/code/quicksort.mas b/src/code/quicksort.mas new file mode 100644 index 00000000..e95df0cd --- /dev/null +++ b/src/code/quicksort.mas @@ -0,0 +1,545 @@ +/ Recursive QuickSort Example Code +/ by Felix Salim, allowed for use by The MARIE.JS Team +/ Copyright (C) 2016. Licensed under the MIT License + +/Note: the comments assume for a basic understanding for the quicksort algorithm + Jump Begin /Skips the variables defined below + +/Variables for the list creation +Size, DEC 0 +Counter, DEC 0 + +/Numeric variables for basic addition +One, DEC 1 +Two, DEC 2 +Four, DEC 4 +MinOne, DEC -1 + +/List management +ListAddress, HEX 330 /Stores the starting address of the list +ListAddPointer, HEX 330 /Points to the current item of the list +ListAllocation, HEX 300 /Stores the addresses of the start addresses + /of all lists created +/Stack management +StackPointer, HEX 700 /Stack's beginning address + +/Temporary labels +t0, DEC 0 /Used to store various (temporary) values +t1, DEC 0 +temp, DEC 0 /This is used specifically to load/store indirectly multiple times + + /The main program reads a list then sorts it: + /First the user is prompted for a size, N, of a list to create, and will prompt N times, each + /time appending the value entered to the list +Begin, Input /Input size + Store Size /Store to both Size and Counter labels + Store Counter + + StoreI ListAddress /Store size value at the list's starting address + + Load ListAddress /Store the list's starting address as reference + StoreI ListAllocation + + Load ListAllocation /Move this pointer up (one value), ready to + Add One /store the address of another list (if needed) + Store ListAllocation + + Load Counter /Load the counter (which decreases every time a value + /is entered to the current list + +EnterItems, Skipcond 800 /Don't end if there are still items left to enter + Jump StopEnterItems + + Load ListAddPointer /Move list pointer up by one value + Add One + Store ListAddPointer + + Input /Enter item + StoreI ListAddPointer /Store to the location of the pointer + + Load Counter /Reduce counter by one + Add MinOne + Store Counter + + Jump EnterItems /Repeat + +StopEnterItems, Load ListAddPointer /Move the list pointer up one more time + Add One + Store ListAddPointer /Reset both list pointer and the actual starting + Store ListAddress /address to the next available spot for a new list + + + /Call the quicksort subroutine + + /Store arguments onto the stack + Load StackPointer /Move stack pointer up by one (allocates a slot in the stack + Add MinOne /for a value to store) + Store StackPointer + + /Store the size of required list to sort on the stack + Load ListAllocation /Load the address of the list to sort. This is at the + Add MinOne /list of the address of lists + + Store temp /Store this value to temp first + + LoadI temp /Then load the list's start address (containing the size value) + /by indirect load + Store temp /Save address to temp + LoadI temp /Load indirectly again to obtain the size value + StoreI StackPointer /Store to stack + + /Store the address of the first item of the list (i.e. not including the size value) + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load ListAllocation /Take address of the list required + Add MinOne /(Negative 1 offset first, as before) + Store temp /Load indirectly to obtain the list's address + LoadI temp + Add One /Add an offset of 1 to ignore the size value + StoreI StackPointer /Store address to the stack + + /Jump to quicksort + JnS quicksort + + /Return from quicksort + Load StackPointer /This moves the stack pointer to its original location (clears + AddI Two /stored values on the stack) from where the subroutine began + StoreI StackPointer + /End quicksort subroutine + + /Print the sorted list + Load ListAllocation /Load the location of the list's address + Add MinOne + Store temp + LoadI temp /This loads the list's address + Store temp + LoadI temp /and take the size of the list + Store t0 /to store into t0 (this is a counter) + + Load temp /Load address from temp and add one + Add One + Store t1 /store to t1. It is a temporary list pointer + + Load t0 /Load counter + +PrintList, Skipcond 800 /Continue to print if the counter hasn't reached 0 + Jump EndMain + + LoadI t1 /Load item in the list pointer + Output + + Load t1 /Move list pointer up + Add One + Store t1 + + Load t0 /Reduce counter by one + Add MinOne + Store t0 + + Jump PrintList + +EndMain, Halt + +/Start of quicksort subroutine +quicksort, HEX 000 /Stores the most recent return address (PC value) + + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load quicksort /Take the return address created from JnS + StoreI StackPointer /and store on the stack for later use. This is done as a + /result of the recursive subroutine + + + /Load the arguments from the caller, and store onto the stack as local variables + /size + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load StackPointer /Obtain the argument 'size' by first loading the stack pointer + Add One /then adding an offset of +3 from the stack pointer + Add Two /to find the relative location of the actual argument required + Store temp /Store the address of where the argument is (to temp) + LoadI temp /and load indirectly from it + StoreI StackPointer /Store the size to the top of the stack + + /listAddress + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load StackPointer /Load the stack pointer (as before) + Add One /Notice the offset (+3) is the same as the previous argument + Add Two /since the stack pointer has moved up + Store temp /Similarly, store the stack pointer with the offset, + LoadI temp /load indirectly from it + StoreI StackPointer /then store the obtained value to the top of the stack + + + /Allocate more local variables + /Save the end address of the list to the stack + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + /The end address requires some arithmetic: + Load StackPointer /Load list address and save to temporary label (t0) + Add One + Store temp + LoadI temp + Store t0 + + Load StackPointer /Load the size of the list + Add Two + Store temp + LoadI temp + + Add MinOne /Reduce the size by one. This value is added to the starting + /address of the list, which gets an address which points + /to the last item of the list + + Add t0 /Add the list address to the modified size value, resulting in the + /required end address + StoreI StackPointer /and store to the stack + + /Calculate and store the left mark (Lmark) + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load StackPointer /Lmark is the list address (which will be described as 'start' as + /a local variable) plus one. The first item is ignored since that + /is being compared with the rest of the list + Add Two /(Variable) start is at offset of +2 + Store temp + LoadI temp /Load start, add one (as described above) and then store to stack + Add One + StoreI StackPointer + + /Calculate and store the right mark (Rmark) + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load StackPointer /Rmark is the ending address of the list, which was already + Add Two /calculated previously. It is stored at an offset of +2 + Store temp + LoadI temp + StoreI StackPointer + + /Compares the start address and end address. This will stop the sort if they are the same + /(i.e. if the size of the list is less than 2) + Load StackPointer /take start address and place into t0 + Add One + Add Two + Store temp + LoadI temp + Store t0 + + Load StackPointer /Load end address + Add Two + Store temp + LoadI temp + + Subt t0 /Find the difference (end - start) + + Skipcond 800 /If start address is less (giving a positive value), then + /continue the sort + Jump EndImmediately /Otherwise, end the subroutine + + /This is the main loop in which items are swapped based on their value compared to the + /starting item. It starts with a condition to check if the marks have crossed or not +MainSort, LoadI StackPointer /Load Rmark (already at the top of the stack) and store to t0 + Store t0 + + Load StackPointer /Load Lmark + Add One + Store temp + LoadI temp + + Subt t0 /Find Lmark - Rmark + + Skipcond 800 /If Lmark > Rmark, then move on to sort the next partitions + Jump ReduceRmark /Otherwise, start/continue the current sort + Jump NextSort + + /Keep reducing Rmark until it finds an item that is less than or equal to the start item +ReduceRmark, Load StackPointer /Load item in start address and store to t0 + Add One + Add Two + Store temp + LoadI temp /This loads the start address + Store temp + LoadI temp /This loads the item in the start address + Store t0 + + Load StackPointer /Load item in the Rmark address + Store temp + LoadI temp /This loads the Rmark address + Store temp + LoadI temp /This loads the item + + Subt t0 /Find the difference between the two items + /L[Rmark] - L[start] (to relate to a high-level language) + + Skipcond 800 /Only continue to move Rmark if the item in it is still greater + /than the item in start address + Jump IncreaseLmark /Otherwise, move on and increase Lmark + + LoadI StackPointer /Decrease Rmark (by one) + Add MinOne + StoreI StackPointer + + Jump ReduceRmark /Repeat the above loop + + /Keep increasing Lmark until it finds an item that is greater than the start item +IncreaseLmark, Load StackPointer /Load item in start address and store to t0 + Add One + Add Two + Store temp + LoadI temp /This loads the start address + Store temp + LoadI temp /This loads the item in the start address + Store t0 + + Load StackPointer /Load item in the Lmark address + Add One + Store temp + LoadI temp /This loads the Lmark address + Store temp + LoadI temp /This loads the item + + Subt t0 /Find the difference between the two items + /L[Lmark] - L[start] + + Skipcond 800 /Unlike when moving the Rmark, this loop is continued if the Lmark + /is less than or equal to the start item. This means the loop breaks + /if L[Lmark] - L[start] > 0 (one condition), instead of finding + /if L[start] - L[Lmarl] <= 0 (two conditions - less/equal) + + Jump InIntermediate /Jump to an intermediate label (in the same loop) if the above + /condition is false + + Jump SwapMarks /If true, however, it moves on to the next part + + /Intermediate label of IncreasingLmark +InIntermediate, Load StackPointer /Move Lmark up by one + Add One + Store temp + LoadI temp + Add One + Store t0 /Save Lmark to t0 first, as it will be stored back into the stack + /(which in itself requires more arithmetics) + + Load StackPointer /Load the stack pointer with an offset for Lmark item (+1) + Add One + Store temp /Save to temp, so that Lmark can be stored indirectly to it + + Load t0 /Load the modified Lmark + StoreI temp /Indirectly store to the relevant stack location + + /If Lmark is at the end of the list, then stop moving it up further + Load StackPointer /Load end address from stack + Add Two + Store temp + LoadI temp + Store t0 + + Load StackPointer /Load Lmark + Add One + Store temp + LoadI temp + + Subt t0 + + Skipcond 000 /If Lmark is greater than or equal to the end address, then stop + /moving it and move on to next part + Jump SwapMarks + + Jump IncreaseLmark /Otherwise, continue to move it + + /This swaps the items in Lmark and Rmark once they point to items + /that met the above conditions +SwapMarks, Load StackPointer /Load Lmark + Add One + Store temp + LoadI temp + Store t0 + + LoadI StackPointer /Load Rmark + + Subt t0 /Find Rmark - Lmark + + Skipcond 800 /Swap if Rmark > Lmark (i.e. don't swap if the marks + /have crossed or are equal) + Jump MainSort /Jump back to the start of the outer loop + + Load StackPointer /Load item in Lmark and store to t0 + Add One + Store temp + LoadI temp + Store temp + LoadI temp + Store t0 + + Load StackPointer /Load item in Rmark address and store to t1 + Store temp + LoadI temp + Store temp + LoadI temp + Store t1 + + Load StackPointer /Save item in Lmark into Rmark + Store temp + LoadI temp /This loads the Rmark address and stores it + Store temp + Load t0 /This loads the item in Lmark (in t0) and + StoreI temp /indirectly stores it into Rmark's address + + Load StackPointer /Save item in Rmark into Lmark + Add One + Store temp + LoadI temp /This loads the Lmark address and stores it + Store temp + Load t1 /This loads the item in Lmark (in t1) and + StoreI temp /indirectly stores it into Rmark's address + + Jump MainSort /Jump back to the start of the outer loop + + /Swaps the start item with the Rmark item and then recursively sorts the remaining halves + /of the list partitioned by Rmark +NextSort, Load StackPointer /Load item in start address to swap with item in Rmark + Add One /(store item in t0 first) + Add Two + Store temp + LoadI temp + Store temp + LoadI temp + Store t0 + + Load StackPointer /Load item in Rmark address and store to t1 + Store temp + LoadI temp + Store temp + LoadI temp + Store t1 + + Load StackPointer /Save item in start into Rmark + Store temp + LoadI temp + Store temp + Load t0 + StoreI temp + + Load StackPointer /Save item in Rmark into start + Add One + Add Two + Store temp + LoadI temp + Store temp + Load t1 + StoreI temp + + /Call quicksort on first half of list, from start address to Rmark - 1 address + /Store the size of the first half + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + /The size is given by Rmark - start + Load StackPointer /Load start address and save to t0 + Add Four + Store temp + LoadI temp + Store t0 + + Load StackPointer /Load Rmark + Add One + Store temp + LoadI temp + + Subt t0 /This subtraction gives the size + StoreI StackPointer + + /Store start address + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load StackPointer /Load start and save to argument + Add One + Add Four + Store temp + LoadI temp + StoreI StackPointer + + /Jump to quicksort + JnS quicksort + + /Return from quicksort + Load StackPointer /Clear stored values + Add Two + Store StackPointer + + + /Call quicksort on the second half of the list, from Rmark + 1 address to end address + /Store the size of the second half + Load StackPointer /Move stack pointer up + Add MinOne + Store StackPointer + + Load StackPointer /Load Rmark and save to t0 + Add One + Store temp + LoadI temp + Store t0 + + Load StackPointer /Load end address + Add Two + Add One + Store temp + LoadI temp + + Subt t0 /This subtraction gives the size + StoreI StackPointer + + /Store start address (which in this case is Rmark + 1) + Load StackPointer /Move stackPointer up + Add MinOne + Store StackPointer + + Load StackPointer /Load Rmark + Add Two + Store temp + LoadI temp + Add One /Add one to that address + StoreI StackPointer /Store to stack + + /Jump to quicksort + JnS quicksort + + /Return from quicksort + Load StackPointer /Clear stored values + Add Two + Store StackPointer + + /End the sort, continuing from where the subroutine was called +EndImmediately, Load StackPointer /Clear stored values created by the subroutine + Add One + Add Four + Store StackPointer + + LoadI StackPointer /Now the stack pointer points to the return address + Store temp /which is loaded and stored to temp + + Load StackPointer /Clear the return address from the stack + Add One + Store StackPointer + + JumpI temp /Return address is still saved in temp, so jump indirectly to it +/End of quicksort subroutine + \ No newline at end of file diff --git a/src/js/marie.js b/src/js/marie.js index 36ec0f70..df7e1ee5 100644 --- a/src/js/marie.js +++ b/src/js/marie.js @@ -301,14 +301,19 @@ var MarieSim, oldValue = this[target]; - this[target] = Utility.uintToInt(src & msk); - if(target == "pc") { - if(0 <= this[target] && this[target] >= 4096) { + if(this[target] >= 4096) { throw new MarieSimError("RuntimeError", "The address " + (this[target]).toString() + " is out of bounds."); } + else if(0 <= this[target]){ + throw new MarieSimError("RuntimeError", "The address -" + (this[target]).toString() + " is out of bounds."); + } } + this[target] = Utility.uintToInt(src & msk); + + + if (typeof source == "string") { if(this.onRegRead) { this.onRegRead.call(this, { @@ -382,10 +387,14 @@ var MarieSim, this[target] += typeof source == "string" ? this[source] : source; if(target == "pc") { - if(0 <= this[target] && this[target] >= 4096) { + if(this[target] >= 4096) { throw new MarieSimError("RuntimeError", "The address " + (this[target]).toString() + " is out of bounds."); } + else if(0 <= this[target]){ + throw new MarieSimError("RuntimeError", "The address -" + (this[target]).toString() + " is out of bounds."); + } } + } if(typeof source == "string") { diff --git a/src/js/tour.js b/src/js/tour.js index d53618e0..78899269 100644 --- a/src/js/tour.js +++ b/src/js/tour.js @@ -24,7 +24,7 @@ $(document).ready(function() { backdrop: true, element: "#program-container", title: "Coding Area", - content: "This is where you type your code here" + content: "This is where you type your code here, you can debug your code by opening 'Watchlist' and clicking to the right of the line number to add breakpoints. Green line shows current excution, grey line shows 'fetch' line " }, { onShow: viewHome, @@ -32,7 +32,7 @@ $(document).ready(function() { backdrop: true, element: "#register-container", title: "Registers", - content: "This shows you the register values" + content: "This area shows you the register values, we have the Accumlator (AC), Program Counter (PC), IR" }, { onShow: viewHome, @@ -40,7 +40,7 @@ $(document).ready(function() { backdrop: true, element: "#tab-container", title: "Values and Outputs", - content: "This shows you the output in Register Log, Output Values and how the data is being transferred in RTL" + content: "This shows you the output in Register Log, Output Values and how the data is being transferred in RTL, MAR, MBR and Input/Output" }, { onShow: viewHome, @@ -48,28 +48,35 @@ $(document).ready(function() { backdrop: true, element: "#status-info", title: "Status bar", - content: "Shows you current status: also shows error messages" + content: "This is the status bar, this area shows you error messages to help you debug your code" + }, + { + onShow: viewHome, + smartPlacement: true, + element: "#output-select", + title: "Select Output Type", + content: "Change the output type here with the options (HEX - Base 8, DEC - Base 10, ASCII - Base 16) . This by default is set to HEX. ", }, { onShow: viewHome, smartPlacement: true, element: "#bottom-menu", title: "Control Bar", - content: "This is the bar used for stepping through the code, and building it" + content: "This is the control bar used for controlling the execution and the assembling of the code" }, { onShow: viewHome, smartPlacement: true, element: "#assemble", title: "Assembling the Code", - content: "Build the code here" + content: "This button builds the code" }, { onShow: viewHome, smartPlacement: true, element: "#step", title: "Step", - content: "Step Through the Code using this button" + content: "This steps one line through the code" }, { onShow: viewHome, @@ -106,13 +113,6 @@ $(document).ready(function() { title: "Delay Slider", content: "This slider sets the timing of the execution of each step" }, - { - onShow: viewHome, - smartPlacement: true, - element: "#output-select", - title: "Select Output Type", - content: "Change the output type here with the options (HEX - Base 8, DEC - Base 10, ASCII - Base 16) . This by default is set to HEX. ", - }, { onShow: viewDatapath, smartPlacement: true, diff --git a/src/templates/about.ejs b/src/templates/about.ejs index 341d909e..1188223d 100644 --- a/src/templates/about.ejs +++ b/src/templates/about.ejs @@ -8,11 +8,29 @@

About MARIE

MARIE ('Machine Architecture that is Really Intuitive and Easy') is a machine architecture and assembly language from The Essentials of Computer Organization and Architecture (Linda Null, Julia Lobur). The publisher provides a set of simulators for the machine, written in Java. However, since using simulators can be rather difficult, we have implemented a web-based version, so that students are able to access it readily and easily. Since beginning the project we have added many features such as importing and exporting of Marie Assembly Source files (*.mas) to provide compatibility with the existing simulators.


+
+

Terms of Use

+ By agreeing to the following terms and conditions, you understand that: +

About MARIE.js

MARIE.js is an implementation of a simulator for a 'Machine Architecture that is Really Intuitive and Easy' in JavaScript.

It is currently developed by Jason Nguyen, Saurabh Joshi and Eric Jiang.

- +

Some example/demostration code is writtern by Felix Salim

+
+

License

+

Copyright (c) 2016 Jason Nguyen, Saurabh Joshi, Eric Jiang

+

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

+ +

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

+ +

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ +

This project is designed by students of:
Faculty of Information Technology, Monash
diff --git a/src/templates/index.ejs b/src/templates/index.ejs index f0ebab17..850cb563 100644 --- a/src/templates/index.ejs +++ b/src/templates/index.ejs @@ -5,10 +5,12 @@

-
+ + +
Assembly code: