jsos

college code for operating system fundamentals in js

git clone https://9o.is/git/jsos.git

commit b852c8b2170d5ac04e461cb842197bd6477e35f0
parent ee4ba2ed237931b7796700000e44847083dfa33c
Author: Jul <jul@9o.is>
Date:   Wed, 12 Sep 2012 12:13:13 -0400

squeezed in project1 just in time.

Diffstat:
A.gitignore | 1+
Dalanbos.css | 125-------------------------------------------------------------------------------
Mglobals.js | 18+++++++++++++++---
Dimages/background.jpg | 0
Aimages/icons28.png | 0
Mindex.html | 126+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mscripts/host/control.js | 129++++++++++++++++++++++++++++++++++++-------------------------------------------
Mscripts/host/cpu.js | 59++++++++++++++++++++++++++++++-----------------------------
Mscripts/host/devices.js | 66+++++++++++++++++++++++++++++++++---------------------------------
Mscripts/os/console.js | 339+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mscripts/os/deviceDriver.js | 35++++++++++++++++++++++++-----------
Mscripts/os/deviceDriverKeyboard.js | 56+++++++++++++++++++++++++++++++++++++-------------------
Mscripts/os/interrupt.js | 9++++-----
Mscripts/os/kernel.js | 8+++++---
Ascripts/os/memoryManager.js | 16++++++++++++++++
Mscripts/os/queue.js | 58++++++++++++++++++++++++----------------------------------
Mscripts/os/shell.js | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Ascripts/os/stack.js | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mscripts/utils.js | 71+++++++++++++++++++++++++++++++++++++----------------------------------
Astyles/julios-buttons.css | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Astyles/julios.css | 21+++++++++++++++++++++
21 files changed, 862 insertions(+), 510 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/alanbos.css b/alanbos.css @@ -1,125 +0,0 @@ -/* alanbos.css */ - -body -{ - background-color: #909193; /* The bottom color of background.jpg. */ - background-image: url(images/background.jpg); - background-repeat: repeat-x; - font-family: Helvetica, Verdana, Arial, sans-serif; - font-size: 10pt; - font-weight: normal; - font-style: normal; -} - -h1 -{ - color: black; - font-size: 24pt; - font-weight: normal; - font-style: normal; - border-bottom: 1px solid #dad8ed; -} - -h2 -{ - font-family: Helvetica, Verdana, Arial, sans-serif; - font-size: 16pt; - font-weight: normal; - font-style: normal; -} - -p.breadcrumbs -{ - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 10pt; - font-weight: normal; - line-height: normal; - color: green; - position: relative; - top: -16px; -} - -td.section -{ - border-top: 1px solid blue; - padding-top: 6px; - padding-bottom: 6px; -} - -td.heading -{ - background-color: black; - color: white; - font-weight: normal; - font-style: normal; -} - -#frame -{ - width: 800px; - height:1000px; - margin-left: auto; - margin-right: auto; - background-color: white; - padding: 10px; /* set in init() */ - border-width: 6px; /* set in init() */ - border-style: double; - border-color: #dad8ed; /* "circles" light-blueish */ -} - -#display -{ - background-color: #DFDBC3; - border: 2px solid red; - cursor: default; -} - -.subheading -{ - font-weight: normal; - font-style: italic; -} - -.instructions -{ - font-size:10pt; - font-weight: normal; - font-style: normal; -} - -.widget -{ - width:100%; - position: relative; - background-color: #dad8ed; /* was #99ffff */; - border: 1px solid blue; -} - -.small_button -{ - width: 60px; -} - -.normal_button -{ - width: 100px; -} - -.large_button -{ - width: 180px; -} - -.footer -{ - color: white; - font-family: Arial, Helvetica, sans-serif; - font-size: 8pt; -} - -.label -{ - color: white; - font-family: Arial, Helvetica, sans-serif; - font-size: 12pt; -} diff --git a/globals.js b/globals.js @@ -11,8 +11,8 @@ // // Global Constants // -var APP_NAME = "AlanBOS"; // 'cause I was at a loss for a better name. -var APP_VERSION = "0.1" +var APP_NAME = "JuliOS"; // 'cause I was at a loss for a better name. +var APP_VERSION = "0.1"; var CPU_CLOCK_INTERVAL = 100; // in ms, or milliseconds, so 1000 = 1 second. @@ -33,10 +33,17 @@ var _Mode = 0; // 0 = Kernel Mode, 1 = User Mode. See page 21. // TODO: Fix the naming convention for these next five global vars. var CANVAS = null; // Initialized in hostInit(). var DRAWING_CONTEXT = null; // Initialized in hostInit(). -var DEFAULT_FONT = "sans"; // Ignored, just a place-holder in this version. +var DEFAULT_FONT = "Open Baskerville 0.0.53"; // Ignored, just a place-holder in this version. var DEFAULT_FONT_SIZE = 13; var FONT_HEIGHT_MARGIN = 4; // Additional space added to font size when advancing a line. +// dom id's +var CANVAS_ID = "display"; +var HALT_BTN = "btnHaltOS"; +var RESET_BTN = "btnReset"; +var TALOG = "taLog"; +var TA_PROGRAM_INPUT = "taProgramInput"; + // Default the OS trace to be on. var _Trace = true; @@ -44,6 +51,7 @@ var _Trace = true; var _KernelInterruptQueue = null; var _KernelBuffers = null; var _KernelInputQueue = null; +var _KernelMemoryManager = null; // Standard input and output var _StdIn = null; @@ -60,3 +68,7 @@ var _SarcasticMode = false; // Global Device Driver Objects - page 12 // var krnKeyboardDriver = null; + +// memory size +var TOTAL_MEMORY = 128; //bytes +var MAX_MEMORY_PROGRAM = 32; //bytes diff --git a/images/background.jpg b/images/background.jpg Binary files differ. diff --git a/images/icons28.png b/images/icons28.png Binary files differ. diff --git a/index.html b/index.html @@ -2,10 +2,11 @@ <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> - <meta name="author" content="Alan G. Labouseur" /> - <link rel="stylesheet" href="alanbos.css" type="text/css" media="screen" /> + <meta name="author" content="Alan G. Labouseur and Julio Cabrera" /> + <link rel="stylesheet" href="styles/julios.css" type="text/css" media="screen" /> + <link rel="stylesheet" href="styles/julios-buttons.css" type="text/css" media="screen" /> <title> - AlanBOS 0.1 - a Browser-based virtual Operating System + JuliOS 0.1 - a Browser-based virtual Operating System </title> <!-- Globals CONSTANTS and _Variables. Must included be first. --> @@ -23,78 +24,76 @@ <script type="text/javascript" src="scripts/os/deviceDriver.js"></script> <script type="text/javascript" src="scripts/os/deviceDriverKeyboard.js"></script> <script type="text/javascript" src="scripts/os/queue.js"></script> + <script type="text/javascript" src="scripts/os/stack.js"></script> <script type="text/javascript" src="scripts/os/shell.js"></script> <script type="text/javascript" src="scripts/os/kernel.js"></script> + <script type="text/javascript" src="scripts/os/memoryManager.js"></script> <!-- Other Routines --> <script type="text/javascript" src="scripts/utils.js"></script> </head> -<body onload="simInit();"> +<body> <table id="tableDisplay" style="border:1px solid white;"> - <tr> - <td> - <input type="button" - id = "btnStartOS" - name="brnStartOS" - class="normal_button" - value="Start" - tabindex="0" - onclick="simBtnStartOS_click(this)" - /> - <input type="button" - id = "btnHaltOS" - name="brnHaltOS" - class="normal_button" - disabled="disabled" - value="Halt" - tabindex="1" - onclick="simBtnHaltOS_click(this)" - /> - <input type="button" - id = "btnReset" - name="brnReset" - class="normal_button" - disabled="disabled" - value="Reset" - tabindex="2" - onclick="simBtnReset_click(this)" - /> - </td> - <td class="label"> - Control Log - </td> - </tr> - <tr valign="top"> - <td id="tdDisplay"> - <canvas id="display" - width="500px" - height="500px" - tabindex="3"> - </canvas> - </td> - <td id="tdLog"> - <textarea name="taLog" - id = "taLog" - rows="36" - cols="48" - ></textarea> - </td> - </tr> + <tr> + <td> + <button type="button" + id = "btnStartOS" + class="btnicon28" + onclick="simBtnStartOS_click(this)"> + <i class="icon28-poweroff"></i></button> + <button type="button" + id = "btnHaltOS" + class="btnicon28" + disabled="disabled" + onclick="simBtnHaltOS_click(this)"> + <i class="icon28-halt"></i></button> + <button type="button" + id = "btnReset" + class="btnicon28" + disabled="disabled" + onclick="simBtnReset_click(this)"> + <i class="icon28-reset"></i></button> + </td> + <td class="label"> + Control Log + </td> + </tr> + <tr valign="top"> + <td id="tdDisplay"> + <canvas id="display" + tabindex="0" + width="800" + height="500"></canvas> + </td> + <td id="tdLog"> + <textarea id = "taLog" + rows="32" + cols="70"></textarea> + </td> + </tr> + <tr> + <td></td> + <td> + <textarea id = "taProgramInput" + rows="5" + cols="70" + placeholder="Input Program hex here"></textarea> + </td> + </tr> </table> -<p></p> - <table width="100%" border="0" cellspacing="0" cellpadding="0"> - <tr valign="top"> - <td align="center" class="footer"> - Copyright &copy; 2008 - 2012 No Rights Reserved. - - Reproduction is prohibited without the express written consent of - Ted Codd, Stevie Ray Vaughan, and Ian Fleming. - </td> - </tr> + <tr valign="top"> + <td align="center" class="footer"> + Copyright &copy; 2008 - 2012 No Rights Reserved. - + Reproduction is prohibited without the express written + consent of Ted Codd, Stevie Ray Vaughan, Ian Fleming, + and Julio Cabrera. + </td> + </tr> </table> </body> -</html> -\ No newline at end of file +</html> diff --git a/scripts/host/control.js b/scripts/host/control.js @@ -16,89 +16,76 @@ ------------ */ -// -// Control Services -// -function simInit() -{ - // Get a global reference to the canvas. TODO: Move this stuff into a Display Device Driver, maybe? - CANVAS = document.getElementById('display'); - // Get a global reference to the drawing context. - DRAWING_CONTEXT = CANVAS.getContext('2d'); - // Enable the added-in canvas text functions (see canvastext.js for provenance and details). - CanvasTextFunctions.enable(DRAWING_CONTEXT); - // Clear the log text box. - document.getElementById("taLog").value=""; - // Set focus on the start button. - document.getElementById("btnStartOS").focus(); // TODO: This does not seem to work. Why? +/* + * Enables the canvas console with text functions. + */ +function simCanvasInit() { + CANVAS = document.getElementById(CANVAS_ID); + DRAWING_CONTEXT = CANVAS.getContext('2d'); + CanvasTextFunctions.enable(DRAWING_CONTEXT); + document.getElementById(TALOG).value=""; } -function simLog(msg, source) -{ - // Check the source. - if (!source) - { - source = "?"; - } - - // Note the OS CLOCK. +/* + * Prints a log in the taLog textarea showing the clock + * pulse, the source, the message, and time in ms. + * + * TODO: Update a log database or streaming device. + */ +function simLog(msg, source) { + if (!source) source = "?"; var clock = _OSclock; - - // Note the REAL clock in milliseconds since January 1, 1970. var now = new Date().getTime(); + + var str = "({ clock:" + clock + ", source:" + source + + ", msg:" + msg + ", now:" + now + " })" + "\n"; - // Build the log string. - var str = "({ clock:" + clock + ", source:" + source + ", msg:" + msg + ", now:" + now + " })" + "\n"; - // WAS: var str = "[" + clock + "]," + "[" + now + "]," + "[" + source + "]," +"[" + msg + "]" + "\n"; - - // Update the log console. - taLog = document.getElementById("taLog"); + taLog = document.getElementById(TALOG); taLog.value = str + taLog.value; - // Optionally udpate a log database or some streaming service. } -// -// Control Events -// -function simBtnStartOS_click(btn) -{ - // Disable the start button... - btn.disabled = true; +/* + * Starts the OS by intiating a cpu and starting the kernel. + * + * This should be called when the power-on or start button + * is clicked. + * <input type="button" onclick"simBtnStartOS_click(this)"/> + */ +function simBtnStartOS_click(btn) { + simCanvasInit(); + // Disable and enable elements appropriately. + btn.disabled = true; + document.getElementById(HALT_BTN).disabled = false; + document.getElementById(RESET_BTN).disabled = false; + document.getElementById(CANVAS_ID).focus(); - // .. enable the Emergency Halt and Reset buttons ... - document.getElementById("btnHaltOS").disabled = false; - document.getElementById("btnReset").disabled = false; - - // .. set focus on the OS console display ... - document.getElementById("display").focus(); - - // ... Create and initialize the CPU ... - _CPU = new cpu(); - _CPU.init(); - - // ... then set the clock pulse simulation to call ?????????. - hardwareClockID = setInterval(simClockPulse, CPU_CLOCK_INTERVAL); - // .. and call the OS Kernel Bootstrap routine. - krnBootstrap(); + _CPU = new cpu(); + _CPU.init(); + hardwareClockID = setInterval(simClockPulse, CPU_CLOCK_INTERVAL); + krnBootstrap(); } -function simBtnHaltOS_click(btn) -{ - simLog("emergency halt", "host"); - simLog("Attempting Kernel shutdown.", "host"); - // Call the OS sutdown routine. - krnShutdown(); - // Stop the JavaScript interval that's simulating our clock pulse. - clearInterval(hardwareClockID); - // TODO: Is there anything else we need to do here? +/* + * Halts the OS by shuting down the kernel and clearing + * the clock. + * TODO: Is there anything else we need to do here? + * + * This should be called when the halt button is clicked. + * <input type="button" onclick"simBtnHaltOS_click(this)"/> + */ +function simBtnHaltOS_click(btn) { + simLog("emergency halt", "host"); + simLog("Attempting Kernel shutdown.", "host"); + + krnShutdown(); + clearInterval(hardwareClockID); } -function simBtnReset_click(btn) -{ - // The easiest and most thorough way to do this is to reload (not refresh) the document. - location.reload(true); - // That boolean parameter is the 'forceget' flag. When it is true it causes the page to always - // be reloaded from the server. If it is false or not specified, the browser may reload the - // page from its cache, which is not what we want. +/* + * Resets the OS by simply reloading the browser page document. + */ +function simBtnReset_click(btn) { + location.reload(true); + //That boolean parameter is the 'forceget' flag. } diff --git a/scripts/host/cpu.js b/scripts/host/cpu.js @@ -13,34 +13,35 @@ Operating System Concepts 8th editiion by Silberschatz, Galvin, and Gagne. ISBN 978-0-470-12872-5 ------------ */ -function cpu() -{ - this.PC = 0; // Program Counter - this.Acc = 0; // Accumulator - this.Xreg = 0; // X register - this.Yreg = 0; // Y register - this.Zflag = 0; // Z-ero flag (Think of it as "isZero".) - this.isExecuting = false; +/* + * The cpu that contains the program counter (PC), + * accumulator (Acc), X register (Xreg), + * Y register (Yreg), Z-ero flag (Zflag). + */ +function cpu() { + this.PC = 0; + this.Acc = 0; + this.Xreg = 0; + this.Yreg = 0; + this.Zflag = 0; + this.isExecuting = false; - this.init = function() - { - this.PC = 0 - this.Acc = 0; - this.Xreg = 0; - this.Yreg = 0; - this.Zflag = 0; - this.isExecuting = false; - } - - this.pulse = function() - { - // TODO: Do we need this? Probably not. - } - - this.cycle = function() - { - krnTrace("CPU cycle"); - // TODO: Accumulate CPU usage and profiling statistics here. - // Do real work here. Set this.isExecuting appropriately. - } + this.init = function() { + this.PC = 0 + this.Acc = 0; + this.Xreg = 0; + this.Yreg = 0; + this.Zflag = 0; + this.isExecuting = false; + } + + // TODO: Do we need this? Probably not. + this.pulse = function(){} + + // TODO: Accumulate CPU usage and profiling + // statistics here. Do real work here. Set + // this.isExecuting appropriately. + this.cycle = function() { + krnTrace("CPU cycle"); + } } diff --git a/scripts/host/devices.js b/scripts/host/devices.js @@ -17,44 +17,44 @@ var hardwareClockID = -1; -// -// Hardware Clock Pulse -// -function simClockPulse() -{ - // Increment the hardware (host) clock. - _OSclock++; - // Call the kernel clock pulse event handler. - krnOnCPUClockPulse(); +/* + * The Hardware Clock Pulse: increments the hardware (host) + * clock and calls the kernel clock pulse event handler. + */ +function simClockPulse() { + _OSclock++; + krnOnCPUClockPulse(); } -// -// Keyboard Interrupt, a HARDWARE Interrupt Request. (See pages 560-561 in text book.) -// -function simEnableKeyboardInterrupt() -{ - // Listen for key presses (keydown, actually) in the document - // and call the simulation processor, which will in turn call the - // os interrupt handler. - document.addEventListener("keydown", simOnKeypress, false); +/* + * The Keyboard Interrupt, a HARDWARE Interrupt Request. + * Listen for keydown event in the document and invoke + * simOnKeypress function. (See pages 560-561 in text book.) + */ +function simEnableKeyboardInterrupt() { + document.addEventListener("keydown", simOnKeypress, false); } -function simDisableKeyboardInterrupt() -{ - document.removeEventListener("keydown", simOnKeypress, false); +/* + * Removes the Keyboard Interrupt. + */ +function simDisableKeyboardInterrupt() { + document.removeEventListener("keydown", simOnKeypress, false); } -function simOnKeypress(event) -{ - // The canvas element CAN receive focus if you give it a tab index. - // Check that we are processing keystrokes only from the canvas's id (as set in index.html). - if (event.target.id == "display") - { - event.preventDefault(); - // Note the pressed key code in the params (Mozilla-specific). - var params = new Array(event.which, event.shiftKey); - // Enqueue this interrupt on the kernal interrupt queue so that it gets to the Interrupt handler. - _KernelInterruptQueue.enqueue( new Interrput(KEYBOARD_IRQ, params) ); - } +/* + * Puts the key pressed in the keyboard interrupt queue so + * that it gets to the Interrupt handler. + * + * NOTE: + * - canvas element ONLY receives focus if you give it a tabindex. + * - the pressed key code in the params is Mozilla-specific. + */ +function simOnKeypress(event) { + if (event.target.id == CANVAS_ID) { + event.preventDefault(); + var params = new Array(event.which, event.shiftKey); + _KernelInterruptQueue.enqueue( new Interrput(KEYBOARD_IRQ, params) ); + } } diff --git a/scripts/os/console.js b/scripts/os/console.js @@ -7,88 +7,273 @@ Note: This is not the Shell. The Shell is the "command line interface" (CLI) or interpreter for this console. ------------ */ -function Console() -{ - // Properties - this.CurrentFont = DEFAULT_FONT; - this.CurrentFontSize = DEFAULT_FONT_SIZE; - this.CurrentXPosition = 0; - this.CurrentYPosition = DEFAULT_FONT_SIZE; - this.buffer = ""; +function Console() { + // Properties + this.CurrentFont = DEFAULT_FONT; + this.CurrentFontSize = DEFAULT_FONT_SIZE; + this.CurrentXPosition = 0; + this.CurrentYPosition = DEFAULT_FONT_SIZE; + this.buffer = ""; + this.statusText = ""; + this.scrollOffset = 0; + this.textDrawBuffer = new Array(); - // Methods - this.init = consoleInit; - this.clearScreen = consoleClearScreen; - this.resetXY = consoleResetXY; - this.handleInput = consoleHandleInput; - this.putText = consolePutText; - this.advanceLine = consoleAdvanceLine; -} - -function consoleInit() -{ - consoleClearScreen(); - consoleResetXY(); -} - -function consoleClearScreen() -{ - DRAWING_CONTEXT.clearRect(0, 0, CANVAS.width, CANVAS.height); -} - -function consoleResetXY() -{ - this.CurrentXPosition = 0; - this.CurrentYPosition = this.CurrentFontSize; -} - -function consoleHandleInput() -{ - while (_KernelInputQueue.getSize() > 0) - { - // Get the next character from the kernel input queue. - var chr = _KernelInputQueue.dequeue(); - // Check to see if it's "special" (enter or ctrl-c) or "normal" (anything else that the keyboard device driver gave us). - if (chr == String.fromCharCode(13)) // Enter key - { - // The enter key marks the end of a console command, so ... - // ... tell the shell ... - _OsShell.handleInput(this.buffer); - // ... and reset our buffer. - this.buffer = ""; - } - // TODO: Write a case for Ctrl-C. - else - { - // This is a "normal" character, so ... - // ... draw it on the screen... - this.putText(chr); - // ... and add it to our buffer. - this.buffer += chr; - } + // Methods + this.init = consoleInit; + this.clearScreen = consoleClearScreen; + this.resetXY = consoleResetXY; + this.handleInput = consoleHandleInput; + this.putText = consolePutText; + this.advanceLine = consoleAdvanceLine; + this.backspace = consoleBackspace; + this.bsod = consoleBSOD; + this.gsod = consoleGSOD; + this.taskbarRefresh = consoleTaskbarRefresh; + this.taskbarSetStatus = consoleSetTaskbarStatus; + this.taskbarStatus = consoleTaskbarStatus; + this.taskbarDateTime = consoleTaskbarDateTime; + this.resetScroll = consoleResetScroll; + this.scroll = consoleScroll; + this.refresh = consoleRefresh; +} + +function consoleInit() { + consoleClearScreen(); + consoleResetXY(); + this.taskbarRefresh(); +} + +function consoleResetScroll() { + this.textDrawBuffer = new Array(); + this.scrollOffset = 0; +} + +function consoleClearScreen() { + DRAWING_CONTEXT.clearRect(0, 0, CANVAS.width, CANVAS.height); +} + +function consoleResetXY() { + this.CurrentXPosition = 0; + this.CurrentYPosition = this.CurrentFontSize; +} + +/* + * Gets the next character from the kernel input queue + * and processes it. + * TODO: Write a case for Ctrl-C. + */ +function consoleHandleInput() { + while (_KernelInputQueue.getSize() > 0) { + var chr = _KernelInputQueue.dequeue(); + + if (isEnter(chr)) handleEnter(this); + else if (isBackspace(chr)) this.backspace(); + else handleText(this, chr); + } +} + +function charCode(keycode) { + return String.fromCharCode(keycode) +} +function isEnter(chr){ return chr == charCode(13) } +function isBackspace(chr){ return chr == charCode(8) } + +/* + * Enter key marks the end of command so send it to shell + * and reset our buffer. + */ +function handleEnter(console) { + _OsShell.handleInput(console.buffer); + console.buffer = ""; +} + +/* + * A "normal" character to be drawn on the screen + * and added to our buffer. + */ +function handleText(console, chr) { + console.putText(chr); + console.buffer += chr; +} + +// +/* + * Draws the text at the current X and Y coordinates and + * moves the current X position. + * Note: the term "text" connotes string or char. + */ +function consolePutText(txt) { + if (txt != "") { + // process by char not by string so we can word wrap + for(var i in txt) { + var chr = txt[i]; + var offset = DRAWING_CONTEXT.measureText( + this.CurrentFont, + this.CurrentFontSize, + chr); + + // the new x position + var offsetx = this.CurrentXPosition + offset; + + // if new x position is outside of canvas, wrap. + if(offsetx >= CANVAS.width) { + this.advanceLine(); + offsetx = offset; + } + + // add the height of a new line * offsetscreen to the y. + var savedYPosition = this.CurrentYPosition + + ((DEFAULT_FONT_SIZE + FONT_HEIGHT_MARGIN)*this.scrollOffset); + this.textDrawBuffer.push(new Array( + this.CurrentXPosition, + savedYPosition, + chr)); //save params to redraw later + + // Draw the text. + DRAWING_CONTEXT.drawText( + this.CurrentFont, + this.CurrentFontSize, + this.CurrentXPosition, + this.CurrentYPosition, + chr); + + // Move to the next position. + this.CurrentXPosition = offsetx; } + } +} + +function consoleAdvanceLine() { + this.CurrentXPosition = 0; + this.CurrentYPosition += DEFAULT_FONT_SIZE + FONT_HEIGHT_MARGIN; + // scroll screen if passed height + if(this.CurrentYPosition > CANVAS.height - (this.CurrentFontSize+20)) { + this.scroll(); + } } -function consolePutText(txt) -{ - // My first inclination here was to write two functions: putChar() and putString(). - // Then I remembered that Javascript is (sadly) untyped and it won't differentiate - // between the two. So rather than be like PHP and write two (or more) functions that - // do the same thing, thereby encouraging confusion and decreasing readability, I - // decided to write one function and use the term "text" to connote string or char. - if (txt != "") - { - // Draw the text at the current X and Y coordinates. - DRAWING_CONTEXT.drawText(this.CurrentFont, this.CurrentFontSize, this.CurrentXPosition, this.CurrentYPosition, txt); - // Move the current X position. - var offset = DRAWING_CONTEXT.measureText(this.CurrentFont, this.CurrentFontSize, txt); - this.CurrentXPosition = this.CurrentXPosition + offset; +function consoleScroll() { + this.scrollOffset++; + this.CurrentYPosition -= DEFAULT_FONT_SIZE + FONT_HEIGHT_MARGIN; + this.refresh(); +} + +/* + * To support scrolling, we must save the canvas, move + * context one line up by the scroll offset, redraw text + * on canvas, and restore the canvas. + */ +function consoleRefresh() { + DRAWING_CONTEXT.save(); + this.clearScreen(); + DRAWING_CONTEXT.translate(0, 0 - + (DEFAULT_FONT_SIZE + FONT_HEIGHT_MARGIN) * this.scrollOffset ); + for( var i = 0 ; i < this.textDrawBuffer.length ; i++) { + if(this.textDrawBuffer[i][1] > (DEFAULT_FONT_SIZE + + FONT_HEIGHT_MARGIN) * this.scrollOffset) { + DRAWING_CONTEXT.drawText( + this.CurrentFont, + this.CurrentFontSize, + this.textDrawBuffer[i][0], + this.textDrawBuffer[i][1], + this.textDrawBuffer[i][2]); } + } + DRAWING_CONTEXT.restore(); +} + +/* + * Deletes the leftmost character by measuring the text and + * clearing it out; also removes the character from the buffer. + */ +function consoleBackspace() { + if (this.buffer.length > 0) { + var charWidth = DRAWING_CONTEXT.measureText( + this.CurrentFont, + this.CurrentFontSize, + this.buffer.slice(-1)); + var offset = this.CurrentXPosition - charWidth; + DRAWING_CONTEXT.clearRect( + offset, + this.CurrentYPosition - this.CurrentFontSize, + this.CurrentXPosition, + this.CurrentYPosition + 2); //fudge + this.refresh(); + this.CurrentXPosition = offset; + this.buffer = this.buffer.slice(0, -1); + } +} + +/* + * BLUE SCREEN OF DEATH + */ +function consoleBSOD(msg) { + _OsShell.promptStr = ""; + DRAWING_CONTEXT.fillStyle = '#89CFF0'; // baby blue + DRAWING_CONTEXT.fillRect(0, 0, CANVAS.width, CANVAS.height); + DRAWING_CONTEXT.drawText( + this.CurrentFont, + this.CurrentFontSize, + 10, //fudge + this.CurrentFontSize + 10, //fudge + msg); +} + +/* + * GREEN SCREEN OF DEATH - just in case + */ +function consoleGSOD() { + _OsShell.promptStr = ""; + DRAWING_CONTEXT.fillStyle = '#5DFC0A'; // greenLED + DRAWING_CONTEXT.fillRect(0, 0, CANVAS.width, CANVAS.height); + DRAWING_CONTEXT.drawText( + this.CurrentFont, + this.CurrentFontSize, + 10, //fudge + this.CurrentFontSize + 10, //fudge + 'Overriding all data... Now save yourself!'); + simDisableKeyboardInterrupt(); +} + +/* + * Draws the date and time on the bottom left of the canvas. + */ +function consoleTaskbarDateTime() { + DRAWING_CONTEXT.drawText( + this.CurrentFont, + this.CurrentFontSize, + 10, + CANVAS.height - this.CurrentFontSize, + Date()); +} + +/* + * Draws the status on the bottom rightish of the canvas. + */ +function consoleTaskbarStatus(status) { + DRAWING_CONTEXT.drawText( + this.CurrentFont, + this.CurrentFontSize, + CANVAS.width / 2, + CANVAS.height - this.CurrentFontSize, + status); +} + +/* + * Sets the status of the status. + */ +function consoleSetTaskbarStatus(status) { + this.statusText = status; } -function consoleAdvanceLine() -{ - this.CurrentXPosition = 0; - this.CurrentYPosition += DEFAULT_FONT_SIZE + FONT_HEIGHT_MARGIN; - // TODO: Handle scrolling. +/* Erases and redraws entire taskbar. */ +function consoleTaskbarRefresh() { + DRAWING_CONTEXT.clearRect( + 0, + CANVAS.height - (this.CurrentFontSize+12), + CANVAS.width, + (this.CurrentFontSize+12)); + + this.taskbarDateTime(); + this.taskbarStatus(this.statusText); } diff --git a/scripts/os/deviceDriver.js b/scripts/os/deviceDriver.js @@ -4,16 +4,29 @@ The "base class" (or 'prototype') for all Device Drivers. ------------------------------ */ -function DeviceDriver() -{ - // Base Attributes - this.version = "0.07"; - this.status = "unloaded"; - this.preemptable = false; - // this.queue = new Queue(); // TODO: We will eventually want a queue for, well, queueing requests for this device to be handled by deferred proceedure calls (DPCs). +function DeviceDriver() { + // Base Attributes + this.version = "0.07"; + this.status = "unloaded"; + this.preemptable = false; - // Base Method pointers. - this.driverEntry = null; // Initialization routine. Should be called when the driver is loaded. - this.isr = null; // Interrupt Service Routine - // TODO: this.dpc = null; // Deferred Procedure Call routine - Start next queued operation on this device. + // TODO: We will eventually want a queue for, well, + // queueing requests for this device to be handled by + // deferred proceedure calls (DPCs). + // this.queue = new Queue(); + + // Base Method pointers. + + /* + * Initialization routine. + * Should be called when the driver is loaded. + */ + this.driverEntry = null; + + /* Interrupt Service Routine */ + this.isr = null; + + // TODO: Deferred Procedure Call routine - Start next + // queued operation on this device. + // this.dpc = null; } diff --git a/scripts/os/deviceDriverKeyboard.js b/scripts/os/deviceDriverKeyboard.js @@ -26,31 +26,49 @@ function krnKbdDriverEntry() function krnKbdDispatchKeyPress(params) { - // Parse the params. TODO: Check that they are valid and osTrapError if not. + // added digits mapped to punctuations + var digits = { + 48:{num:'0', punc:')'}, + 49:{num:'1', punc:'!'}, + 50:{num:'2', punc:'@'}, + 51:{num:'3', punc:'#'}, + 52:{num:'4', punc:'$'}, + 53:{num:'5', punc:'%'}, + 54:{num:'6', punc:'^'}, + 55:{num:'7', punc:'&'}, + 56:{num:'8', punc:'*'}, + 57:{num:'9', punc:'('}}; + + // Parse the params. var keyCode = params[0]; var isShifted = params[1]; + + // chack validity. + if (typeof keyCode !== 'number' || typeof isShifted !== 'boolean') + krnTrapError('Invalid paramaters for krnKbdDispatchKeyPress.'); + krnTrace("Key code:" + keyCode + " shifted:" + isShifted); var chr = ""; + // Check to see if we even want to deal with the key that was pressed. - if ( ((keyCode >= 65) && (keyCode <= 90)) || // A..Z - ((keyCode >= 97) && (keyCode <= 123)) ) // a..z + if (((keyCode >= 65) && (keyCode <= 90)) || // A..Z + ((keyCode >= 97) && (keyCode <= 123))) // a..z { - // Determine the character we want to display. - // Assume it's lowercase... - chr = String.fromCharCode(keyCode + 32); - // ... then check the shift key and re-adjust if necessary. - if (isShifted) - { - chr = String.fromCharCode(keyCode); - } - // TODO: Check for caps-lock and handle as shifted if so. - _KernelInputQueue.enqueue(chr); - } - else if ( ((keyCode >= 48) && (keyCode <= 57)) || // digits - (keyCode == 32) || // space - (keyCode == 13) ) // enter + // Assume it's lowercase... + chr = String.fromCharCode(keyCode + 32); + if (isShifted) chr = String.fromCharCode(keyCode); + + // TODO: Check for caps-lock and handle as shifted if so. + _KernelInputQueue.enqueue(chr); + } else if ((keyCode == 32) || // space + (keyCode == 13) || // enter + (keyCode == 8)) //backspace { - chr = String.fromCharCode(keyCode); - _KernelInputQueue.enqueue(chr); + chr = String.fromCharCode(keyCode); + _KernelInputQueue.enqueue(chr); + } else if((keyCode >= 48) && (keyCode <= 57)) { // digits + if(isShifted) chr = digits[keyCode].punc; + else chr = digits[keyCode].num; + _KernelInputQueue.enqueue(chr); } } diff --git a/scripts/os/interrupt.js b/scripts/os/interrupt.js @@ -2,9 +2,8 @@ Interrupt.js ------------ */ -function Interrput(_irq, _params) -{ - // Properties - this.irq = _irq; - this.params = _params; +function Interrput(_irq, _params) { + // Properties + this.irq = _irq; + this.params = _params; } diff --git a/scripts/os/kernel.js b/scripts/os/kernel.js @@ -21,11 +21,12 @@ function krnBootstrap() // Page 8. _KernelInterruptQueue = new Queue(); // A (currently) non-priority queue for interrupt requests (IRQs). _KernelBuffers = new Array(); // Buffers... for the kernel. _KernelInputQueue = new Queue(); // Where device input lands before being processed out somewhere. + _KernelMemoryManager = new MemoryManager(); _Console = new Console(); // The console output device. - + // Initialize the Console. _Console.init(); - + // Initialize standard input and output to the _Console. _StdIn = _Console; _StdOut = _Console; @@ -66,6 +67,7 @@ function krnShutdown() function krnOnCPUClockPulse() { + _Console.taskbarRefresh(); /* This gets called from the host hardware every time there is a hardware clock pulse. This is NOT the same as a TIMER, which causes an interrupt and is handled like other interrupts. This, on the other hand, is the clock pulse from the hardware (or host) that tells the kernel @@ -183,6 +185,6 @@ function krnTrace(msg) function krnTrapError(msg) { simLog("OS ERROR - TRAP: " + msg); - // TODO: Display error on console, perhaps in some sort of colored screen. (Perhaps blue?) + _Console.bsod(msg); krnShutdown(); } diff --git a/scripts/os/memoryManager.js b/scripts/os/memoryManager.js @@ -0,0 +1,16 @@ +/* + * Manages the OS memory. + */ + +function MemoryManager() { + this.memory = new MemoryStack(TOTAL_MEMORY); + this.load = memoryManagerLoad; +} + +/* + * Loads a program (hex or bytes) into the memory stack. + * @param hex an array of bytes + */ +function memoryManagerLoad(bytes) { + this.memory.allocateBytes(bytes); +} diff --git a/scripts/os/queue.js b/scripts/os/queue.js @@ -7,44 +7,34 @@ ------------ */ -function Queue() -{ - // Properties - this.q = new Array(); +function Queue() { + this.q = new Array(); - // Methods - this.getSize = function() - { - return this.q.length; - } + this.getSize = function(){ + return this.q.length; + } - this.isEmpty = function() - { - return (this.q.length == 0); - } + this.isEmpty = function() { + return (this.q.length == 0); + } - this.enqueue = function(element) - { - this.q.push(element); - } + this.enqueue = function(element) { + this.q.push(element); + } - this.dequeue = function() - { - var retVal = null; - if (this.q.length > 0) - { - retVal = this.q.shift(); - } - return retVal; + this.dequeue = function() { + var retVal = null; + if (this.q.length > 0) { + retVal = this.q.shift(); } + return retVal; + } - this.toString = function() - { - retVal = ""; - for (i in this.q) - { - retVal += "[" + this.q[i] + "] "; - } - return retVal; - } + this.toString = function() { + retVal = ""; + for (i in this.q) { + retVal += "[" + this.q[i] + "] "; + } + return retVal; + } } diff --git a/scripts/os/shell.js b/scripts/os/shell.js @@ -9,7 +9,7 @@ function Shell() { // Properties - this.promptStr = ">"; + this.promptStr = "$"; this.commandList = []; this.curses = "[fuvg],[cvff],[shpx],[phag],[pbpxfhpxre],[zbgureshpxre],[gvgf]"; this.apologies = "[sorry]"; @@ -82,6 +82,41 @@ function shellInit() sc.function = shellPrompt; this.commandList[this.commandList.length] = sc; + // date + sc = new ShellCommand(); + sc.command = "date"; + sc.description = "- Displays the current date and time." + sc.function = shellDate; + this.commandList[this.commandList.length] = sc; + + // whereami + sc = new ShellCommand(); + sc.command = "whereami"; + sc.description = "- Displays where you are." + sc.function = shellWhereami; + this.commandList[this.commandList.length] = sc; + + // qwikerase + sc = new ShellCommand(); + sc.command = "qwe"; + sc.description = "- QwikErase: Overrides all data in filesystem." + sc.function = shellQuickerase; + this.commandList[this.commandList.length] = sc; + + // status + sc = new ShellCommand(); + sc.command = "status"; + sc.description = "- Sets the console's status."; + sc.function = shellStatus; + this.commandList[this.commandList.length] = sc; + + // load + sc = new ShellCommand(); + sc.command = "load"; + sc.description = "- Loads an external program."; + sc.function = shellLoad; + this.commandList[this.commandList.length] = sc; + // processes - list the running processes and their IDs // kill <id> - kills the specified process id. @@ -140,6 +175,11 @@ function shellHandleInput(buffer) { this.execute(shellApology); } + else if(cmd == "") + { + _StdIn.advanceLine(); + _StdIn.putText(this.promptStr); + } else // It's just a bad command. { this.execute(shellInvalidCommand); @@ -255,7 +295,7 @@ function shellApology() function shellVer(args) { - _StdIn.putText(APP_NAME + " version " + APP_VERSION); + _StdIn.putText(APP_NAME + " v." + APP_VERSION); } function shellHelp(args) @@ -280,6 +320,7 @@ function shellCls(args) { _StdIn.clearScreen(); _StdIn.resetXY(); + _StdIn.resetScroll(); } function shellMan(args) @@ -358,3 +399,70 @@ function shellPrompt(args) _StdIn.putText("Usage: prompt <string> Please supply a string."); } } + +/* + * Displays the current date and time in the format: "MM/DD/YYYY HH:MM:SS" + */ +function shellDate(args) +{ + _StdIn.putText(Date()); +} + +/* + * Displays where you are. + */ +function shellWhereami(args) { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + function (position) { + _StdIn.putText('lat:' + position.coords.latitude + ' lng:' + position.coords.longitude); + }.bind(this), + function () {}.bind(this)); //failure + } else { + _StdIn.putText("Cybertron. WIll self-destruct in 3... 2... 1..."); + setTimeout(function(){_Console.bsod("Self Destructed.")},3500); + } + return false; +} + +// TODO: Override all data in filesystem in under 10 seconds +// (when the filesystem is implemented). +function shellQuickerase(args) +{ + _Console.gsod(); +} + +/* + * Sets the status of the status. + */ +function shellStatus(args) +{ + if (args.length > 0) + { + var status = args.join(" "); + _Console.taskbarSetStatus(status); + _Console.taskbarRefresh(); + } + else + { + _StdOut.putText("Usage: status <string> Please supply a status."); + } +} + +function shellLoad(args) { + var hex = trim(document.getElementById(TA_PROGRAM_INPUT).value.replace(/\n/g, " ")); + if(isValidHex(hex)) { // in utils.js + var bytes = hex.split(" "); + if(bytes.length > 1) { + if (bytes.length <= MAX_MEMORY_PROGRAM) { + // pass the hex to kernel's memory manager + _KernelMemoryManager.load(bytes); + _StdOut.putText("Your program has been successfully loaded."); + } else { + _StdOut.putText("Program is too large. Must be less than "+MAX_MEMORY_PROGRAM); + } + } else _StdOut.putText("Input Program textarea is empty."); + } else { + _StdOut.putText("Invalid program. Make sure it's properly formatted hex."); + } +} diff --git a/scripts/os/stack.js b/scripts/os/stack.js @@ -0,0 +1,70 @@ +/* ------------ + Stack.js + + A simple Stack, which is really just a dressed-up Javascript Array. + See the Javascript Array documentation at http://www.w3schools.com/jsref/jsref_obj_array.asp . + Can be used as a 32-bit memory stack. + + ------------ */ + +/* Just a stack. */ +function Stack() { + this.q = new Array(); + + this.getSize = function(){ + return this.q.length; + } + + this.empty = function() { + return (this.q.length == 0); + } + + this.push = function(element) { + + this.q.push(element); + } + + this.pop = function() { + var element = this.peek(); + q.pop(); + return element; + } + + this.peek = function() { + if(this.getSize() > 0) + return q[this.getSize() - 1]; + } + + this.toString = function() { + retVal = ""; + for (i in this.q) { + retVal += "[" + this.q[i] + "] "; + } + return retVal; + } +} + +/* + * A simple stack with a limit. If you pass the limit of + * maximum bytes, the kernel crashes with a stack overflow. + */ +function MemoryStack(maxBytes) { + this.stack = new Stack(); + + this.allocateByte = function(byte) { + if(this.stack.getSize() < maxBytes) + this.stack.push(byte); + else + krnTrapError("Stack overflow.") + } + + this.deallocateByte = function() { + this.stack.pop(); + } + + this.allocateBytes = function(bytes) { + for (byte in bytes) { + this.allocateByte(byte); + } + } +} diff --git a/scripts/utils.js b/scripts/utils.js @@ -4,41 +4,44 @@ Utility functions. -------- */ -function trim(str) // Use a regular expression to remove leading and trailing spaces. -{ - return str.replace(/^\s+ | \s+$/g, ""); - /* - Huh? Take a breath. Here we go: - - The "|" separates this into two expressions, as in A or B. - - "^\s+" matches a sequence of one or more whitespace characters at the beginning of a string. - - "\s+$" is the same thing, but at the end of the string. - - "g" makes is global, so we get all the whitespace. - - "" is nothing, which is what we replace the whitespace with. - */ - +/* + * Removes leading and trailing spaces. + */ +function trim(str) { + return str.replace(/^\s+ | \s+$/g, ""); } -function rot13(str) // An easy-to understand implementation of the famous and common Rot13 obfuscator. -{ // You can do this in three lines with a complex regular experssion, but I'd have - var retVal = ""; // trouble explaining it in the future. There's a lot to be said for obvious code. - for (var i in str) - { - var ch = str[i]; - var code = 0; - if ("abcedfghijklmABCDEFGHIJKLM".indexOf(ch) >= 0) - { - code = str.charCodeAt(i) + 13; // It's okay to use 13. It's not a magic number, it's called rot13. - retVal = retVal + String.fromCharCode(code); - } - else if ("nopqrstuvwxyzNOPQRSTUVWXYZ".indexOf(ch) >= 0) - { - code = str.charCodeAt(i) - 13; // It's okay to use 13. See above. - retVal = retVal + String.fromCharCode(code); - } - else - { - retVal = retVal + ch; - } +/* + * Rotates each character of a string to the thirteenth spot. + * ie. a to n and z to m. + */ +function rot13(str) { + var retVal = ""; + for (var i in str) { + var ch = str[i]; + var code = 0; + if ("abcedfghijklmABCDEFGHIJKLM".indexOf(ch) >= 0) { + code = str.charCodeAt(i) + 13; + retVal = retVal + String.fromCharCode(code); + } else if ("nopqrstuvwxyzNOPQRSTUVWXYZ".indexOf(ch) >= 0) { + code = str.charCodeAt(i) - 13; + retVal = retVal + String.fromCharCode(code); + } else { + retVal = retVal + ch; } - return retVal; + } + return retVal; +} + +/* + * Matches hex pattern. ie. FF 00 5G 8D 98 + */ +function isValidHex(str) { + for (var i in str) { + var ch = str[i]; + if ("abcedfABCDEF0123456789 ".indexOf(ch) < 0) { + return false; + } + } + return true; } diff --git a/styles/julios-buttons.css b/styles/julios-buttons.css @@ -0,0 +1,53 @@ +[class^="icon28-"] { + display: inline-block; + width: 28px; + height: 28px; + margin-top: 4px; + line-height: 28px; + vertical-align: text-top; + background-image: url("../images/icons28.png"); + background-position: 28px 28px; + background-repeat: no-repeat; +} +.icon28-poweroff { background-position: 0 0; } +.icon28-halt { background-position: -28px 0; } +.icon28-reset { background-position: -56px 0; } +.btnicon28 { + border-radius: 1em; + font-size: 30px; + line-height: 1.2em; + padding: 0.3em 1em; + border-width: 1px; + background-image: -moz-radial-gradient(50% 10%, circle, #ffffff 0%, #c1c1c1 30px); + border-color: #b7b7b7; + text-shadow: #fff 0px 1px 1px; + box-shadow: rgba(255,255,255,0.867) 0 0 0.1em 1px inset; + background-clip: padding-box; + padding: 8px 0; + margin: 0 3px; + border-width: 2px; + width: 56px; +} +.btnicon28[disabled] { opacity:0.4; } +.btnicon28, +.btnicon28:visited { color: #222 } +.btnicon28:hover, +.btnicon28:focus { + background-color: #fff; + background-image: -moz-radial-gradient(50% 10%, circle, #fcfcfc 0%, #b9b9b9 30px); + border-color: #afafaf; + text-shadow: #fff 0px 1px 1px; + outline: none; +} +.btnicon28:hover, +.btnicon28:hover:visited, +.btnicon28:focus, +.btnicon28:focus:visited { color: #222 } +.btnicon28:active { + background-color: #fff; + background-image: -moz-radial-gradient(50% 10%, circle, #d8d8d8 0%, #f1f1f1 30px); + border-color: #a7a7a7; + box-shadow: #b7b7b7 0 0.08em 0.1em 1px inset; +} +.btnicon28:active, +.btnicon28:active:visited { color: #222; } diff --git a/styles/julios.css b/styles/julios.css @@ -0,0 +1,21 @@ +/* julios.css */ + +body { + font-family: 'Open Baskerville 0.0.53'; + font-weight: normal; + font-style: normal; + font-size: 10pt; +} + +#display { + background-color: #fff; + cursor: default; + border: 0.1em solid black; + outline: none; + font-size: 10pt; +} + +.footer { + padding-top: 30px; + font-size: 8pt; +}