Setup color scheme for inputs and outputs.
[CS-101.git] / digital_logic_simulator.html
blob2fbc5475cb59154360dce1bccb8d2abcfcf72b23
1 <html>
2 <title>Digital Logic Simulator</title>
3 <script>
5 var grid_status = 1; /* boolean status of stage grid lines */
6 var grid_size = 50; /* this is stored here for reference */
7 var canvas; /* object id of canvas tag */
8 var ctx; /* context of canvas */
9 var item_selected = "gate_and" /* only one type of object can be drawn at a time */
11 var color_on = "#fe0"; /* color of objects in high state */
12 var color_on_hlt = "#f90";
14 var color_off = "#bbb"; /* color of objects in low state */
15 var color_off_hlt = "#ddd";
17 var out = new Array(); /* output bits */
18 var input = new Array(); /* intput bits */
19 var grid = new Array(); /* status of grid - all details stored here */
21 /* create new output - only called during init phase */
22 function output(value, xpos, ypos)
24 this.val = value;
25 this.xpos = xpos;
26 this.ypos = ypos;
29 /* each square on grid has an associated block of data tied to it */
30 function grid(type, xpos, ypos)
32 this.type = type; /* type of entity @ location */
33 this.value = value; /* many entities have a value associated */
34 this.xpos = xpos; /* horiz position on grid */
35 this.ypos = ypos; /* vertical position on grid */
38 /* flip bit of specified input and redraw on screen */
39 function input_flip(v)
41 if(v == 'undefined') { alert("Cannot flip unknown value"); }
42 if(input[v].val == 0) { input[v].val = 1; } else { input[v].val = 0; }
43 // redraw output on screen
44 draw_input_simple(v);
48 /* flip bit of specified output and redraw on screen */
49 function output_flip(v)
51 if(v == 'undefined') { alert("Cannot flip unknown value"); }
52 if(out[v].val == 0) { out[v].val = 1; } else { out[v].val = 0; }
53 // redraw output on screen
54 draw_output_simple(v);
57 /* reset all outputs to zero and redraw on screen */
58 function output_reset()
60 for(var i = 0; i < 9; i++) {
61 out[i].val = 0;
62 // redraw outputs on screen
63 draw_output_simple(i);
67 /* converts decimal degrees to radians */
68 function deg_to_rad(deg)
70 return (Math.PI/180)*deg;
73 /* create all output data structures and draw inital values on screen */
74 function init_outputs()
76 var x;
78 for(x = 0; x < 9; x++) {
79 out[x] = new output(0,15,x+2);
80 draw_output(15,x+2, x, 0);
83 for(y = "A", x = 0; x < 9; x++, y = String.fromCharCode(y.charCodeAt() + 1)) {
84 input[x] = new output(0,0,x+2);
85 draw_input(0,x+3, y);
89 /* intial setup of page - must be called on page load */
90 function init_form()
92 var x; var y;
93 /* initalize canvas element for use */
94 canvas = document.getElementById("stage");
95 ctx = canvas.getContext("2d");
96 /* get width and height of window and set stage (canvas) with it. */
97 canvas.height = window.innerHeight-125;
98 canvas.width = window.innerWidth - 45;
99 init_outputs();
100 if(grid_status) {draw_grid(); }
101 /* temporary */
102 draw_and_gate(1,0);
103 draw_not_gate(4,0);
104 draw_or_gate(7,0);
105 draw_nor_gate(11,0);
106 draw_xor_gate(1,3);
107 draw_nand_gate(4,3);
108 draw_clock(0,0,1);
109 draw_clock(0,1,0);
112 function draw_clock(x,y,phase)
114 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
115 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
116 if(phase > 1 || phase < 0) { alert("Clock phase not sent"); return ; }
117 x = (x*grid_size) + (grid_size/2); /* offset from conrner of grid */
118 y = (y*grid_size) + (grid_size/2);
119 ctx.strokeStyle = "#f33";
120 ctx.lineWidth = 2;
121 ctx.moveTo(x,y);
122 ctx.beginPath();
123 ctx.arc(x,y,15, deg_to_rad(360), deg_to_rad(0), false);
124 ctx.stroke();
125 ctx.font = "10pt Arial";
126 ctx.textAlign = "center";
127 ctx.textBaseline = "middle";
128 ctx.fillText("CLK", x, y);
129 /* draw line over text */
130 if(phase == 0) {
131 ctx.strokeStyle = "#000";
132 ctx.moveTo(x,y);
133 ctx.beginPath();
134 ctx.lineTo(x-8,y-8);
135 ctx.lineTo(x+8,y-8);
136 ctx.stroke();
140 /* inputs have are represented by a character with a parameter v */
141 function draw_input(x,y,v,s)
143 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
144 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
145 x = (x*grid_size) + (grid_size/2); /* offset from corner of grid */
146 y = (y*grid_size) + (grid_size/2);
147 if(s) { ctx.strokeStyle = color_on_hlt } else { ctx.strokeStyle = color_off; }
148 if(s) { ctx.fillStyle = color_on } else { ctx.fillStyle = color_off_hlt; }
149 ctx.lineWidth = 2;
150 ctx.moveTo(x,y);
151 /* draw background circle */
152 ctx.beginPath();
153 ctx.arc(x,y,15, deg_to_rad(360), deg_to_rad(0), false);
154 ctx.fill();
156 ctx.beginPath();
157 ctx.arc(x,y,15, deg_to_rad(360), deg_to_rad(0), false);
158 ctx.stroke();
160 if(s) { ctx.fillStyle = color_on_hlt } else { ctx.fillStyle = color_off; }
161 /* draw character on top */
162 ctx.font = "15pt Arial";
163 ctx.textAlign = "center";
164 ctx.textBaseline = "middle";
165 ctx.fillText(v, x, y);
168 /* simple version with auto lookup to data structure */
169 function draw_input_simple(v)
171 var x;
172 if(v == 'undefined') { alert("Cannot modify unknown output"); }
173 // TODO: Make this work with lib function instead...
174 switch(v) {
175 case 1:
176 x = "A";
177 break;
178 case 2:
179 x = "B";
180 break;
181 case 3:
182 x = "C";
183 break;
184 case 4:
185 x = "D";
186 break;
187 case 5:
188 x = "E";
189 break;
190 case 6:
191 x = "F";
192 break;
193 case 7:
194 x = "G";
195 break;
196 case 8:
197 x = "H";
198 break;
200 draw_input(input[v].xpos, input[v].ypos, x, input[v].val);
203 /* draw output button.
205 x = grid position on x axis.
206 y = grid position on y axis.
207 v = char to print inside button.
208 s = state of output (on or off)
210 function draw_output(x,y,v,s)
212 var w = 30; /* width of box */
213 var tx = x; var ty = y;
214 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
215 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
217 tx = x * grid_size + (grid_size / 2);
218 ty = y * grid_size + (grid_size / 2);
221 x = (x * grid_size) + (grid_size / 5); /* offset from corner of grid */
222 y = (y * grid_size) + (grid_size / 5);
224 /* draw filled box around char */
225 if(s) { ctx.fillStyle = color_on } else { ctx.fillStyle = color_off_hlt; }
226 ctx.lineWidth = 2;
227 ctx.moveTo(x,y);
228 ctx.beginPath();
229 ctx.lineTo(x+w,y);
230 ctx.lineTo(x+w,y+w);
231 ctx.lineTo(x,y+w);
232 ctx.lineTo(x,y);
233 ctx.lineTo(x+w,y);
234 ctx.fill();
236 /* draw outline box around char */
237 if(s) { ctx.strokeStyle = color_on_hlt } else { ctx.strokeStyle = color_off; }
238 ctx.lineWidth = 2;
239 ctx.moveTo(x,y);
240 ctx.beginPath();
241 ctx.lineTo(x+w,y);
242 ctx.lineTo(x+w,y+w);
243 ctx.lineTo(x,y+w);
244 ctx.lineTo(x,y);
245 ctx.lineTo(x+w,y);
246 ctx.stroke();
248 /* draw char inside box */
249 if(s) { ctx.fillStyle = color_on_hlt; } else { ctx.fillStyle = color_off; }
250 ctx.font = "15pt Arial";
251 ctx.textAlign = "center";
252 ctx.textBaseline = "middle";
253 ctx.fillText(v, tx, ty);
256 /* simple version with auto lookup to data structure */
257 function draw_output_simple(v)
259 if(v == 'undefined') { alert("Cannot modify unknown output"); }
260 draw_output(out[v].xpos, out[v].ypos, v, out[v].val);
263 /* draw faint gridlines on stage - used as a guide for the user */
264 function draw_grid()
266 var x, y; /* current x and y position */
267 var offset = 10; /* x and y maximum offset (far bottom or side of the window) */
268 ctx.strokeStyle = "#ccc";
269 ctx.lineWidth = 1;
270 /* draw vertical lines */
271 for(x = grid_size, y = 0, offset = window.innerWidth; x < window.innerWidth; x = x + grid_size)
273 ctx.beginPath();
274 ctx.moveTo(x,y);
275 ctx.lineTo(x,y+offset);
276 ctx.stroke();
278 /* draw horizontal lines */
279 for(x = 0, y = grid_size, offset = window.innerWidth; y < window.innerWidth; y = y + grid_size)
281 ctx.beginPath();
282 ctx.moveTo(x,y);
283 ctx.lineTo(x+offset,y);
284 ctx.stroke();
288 function draw_and_gate(x,y)
290 var h = 50; /* height of square of gate */
291 var w = 30; /* width of square area of gate */
292 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
293 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
294 ctx.strokeStyle = "#11f";
295 ctx.lineWidth = 3;
296 x = 10 + (grid_size*x); /* offset from conrner of grid */
297 y = 10 + (grid_size*y);
298 ctx.beginPath();
299 ctx.moveTo(x,y);
300 ctx.lineTo(x+w, y);
301 ctx.arc( x+w, y+(h/2), (h/2), deg_to_rad(-90), deg_to_rad(90), false);
302 ctx.lineTo(x+w, y+h);
303 ctx.lineTo(x,y+h);
304 ctx.lineTo(x,y);
305 ctx.stroke();
308 function draw_nand_gate(x,y)
310 var h = 50; /* height of square of gate */
311 var w = 30; /* width of square area of gate */
312 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
313 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
314 ctx.strokeStyle = "#11f";
315 ctx.lineWidth = 3;
316 x = 10 + (grid_size*x); /* offset from conrner of grid */
317 y = 10 + (grid_size*y);
318 ctx.beginPath();
319 ctx.moveTo(x,y);
320 ctx.lineTo(x+w, y);
321 ctx.arc( x+w, y+(h/2), (h/2), deg_to_rad(-90), deg_to_rad(90), false);
322 ctx.lineTo(x+w, y+h);
323 ctx.lineTo(x,y+h);
324 ctx.lineTo(x,y);
325 ctx.stroke();
326 /* nose */
327 ctx.beginPath();
328 ctx.arc( x+(w*2), y+(h/2),5, deg_to_rad(0), deg_to_rad(360), false);
329 ctx.stroke();
332 function draw_not_gate(x,y)
334 var h = 50; /* height of square of gate */
335 var w = 40; /* width of square area of gate */
336 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
337 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
338 ctx.strokeStyle = "#11f";
339 ctx.lineWidth = 3;
340 ctx.lineJoin = 'bevel';
341 x = 10 + (grid_size*x); /* offset from conrner of grid */
342 y = 10 + (grid_size*y);
344 /* triangle */
345 ctx.beginPath();
346 ctx.moveTo(x,y);
347 ctx.lineTo(x+w,y+(h/2));
348 ctx.lineTo(x,y+h);
349 ctx.lineTo(x,y);
350 ctx.stroke();
352 /* nose */
353 ctx.beginPath();
354 ctx.arc( x+w+6, y+(h/2),5, deg_to_rad(0), deg_to_rad(360), false);
355 ctx.stroke();
358 function draw_or_gate(x,y)
360 var h = 50; /* height of square of gate */
361 var w = 21; /* width of square area of gate */
362 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
363 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
364 ctx.strokeStyle = "#11f";
365 ctx.lineWidth = 3;
366 ctx.lineJoin = 'bevel';
367 x = 10 + (grid_size*x); /* offset from conrner of grid */
368 y = 10 + (grid_size*y);
369 /* back curve - inputs */
370 ctx.beginPath();
371 ctx.arc(x-(2*w), y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
372 ctx.stroke();
373 /* top line */
374 ctx.beginPath();
375 ctx.moveTo(x,y);
376 ctx.lineTo(x+w,y);
377 ctx.stroke();
378 /* top curve */
379 ctx.beginPath();
380 ctx.arc(x+w, y+h, h, deg_to_rad(-90), deg_to_rad(-30), false);
381 ctx.stroke();
382 /* bottom line */
383 ctx.beginPath();
384 ctx.moveTo(x,y+h);
385 ctx.lineTo(x+w,y+h);
386 ctx.stroke();
387 /* bottom curve */
388 ctx.beginPath();
389 ctx.arc(x+w, y, h, deg_to_rad(30), deg_to_rad(90), false);
390 ctx.stroke();
393 function draw_nor_gate(x,y)
395 var h = 50; /* height of square of gate */
396 var w = 21; /* width of square area of gate */
397 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
398 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
399 ctx.strokeStyle = "#11f";
400 ctx.lineWidth = 3;
401 ctx.lineJoin = 'bevel';
402 x = 10 + (grid_size*x); /* offset from conrner of grid */
403 y = 10 + (grid_size*y);
404 /* back curve - inputs */
405 ctx.beginPath();
406 ctx.arc(x-(2*w), y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
407 ctx.stroke();
408 /* top line */
409 ctx.beginPath();
410 ctx.moveTo(x,y);
411 ctx.lineTo(x+w,y);
412 ctx.stroke();
413 /* top curve */
414 ctx.beginPath();
415 ctx.arc(x+w, y+h, h, deg_to_rad(-90), deg_to_rad(-30), false);
416 ctx.stroke();
417 /* bottom line */
418 ctx.beginPath();
419 ctx.moveTo(x,y+h);
420 ctx.lineTo(x+w,y+h);
421 ctx.stroke();
422 /* bottom curve */
423 ctx.beginPath();
424 ctx.arc(x+w, y, h, deg_to_rad(30), deg_to_rad(90), false);
425 ctx.stroke();
426 /* nose */
427 ctx.beginPath();
428 ctx.arc(x+(w*3)+6, y+(h/2),5, deg_to_rad(0), deg_to_rad(360), false);
429 ctx.stroke();
432 function draw_xor_gate(x,y)
434 var h = 50; /* height of square of gate */
435 var w = 21; /* width of square area of gate */
436 if(x == 'undefined' || y == 'undefined') { alert("Coordinates Not Sent to Function"); return; }
437 if(x < 0 || y < 0) { alert("Coordinates Cannot Be Negative"); return ; }
438 ctx.strokeStyle = "#11f";
439 ctx.lineWidth = 3;
440 ctx.lineJoin = 'bevel';
441 x = 10 + (grid_size*x); /* offset from conrner of grid */
442 y = 10 + (grid_size*y);
443 /* back curve - inputs */
444 ctx.beginPath();
445 ctx.arc(x-(2*w), y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
446 ctx.stroke();
447 /* extra back curve - inputs */
448 ctx.beginPath();
449 ctx.arc(x-(2*w)-10, y +(h/2), h, deg_to_rad(-30), deg_to_rad(30), false);
450 ctx.stroke();
451 /* top line */
452 ctx.beginPath();
453 ctx.moveTo(x,y);
454 ctx.lineTo(x+w,y);
455 ctx.stroke();
456 /* top curve */
457 ctx.beginPath();
458 ctx.arc(x+w, y+h, h, deg_to_rad(-90), deg_to_rad(-30), false);
459 ctx.stroke();
460 /* bottom line */
461 ctx.beginPath();
462 ctx.moveTo(x,y+h);
463 ctx.lineTo(x+w,y+h);
464 ctx.stroke();
465 /* bottom curve */
466 ctx.beginPath();
467 ctx.arc(x+w, y, h, deg_to_rad(30), deg_to_rad(90), false);
468 ctx.stroke();
471 /* user changes what type of gate will be drawn next */
472 function change_selection(sel)
474 var button = document.getElementById(sel);
475 if(!button) { alert("Cannot Find Selected Button"); return; }
476 /* enable old button */
477 document.getElementById(item_selected).disabled = false;
478 /* disable new button */
479 button.disabled = true;
480 /* set variable */
481 item_selected = sel;
484 /* returns coordinates of canvas in pixels */
485 function cnvs_get_coordinates(e)
487 var x_offset = canvas.offsetLeft;
488 var y_offset = canvas.offsetTop;
489 if(canvas == 'undefined') { alert("Canvas parameter is undefined"); }
490 x_offset = e.clientX - x_offset;
491 y_offset = e.clientY - y_offset;
492 document.getElementById("xycoordinates").innerHTML="Coordinates: (" + x_offset + "," + y_offset + ")";
493 return [x_offset,y_offset];
496 /* canvas has been clicked find out which grid and make correct change to square if needed. */
497 function cnvs_clicked(e)
499 var coords = cnvs_get_coordinates(e);
500 var x_pos = Math.floor(coords[0] / grid_size);
501 var y_pos = Math.floor(coords[1] / grid_size);
503 alert(x_pos + " " + y_pos);
505 // if an input or output, flip value
508 // ...otherwise perform whatever the current selected function is
511 </script>
513 <style type="text/css">
515 #stage {
516 border: solid 1px #000;
519 </style>
520 <body onLoad="init_form();">
522 <center><h2>Digital Logic Simulator</h2></center>
523 <center>
524 <button id="gate_and" onClick='change_selection("gate_and");' disabled >AND</button>
525 &nbsp;&nbsp;
526 <button id="gate_nand" onClick='change_selection("gate_nand");'>NAND</button>
527 &nbsp;&nbsp;
528 <button id="gate_nor" onClick='change_selection("gate_nor");'>NOR</button>
529 &nbsp;&nbsp;
530 <button id="gate_not" onClick='change_selection("gate_not");'>NOT</button>
531 &nbsp;&nbsp;
532 <button id="gate_or" onClick='change_selection("gate_or");'>OR</button>
533 &nbsp;&nbsp;
534 <button id="gate_xor" onClick='change_selection("gate_xor");'>XOR</button>
535 &nbsp;&nbsp;
536 <button id="gate_connect" onClick='change_selection("gate_connect");'>Connect</button>
537 &nbsp;&nbsp;
538 <button id="gate_connect" onClick='input_flip(2);'>In Flip</button>
539 &nbsp;&nbsp;
540 <button id="gate_connect" onClick='output_flip(2);'>Out Flip</button>
541 </center>
543 <div id=xycoordinates>&nbsp;</div>
545 <canvas id="stage" width="200" height="200" onMouseMove="cnvs_get_coordinates(event)" onClick="cnvs_clicked(event);">
546 Your browser does not support HTML5 Canvas.
547 </canvas>
549 </body>
550 </html>