summary refs log tree commit diff
path: root/pc-thing/ramgen.ts
blob: f6e419f101014486f7d851dee6a7a34c591bea2a (plain)
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])))