hdl 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  A parser and emulator for a minimalist [hardware description language](http://en.wikipedia.org/wiki/Hardware_description_language).
4
4
 
5
+ HDL is a playground for building your own logic gates and interconnecting them. It's a good place to start if you're learning about boolean expressions and electronics. With a little patience, you could build some seriously powerful chips, from a ripple-carry adder, to a fully-blown arithmetic logic unit.
6
+
7
+ The first step is to define a 'primitive'. This is a gate that acts as a truth table. On top of this you can build increasingly more complex chips. 'nand' and 'nor' are good choices because they are [universal logic gates](https://en.wikipedia.org/wiki/Logic_gate#Universal_logic_gates).
8
+
9
+ Let's say you start by building a truth table for 'nand'. You could then derive logic gates for 'and' and 'or', and then an 'xor'. Now that you've padded out your toolset a bit, you could attempt to build a 'half_adder', then perhaps a 'full_adder'. You'd then have everything you need to build a 'ripple_carry_adder'.
10
+
5
11
  ## Chips
6
12
 
7
13
  Here's an example definition of a chip called 'and.hdl':
@@ -19,6 +25,24 @@ The equivalent circuit diagram is:
19
25
 
20
26
  !['and' gate from 'nand'](http://upload.wikimedia.org/wikipedia/commons/1/16/AND_from_NAND.svg)
21
27
 
28
+ We declare that this chip has two inputs, namely 'a' and 'b' and a single output called 'out'.
29
+
30
+ The chip is comprised of two 'nand' gates. Each assignment is a connection between the pins on this chip, to the pins on another chip. Let's take the first 'nand', for example:
31
+
32
+ ```ruby
33
+ nand(a=a, b=b, out=x)
34
+ ```
35
+
36
+ Here's how you might write this in English:
37
+
38
+ * Connect the 'a' input of 'nand' to the 'a' input of this chip
39
+ * Connect the 'b' input of 'nand' to the 'b' input of this chip
40
+ * Connect the 'out' output of 'nand' to the intermediate pin 'x'
41
+
42
+ The pins on the left of each assignment are for the 'foreign' chip. The pins on the right are for this chip.
43
+
44
+ We're declaring an intermediate pin 'x' on the fly here. Intermediate pins allow you to interconnect things within your chip. In this case, 'x' is used for the second 'nand' expression.
45
+
22
46
  ## Tables
23
47
 
24
48
  The above chip references another chip called 'nand'.
@@ -39,6 +63,12 @@ outputs out
39
63
 
40
64
  If you'd prefer, you can use 'T' and 'F'.
41
65
 
66
+ If you've ever worked with truth tables before, this should be straightforward. All we're doing here is listing what the output value should be for every possible set of inputs.
67
+
68
+ In theory, you could write a truth table for any chip. However, it's much better to derive a chip from others. You should really focus on minimizing the number of primitive chips you depend on.
69
+
70
+ If you get stuck trying to figure out how to derive your chip, you could always write it as a truth table and come back to it. You'd simply swap the truth table out with a schema definition once you've figured it out.
71
+
42
72
  ## Ruby
43
73
 
44
74
  Now that we've satisfied the 'nand' dependency, we can write some Ruby:
@@ -53,6 +83,10 @@ chip.evaluate(a: true, b: false)
53
83
 
54
84
  The 'nand' chip is automatically loaded when it is referenced.
55
85
 
86
+ When we call 'evaluate', we're actually emulating the hardware of the chips. The 'and' chip will wire the given inputs into each 'nand', and ask them to evaluate.
87
+
88
+ The second 'nand' will actually have to wait on the first because it depends on that intermediate pin 'x'. Once it's had its turn, it wires its output to the output of 'and' and we get our return value.
89
+
56
90
  ## Path
57
91
 
58
92
  By default, chips in the current directory will be discovered.
@@ -63,6 +97,8 @@ You can expand this search by adding to your path:
63
97
  HDL.path << "chips"
64
98
  ```
65
99
 
100
+ This might be useful to group similar chips together, or to keep a hierarchy of dependencies in subdirectories.
101
+
66
102
  ## Parsing
67
103
 
68
104
  If you'd rather parse your chips directly in Ruby, you can do so with:
@@ -73,7 +109,7 @@ chip = HDL.parse(name, definition)
73
109
 
74
110
  This might be useful if you're storing definitions in a database.
75
111
 
76
- ## Miscellaneous
112
+ ## Query methods
77
113
 
78
114
  Here are some useful methods for querying properties of chips:
79
115
 
@@ -113,9 +149,10 @@ chip.dependees # Chips that use this chip.
113
149
 
114
150
  I'm not an electronics engineer. If you are, you could probably build in all kinds of cool features and optimisations.
115
151
 
116
- Here a few features that might be in the pipeline:
152
+ Here are a few features that might be in the pipeline:
117
153
 
118
- * Let me build a CNF expression for a chip
154
+ * A bespoke test framework that uses tabular test files
155
+ * Support for generating conjunctive normal form expressions
119
156
  * Query method for circuit fan-outs for chips
120
157
  * Evaluate and return outputs with internal pins
121
158
  * Support for buses, mostly for convenience
data/lib/hdl/base.rb CHANGED
@@ -2,7 +2,7 @@ module HDL
2
2
  class << self
3
3
 
4
4
  def version
5
- "1.0.1"
5
+ "1.0.2"
6
6
  end
7
7
 
8
8
  def path
@@ -30,8 +30,10 @@ class HDL::SchemaChip < HDL::Chip
30
30
  end
31
31
 
32
32
  def evaluate(pins = {})
33
- check_pins!(pins)
34
- evaluator.evaluate(pins)
33
+ memoize(pins) do
34
+ check_pins!(pins)
35
+ evaluator.evaluate(pins)
36
+ end
35
37
  end
36
38
 
37
39
  private
@@ -18,10 +18,11 @@ class HDL::TableChip < HDL::Chip
18
18
  end
19
19
 
20
20
  def evaluate(pins = {})
21
- check_pins!(pins)
22
-
23
- row = find_row(pins)
24
- select_outputs(row)
21
+ memoize(pins) do
22
+ check_pins!(pins)
23
+ row = find_row(pins)
24
+ select_outputs(row)
25
+ end
25
26
  end
26
27
 
27
28
  private
data/lib/hdl/chip.rb CHANGED
@@ -38,4 +38,9 @@ class HDL::Chip
38
38
  end
39
39
  end
40
40
 
41
+ def memoize(pins, &block)
42
+ @memo ||= {}
43
+ @memo[pins] ||= yield
44
+ end
45
+
41
46
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hdl
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 1
10
- version: 1.0.1
9
+ - 2
10
+ version: 1.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Chris Patuzzo
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-06-02 00:00:00 +01:00
18
+ date: 2013-06-22 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency