summary refs log tree commit diff
path: root/eater.ts
blob: 683b23a40b6b1ea838863f1ff692505756fa4f35 (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
// deno-lint-ignore-file no-process-globals
import The65c02 from "./65c02.ts";
import matrix from "./opcode_matrix.json" with { type: "json" };
import { type Buffer } from "node:buffer";
// eater.ts
// a runtime meant to mimic ben eater's 65c02 computer

if (!process.stdin.isRaw)
    process.stdin.setRawMode(true)

// the thing used for ram
const ram = new Uint8Array(2**16);

// initiate the emulator
const cpu = new The65c02(function (this: The65c02) {
    // since this is controlled by the user it's easy
    // to map things into address space
    this.io.data.set(ram[this.io.address.num()] ?? 0)
    if (this.io.address.num() == 0x5000
        && ram[0x5001])
        ram[0x5001] = 0;
}, function (this: The65c02) {
    if (this.io.address.num() == 0x5000) {
        return Deno.stdout.write(new Uint8Array([this.io.data.num()]))
    }
    // write
    ram[this.io.address.num()] = this.io.data.num()
})

const binStart = 0;

await cpu.loadInstructions()

cpu.stackPointer.set(0xff)

const code = Deno.readFileSync('a.out')

// mem address $0000
ram[0xFFFC] = binStart & 0x00FF
ram[0xFFFD] = (binStart & 0xFF00) >> 8

// write code to ram before execution
for (let offset = 0; offset < code.length; offset++) {
    const byte = code[offset];
    ram[binStart  + offset] = byte;
}

// pull RESB low to reset the 65c02
cpu.io.reset.LO()
cpu.cycle()

//the cpu reset, pull RESB high and start execution!
cpu.io.reset.HI()


let running = true;

process.stdin.on('data', (data: Buffer) => {
    if (data[0] == 3)
        return running = false;
    ram[0x5000] = data[0];
    ram[0x5001] = 0x08;
})

// repeat until the cpu requests an interrupt
const clock = setInterval(() => {
    if (!running) {
        Deno.writeFileSync('ram.bin', ram)
        clearInterval(clock)
        
        process.stdin.setRawMode(false);
        Deno.exit(0)
    }
    if(cpu.io.interruptRequest.high && !cpu.IRQBDisable)
        cpu.io.interruptRequest.LO();
    const instId = ram[cpu.programCounter.num()]
        .toString(16)
        .padStart(2, '0');
    const goog = (matrix as Record<string, { mnemonic: string, mode: string }>)[instId];
    if (!goog) {
        console.log('uh', instId, 'unknown')
        throw 'oh no';
    }
    const instr = goog;
    console.log(`\
       PC  AC XR YR SP NV-BDIZC
6502: ${cpu.programCounter.num().toString(16).padStart(4, '0')} ${cpu.regA.num().toString(16).padStart(2, '0')} ${cpu.regX.num().toString(16).padStart(2, '0')} ${cpu.regY.num().toString(16).padStart(2, '0')} ${cpu.stackPointer.num().toString(16).padStart(2, '0')} ${cpu.stackPointer.num().toString(2).padStart(8, '0')}`)
    console.debug(cpu.programCounter.num().toString(16).padStart(4, '0'),instr.mnemonic, instr.mode)
    cpu.cycle();
// 1MHz i think
}, 100)