2 <title>Digital Logic Simulator
</title>
4 /* DEFAULT COLOR SETTINGS */
5 var color_on
= "#fe0"; /* color of objects in high state */
6 var color_on_hlt
= "#f90";
8 var color_off
= "#bbb"; /* color of objects in low state */
9 var color_off_hlt
= "#ddd";
11 /* GENERAL DATA STRUCTRURES */
12 var stage
= new Array(); /* status of stage - all details stored here */
13 var stage_rows
= 0; /* number of rows on stage */
14 var stage_cols
= 0; /* number of columns on stage */
15 var grid_status
= 1; /* boolean status of stage grid lines */
16 var grid_size
= 50; /* this is stored here for reference */
17 var canvas
; /* object id of canvas tag */
18 var ctx
; /* context of canvas */
19 var item_selected
= "gate_and" /* only one type of object can be drawn at a time */
21 var out
= new Array(); /* output bits */
22 var input
= new Array(); /* intput bits */
24 /* each square on grid has an associated block of data tied to it */
25 function grid(type
, value
)
27 this.type
= type
; /* type of entity @ location */
28 this.value
= value
; /* many entities have a value associated */
29 this.name
= ''; /* used for inputs and outputs */
32 /* flip bit of specified input and redraw on screen */
33 function input_flip(v
)
35 if(v
== 'undefined') { alert("Cannot flip unknown value"); }
36 if(input
[v
].val
== 0) { input
[v
].val
= 1; } else { input
[v
].val
= 0; }
37 // redraw output on screen
41 /* flip bit of specified output and redraw on screen */
42 function output_flip(v
)
44 if(v
== 'undefined') { alert("Cannot flip unknown value"); }
45 if(out
[v
].val
== 0) { out
[v
].val
= 1; } else { out
[v
].val
= 0; }
46 // redraw output on screen
47 draw_output_simple(v
);
50 /* reset all outputs to zero and redraw on screen */
51 function output_reset()
53 for(var i
= 0; i
< 9; i
++) {
55 // redraw outputs on screen
56 draw_output_simple(i
);
60 /* converts decimal degrees to radians */
61 function deg_to_rad(deg
)
63 return (Math
.PI
/180)*deg
;
66 /* create all output data structures and draw inital values on screen */
71 /* create blank grid data structure */
72 for(x
= 0; x
< stage_cols
; x
++) {
73 stage
[x
] = new Array();
74 for(y
= 0; y
< stage_rows
; y
++) {
75 stage
[x
][y
] = new grid('', '');
80 stage
[0][0].type
= "clock";
81 stage
[0][1].type
= "clock_";
84 for(x
= 0; x
< 5; x
++) {
85 stage
[15][x
+3].type
= "input";
86 stage
[15][x
+3].value
= 0;
87 stage
[15][x
+3].name
= x
;
91 for(y
= "A", x
= 0; x
< 5; x
++, y
= String
.fromCharCode(y
.charCodeAt() + 1)) {
92 stage
[0][x
+3].type
= "output";
93 stage
[0][x
+3].value
= 0;
94 stage
[0][x
+3].name
= y
;
97 /* reset all command buttons */
98 item_selected
= "gate_and";
99 document
.getElementById("gate_and").disabled
= true;
100 document
.getElementById("gate_nand").disabled
= false;
101 document
.getElementById("gate_nor").disabled
= false;
102 document
.getElementById("gate_not").disabled
= false;
103 document
.getElementById("gate_or").disabled
= false;
104 document
.getElementById("gate_xor").disabled
= false;
105 document
.getElementById("delete").disabled
= false;
109 move through each grid in stage and draw contents.
110 this function can be used to refresh the screen at any time.
112 function draw_stage()
115 /* loop through all grids on stage, drawing contents */
116 for(x
=0; x
< stage_cols
; x
++) {
117 for(y
= 0; y
< stage_rows
; y
++) {
118 switch(stage
[x
][y
].type
) {
135 /* draw lines (wires) connecting gates */
142 /* intial setup of page - must be called on page load */
146 /* initalize canvas element for use */
147 canvas
= document
.getElementById("stage");
148 ctx
= canvas
.getContext("2d");
149 /* get width and height of window and set stage (canvas) with it. */
150 canvas
.height
= window
.innerHeight
-125;
151 canvas
.width
= window
.innerWidth
- 45;
152 if(grid_status
) {draw_grid(); }
157 function draw_clock(x
,y
,phase
)
159 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
160 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
161 if(phase
> 1 || phase
< 0) { alert("Clock phase not sent"); return ; }
162 x
= (x
*grid_size
) + (grid_size
/2); /* offset
from conrner
of grid */
163 y
= (y
*grid_size
) + (grid_size
/2);
164 ctx
.strokeStyle
= "#f33";
168 ctx
.arc(x
,y
,15, deg_to_rad(360), deg_to_rad(0), false);
170 ctx
.font
= "10pt Arial";
171 ctx
.textAlign
= "center";
172 ctx
.textBaseline
= "middle";
173 ctx
.fillText("CLK", x
, y
);
174 /* draw line over text */
176 ctx
.strokeStyle
= "#000";
185 /* inputs have are represented by a character with a parameter v */
186 function draw_input(x
,y
)
188 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
189 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
190 var s
= stage
[x
][y
].value
;
191 var name
= stage
[x
][y
].name
;
192 x
= (x
*grid_size
) + (grid_size
/2); /* offset
from corner
of grid */
193 y
= (y
*grid_size
) + (grid_size
/2);
194 if(s
) { ctx
.strokeStyle
= color_on_hlt
} else { ctx
.strokeStyle
= color_off
; }
195 if(s
) { ctx
.fillStyle
= color_on
} else { ctx
.fillStyle
= color_off_hlt
; }
198 /* draw background circle */
200 ctx
.arc(x
,y
,15, deg_to_rad(360), deg_to_rad(0), false);
204 ctx
.arc(x
,y
,15, deg_to_rad(360), deg_to_rad(0), false);
207 if(s
) { ctx
.fillStyle
= color_on_hlt
} else { ctx
.fillStyle
= color_off
; }
208 /* draw character on top */
209 ctx
.font
= "15pt Arial";
210 ctx
.textAlign
= "center";
211 ctx
.textBaseline
= "middle";
212 ctx
.fillText(name
, x
, y
);
215 /* simple version with auto lookup to data structure */
216 function draw_input_simple(v
)
219 if(v
== 'undefined') { alert("Cannot modify unknown output"); }
220 // TODO: Make this work with lib function instead...
247 draw_input(input
[v
].xpos
, input
[v
].ypos
, x
, input
[v
].val
);
250 /* draw output button.
252 x = grid position on x axis.
253 y = grid position on y axis.
255 function draw_output(x
,y
)
257 var w
= 30; /* width of box */
258 var tx
= x
; var ty
= y
;
259 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
260 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
261 var s
= stage
[x
][y
].value
;
262 var name
= stage
[x
][y
].name
;
263 tx
= x
* grid_size
+ (grid_size
/ 2);
264 ty
= y
* grid_size
+ (grid_size
/ 2);
267 x
= (x
* grid_size
) + (grid_size
/ 5); /* offset from corner of grid */
268 y
= (y
* grid_size
) + (grid_size
/ 5);
270 /* draw filled box around char */
271 if(s
) { ctx
.fillStyle
= color_on
} else { ctx
.fillStyle
= color_off_hlt
; }
282 /* draw outline box around char */
283 if(s
) { ctx
.strokeStyle
= color_on_hlt
} else { ctx
.strokeStyle
= color_off
; }
294 /* draw char inside box */
295 if(s
) { ctx
.fillStyle
= color_on_hlt
; } else { ctx
.fillStyle
= color_off
; }
296 ctx
.font
= "15pt Arial";
297 ctx
.textAlign
= "center";
298 ctx
.textBaseline
= "middle";
299 ctx
.fillText(name
, tx
, ty
);
302 /* simple version with auto lookup to data structure */
303 function draw_output_simple(v
)
305 if(v
== 'undefined') { alert("Cannot modify unknown output"); }
306 draw_output(out
[v
].xpos
, out
[v
].ypos
, v
, out
[v
].val
);
309 /* draw faint gridlines on stage - used as a guide for the user */
312 var x
, y
; /* current x and y position */
313 var offset
= 10; /* x and y maximum offset (far bottom or side of the window) */
314 ctx
.strokeStyle
= "#ccc";
316 /* draw vertical lines */
317 for(x
= grid_size
, y
= 0, offset
= window
.innerWidth
; x
< window
.innerWidth
; x
= x
+ grid_size
)
321 ctx
.lineTo(x
,y
+offset
);
325 /* draw horizontal lines */
326 for(x
= 0, y
= grid_size
, offset
= window
.innerWidth
; y
< window
.innerWidth
; y
= y
+ grid_size
)
330 ctx
.lineTo(x
+offset
,y
);
336 function draw_and_gate(x
,y
)
338 var h
= 50; /* height of square of gate */
339 var w
= 30; /* width of square area of gate */
340 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
341 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
342 ctx
.strokeStyle
= "#11f";
344 x
= 10 + (grid_size
*x
); /* offset from conrner of grid */
345 y
= 10 + (grid_size
*y
);
349 ctx
.arc( x
+w
, y
+(h
/2), (h/2), deg_to_rad(-90), deg_to_rad(90), false);
350 ctx
.lineTo(x
+w
, y
+h
);
356 function draw_nand_gate(x
,y
)
358 var h
= 50; /* height of square of gate */
359 var w
= 30; /* width of square area of gate */
360 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
361 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
362 ctx
.strokeStyle
= "#11f";
364 x
= 10 + (grid_size
*x
); /* offset from conrner of grid */
365 y
= 10 + (grid_size
*y
);
369 ctx
.arc( x
+w
, y
+(h
/2), (h/2), deg_to_rad(-90), deg_to_rad(90), false);
370 ctx
.lineTo(x
+w
, y
+h
);
376 ctx
.arc( x
+(w
*2), y
+(h
/2),5, deg_to_rad(0), deg_to_rad(360), false);
380 function draw_not_gate(x
,y
)
382 var h
= 50; /* height of square of gate */
383 var w
= 40; /* width of square area of gate */
384 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
385 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
386 ctx
.strokeStyle
= "#11f";
388 ctx
.lineJoin
= 'bevel';
389 x
= 10 + (grid_size
*x
); /* offset from conrner of grid */
390 y
= 10 + (grid_size
*y
);
395 ctx
.lineTo(x
+w
,y
+(h
/2));
402 ctx
.arc( x
+w
+6, y
+(h
/2),5, deg_to_rad(0), deg_to_rad(360), false);
406 function draw_or_gate(x
,y
)
408 var h
= 50; /* height of square of gate */
409 var w
= 21; /* width of square area of gate */
410 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
411 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
412 ctx
.strokeStyle
= "#11f";
414 ctx
.lineJoin
= 'bevel';
415 x
= 10 + (grid_size
*x
); /* offset from conrner of grid */
416 y
= 10 + (grid_size
*y
);
417 /* back curve - inputs */
419 ctx
.arc(x
-(2*w
), y
+(h
/2), h
, deg_to_rad(-30), deg_to_rad(30), false);
428 ctx
.arc(x
+w
, y
+h
, h
, deg_to_rad(-90), deg_to_rad(-30), false);
437 ctx
.arc(x
+w
, y
, h
, deg_to_rad(30), deg_to_rad(90), false);
441 function draw_nor_gate(x
,y
)
443 var h
= 50; /* height of square of gate */
444 var w
= 21; /* width of square area of gate */
445 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
446 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
447 ctx
.strokeStyle
= "#11f";
449 ctx
.lineJoin
= 'bevel';
450 x
= 10 + (grid_size
*x
); /* offset from conrner of grid */
451 y
= 10 + (grid_size
*y
);
452 /* back curve - inputs */
454 ctx
.arc(x
-(2*w
), y
+(h
/2), h
, deg_to_rad(-30), deg_to_rad(30), false);
463 ctx
.arc(x
+w
, y
+h
, h
, deg_to_rad(-90), deg_to_rad(-30), false);
472 ctx
.arc(x
+w
, y
, h
, deg_to_rad(30), deg_to_rad(90), false);
476 ctx
.arc(x
+(w
*3)+6, y
+(h
/2),5, deg_to_rad(0), deg_to_rad(360), false);
480 function draw_xor_gate(x
,y
)
482 var h
= 50; /* height of square of gate */
483 var w
= 21; /* width of square area of gate */
484 if(x
== 'undefined' || y
== 'undefined') { alert("Coordinates Not Sent to Function"); return; }
485 if(x
< 0 || y
< 0) { alert("Coordinates Cannot Be Negative"); return ; }
486 ctx
.strokeStyle
= "#11f";
488 ctx
.lineJoin
= 'bevel';
489 x
= 10 + (grid_size
*x
); /* offset from conrner of grid */
490 y
= 10 + (grid_size
*y
);
491 /* back curve - inputs */
493 ctx
.arc(x
-(2*w
), y
+(h
/2), h
, deg_to_rad(-30), deg_to_rad(30), false);
495 /* extra back curve - inputs */
497 ctx
.arc(x
-(2*w
)-10, y
+(h
/2), h
, deg_to_rad(-30), deg_to_rad(30), false);
506 ctx
.arc(x
+w
, y
+h
, h
, deg_to_rad(-90), deg_to_rad(-30), false);
515 ctx
.arc(x
+w
, y
, h
, deg_to_rad(30), deg_to_rad(90), false);
519 /* user changes what type of gate will be drawn next */
520 function change_selection(sel
)
522 var button
= document
.getElementById(sel
);
523 if(!button
) { alert("Cannot Find Selected Button"); return; }
524 /* enable old button */
525 document
.getElementById(item_selected
).disabled
= false;
526 //alert("enabling " + item_selected);
527 /* disable new button */
528 button
.disabled
= true;
533 /* returns coordinates of canvas in pixels */
534 function cnvs_get_coordinates(e
)
536 var x_offset
= canvas
.offsetLeft
;
537 var y_offset
= canvas
.offsetTop
;
538 if(canvas
== 'undefined') { alert("Canvas parameter is undefined"); }
539 x_offset
= e
.clientX
- x_offset
;
540 y_offset
= e
.clientY
- y_offset
;
541 document
.getElementById("xycoordinates").innerHTML
="Coordinates: (" + x_offset
+ "," + y_offset
+ ")";
542 return [x_offset
,y_offset
];
545 /* canvas has been clicked find out which grid and make correct change to square if needed. */
546 function cnvs_clicked(e
)
548 var coords
= cnvs_get_coordinates(e
);
549 var x_pos
= Math
.floor(coords
[0] / grid_size
);
550 var y_pos
= Math
.floor(coords
[1] / grid_size
);
551 // if delete command, remove contents of grid
552 if(item_selected
== "delete") {
553 // cannot allow inputs and outputs to be deleted
554 if(stage
[x_pos
][y_pos
].type
== "input" || stage
[x_pos
][y_pos
].type
== "output") { return; }
555 stage
[x_pos
][y_pos
].type
= "";
559 // if an input or output, flip value
561 // ...otherwise perform whatever the current selected function is
562 if(stage
[x_pos
][y_pos
].type
!= "") { return; } // check for presence of an item
563 switch(item_selected
) {
565 stage
[x_pos
][y_pos
].type
= "and";
566 draw_and_gate(x_pos
,y_pos
);
569 stage
[x_pos
][y_pos
].type
= "nand";
570 draw_nand_gate(x_pos
,y_pos
);
573 stage
[x_pos
][y_pos
].type
= "nor";
574 draw_nor_gate(x_pos
,y_pos
);
577 stage
[x_pos
][y_pos
].type
= "not";
578 draw_not_gate(x_pos
,y_pos
);
581 stage
[x_pos
][y_pos
].type
= "or";
582 draw_or_gate(x_pos
,y_pos
);
585 stage
[x_pos
][y_pos
].type
= "xor";
586 draw_xor_gate(x_pos
,y_pos
);
593 <style type=
"text/css">
596 border: solid
1px #000;
600 <body onLoad=
"init_form();">
602 <center><h2>Digital Logic Simulator
</h2></center>
604 <button type=
"button" id=
"gate_and" onClick='change_selection(
"gate_and");'
disabled=
"disabled">AND
</button>
606 <button type=
"button" id=
"gate_nand" onClick='change_selection(
"gate_nand");'
>NAND
</button>
608 <button type=
"button" id=
"gate_nor" onClick='change_selection(
"gate_nor");'
>NOR
</button>
610 <button type=
"button" id=
"gate_not" onClick='change_selection(
"gate_not");'
>NOT
</button>
612 <button type=
"button" id=
"gate_or" onClick='change_selection(
"gate_or");'
>OR
</button>
614 <button type=
"button" id=
"gate_xor" onClick='change_selection(
"gate_xor");'
>XOR
</button>
616 <button type=
"button" id=
"delete" onClick='change_selection(
"delete");'
>Delete
</button>
618 <button type=
"button" id=
"gate_connect" onClick='change_selection(
"gate_connect");'
>Connect
</button>
621 <div id=xycoordinates
> </div>
623 <canvas id=
"stage" width=
"200" height=
"200" onMouseMove=
"cnvs_get_coordinates(event)" onClick=
"cnvs_clicked(event);">
624 Your browser does not support HTML5 Canvas.