1 |
12 |
alfik |
/*
|
2 |
|
|
* Copyright 2010, Aleksander Osman, alfik@poczta.fm. All rights reserved.
|
3 |
|
|
*
|
4 |
|
|
* Redistribution and use in source and binary forms, with or without modification, are
|
5 |
|
|
* permitted provided that the following conditions are met:
|
6 |
|
|
*
|
7 |
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
8 |
|
|
* conditions and the following disclaimer.
|
9 |
|
|
*
|
10 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
11 |
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
12 |
|
|
* provided with the distribution.
|
13 |
|
|
*
|
14 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
15 |
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
16 |
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
17 |
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
18 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
19 |
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
20 |
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
21 |
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
22 |
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23 |
|
|
*/
|
24 |
|
|
|
25 |
|
|
package ao68000_tool;
|
26 |
|
|
|
27 |
|
|
import java.io.OutputStream;
|
28 |
|
|
import java.io.FileInputStream;
|
29 |
|
|
import java.io.FileOutputStream;
|
30 |
|
|
import java.io.File;
|
31 |
|
|
import java.util.Vector;
|
32 |
|
|
import java.util.HashMap;
|
33 |
|
|
import java.util.HashSet;
|
34 |
|
|
|
35 |
|
|
class GenerateMicrocode {
|
36 |
|
|
static void entry(boolean newline, String name) throws Exception {
|
37 |
|
|
/*
|
38 |
|
|
* if newline is true: end of last line
|
39 |
|
|
* if name is "offset_" + label: branch label
|
40 |
|
|
* if name is "label_" + label: label declaration
|
41 |
|
|
*/
|
42 |
|
|
|
43 |
|
|
if(ParseParams.prefixes == null || labels == null || lines == null) throw new Exception("Entry validator not initialized.");
|
44 |
|
|
|
45 |
|
|
// save last line
|
46 |
|
|
if(newline == true && current_line != null && current_line.size() > 0) lines.add(current_line);
|
47 |
|
|
// prepare a new line
|
48 |
|
|
if(newline == true) current_line = new HashMap<String,String>();
|
49 |
|
|
|
50 |
|
|
// save label location
|
51 |
|
|
if(name.startsWith("label_")) {
|
52 |
|
|
String label = name.substring(6);
|
53 |
|
|
if(labels.containsKey(label)) throw new Exception("Double label declaration: " + label);
|
54 |
|
|
labels.put(label, lines.size());
|
55 |
|
|
return;
|
56 |
|
|
}
|
57 |
|
|
|
58 |
|
|
// get prefix
|
59 |
|
|
String prefix = "PROCEDURE_";
|
60 |
|
|
if(name.startsWith("offset_")) {
|
61 |
|
|
String label = name.substring(7);
|
62 |
|
|
name = "label_" + label;
|
63 |
|
|
}
|
64 |
|
|
else {
|
65 |
|
|
prefix = null;
|
66 |
|
|
for(String p : ParseParams.prefixes) {
|
67 |
|
|
if(name.startsWith(p)) {
|
68 |
|
|
prefix = p;
|
69 |
|
|
break;
|
70 |
|
|
}
|
71 |
|
|
}
|
72 |
|
|
}
|
73 |
|
|
|
74 |
|
|
if(prefix == null) throw new Exception("Unknown prefix for name: " + name);
|
75 |
|
|
|
76 |
|
|
// check for double prefix
|
77 |
|
|
if(current_line.containsKey(prefix)) throw new Exception("Double prefix call: " + prefix);
|
78 |
|
|
|
79 |
|
|
// extend current line
|
80 |
|
|
current_line.put(prefix, name);
|
81 |
|
|
}
|
82 |
|
|
|
83 |
|
|
static void fill_bit_part(int array[], int start, int end, int value) throws Exception {
|
84 |
|
|
while(start <= end) {
|
85 |
|
|
int bit = value & 0x1;
|
86 |
|
|
|
87 |
|
|
array[start] = bit;
|
88 |
|
|
|
89 |
|
|
value >>= 1;
|
90 |
|
|
start++;
|
91 |
|
|
}
|
92 |
|
|
}
|
93 |
|
|
static void final_process(OutputStream out) throws Exception {
|
94 |
|
|
if(ParseParams.prefixes == null || labels == null || lines == null) throw new Exception("Final validator not initialized.");
|
95 |
|
|
// add last line
|
96 |
|
|
if(current_line != null && current_line.size() > 0) lines.add(current_line);
|
97 |
|
|
|
98 |
|
|
|
99 |
|
|
int i=0;
|
100 |
|
|
// resolve labels
|
101 |
|
|
for(HashMap<String,String> line : lines) {
|
102 |
|
|
if(line.containsKey("PROCEDURE_")) {
|
103 |
|
|
String value = line.get("PROCEDURE_");
|
104 |
|
|
|
105 |
|
|
if(value.startsWith("label_")) {
|
106 |
|
|
String label = value.substring(6);
|
107 |
|
|
|
108 |
|
|
if(labels.containsKey(label) == false) throw new Exception("Unresolved label: " + label);
|
109 |
|
|
int label_value = labels.get(label);
|
110 |
|
|
|
111 |
|
|
int delta = label_value - i;
|
112 |
|
|
|
113 |
|
|
if(delta < 0 || delta > 15) throw new Exception("Label: " + label + " out of bounds: " + delta);
|
114 |
|
|
line.put("PROCEDURE_", "value_" + delta);
|
115 |
|
|
}
|
116 |
|
|
}
|
117 |
|
|
i++;
|
118 |
|
|
}
|
119 |
|
|
|
120 |
|
|
// prepare output header
|
121 |
|
|
int depth = 1;
|
122 |
|
|
while(depth < lines.size()) depth *= 2;
|
123 |
|
|
|
124 |
|
|
out.write(new String("DEPTH = " + depth + ";\n").getBytes());
|
125 |
|
|
out.write(new String("WIDTH = " + bit_line.length + ";\n").getBytes());
|
126 |
|
|
out.write(new String("ADDRESS_RADIX = DEC;\n").getBytes());
|
127 |
|
|
out.write(new String("DATA_RADIX = BIN;\n").getBytes());
|
128 |
|
|
out.write(new String("CONTENT\n").getBytes());
|
129 |
|
|
out.write(new String("BEGIN\n").getBytes());
|
130 |
|
|
|
131 |
|
|
i=0;
|
132 |
|
|
HashSet<String> set = new HashSet<String>();
|
133 |
|
|
Vector<String> bit_lines = new Vector<String>();
|
134 |
|
|
// prepare final bit array
|
135 |
|
|
for(HashMap<String,String> line : lines) {
|
136 |
|
|
for(int j=0; j<bit_line.length; j++) bit_line[j] = 0;
|
137 |
|
|
|
138 |
|
|
for(String prefix : ParseParams.prefixes) {
|
139 |
|
|
if(line.containsKey(prefix)) {
|
140 |
|
|
String string_value = line.get(prefix);
|
141 |
|
|
|
142 |
|
|
int value = 0;
|
143 |
|
|
if(string_value.startsWith("value_")) {
|
144 |
|
|
value = Integer.parseInt(string_value.substring(6));
|
145 |
|
|
}
|
146 |
|
|
else {
|
147 |
|
|
if(ParseParams.name_values.containsKey(string_value) == false) throw new Exception("Unknown value: " + string_value);
|
148 |
|
|
value = ParseParams.name_values.get(string_value);
|
149 |
|
|
}
|
150 |
|
|
int start = ParseParams.prefix_locations.get(prefix + "start");
|
151 |
|
|
int end = ParseParams.prefix_locations.get(prefix + "end");
|
152 |
|
|
|
153 |
|
|
fill_bit_part(bit_line, start, end, value);
|
154 |
|
|
}
|
155 |
|
|
}
|
156 |
|
|
|
157 |
|
|
// prepare output
|
158 |
|
|
String addr = "" + i + ": ";
|
159 |
|
|
while(addr.length() < 8) addr = " " + addr;
|
160 |
|
|
out.write(new String(addr).getBytes());
|
161 |
|
|
|
162 |
|
|
String bits = "";
|
163 |
|
|
for(int j=bit_line.length-1; j>=0; j--) {
|
164 |
|
|
bits += bit_line[j];
|
165 |
|
|
}
|
166 |
|
|
set.add(bits);
|
167 |
|
|
bit_lines.add(bits);
|
168 |
|
|
out.write(new String(bits + ";\n").getBytes());
|
169 |
|
|
|
170 |
|
|
i++;
|
171 |
|
|
}
|
172 |
|
|
out.write(new String("END;\n").getBytes());
|
173 |
|
|
|
174 |
|
|
|
175 |
|
|
// prepare a compact microcode with a microcode decoder
|
176 |
|
|
// microcode reduced to 500x8 bits = 4000 bits, but microcode decoder takes about 1000 LE
|
177 |
|
|
// so currently unused
|
178 |
|
|
/*
|
179 |
|
|
i = set.size();
|
180 |
|
|
int bit_size = 0;
|
181 |
|
|
while(i > 0) {
|
182 |
|
|
bit_size++;
|
183 |
|
|
i /= 2;
|
184 |
|
|
}
|
185 |
|
|
System.out.println("Set size: " + set.size() + ", bit size: " + bit_size + ", bit_line.length: " + bit_line.length);
|
186 |
|
|
|
187 |
|
|
String empty_line = "";
|
188 |
|
|
i = 0;
|
189 |
|
|
while(i < bit_line.length) {
|
190 |
|
|
empty_line += "0";
|
191 |
|
|
i++;
|
192 |
|
|
}
|
193 |
|
|
|
194 |
|
|
|
195 |
|
|
String verilog = "assign micro_data =" + "\n";
|
196 |
|
|
|
197 |
|
|
verilog += "(encoded == " + bit_size + "'d" + 0 + ") ? " + bit_line.length + "'b" + empty_line + " :" + "\n";
|
198 |
|
|
HashMap<String, Integer> bit_line_numbers = new HashMap<String, Integer>();
|
199 |
|
|
i = 1;
|
200 |
|
|
for(String line : set) {
|
201 |
|
|
verilog += "(encoded == " + bit_size + "'d" + i + ") ? " + bit_line.length + "'b" + line + " :" + "\n";
|
202 |
|
|
|
203 |
|
|
bit_line_numbers.put(line, i);
|
204 |
|
|
i++;
|
205 |
|
|
}
|
206 |
|
|
verilog += bit_line.length + "'b" + empty_line + ";" + "\n";
|
207 |
|
|
|
208 |
|
|
i=0;
|
209 |
|
|
for(String line : bit_lines) {
|
210 |
|
|
String addr = "" + i + ": ";
|
211 |
|
|
while(addr.length() < 8) addr = " " + addr;
|
212 |
|
|
System.out.print(addr);
|
213 |
|
|
|
214 |
|
|
String content = "" + bit_line_numbers.get(line) + ";";
|
215 |
|
|
System.out.println(content);
|
216 |
|
|
|
217 |
|
|
i++;
|
218 |
|
|
}
|
219 |
|
|
System.out.println("Verilog:\n" + verilog);
|
220 |
|
|
*/
|
221 |
|
|
}
|
222 |
|
|
static String get_microcode_defines() throws Exception {
|
223 |
|
|
if(ParseParams.prefix_locations == null || ParseParams.prefixes == null) throw new Exception("No prefix_locations or prefixes set.");
|
224 |
|
|
|
225 |
|
|
String output = "";
|
226 |
|
|
|
227 |
|
|
for(String s : ParseParams.prefixes) {
|
228 |
|
|
int start = ParseParams.prefix_locations.get(s + "start");
|
229 |
|
|
int end = ParseParams.prefix_locations.get(s + "end");
|
230 |
|
|
|
231 |
|
|
String short_name = s.substring(0, s.length()-1);
|
232 |
|
|
short_name = short_name.toLowerCase();
|
233 |
|
|
|
234 |
|
|
String str = "`define MICRO_DATA_" + short_name;
|
235 |
|
|
while(str.length() < 85) str += " ";
|
236 |
|
|
output += str + "micro_data[" + end + ":" + start + "]\n";
|
237 |
|
|
}
|
238 |
|
|
output += "\n";
|
239 |
|
|
|
240 |
|
|
for(String label : labels.keySet()) {
|
241 |
|
|
if(label.startsWith("MICROPC_")) {
|
242 |
|
|
String str = "`define " + label;
|
243 |
|
|
while(str.length() < 85) str += " ";
|
244 |
|
|
output += str + "9'd" + labels.get(label) + "\n";
|
245 |
|
|
}
|
246 |
|
|
}
|
247 |
|
|
return output;
|
248 |
|
|
}
|
249 |
|
|
static void generate(OutputStream microcode_os, String file_name) throws Exception {
|
250 |
|
|
bit_line = new int[ParseParams.control_bit_offset];
|
251 |
|
|
lines = new Vector<HashMap<String,String>>();
|
252 |
|
|
labels = new HashMap<String,Integer>();
|
253 |
|
|
|
254 |
|
|
Microcode.microcode(new Parser());
|
255 |
|
|
|
256 |
|
|
final_process(microcode_os);
|
257 |
|
|
String locations = get_microcode_defines();
|
258 |
|
|
|
259 |
|
|
// load file
|
260 |
|
|
File file = new File(file_name);
|
261 |
|
|
byte bytes[] = new byte[(int)file.length()];
|
262 |
|
|
FileInputStream in = new FileInputStream(file);
|
263 |
|
|
if( in.read(bytes) != bytes.length ) throw new Exception("Can not read from file: " + file.getCanonicalPath());
|
264 |
|
|
in.close();
|
265 |
|
|
|
266 |
|
|
// find 'MICROCODE - DO NOT EDIT BELOW' and 'MICROCODE - DO NOT EDIT ABOVE' substrings
|
267 |
|
|
String all_string = new String(bytes);
|
268 |
|
|
int start_index = all_string.indexOf("MICROCODE - DO NOT EDIT BELOW");
|
269 |
|
|
if(start_index == -1) throw new Exception("Can not find 'MICROCODE - DO NOT EDIT BELOW' substring in " + file.getCanonicalPath());
|
270 |
|
|
start_index += new String("MICROCODE - DO NOT EDIT BELOW").length();
|
271 |
|
|
int end_index = all_string.indexOf("MICROCODE - DO NOT EDIT ABOVE");
|
272 |
|
|
if(end_index == -1) throw new Exception("Can not find 'MICROCODE - DO NOT EDIT ABOVE' substring in " + file.getCanonicalPath());
|
273 |
|
|
|
274 |
|
|
String output_string = all_string.substring(0, start_index) + "\n" + locations + "// " + all_string.substring(end_index, all_string.length());
|
275 |
|
|
|
276 |
|
|
FileOutputStream out = new FileOutputStream(file);
|
277 |
|
|
out.write(output_string.getBytes());
|
278 |
|
|
out.close();
|
279 |
|
|
}
|
280 |
|
|
static HashMap<String, String> current_line;
|
281 |
|
|
static Vector<HashMap<String, String>> lines;
|
282 |
|
|
static HashMap<String, Integer> labels;
|
283 |
|
|
static int bit_line[];
|
284 |
|
|
}
|