e76643408cccd23f7fb744bb9228377d7bd08129
[ScratchNES.git] / src / CPU / build-cpu.js
1 /* build-cpu.js
2 * this is the heart of the metaprogram
3 * at the entrypoint, the instruction set is complete and annotated,
4 * and the reference document is available.
5 * We can just sit back, relax, and put together parts :-)
6 */
7
8 var fs = require("fs");
9
10 // avoid excessive disk use
11 var instruction_cache = {};
12 var addressing_cache = {};
13
14 // read the table in
15 var table = JSON.parse(fs.readFileSync("bin/table.json").toString());
16
17 // jump table emission, etc.
18 var emission = [
19 "mapper read PC",
20 "set opcode to M"
21 ];
22
23 table = table.slice(0, 16);
24
25 var sources = table.map(function(x, i) {
26 if(x) {
27 var instruction = [];
28
29 // add stub for addressing mode
30 // load if not already in-memory
31
32 if(!addressing_cache[x.addressing]) {
33 addressing_cache[x.addressing] =
34 fs.readFileSync("addressing/" + x.addressing)
35 .toString().trim().split("\n");
36
37 if(addressing_cache[x.addressing][0].trim().length == 0)
38 addressing_cache[x.addressing] = [];
39 }
40
41 instruction = instruction.concat(addressing_cache[x.addressing]);
42
43 // add stub for instruction
44 if(!instruction_cache[x.name]) {
45 instruction_cache[x.name] =
46 fs.readFileSync("instructions/" + x.name)
47 .toString().trim().split("\n");
48 }
49
50 // follow the flags
51 var flags = instruction_cache[x.name][0].replace(/ /g, '').split(',');
52 var negQ = false, zeroQ = false, mode = null, operand = null;
53
54 flags.forEach(function(flag) {
55 if(flag == "N") negQ = true;
56 else if(flag == "Z") zeroQ = true;
57 else if(["R", "RW", "IMPLIED", "RAW", "BRANCH"].indexOf(flag) > -1)
58 mode = flag;
59 else if (["A", "X", "Y", "tmp"].indexOf(flag) > -1)
60 operand = flag;
61 else
62 console.error("Unknown flag " + flag + " for instruction " + x.name);
63 });
64
65 var ins = instruction_cache[x.name].slice(1);
66
67 if(mode == "R") {
68 instruction.push("mapper read address");
69 instruction.push("set OP to M");
70 } else if(mode == "RW") {
71 if(x.addressing == "accumulator") {
72 ins = ins.map(function(q) {
73 return q.replace(/OP/g, "A");
74 });
75 } else {
76 instruction.push("mapper read address");
77 instruction.push("set OP to M");
78 }
79
80 ins = ins.map(function(q) {
81 if(x.addressing != "accumulator") {
82 return q.replace(/set OP to/, "mapper write address");
83 } else {
84 return q;
85 }
86 });
87 } else if(mode == "IMPLIED") {
88
89 } else {
90 console.error("Unsupported mode " + mode);
91 }
92
93 // add the actual code of the instruction
94 instruction = instruction.concat(ins);
95
96 instruction = instruction.concat([
97 'say "' + x.assembler + '" for 2 secs',
98 'change PC by ' + x.size
99 ]);
100
101 return instruction.join("\n");
102 } else {
103 return [
104 'say "Illegal Opcode ' + i + ' used, ignoring." for 2 secs',
105 'change PC by 1'
106 ].join("\n");
107 }
108 });
109
110 // dump out an 8 level deep BST
111 console.log(bst(sources, 0, 15).join('\n'));
112
113 function bst(sources, start, end) {
114 if(start == end)
115 return [sources[start]];
116
117 if(start + 1 == end)
118 return [
119 "if opcode = " + start + " then",
120 sources[start],
121 "else",
122 sources[end],
123 "end"
124 ];
125
126 var emission = ["if opcode < " + (start+end+1)/2 + " then"]
127 .concat(bst(sources, start, start + (end-start-1) / 2))
128 .concat(["else"])
129 .concat(bst(sources, start + (end-start+1) / 2, end))
130 .concat(["end"]);
131
132 return emission;
133 }
This page took 0.083301 seconds and 3 git commands to generate.