1 | #include <map>
|
---|
2 | #include <vector>
|
---|
3 | #include <stdint.h>
|
---|
4 |
|
---|
5 | #include <arpa/inet.h>
|
---|
6 |
|
---|
7 | struct __attribute__((packed)) BAS_Data {
|
---|
8 | uint8_t type;
|
---|
9 | uint16_t length;
|
---|
10 | std::vector<uint8_t> data;
|
---|
11 | };
|
---|
12 |
|
---|
13 | bool BAS_ReadChunk(FILE* in, BAS_Data& out) {
|
---|
14 | // Read the chunk header
|
---|
15 | int value = fread(&out, 3, 1, in);
|
---|
16 | if (value == 0)
|
---|
17 | return false;
|
---|
18 |
|
---|
19 | // 6809 is little endian, take that into account...
|
---|
20 | out.length = ntohs(out.length);
|
---|
21 |
|
---|
22 | // Resize the data member to the proper size and read the data to it.
|
---|
23 | out.data.reserve(out.length);
|
---|
24 | fread(&out.data[0], out.length, 1, in);
|
---|
25 |
|
---|
26 | return true;
|
---|
27 | };
|
---|
28 |
|
---|
29 | struct __attribute__((packed)) BAS_Line {
|
---|
30 | uint16_t offset;
|
---|
31 | uint16_t number;
|
---|
32 | uint8_t data[];
|
---|
33 | };
|
---|
34 |
|
---|
35 | void BAStoASCII(BAS_Data& data)
|
---|
36 | {
|
---|
37 | std::map<uint8_t, const char*> Opcodes;
|
---|
38 | std::map<uint8_t, const char*> Functions;
|
---|
39 |
|
---|
40 | // FLOW CONTROL
|
---|
41 | Opcodes[0x80] = "END";
|
---|
42 | Opcodes[0x81] = "FOR";
|
---|
43 | Opcodes[0x82] = "NEXT";
|
---|
44 | Opcodes[0x83] = "DATA";
|
---|
45 | Opcodes[0x84] = "DIM";
|
---|
46 | Opcodes[0x85] = "READ";
|
---|
47 | //
|
---|
48 | Opcodes[0x87] = "GO";
|
---|
49 | //
|
---|
50 | Opcodes[0x89] = "IF";
|
---|
51 | Opcodes[0x8A] = "RESTORE";
|
---|
52 | Opcodes[0x8B] = "RETURN";
|
---|
53 | //
|
---|
54 | Opcodes[0x93] = "DEFINT";
|
---|
55 | // CURSOR
|
---|
56 | Opcodes[0x9C] = "LOCATE";
|
---|
57 | Opcodes[0x9D] = "CLS";
|
---|
58 | // MACHINE
|
---|
59 | Opcodes[0xA2] = "EXEC";
|
---|
60 | // DISPLAY
|
---|
61 | Opcodes[0xA4] = "COLOR";
|
---|
62 | Opcodes[0xA5] = "LINE";
|
---|
63 | Opcodes[0xA6] = "BOX";
|
---|
64 | //
|
---|
65 | Opcodes[0xA8] = "ATTRB";
|
---|
66 | Opcodes[0xA9] = "DEF"; // FIXME DEFGR$
|
---|
67 | Opcodes[0xAA] = "POKE";
|
---|
68 | Opcodes[0xAB] = "PRINT";
|
---|
69 | //
|
---|
70 | Opcodes[0xAE] = "CLEAR";
|
---|
71 |
|
---|
72 | // SOUND
|
---|
73 | Opcodes[0xB9] = "PLAY";
|
---|
74 |
|
---|
75 | // SUB-CODES
|
---|
76 | Opcodes[0xBB] = "TO";
|
---|
77 | Opcodes[0xBC] = "SUB";
|
---|
78 | //
|
---|
79 | Opcodes[0xBF] = "USING";
|
---|
80 | //
|
---|
81 | Opcodes[0xC4] = "THEN";
|
---|
82 | //
|
---|
83 | Opcodes[0xC6] = "STEP";
|
---|
84 |
|
---|
85 | // OPERATORS
|
---|
86 | Opcodes[0xC7] = "+";
|
---|
87 | Opcodes[0xC8] = "-";
|
---|
88 | Opcodes[0xC9] = "*";
|
---|
89 | Opcodes[0xCA] = "/";
|
---|
90 | //
|
---|
91 | Opcodes[0xCC] = "AND";
|
---|
92 | Opcodes[0xCD] = "OR";
|
---|
93 | //
|
---|
94 | Opcodes[0xD3] = ">";
|
---|
95 | Opcodes[0xD4] = "=";
|
---|
96 | Opcodes[0xD5] = "<";
|
---|
97 |
|
---|
98 |
|
---|
99 | Functions[0x81] = "INT";
|
---|
100 | Functions[0x82] = "ABS";
|
---|
101 | Functions[0x8B] = "LEN";
|
---|
102 | Functions[0x8E] = "ASC";
|
---|
103 | Functions[0x8F] = "CHR$";
|
---|
104 | Functions[0x99] = "GR$";
|
---|
105 | Functions[0x9A] = "LEFT$";
|
---|
106 | Functions[0x9C] = "MID$";
|
---|
107 | Functions[0x9F] = "RND";
|
---|
108 | Functions[0xA0] = "INKEY$";
|
---|
109 | Functions[0xA1] = "INPUT$";
|
---|
110 | Functions[0xA4] = "SCREEN";
|
---|
111 |
|
---|
112 | /* ################################ */
|
---|
113 |
|
---|
114 | BAS_Line* currentLine;
|
---|
115 | currentLine = (BAS_Line*)&data.data[0];
|
---|
116 |
|
---|
117 | bool func = false;
|
---|
118 | while(currentLine->offset) {
|
---|
119 | // Endianness fixup
|
---|
120 | currentLine->offset = ntohs(currentLine->offset);
|
---|
121 | currentLine->number = ntohs(currentLine->number);
|
---|
122 |
|
---|
123 | printf("%d ", currentLine->number);
|
---|
124 |
|
---|
125 | for (int i = 0; currentLine->data[i]; i++) {
|
---|
126 | uint8_t c = currentLine->data[i];
|
---|
127 | if (c < 128 && isprint(c))
|
---|
128 | putchar(c);
|
---|
129 | else if (c == 0xFF) {
|
---|
130 | func = true;
|
---|
131 | continue;
|
---|
132 | } else if ((!func) && (Opcodes.find(c) != Opcodes.end()))
|
---|
133 | printf("\x1B[31m%s\x1B[0m", Opcodes[c]);
|
---|
134 | else if (func && (Functions.find(c) != Functions.end()))
|
---|
135 | printf("\x1B[32m%s\x1B[0m", Functions[c]);
|
---|
136 | else {
|
---|
137 | printf("\n*** UNKNOWN %s %x ***\n", func?"FUNCTION":"OPCODE", c);
|
---|
138 | for (int k = 0; currentLine->data[k]; k++)
|
---|
139 | printf("%02X ", currentLine->data[k]);
|
---|
140 | puts("");
|
---|
141 | exit(EXIT_FAILURE);
|
---|
142 | }
|
---|
143 | func = false;
|
---|
144 | }
|
---|
145 | currentLine = (BAS_Line*)&data.data[currentLine->offset - 0x25A4];
|
---|
146 | puts("");
|
---|
147 | }
|
---|
148 | }
|
---|
149 |
|
---|
150 | int main(int argc, char* argv[])
|
---|
151 | {
|
---|
152 | if (argc < 2)
|
---|
153 | {
|
---|
154 | fprintf(stderr, "%s file.bas\n", argv[0]);
|
---|
155 | return 1;
|
---|
156 | }
|
---|
157 |
|
---|
158 | FILE* in;
|
---|
159 | BAS_Data h;
|
---|
160 |
|
---|
161 | in = fopen(argv[1], "rb");
|
---|
162 |
|
---|
163 | while(BAS_ReadChunk(in, h))
|
---|
164 | {
|
---|
165 | BAStoASCII(h);
|
---|
166 | };
|
---|
167 |
|
---|
168 | }
|
---|