Assembling the Machine (v2)

Read time: 10 minutes (2549 words)

The scheme I showed in our earlier labs will ultimately be used to build the simulator, perhaps modified so the HDL language used is more like Verilog. However, completing the current scheme for the machine proved difficult enough to lead me to look for other ideas.

Enter JSON

JSON is a popular encoding scheme for data these days. Those familiar with Python will find the notation very similar to Python dictionaries.

JSON is commonly used to transfer data over web interfaces between serves working on a single application. Multiple Docker containers can pass data back and forth easily using this data type, even if the containers are working with different languages.

JSON is basically a text file format. There are many libraries available to deal with JSON data, and I found one for C++ code on GitHub:

This package provides a single C++ header file that provides the code needed to access JSON data or create it.

For our machine building, all we need to be able to do is read a JSON data file, and parse the required data to use in building the machine. We can easily set up the data file using a test editor.

Warning

JSON is very picky about using double quotes for strings, and using commas properly. The file will fail to read for simple mistakes.

JSON Driven CPU Diagrams

I have been working on a Python application to generate the CPU system diagrams for this course:

Note

GitHub makes it easy to publish a website based on HTML files in a “docs” folder in your project. See me if you want to try this for a group project, or look tat this project to see how it was set up. The GitHub “settings” page for your repository has the controls needed to activate this.

This project has example data files we can use to test out this idea,

Here is a sample data file:

example.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[
    {
        "part": "REG2",
        "label": "pc",
        "x": "4",
        "y": "0",
        "scale": "1",
        "color": "green"
    },
    {
        "part": "MUX2",
        "label": "mux1",
        "x": "2",
        "y": "1",
        "scale": "1",
        "color": "green"
    },
    {
        "part": "WIRE",
        "source": "alu.pin3",
        "drives": "mux1.pin1"
    }
]

Testing JSON Reading

In the finest tradition of testing new ideas, I set up a simple program to see if I could read an example data file I use in the diagram project.

The single C++ header file needed to run this example program can be downloaded here:

Simply drop this file in your project include directory.

Here is the (somewhat long) test code I came up with:

test_json.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <fstream>
#include <string>

#include "json.hpp"
using json = nlohmann::json;

float get_float(json data, std::string val) {
    json k;
    std::string k_str;
    auto k_val = data.find(val);
    if(k_val != data.end()) {
        k_str = *k_val;
        return std::strtof((k_str).c_str(),0);
    }
    return -999.0;
}

std::string get_string(json data, std::string val) {
    json k;
    std::string k_str;
    auto k_val = data.find(val);
    if(k_val != data.end())
        k_str = *k_val;
    else k_str = "NONE";
    return k_str;
}

int main(void) {
    std::cout << "JSON Reader" << std::endl;
    json j;
    std::ifstream fin("example.json");
    fin >> j;
    fin.close();

    // show looping over entries
    json k, k_part;
    std::string part;
    for(json::iterator it = j.begin(); it != j.end(); it++) {
        std::cout << *it << std::endl;
        k = *it;
        auto k_part = k.find("part");
        if(k_part != k.end()) {
            part = *k_part;
            std::cout << "part:" << part << std::endl;
        } else
           std::cout<< "part not found" << std::endl;
    }

    // display part count
    std::cout << "Part count: " << j.size() << std::endl;

    // display pretty output
    std::ofstream fout("pretty.json");
    fout << std::setw(4) << j << std::endl;

    // display [art placement
    for(json::iterator it = j.begin(); it != j.end(); it++) {
        std::string part = get_string(*it, "part");
        std::cout
            << "part: "
            << part;
        if(part != "WIRE") {
            float x = get_float(*it, "x");
            float y = get_float(*it, "y");
            std::cout
                << " x="
                << x
                << " y="
                << y
                << std::endl;
        } else {
            std::string drives = get_string(*it, "drives");
            std::string source = get_string(*it, "source");
            std::cout
                << " source="
                << source
                << " drives="
                << drives
                << std::endl;
        }

    }

}

Note

This must be compiled as a C++11 project. The Makefile handles that.

Here is the Makefile I used for this test:

Makefile
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CFLAGS 	:= -std=c++11 -Iinclude
CSRCS	:= $(wildcard *.cpp)
COBJS	:= $(CSRCS:.cpp=.o)

TARGET	:= json-reader

# build targets follow —————————-
.PHONY: all
all:	$(TARGET) ## build application

$(TARGET):	$(COBJS)
	g++ -o $@ $^

%.o:	%.cpp
	g++ -c $(CFLAGS) -o $@ $<

.PHONY: run ## run application
run:	$(TARGET)
	./$(TARGET)

.PHONY: clean	## clean all build artifacts
clean:
	rm -f $(TARGET) *.o

Here is an example of running the test code:

$ make clean
rm -f json-reader *.o
$ make
g++ -c -std=c++11 -Iinclude -o test_json.o test_json.cpp
g++ -o json-reader test_json.o
$ make run
./json-reader
JSON Reader
{"color":"green","label":"pc","part":"REG2","scale":"1","x":"4","y":"0"}
part:REG2
{"color":"green","label":"mux1","part":"MUX2","scale":"1","x":"2","y":"1"}
part:MUX2
{"drives":"mux1.pin1","part":"WIRE","source":"alu.pin3"}
part:WIRE
Part count: 3
part: REG2 x=4 y=0
part: MUX2 x=2 y=1
part: WIRE source=alu.pin3 drives=mux1.pin1

This is enough to build our machine from a JSON data file.

Creating the Machine

With this test code, we can assemble the machine using code we have already developed. The only thing we need to do it pull out the current code that parses the HDL file we used, and replace it with code that reads the same data from the JSON file.