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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
import { PC } from "./pc.ts";
const pc = new PC()
const commands = []
const commandData: Record<string, any> = {}
const dir = Deno.readDirSync('instructions_new');
for (const filename of dir) {
commands.push(filename.name.replace(/\..*?$/g, ''))
commandData[filename.name.replace(/\..*?$/g, '')] = (await import('./instructions_new/' + filename.name)).default
}
commands.push('end')
commandData.end = {
args: 0
}
interface ObjectFile {
// number is the ammount of bytes to skip
code: (string | number)[],
offset: number,
// line number, data
data: [number, number[]][]
}
// console.log(commands, commands.length, (commands.length - 1).toString(16))
const object: ObjectFile = JSON.parse(new TextDecoder().decode(Deno.readFileSync('code.o')))
const code = object.code
const offset = object.offset ?? 2**16 / 2
const ram = []
const instructions = []
for (const element of code) {
if (typeof element == 'number') {
instructions.push(element)
continue;
}
const [command, ...args] = element.split(' ');
switch (command) {
case '.hex':
instructions.push([parseInt(args[0], 16)]);
continue;
// deno-lint-ignore no-case-declarations
case '.str':
const str = [...element.matchAll(/"(.*?)(?<!\\)"/g)][0][1].replaceAll('\\"', '"')
instructions.push(new Array(str.length).fill(0).map((_, i) => str.charCodeAt(i)));
continue;
}
const parsedArgs = args.map(arg => {
if (arg.startsWith('$')) return arg // line numbers can pass
if (arg.match(/^\[.*\]$/)) return arg // line numbers can pass
if (!isNaN(+arg)) {
// make sure its a uint16
return Math.floor(+arg) & 0xFFFF
}
arg = arg.toLowerCase();
if (!pc.regNames.split('').includes(arg)) throw 'whar '+arg
return arg
})
const inst = Object.entries(pc.instructions).find(([_, b]) => b == command);
if (!inst) throw 'erm,, what the sigma ' + command + ' (' + inst + ')'
if (!commandData[command]) throw 'no command data for ' + command + ' (' + inst + ')'
if (commandData[command].args != args.length)
throw `mismatch of ${command} arg length ${commandData[command].args} != ${args.length}`
instructions.push([+inst[0], ...parsedArgs])
}
const instructionAddresses: number[] = [];
let addr = offset;
for (const instr of instructions) {
instructionAddresses.push(addr);
addr += typeof instr == 'number' ? instr : instr.length
}
let i = 0
for (const instr of instructions) {
// console.log(instr, Array.isArray(instr) ? instr[0].toString(16) : null)
if (typeof instr == 'number') {
// console.log(ram.length, instr, new Array<number>(instr).fill(0))
ram.push(...new Array<number>(instr).fill(0))
continue;
}
const newInstr: number[] = instr.map<number>(i => {
if (typeof i !== 'string') return i;
const m = i.match(/^\[(.*)\]$/)
if (m) {
const ln = m[1]
if (!instructionAddresses[+ln]) throw 'a '+i
// console.log(i, instructionAddresses[+i.replace('$', '')])
return instructionAddresses[+ln]
}
if (!i.startsWith('$')) return i.charCodeAt(0);
if (!instructionAddresses[+i.replace('$', '')]) throw 'a '+i
// console.log(i, instructionAddresses[+i.replace('$', '')])
return instructionAddresses[+i.replace('$', '')]
})
// console.log(instructionAddresses[i], (instructionAddresses[i] * 2).toString(16), commands[newInstr[0]], newInstr)
ram.push(...newInstr)
i++
}
for (const element of object.data) {
// console.log(instructionAddresses[element[0]] - offset, element[0], element[1])
ram.splice(instructionAddresses[element[0]] - offset, element[1].length, ...element[1])
}
Deno.writeFileSync(Deno.args[0] ?? 'iram.bin', Uint8Array.from(ram.map(a => [a & 0x00FF, (a & 0xFF00) >> 8]).flatMap(([a, b]) => [a, b])))
|