diff --git a/book/.gitignore b/book/.gitignore index c332cb36c..acac0987f 100644 --- a/book/.gitignore +++ b/book/.gitignore @@ -1,10 +1,13 @@ *.aux *.bbl *.blg +*.fdb_latexmk +*.fls *.lof *.log *.lol *.lot +*.synctex.gz *.toc *.blg *.bbl diff --git a/book/ibcm-chapter.pdf b/book/ibcm-chapter.pdf index 53fc79cba..61da8cfd8 100644 Binary files a/book/ibcm-chapter.pdf and b/book/ibcm-chapter.pdf differ diff --git a/book/ibcm.tex b/book/ibcm.tex index 548b05865..449846eac 100644 --- a/book/ibcm.tex +++ b/book/ibcm.tex @@ -735,21 +735,13 @@ \section{The IBCM Simulator/Debugger} you will lose any and all changes you have made to the memory locations! -\item The simulator page is a PHP script, which means that it will not - work if you are viewing it as a local file (if the beginning of your - URL is ``file://'' instead of ``http://''), or if the web server - hosting this page does not have PHP installed (this latter - restriction includes UVa's Collab web server). - -\item Browser compatibility: It has been tested in Internet Explorer - under Windows, Safari under Mac OS X, and Firefox under Windows, Mac - OS X, and Ubuntu Linux. Note that the display of the changing of the - values as the simulation is run (the PC, memory values, etc.) will - only work on some browser / operating system combinations (Firefox, - in particular, works well for this). The other browsers will have - the same end state after the program is run, but will not animate - the execution of the IBCM program when 'Run' is pressed (the 'Step' - command will still animate each step). +\item Browser compatibility: The simulator should work under any major + browsers released after 2018. Note that the display of the changing + of the values as the simulation is run (the PC, memory values, etc.) + only works under Firefox. The other browsers will have the same end + state after the program is run, but will not animate the execution + of the IBCM program when 'Run' is pressed (the 'Step' command will + still animate each step). \item The format of your program file is very rigid~-- the first four characters of each line are interpreted as a hexadecimal number. The @@ -1312,12 +1304,10 @@ \subsection{Materials Available} One of the assignments is to write a quine, or an IBCM program that will print itself out~-- the smallest quine produced is nine IBCM commands. -\item An online PHP/Javascript simulator, which is the primary way that +\item An online Javascript simulator, which is the primary way that the students program in IBCM. This is shown above in - Figure~\ref{wwwinterface}. The PHP is used to allow loading of an - IBCM program from a text file; the Javascript implements the IBCM - simulator in the browser itself. The simulator works across all - major browsers on all major operating systems. + Figure~\ref{wwwinterface}. The simulator works across all major + browsers released after 2018. \item A C++-based command-line program, which can both compile and execute IBCM programs. Not surprisingly, this is much faster than the online simulator. This is particularly useful for automated diff --git a/ibcm/directions.html b/ibcm/directions.html index 0c6baf8ef..72963309d 100644 --- a/ibcm/directions.html +++ b/ibcm/directions.html @@ -1,178 +1,176 @@ - - - - - - - IBCM Interface: Directions - - - - - -
-
-

IBCM Interface

- - -
- - -
- -

To get started programming IBCM programs, there are two documents -(both listed on the documentation section of -the main page): -the IBCM Principles of Operation describes -the IBCM language and all of the 16 available instructions, and -the IBCM code examples lists, and -explains, two programs that have been written in IBCM. Those programs -can be downloaded directly here -and here.

- -

The IBCM is not a real computer, of course. Nonetheless, one can -run programs written for it. The trick is that we have written a -PHP/Javascript "simulator", a program that makes another computer -behave more-or-less like the IBCM 2.2. The IBCM 2.2 simulator will -execute all the instructions of the machine and show the contents of -memory locations and the accumulator as it executes.

- -

To load a file, use the Browse button at the top of the -simulator page. Find the IBCM file, -and click on the "Load" button. The format of your program file is -very rigid -- the first four characters of each line are interpreted -as a hexadecimal number. The number on the first line is loaded into -location zero, the next into location one and so on. Characters after -the first four on each line are ignored, so you should use them to -comment the code. An invalid file will either not load up at all, or -will load up gibberish.

- -

The left side of the simulator lists all the memory locations -(using the hexadecimal address), the value in memory (if any), and the -PC (program counter) value. Note that any blank value field is -interpreted as'0000', as per the IBCM specification. The simulator -leaves uninitialized values blank to increase readability.

- -

The value column consists of a series of text boxes, which allow -you to directly edit the values in memory. The simulator will read -the current memory location from the appropriate textbox when -executing an instruction. You can undo any edits by using the Revert -button, described below. The IBCM simulator does not check to ensure -that your entered values are valid -- it is up to the user to do this. -Note that all hexadecimal values must be 4 digits (i.e. '0000', not -'0'), or else the simulator will not work correctly. Be sure -to read the section about crashing browsers and losing your work, -below. There is no way to save your edited work -- you will -need to copy the changes by hand. This is party due to a browser -limitation, and partly due to the fact that memory editing is meant to -be a debugging tool, not a means to write entire IBCM programs from -scratch.

- -

The 'PC' column lists the current value of the program counter. It -can have three values. Normally, it will have a left pointing arrow -('<-'), which indicates the next instruction that will be -executed. If the simulator is waiting for input, it will have a -capital 'I' (for Input) next to the input instruction that is -currently awaiting a value. Lastly, if the program has halted, then a -capital 'H' (for Halt) will be next to the halt instruction that was -executed.

- -

On the right side, the values of the accumulator and program -counter are listed, both in hexadecimal notation. The PC field will -also list, next to the hexadecimal address, if the simulator is -awaiting input or is halted. The Input box is used to read in user -input when a program requests it. When the simulator is waiting for -input, it will flash the 'Input' text. In addition, the simulator -will specify which type of input is being requested: 'hex' or 'asc' -for hexadecimal or ASCII input, respectively. Note that for entering -a hexadecimal value, you do not need to enter all 4 digits: i.e., you -can enter '12' instead of '0012'. This is distinctly different that -editing memory locations (you have to enter all 4 digits for those). -If you enter multiple characters for ASCII input, it will only read in -the first one.

- -

Below this are four buttons. Two control execution: Run, which -will start a program executing, and Step, which will execute a single -instruction. Note that Run will execute until either a halt command -is reached, or until an input command is reached. The other two -buttons control the resetting of the IBCM program. The Reset button -will reset the PC and accumulator, in effect allowing the program to -run again. It will not, however, modify any memory locations. The -Revert button will do what a Reset does, but will also reload the -memory locations to what they were when the file was last loaded (it -does not load the file from disk again). Thus, if you have edited any -of the memory locations (or the IBCM program has modified them), then -those changes will be erased on a Revert, but not on a Reset. Note -that a Revert will not modify memory addresses outside the range that -was loaded (i.e. any 'blank' values).

- -

Any output is displayed in the text area below these buttons. Each -output command prints the value (hexadecimal or ASCII character) on a -separate line.

- -

A few notes:

- - - - - -
-
-
- - - - + + diff --git a/ibcm/ibcm.css b/ibcm/ibcm.css index 33a760477..62af0b7b7 100644 --- a/ibcm/ibcm.css +++ b/ibcm/ibcm.css @@ -4,12 +4,84 @@ /* Created Day 01.12.2006 */ /* ======================================================== */ +* { + box-sizing: border-box; +} + +.grid { + display: grid; + grid-template-columns: 1fr 1fr; + column-gap: 1rem; + row-gap: 1rem; +} + +.grid .settings { + grid-column: 1 / 3; +} + +#instructionsTable { + width: 300px; +} + +#instructionsTable th { + position: sticky; + top: -2px; /* counteract the 2px border-top */ + background-color: #ffffff; +} + +.controls .internal { + position: sticky; + -webkit-position: sticky; /* Safari is still prefixed as of Safari 13, released Sept. 2019 */ + top: 1rem; +} + +.divider { + margin: 1.5rem 0; +} + +.input-group { + display: grid; + margin-bottom: 1.5rem; + grid-template-columns: 1fr 1fr; +} + +.input-group label { + text-align: right; + margin-right: 0.5rem; +} + +.control-grid { + display: flex; + flex-direction: row; + justify-content: center; +} + +.control-grid button { + margin: 0 0.25rem; +} + +.output-group { + text-align: center; +} + +.output-group label { + display: block; + margin-bottom: 0.5rem; +} + +.monospace-input { + font-family: monospace; +} + +.active { + font-style: italic; +} + body { margin: 0px; background: url(img/top_bg.gif); background-repeat: repeat-x; font-family: Verdana, Arial, sans-serif; - font-size: .6em; } p { @@ -78,7 +150,7 @@ blockquote{ #wrap { margin-left: auto; margin-right: auto; - width: 730px; + width: 50vw; } @@ -96,7 +168,7 @@ blockquote{ #top h2 { color: White; letter-spacing: 3px; - font-size: 2.4em; + font-size: 1.5em; font-weight: normal; position: relative; margin: 0px; @@ -302,24 +374,19 @@ blockquote{ /**** Table ***/ -div#tbl-container { - width: 309px; - height: 750px; - overflow: auto; -/* scrollbar-base-color:#ffeaff;*/ -} - table { table-layout: fixed; border-collapse: collapse; background-color: #f5f5f5; /* whitesmoke */ - margin-left: auto; - margin-right: auto; + margin: 0 auto; } -table.foo { - table-layout: fixed; - border-collapse: collapse; - background-color: #f5f5f5; /* whitesmoke */ - margin-right: auto; +table td, table th { + padding: 0.5rem; + border: 1px solid gray; +} + +table th { + border-top: 2px solid gray; + border-bottom: 2px solid gray; } diff --git a/ibcm/ibcm.html b/ibcm/ibcm.html index 9aa2e5a45..cfd021fd1 100644 --- a/ibcm/ibcm.html +++ b/ibcm/ibcm.html @@ -18,8 +18,8 @@

Progr

IBCM was described in a SIGCSE 2011 article: "IBCM: The Itty Bitty Computing Machine" by Aaron Bloomfield and William Wulf (Proceedings of the 42nd ACM Technical Symposium on Computer Science Education (SIGCSE), March 2011, Dallas, TX); that article describes the Turing completeness of IBCM. Due to copyright restrictions, that article cannot be included in this repository. However, much of that material is similar to the material found in the book chapter on IBCM.

The primary mechanism for learning IBCM is through the IBCM slide set and the IBCM book chapter. The material in both of those largely duplicates itself, but in different formats. IBCM is utilized through an online set of web pages, described next. A few C++ utilities are described at the bottom of this page.

Website

-

The IBCM is utilized through an online series of webpages. The IBCM simulator needs PHP in order to run, and thus must be run from a web server (i.e., not as a local file). Most of the computational load is on the client side (via Javascript), and little is on the server side. There are a few mirros of this website available, which are listed below. All the necessary code to run a separate copy are included in this repository.

-

The primary file for the website is index.html, and the directions are on the directions.html page. The simulator itself is on the simulator.php page -- but as described above, this must be run on an actual web server. Two supporting files (simulator.js and ibcm.css) and the entire img/ directory are needed as well. Note that two of the programs listed below (summation.ibcm and array-summation.ibcm) are linked to from the various website pages.

+

The IBCM is utilized through an online series of webpages and requires a modern browser released after 2018. All the necessary code to run a separate copy are included in this repository.

+

The primary file for the website is index.html, and the directions are on the directions.html page. The simulator itself is on the simulator.html page. Two supporting files (simulator.js and ibcm.css) and the entire img/ directory are needed as well. Note that two of the programs listed below (summation.ibcm and array-summation.ibcm) are linked to from the various website pages.

The simulator can be accessed via http://pegasus.cs.virginia.edu/ibcm/.

Sample IBCM code

The sample IBCM code included in this repository:

diff --git a/ibcm/ibcm.md b/ibcm/ibcm.md index 47201bf12..196af14f1 100644 --- a/ibcm/ibcm.md +++ b/ibcm/ibcm.md @@ -13,9 +13,9 @@ The primary mechanism for learning IBCM is through the [IBCM slide set](../slide Website ------- -The IBCM is utilized through an online series of webpages. The IBCM simulator needs PHP in order to run, and thus must be run from a web server (i.e., not as a local file). Most of the computational load is on the client side (via Javascript), and little is on the server side. There are a few mirros of this website available, which are listed below. All the necessary code to run a separate copy are included in this repository. +The IBCM is utilized through an online series of webpages and requires a modern browser released after 2018. All the necessary code to run a separate copy are included in this repository. -The primary file for the website is [index.html](index.html), and the directions are on the [directions.html](directions.html) page. The simulator itself is on the [simulator.php](simulator.php) page -- but as described above, this must be run on an actual web server. Two supporting files ([simulator.js](simulator.js) and [ibcm.css](ibcm.css)) and the entire img/ directory are needed as well. Note that two of the programs listed below ([summation.ibcm](summation.ibcm) and [array-summation.ibcm](array-summation.ibcm)) are linked to from the various website pages. +The primary file for the website is [index.html](index.html), and the directions are on the [directions.html](directions.html) page. The simulator itself is on the [simulator.html](simulator.html) page. Two supporting files ([simulator.js](simulator.js) and [ibcm.css](ibcm.css)) and the entire img/ directory are needed as well. Note that two of the programs listed below ([summation.ibcm](summation.ibcm) and [array-summation.ibcm](array-summation.ibcm)) are linked to from the various website pages. The simulator can be accessed via [http://pegasus.cs.virginia.edu/ibcm/](http://pegasus.cs.virginia.edu/ibcm/). diff --git a/ibcm/index.html b/ibcm/index.html index d70bd744e..7a50868d0 100644 --- a/ibcm/index.html +++ b/ibcm/index.html @@ -1,75 +1,104 @@ - - + + + - - - - IBCM Interface: Home - - + + - - -
-
-

IBCM Interface

- - -
+ + - -
- -
+ -
-

The Itty Bitty Computing Machine

-

The Itty Bitty Computing Machine (IBCM) is a machine language meant to provide a one-week introduction to machine language in a CS2 or CS3 course; this web site is an interface to emulate IBCM programs. IBCM was developed at, and is still used by, the University of Virginia in CS 2150, Program and Data Representation, to teach machine language.

-

The IBCM simulator, along with all the documentation and source code, is availabe on github at http://github.com/aaronbloomfield/pdr. All the materials are released under a Creative Commons Attribution-ShareAlike 4.0 International License.

-

There are a number of documentation sources:

- -

Be sure to look at the browser compatability section at the bottom of the directions page. And please report any bugs you found via the github repo (just fill out an issue).

-

The simulator page is a PHP script, which means that it will not work if you are viewing it as a local file (i.e., if the beginning of your URL is "file://" instead of "http://"), or if the web server hosting this page does not have PHP installed (this includes UVa's Collab web server).

+ IBCM Interface: Home + -

Mirrors

-

The IBCM interface is hosted at the following locations, which all allow the simulator's PHP script to work properly.

+ + +
+
+

IBCM Interface

+ + +
-

Command-line version

-

Two command-line versions were written that will check, compile, and execute IBCM programs. They are available in the github repo, in the "ibcm/" sub-directory. One of them (ibcm-parse.cpp) just parses an IBCM program to ensure it matches the desired format; this is used to, in effect, "compile" a program to ensure the syntax is correct. The second, ibcm-simulate.cpp, is used to actually compile and run IBCM programs. Run the compiled version of ibcm-simulate.cpp with a "-help" flag to see the available options.

+ +
+ +
-

Credits

-

This online IBCM simulator was developed by Nick Williams and Aaron Bloomfield in 2008. IBCM itself was designed by William Wulf. The HTML template for this website was taken from oswd.org.

-
+
+

The Itty Bitty Computing Machine

+

The Itty Bitty Computing Machine (IBCM) is a machine language meant to provide a one-week + introduction to machine language in a CS2 or CS3 course; this web site is an interface to + emulate IBCM programs. IBCM was developed at, and is still used by, the University of Virginia + in CS 2150, Program and Data Representation, to teach machine language.

+

The IBCM simulator, along with all the documentation and source code, is availabe on github at https://github.com/uva-cs/pdr. All the materials + are released under a Creative Commons + Attribution-ShareAlike 4.0 International License.

+

There are a number of documentation sources:

+ +

Be sure to look at the browser compatability section at the bottom of the directions page. And please report any bugs you found via the github repo (just fill out an issue).

+

The simulator page is a PHP script, which means that it will not work + if you are viewing it as a local file (i.e., if the beginning of your URL is "file://" instead + of "http://"), or if the web server hosting this page does not have PHP installed (this includes + UVa's Collab web server).

-
+

Mirrors

+

The IBCM interface is hosted at the following locations, which all allow the simulator's PHP + script to work properly.

+ - - +

Command-line version

+

Two command-line versions were written that will check, compile, and execute IBCM programs. They + are available in the github repo, in the "ibcm/" + sub-directory. One of them (ibcm-parse.cpp) just parses an IBCM program to ensure it matches the + desired format; this is used to, in effect, "compile" a program to ensure the syntax is correct. + The second, ibcm-simulate.cpp, is used to actually compile and run IBCM programs. Run the + compiled version of ibcm-simulate.cpp with a "-help" flag to see the available options.

- -
-
-
+

Credits

+

This online IBCM simulator was developed by Nick Williams and Aaron Bloomfield in 2008. IBCM + itself was designed by William Wulf. The HTML template for this website was taken from oswd.org.

+
+ +
- - + + +
-
- + + diff --git a/ibcm/simulator.html b/ibcm/simulator.html new file mode 100644 index 000000000..626ad500f --- /dev/null +++ b/ibcm/simulator.html @@ -0,0 +1,109 @@ + + + + + + + + + + + + + IBCM Interface: Simulator + + + + +
+
+

IBCM Interface

+ + +
+ + +
+

Directions for how to use this simulator are available.

+
+
+

+ Load IBCM file: + +

+

+

+ Load all of memory: + + (leave unchecked if unsure) +

+

+ Enable watchdog timer: + + (check to guard against infinite loops) +

+

+
+
+ + + + + + + + + + +
MemValuePC
+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + + +
+
+
+ + +
+
+
+
+
+ + + +
+ + + + diff --git a/ibcm/simulator.js b/ibcm/simulator.js index 2941ccd5d..bca6b0203 100644 --- a/ibcm/simulator.js +++ b/ibcm/simulator.js @@ -1,408 +1,343 @@ -// Handle ENTER (key id 13) key press -// adapted from http://www.digitalsymmetry.co.uk/web-design-code.php?id=32 -nn=(document.layers)?true:false; -ie=(document.all)?true:false; -function keyDown(e) { - var evt=(e)?e:(window.event)?window.event:null; - if(evt) { - var key=(evt.charCode)?evt.charCode:((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0)); - if(key==13) { - handleReturn(); - } - } -} -document.onkeydown=keyDown; -if(nn) document.captureEvents(Event.KEYDOWN); -function handleReturn () { - if ( during_input ) - run_simulator(); -} +const INSTRUCTION_REGEX = /[a-fA-F0-9]{4}/; +const WATCHDOG_MAX_LIMIT = 1000; -var pchex = "0000"; -var pchexbak = "0000"; -var during_input = 0; +let instructions = []; -function reset() { - document.getElementById("accum").value = "0000"; - document.getElementById("pc").value = "0000"; - if ( pchex != "xxxx" ) - document.getElementById("pc"+pchex).innerHTML=""; // erase old PC - document.getElementById("pc"+pchexbak).innerHTML=""; // erase old PC - document.getElementById("pc0000").innerHTML = "<-"; - pchex = "0000"; - document.getElementById("inputtitle").innerHTML = "Input:"; - document.getElementById("input").value = ""; - document.getElementById("output").value = ""; - during_input = 0; - document.getElementById("bptitle").innerHTML = "Breakpoint (4 digits): "; - document.getElementById("watchwarning").innerHTML = ""; -} +let pc = "0000"; +let awaiting_input = false; +let halted = false; +// Handle enter +const userInput = document.getElementById('input'); +userInput.addEventListener('keyup', event => { if (event.key === 'Enter') run_simulator(); }); -/** -* -* Javascript sprintf -* http://www.webtoolkit.info/ -* -* -**/ - -sprintfWrapper = { - - init : function () { - - if (typeof arguments == "undefined") { return null; } - if (arguments.length < 1) { return null; } - if (typeof arguments[0] != "string") { return null; } - if (typeof RegExp == "undefined") { return null; } - - var string = arguments[0]; - var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g); - var matches = new Array(); - var strings = new Array(); - var convCount = 0; - var stringPosStart = 0; - var stringPosEnd = 0; - var matchPosEnd = 0; - var newString = ''; - var match = null; - - while (match = exp.exec(string)) { - if (match[9]) { convCount += 1; } - - stringPosStart = matchPosEnd; - stringPosEnd = exp.lastIndex - match[0].length; - strings[strings.length] = string.substring(stringPosStart, stringPosEnd); - - matchPosEnd = exp.lastIndex; - matches[matches.length] = { - match: match[0], - left: match[3] ? true : false, - sign: match[4] || '', - pad: match[5] || ' ', - min: match[6] || 0, - precision: match[8], - code: match[9] || '%', - negative: parseInt(arguments[convCount]) < 0 ? true : false, - argument: String(arguments[convCount]) - }; - } - strings[strings.length] = string.substring(matchPosEnd); +// Reload table when `loadmem` is toggled +const loadmemInput = document.getElementById('loadmem'); +loadmemInput.addEventListener('change', create_ibcm_memory_table); - if (matches.length == 0) { return string; } - if ((arguments.length - 1) < convCount) { return null; } +const fileInput = document.getElementById('userfile'); +fileInput.addEventListener('change', readIBCMFile); - var code = null; - var match = null; - var i = null; +function readIBCMFile() { + if (this.files.length !== 1) { + return; + } - for (i=0; i processIBCMFile(e.target.result); + reader.readAsText(file); +} + +function processIBCMFile(text) { + instructions = []; // Reset instructions array - newString += strings[i]; - newString += substitution; + const lines = text.split(/\r?\n/) // Split on newlines + let currentLine = 0; // Zero-indexed indicator of which line we are parsing + for (let line of lines) { + line = line.trim(); // Trim whitespace + // Ignore blank or commented-out lines + if (line.length === 0 || line.startsWith('#') || line.startsWith('//')) { + continue; } - newString += strings[i]; - return newString; + // Test for invalid input + const result = INSTRUCTION_REGEX.exec(line); + if (result === null || result.index !== 0) { + document.getElementById('error').innerText = `Could not read line ${currentLine + 1} -- make sure it is valid and try again`; + revert(); + return; + } - }, + instructions.push(result[0]); + document.getElementById(`v${currentLine.toString(16).padStart(4, '0')}`).value = result[0]; - convert : function(match, nosign){ - if (nosign) { - match.sign = ''; - } else { - match.sign = match.negative ? '-' : match.sign; - } - var l = match.min - match.argument.length + 1 - match.sign.length; - var pad = new Array(l < 0 ? 0 : l).join(match.pad); - if (!match.left) { - if (match.pad == "0" || nosign) { - return match.sign + pad + match.argument; - } else { - return pad + match.sign + match.argument; - } - } else { - if (match.pad == "0" || nosign) { - return match.sign + match.argument + pad.replace(/0/g, ' '); - } else { - return match.sign + match.argument + pad; - } - } + // Only increment currentLine if we successfully parse the line + currentLine++; } -} -sprintf = sprintfWrapper.init; + // Fill in everything else with 0000s + for (let i = currentLine; i < document.getElementsByClassName('address').length; i++) { + document.getElementById(`v${i.toString(16).padStart(4, '0')}`).value = '0000'; + } -function create_ibcm_memory_table() { - str = "\n"; - var top = 100; - if ( document.simulate.loadmem.checked ) - top = 4096; - for ( i = 0; i < top; i++ ) { - divname = sprintf ("%04x", i); - str += "\n"; - } - str += "
" + divname + "
"; - document.getElementById("memtable").innerHTML = str; + // New program; reset + reset(); } +function create_ibcm_memory_table() { + const top = loadmemInput.checked ? 4096 : 100; -function init() { - create_ibcm_memory_table(); - revert(); -} - -function run_simulator () { - // initialize watchdog vars - var useWatchdogTimer = document.getElementById("watchtimer").checked; - var watchdogCounter = 1; - var watchdogMaxLimit = 10000; - document.getElementById("watchwarning").innerHTML = ""; + let tableRows = ""; + for (let i = 0; i < top; i++) { + const divname = i.toString(16).padStart(4, '0'); + tableRows += `${divname}
`; + } + document.getElementById('instructionsTable').getElementsByTagName('tbody')[0].innerHTML = tableRows; - // initialize breakpoint vars - var breakpoint = document.getElementById("breakpoint").value.toLowerCase(); - document.getElementById("bptitle").innerHTML = "Breakpoint (4 digits): "; + // We need to reset because we've cleared all the existing program information at this point + reset(); +} - // run until the breakpoint is hit or the watchdog counter reaches its limit - execute_instruction(); - while ( (pchex != "xxxx") && (!during_input) && (pchex != breakpoint) && (useWatchdogTimer ? watchdogCounter < watchdogMaxLimit : true) ) { - execute_instruction(); - watchdogCounter++; - } - if ( pchex == breakpoint ) { - document.getElementById("bptitle").innerHTML = "Breakpoint (4 digits): "; - } else if (useWatchdogTimer && watchdogCounter >= watchdogMaxLimit) { - document.getElementById("watchwarning").innerHTML = sprintf("Watchdog timed out after %d instructions. If this is expected, continue with 'Run'.", watchdogMaxLimit); - } +function init() { + create_ibcm_memory_table(); } -function step_simulator () { - document.getElementById("bptitle").innerHTML = "Breakpoint (4 digits): "; - execute_instruction(); +function revert() { + reset(); + for (let i = 0; i < instructions.length; i++) { + document.getElementById(`v${i.toString(16).padStart(4, '0')}`).value = instructions[i]; + } } -function convert_hex_digit_to_decimal (hex) { - if ( hex <= '9' ) - return hex; - else - return hex.toLowerCase().charCodeAt(0)-"a".charCodeAt(0)+10; +function reset() { + document.getElementById("accum").value = "0000"; + document.getElementById("pc").value = "0000"; + document.getElementById("pc" + pc).innerHTML = ""; // erase old PC + document.getElementById("pc0000").innerHTML = "<-"; + document.getElementById("inputtitle").innerHTML = "Input:"; + document.getElementById("input").value = ""; + document.getElementById("output").value = ""; + document.getElementById("bptitle").classList.remove('active'); + document.getElementById("watchwarning").innerHTML = ""; + + pc = "0000"; + awaiting_input = false; + halted = false; } -function get_IBCM_opcode (hexinst) { - return convert_hex_digit_to_decimal(hexinst.charAt(0)); +function run_simulator() { + // initialize watchdog vars + const useWatchdogTimer = document.getElementById("watchtimer").checked; + let watchdogCounter = 1; + document.getElementById("watchwarning").innerHTML = ""; + + // initialize breakpoint vars + const breakpoint = document.getElementById("breakpoint").value.toLowerCase(); + document.getElementById('bptitle').classList.remove('active'); + + // run until the breakpoint is hit or the watchdog counter reaches its limit + do { + execute_instruction(); + watchdogCounter++; + } while (!halted && !awaiting_input && pc != breakpoint && (useWatchdogTimer ? watchdogCounter < WATCHDOG_MAX_LIMIT : true)); + + if (pc === breakpoint) { + document.getElementById('bptitle').classList.add('active'); + } else if (useWatchdogTimer && watchdogCounter >= WATCHDOG_MAX_LIMIT) { + document.getElementById("watchwarning").innerHTML = `Watchdog timed out after ${WATCHDOG_MAX_LIMIT} instructions. If this is expected, continue with 'Run'.`; + } } -function get_IBCM_address (hexinst) { - return parseInt(hexinst.substring(1,4),16); + +function step_simulator() { + document.getElementById('bptitle').classList.remove('active'); + execute_instruction(); } -function get_IBCM_2bitop (hexinst) { - return Math.floor(convert_hex_digit_to_decimal(hexinst.charAt(1))/4); + +function execute_instruction() { + let instruction = document.getElementById('v' + pc).value; + if (instruction === "") { + instruction = "0000"; + } + + const opcode = get_IBCM_opcode(instruction); + const address = instruction.substring(1, 4).toLowerCase(); + let accum = document.getElementById("accum").value; + document.getElementById("pc" + pc).innerHTML = ""; // erase old PC + if (!awaiting_input) { + increment_pc(); + } + + let immediate = ''; + switch (opcode) { + case 0x0: // halt + pc = dec_to_hex(hex_to_dec(pc) - 1); + document.getElementById("pc" + pc).innerHTML = "H"; + document.getElementById("pc").value = pc + " (halted)"; + halted = true; + break; + case 0x1: // I/O + const output = document.getElementById("output"); + const asciimode = get_IBCM_2bitop(instruction); + switch (asciimode) { + case 0: // read hex + // FALL THRU + case 1: // read ascii + if (!awaiting_input) { + if (asciimode) { + document.getElementById("inputtitle").innerHTML = "Input (asc):"; + } else { + document.getElementById("inputtitle").innerHTML = "Input (hex):"; + } + + document.getElementById("input").value = ""; + pc = dec_to_hex(hex_to_dec(pc) - 1); + document.getElementById("pc" + pc).innerHTML = "I"; + document.getElementById("pc").value = pc + " (awaiting input)"; + awaiting_input = true; + document.getElementById("input").focus(); + return; + } else { + // is the value empty? + if (document.getElementById("input").value === "") { + document.getElementById("pc" + pc).innerHTML = "I"; + document.getElementById("input").focus(); + return; + } + + document.getElementById("inputtitle").innerHTML = "Input:"; + document.getElementById("pc" + pc).innerHTML = ""; // remove the 'I' + awaiting_input = false; + increment_pc(); + if (asciimode) { + accum = dec_to_hex(document.getElementById("input").value.charCodeAt(0)); + } else { // hex + accum = dec_to_hex(parseInt(document.getElementById("input").value, 16)); + } + } + break; + case 2: // write hex + output.value += accum + "\n"; + break; + case 3: // write ascii + output.value += String.fromCharCode(hex_to_dec(accum) & 0xff) + "\n"; + break; + } + break; + case 0x2: // shifts + const shiftamount = get_IBCM_shift(instruction); + let accdec = hex_to_dec(accum); + switch (get_IBCM_2bitop(instruction)) { + case 0: // shift left + accdec = (accdec << shiftamount) & 0xffff; + break; + case 1: // shift right + accdec = (accdec >> shiftamount) & (0xffff >> shiftamount); + break; + case 2: // rotate left + accdec = ((accdec << shiftamount) & 0xffff) | ((accdec >> 16 - shiftamount) & (0xffff >> 16 - shiftamount)); + break; + case 3: // rotate right + accdec = ((accdec >> shiftamount) & (0xffff >> shiftamount)) | ((accdec << 16 - shiftamount) & 0xffff); + break; + } + accum = dec_to_hex(accdec); + break; + case 0x3: // load + accum = document.getElementById("v0" + address).value; + break; + case 0x4: // store + document.getElementById("v0" + address).value = accum; + break; + case 0x5: // add + immediate = document.getElementById("v0" + address).value; + accum = dec_to_hex(hex_to_dec(accum) + hex_to_dec(immediate)); + break; + case 0x6: // sub + immediate = document.getElementById("v0" + address).value; + accum = dec_to_hex(hex_to_dec(accum) - hex_to_dec(immediate)); + break; + case 0x7: // and + immediate = document.getElementById("v0" + address).value; + accum = dec_to_hex(hex_to_dec(accum) & hex_to_dec(immediate)); + break; + case 0x8: // or + immediate = document.getElementById("v0" + address).value; + accum = dec_to_hex(hex_to_dec(accum) | hex_to_dec(immediate)); + break; + case 0x9: // xor + immediate = document.getElementById("v0" + address).value; + accum = dec_to_hex(hex_to_dec(accum) ^ hex_to_dec(immediate)); + break; + case 0xa: // not + accum = dec_to_hex(~hex_to_dec(accum)); + break; + case 0xb: // nop + // do nothing + break; + case 0xc: // jmp + pc = "0" + address; + break; + case 0xd: // jmpe + if (accum === "0000") + pc = "0" + address; + break; + case 0xe: // jmpl + if (hex_to_dec(accum) < 0) + pc = "0" + address; + break; + case 0xf: // brl + accum = pc; + pc = "0" + address; + break; + } + + if (!halted) { + document.getElementById("pc" + pc).innerHTML = "<-"; // set new PC + document.getElementById("pc").value = pc; + } + + document.getElementById("accum").value = accum.toLowerCase(); } -function get_IBCM_shift (hexinst) { - return convert_hex_digit_to_decimal(hexinst.charAt(3)); + +function increment_pc() { + pc = dec_to_hex(hex_to_dec(pc) + 1); } -function increment_pc () { - pchex = convert_dec_to_hex4(eval(convert_hex_to_dec(pchex)+1)); +// Given an IBCM instruction abcd: +// a is the opcode +// For I/O instructions: +// - b is the input/output and ascii/hex switch +// - 0: input hex (binary 0000, dec 0) +// - 4: input ascii (binary 0100, dec 4) +// - 8: output hex (binary 1000, dec 8) +// - c: output ascii (binary 1100, dec 12) +// - c, d unused +// For shift instructions: +// - b is the shift/rotate and left/right switch +// - 0: shift left (binary 0000, dec 0) +// - 4: shift right (binary 0100, dec 4) +// - 8: rotate left (binary 1000, dec 8) +// - c: rotate right (binary 1100, dec 12) +// - c is unused +// - d is the count to shift by +// For all other instructions: +// - bcd is the address +function get_IBCM_opcode(instruction) { + return hex_to_dec(instruction.charAt(0)); } -function convert_dec_to_hex4 (value) { - if ( value < 0 ) - value += 65536; - hex = value.toString(16); - if ( hex.length < 4 ) - hex = "0" + hex; - if ( hex.length < 4 ) - hex = "0" + hex; - if ( hex.length < 4 ) - hex = "0" + hex; - hex = hex.toLowerCase(); - return hex; +function get_IBCM_address(instruction) { + return hex_to_dec(instruction.substring(1, 4)); } -function convert_hex_to_dec (hex) { - if ( parseInt(hex,16) > 32767 ) - return parseInt(hex,16) - 65536; - else - return parseInt(hex,16); +function get_IBCM_2bitop(instruction) { + return Math.floor(hex_to_dec(instruction.charAt(1)) / 4); } -function execute_instruction () { - var hexinst = document.getElementById('v'+pchex).value; - if ( hexinst == "" ) - hexinst = "0000"; - opcode = eval(get_IBCM_opcode(hexinst)); - var accum = document.getElementById("accum").value; - hexaddress = hexinst.substring(1,4).toLowerCase(); - document.getElementById("pc"+pchex).innerHTML=""; // erase old PC - if ( !during_input ) - increment_pc(); - - switch (opcode) { - case 0: // halt - pchex = convert_dec_to_hex4(eval(convert_hex_to_dec(pchex)-1)); - document.getElementById("pc"+pchex).innerHTML="H"; - document.getElementById("pc").value = pchex + " (halted)"; - pchexbak = pchex; // so the 'H' can be erased by the reset button - pchex = "xxxx"; - break; - case 1: // I/O - var input = document.getElementById("input"); - var output = document.getElementById("output"); - asciimode = get_IBCM_2bitop(hexinst); - switch ( asciimode ) { - case 0: // read hex - // FALL THRU - case 1: // read ascii - if ( !during_input ) { - if ( asciimode ) - document.getElementById("inputtitle").innerHTML = "Input (asc):"; - else - document.getElementById("inputtitle").innerHTML = "Input (hex):"; - document.getElementById("input").value = ""; - pchex = convert_dec_to_hex4(eval(convert_hex_to_dec(pchex)-1)); - document.getElementById("pc"+pchex).innerHTML="I"; - document.getElementById("pc").value = pchex + " (awaiting input)"; - during_input = 1; - document.getElementById("input").focus(); - return; - } else { - // is the value empty? - if ( document.getElementById("input").value == "" ) { - document.getElementById("pc"+pchex).innerHTML="I"; - document.getElementById("input").focus(); - return; - } +function get_IBCM_shift(instruction) { + return hex_to_dec(instruction.charAt(3)); +} - document.getElementById("inputtitle").innerHTML = "Input:"; - document.getElementById("pc"+pchex).innerHTML=""; // remove the 'I' - during_input = 0; - increment_pc(); - if ( asciimode ) { - accum = convert_dec_to_hex4(document.getElementById("input").value.charCodeAt(0)); - } else { // hex - accum = convert_dec_to_hex4(parseInt(document.getElementById("input").value,16)); - } - } - break; - case 2: // write hex - output.value += accum + "\n"; - break; - case 3: // write ascii - output.value += String.fromCharCode(convert_hex_to_dec(accum) & 0xff) + "\n"; - break; +// Treats the hex value as a signed short (4 bytes), +// but is otherwise the same as Number.parseInt(hex, 16) +function hex_to_dec(hex) { + let result = Number.parseInt(hex, 16); + if (result > 32767) { + return result - 65536; + } else { + return result; } - break; - - case 2: // shifts - shiftamount = get_IBCM_shift(hexinst); - accdec = convert_hex_to_dec(accum); - switch ( get_IBCM_2bitop(hexinst) ) { - case 0: // shift left - accdec = (accdec << shiftamount) & 0xffff; - break; - case 1: // shift right - accdec = (accdec >> shiftamount) & (0xffff >> shiftamount); - break; - case 2: // rotate left - accdec = ((accdec << shiftamount) & 0xffff) | ((accdec >> 16-shiftamount) & (0xffff >> 16-shiftamount)); - break; - case 3: // rotate right - accdec = ((accdec >> shiftamount) & (0xffff >> shiftamount)) | ((accdec << 16-shiftamount) & 0xffff); - break; +} + +function dec_to_hex(dec) { + if (dec < 0) { + dec += 65536; } - accum = convert_dec_to_hex4(accdec); - break; - case 3: // load - var accum = document.getElementById("v0"+hexaddress).value; - break; - case 4: // store - document.getElementById("v0"+hexaddress).value = accum; - break; - case 5: // add - var val = document.getElementById("v0"+hexaddress).value; - accum = convert_dec_to_hex4(eval(convert_hex_to_dec(accum)+convert_hex_to_dec(val))); - break; - case 6: // sub - var val = document.getElementById("v0"+hexaddress).value; - accum = convert_dec_to_hex4(eval(convert_hex_to_dec(accum)-convert_hex_to_dec(val))); - break; - case 7: // and - var val = document.getElementById("v0"+hexaddress).value; - accum = convert_dec_to_hex4(eval(convert_hex_to_dec(accum)&convert_hex_to_dec(val))); - break; - case 8: // or - var val = document.getElementById("v0"+hexaddress).value; - accum = convert_dec_to_hex4(eval(convert_hex_to_dec(accum)|convert_hex_to_dec(val))); - break; - case 9: // xor - var val = document.getElementById("v0"+hexaddress).value; - accum = convert_dec_to_hex4(eval(convert_hex_to_dec(accum)^convert_hex_to_dec(val))); - break; - case 10: // not - accum = convert_dec_to_hex4(eval(~convert_hex_to_dec(accum))); - break; - case 11: // nop - // do nothing - break; - case 12: // jmp - pchex = "0"+hexaddress; - break; - case 13: // jmpe - if ( accum == "0000" ) - pchex = "0"+hexaddress; - break; - case 14: // jmpl - if ( convert_hex_to_dec(accum) < 0 ) - pchex = "0"+hexaddress; - break; - case 15: // brl - accum = pchex; - pchex = "0"+hexaddress; - break; - } - - if ( pchex != "xxxx" ) { - document.getElementById("pc"+pchex).innerHTML="<-"; // set new PC - document.getElementById("pc").value = pchex; - } - - document.getElementById("accum").value = accum.toLowerCase(); + return dec.toString(16).padStart(4, '0'); } diff --git a/ibcm/simulator.php b/ibcm/simulator.php deleted file mode 100644 index 20e0385ca..000000000 --- a/ibcm/simulator.php +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - IBCM Interface: Simulator - - - - - - - - - - - -
-
-

IBCM Interface

- - -
- - -
-

Directions for how to use this simulator are available.

- - - - - - - - - - -
- -
-

Load IBCM file: - - -

-

- -

-

Load all of memory: > (leave unchecked if unsure)

-

Enable watchdog timer: > (check to guard against infinite loops)

-

-
- -
-
MemValuePC
-
-
-
-
- - - - - - - - - -

Accumulator (hex):

 
  

PC (hex):

 
  

Breakpoint (4 digits):

 
  

Input:

 
- -

 


 

- - - - - - - - - - -
- -

 


 

- - -

Output

- - - -
-
- -
- -
- - - - -
- -