@8bitscript/c64 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 8BitScript contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,121 @@
1
+ ; @8bitscript/c64 — the CPU's vectors, and the raster interrupt's handler.
2
+ ;
3
+ ; Linked into every C64 program through this package's "8bitscript".native
4
+ ; list (package.json; docs/packages.md). Three pieces, in their own
5
+ ; sections so the linker keeps only what a program reaches:
6
+ ;
7
+ ; .init.250 runs before main() in every program: points the
8
+ ; NMI and IRQ vectors at $FFFA/$FFFE — RAM under
9
+ ; the KERNAL ROM, which @8bitscript/c64's
10
+ ; setupVideo() banks out for good — at a bare rti,
11
+ ; so RESTORE does nothing and a stray IRQ returns.
12
+ ; __8bs_c64_raster_install called (jsr, from raster.8bs's enable())
13
+ ; to move the IRQ vector to the handler. Dropped
14
+ ; from a program that never enables the interrupt,
15
+ ; and the handler with it: a program that does not
16
+ ; import @8bitscript/c64/raster carries the vector
17
+ ; stub only.
18
+ ; __8bs_c64_raster_irq the handler: a list of (line, address, value)
19
+ ; entries at $0200, applied at their raster lines.
20
+ ;
21
+ ; ---- the list -------------------------------------------------------------
22
+ ;
23
+ ; $0200-$02FB up to 63 entries of 4 bytes: raster line (0-255), address
24
+ ; low, address high, value. In ascending line order; entries
25
+ ; on one line are applied together, first to last.
26
+ ; $0300 end: the number of entries times 4 (an index limit).
27
+ ; $0301 the index (times 4) of the next entry to apply.
28
+ ; $0302 the line of the entry just applied (the handler's own).
29
+ ;
30
+ ; raster.8bs owns the same numbers (RasterList.*). The KERNAL's tables at
31
+ ; $0200-$03FF are dead once the program owns the machine, and nothing in
32
+ ; the SDK's link scripts (link.ld, commodore.ld) claims them; the REU
33
+ ; probe's byte is at $033C, above all of this.
34
+ ;
35
+ ; ---- the handler ------------------------------------------------------------
36
+ ;
37
+ ; On the raster interrupt: acknowledge it, apply every entry from the
38
+ ; current index whose line equals the first one's, set the raster compare
39
+ ; to the next entry's line (or the first entry's, past the end — which is
40
+ ; a lower line, so it fires next frame), return. The store goes through
41
+ ; its own operand (self-modifying code: the program is in RAM), so no zero
42
+ ; page is touched — the compiler owns $02-$8F, and the handler must not.
43
+ ; A and X are saved; Y is not used. Cost: about 30 cycles before the first
44
+ ; store and 25 per entry, plus the up-to-7-cycle wait for the instruction
45
+ ; the interrupt lands in — the write lands a few cycles into the line, in
46
+ ; the border with lines chosen so, in the picture otherwise.
47
+ ;
48
+ ; Interrupt sources: only the VIC's raster compare. raster.8bs clears both
49
+ ; CIAs' interrupt masks before the first cli, so nothing else reaches
50
+ ; this handler — the KERNAL's timer would, and the acknowledge here is
51
+ ; $D019's alone.
52
+
53
+ .section .init.250,"ax",@progbits
54
+ lda #<__8bs_c64_rti
55
+ sta 0xFFFA
56
+ sta 0xFFFE
57
+ lda #>__8bs_c64_rti
58
+ sta 0xFFFB
59
+ sta 0xFFFF
60
+
61
+ .section .text.__8bs_c64_rti,"ax",@progbits
62
+ .global __8bs_c64_rti
63
+ __8bs_c64_rti:
64
+ rti
65
+
66
+ .section .text.__8bs_c64_raster_install,"ax",@progbits
67
+ .global __8bs_c64_raster_install
68
+ __8bs_c64_raster_install:
69
+ pha
70
+ lda #<__8bs_c64_raster_irq
71
+ sta 0xFFFE
72
+ lda #>__8bs_c64_raster_irq
73
+ sta 0xFFFF
74
+ pla
75
+ rts
76
+
77
+ .section .text.__8bs_c64_raster_irq,"ax",@progbits
78
+ .global __8bs_c64_raster_irq
79
+ __8bs_c64_raster_irq:
80
+ pha
81
+ txa
82
+ pha
83
+ lda #0x01
84
+ sta 0xD019 ; acknowledge the raster interrupt
85
+ ldx 0x0301
86
+ __8bs_c64_raster_apply:
87
+ cpx 0x0300
88
+ bcs __8bs_c64_raster_wrap
89
+ lda 0x0201,x
90
+ sta __8bs_c64_raster_store+1
91
+ lda 0x0202,x
92
+ sta __8bs_c64_raster_store+2
93
+ lda 0x0203,x
94
+ __8bs_c64_raster_store:
95
+ sta 0xFFFF ; the operand is rewritten above
96
+ lda 0x0200,x
97
+ sta 0x0302
98
+ inx
99
+ inx
100
+ inx
101
+ inx
102
+ cpx 0x0300
103
+ bcs __8bs_c64_raster_wrap
104
+ lda 0x0200,x
105
+ cmp 0x0302
106
+ beq __8bs_c64_raster_apply ; the next entry is on this line too
107
+ sta 0xD012
108
+ stx 0x0301
109
+ pla
110
+ tax
111
+ pla
112
+ rti
113
+ __8bs_c64_raster_wrap:
114
+ ldx #0
115
+ stx 0x0301
116
+ lda 0x0200
117
+ sta 0xD012
118
+ pla
119
+ tax
120
+ pla
121
+ rti
package/package.json ADDED
@@ -0,0 +1,396 @@
1
+ {
2
+ "name": "@8bitscript/c64",
3
+ "version": "0.1.0",
4
+ "description": "C64 target support for 8BitScript: the hardware underneath the portable APIs.",
5
+ "license": "MIT",
6
+ "8bitscript": {
7
+ "entry": "./src/index.8bs",
8
+ "native": [
9
+ "./native/6502/raster.s"
10
+ ],
11
+ "exports": {
12
+ "./screen": "./src/screen.8bs",
13
+ "./text": "./src/text.8bs",
14
+ "./video": "./src/geometry.8bs",
15
+ "./sprites": "./src/sprites.8bs",
16
+ "./keyboard": "./src/keyboard.8bs",
17
+ "./keys": "./src/keys.8bs",
18
+ "./joystick": "./src/joystick.8bs",
19
+ "./sid": "./src/sid.8bs",
20
+ "./reu": "./src/reu.8bs",
21
+ "./mouse": "./src/mouse.8bs",
22
+ "./raster": "./src/raster.8bs",
23
+ "./bitmap": "./src/bitmap.8bs",
24
+ "./charset": "./src/charset.8bs",
25
+ "./scroll": "./src/scroll.8bs",
26
+ "./input": "./src/input.8bs",
27
+ "./pointer": "./src/pointer.8bs",
28
+ "./random": "./src/random.8bs"
29
+ },
30
+ "hardware": {
31
+ "facts": {
32
+ "video.columns": 40,
33
+ "video.rows": 25,
34
+ "video.cellWidth": 8,
35
+ "video.cellHeight": 8,
36
+ "video.palette": 16,
37
+ "video.cellColors": 2,
38
+ "video.colorPerCell": true,
39
+ "video.glyphs": 256,
40
+ "video.blockWidth": 2,
41
+ "video.blockHeight": 2,
42
+ "video.bitmap": true,
43
+ "video.layers": 1,
44
+ "video.scroll": true,
45
+ "video.sprites": 8,
46
+ "video.spritesPerLine": 8,
47
+ "video.spriteWidth": 24,
48
+ "video.spriteHeight": 21,
49
+ "video.spriteColors": 3,
50
+ "video.frameRate": 60,
51
+ "audio.voices": 3,
52
+ "audio.noise": true,
53
+ "audio.envelope": true,
54
+ "audio.filter": true,
55
+ "audio.pcm": true,
56
+ "audio.volume": true,
57
+ "audio.entropy": true,
58
+ "input.keyboard": true,
59
+ "input.joysticks": 2,
60
+ "input.pads": 0,
61
+ "input.mouse": false,
62
+ "input.paddles": false,
63
+ "storage.save": true,
64
+ "memory.ram": 51199,
65
+ "memory.banked": false,
66
+ "memory.bankedKib": 0,
67
+ "storage.kib": 164
68
+ },
69
+ "options": {
70
+ "ram": {
71
+ "label": "RAM Expansion Unit",
72
+ "default": "none",
73
+ "detect": "@8bitscript/c64/reu",
74
+ "values": {
75
+ "none": {
76
+ "label": "No expansion"
77
+ },
78
+ "reu128": {
79
+ "label": "REU, 128 KiB",
80
+ "run": {
81
+ "x64sc": [
82
+ "-reu",
83
+ "-reusize",
84
+ "128"
85
+ ]
86
+ },
87
+ "facts": {
88
+ "memory.banked": true,
89
+ "memory.bankedKib": 128
90
+ }
91
+ },
92
+ "reu256": {
93
+ "label": "REU, 256 KiB",
94
+ "run": {
95
+ "x64sc": [
96
+ "-reu",
97
+ "-reusize",
98
+ "256"
99
+ ]
100
+ },
101
+ "facts": {
102
+ "memory.banked": true,
103
+ "memory.bankedKib": 256
104
+ }
105
+ },
106
+ "reu512": {
107
+ "label": "REU, 512 KiB",
108
+ "run": {
109
+ "x64sc": [
110
+ "-reu",
111
+ "-reusize",
112
+ "512"
113
+ ]
114
+ },
115
+ "facts": {
116
+ "memory.banked": true,
117
+ "memory.bankedKib": 512
118
+ }
119
+ },
120
+ "reu1m": {
121
+ "label": "REU, 1 MiB",
122
+ "run": {
123
+ "x64sc": [
124
+ "-reu",
125
+ "-reusize",
126
+ "1024"
127
+ ]
128
+ },
129
+ "facts": {
130
+ "memory.banked": true,
131
+ "memory.bankedKib": 1024
132
+ }
133
+ },
134
+ "reu2m": {
135
+ "label": "REU, 2 MiB",
136
+ "run": {
137
+ "x64sc": [
138
+ "-reu",
139
+ "-reusize",
140
+ "2048"
141
+ ]
142
+ },
143
+ "facts": {
144
+ "memory.banked": true,
145
+ "memory.bankedKib": 2048
146
+ }
147
+ },
148
+ "reu4m": {
149
+ "label": "REU, 4 MiB",
150
+ "run": {
151
+ "x64sc": [
152
+ "-reu",
153
+ "-reusize",
154
+ "4096"
155
+ ]
156
+ },
157
+ "facts": {
158
+ "memory.banked": true,
159
+ "memory.bankedKib": 4096
160
+ }
161
+ },
162
+ "reu8m": {
163
+ "label": "REU, 8 MiB",
164
+ "run": {
165
+ "x64sc": [
166
+ "-reu",
167
+ "-reusize",
168
+ "8192"
169
+ ]
170
+ },
171
+ "facts": {
172
+ "memory.banked": true,
173
+ "memory.bankedKib": 8192
174
+ }
175
+ },
176
+ "reu16m": {
177
+ "label": "REU, 16 MiB",
178
+ "run": {
179
+ "x64sc": [
180
+ "-reu",
181
+ "-reusize",
182
+ "16384"
183
+ ]
184
+ },
185
+ "facts": {
186
+ "memory.banked": true,
187
+ "memory.bankedKib": 16384
188
+ }
189
+ }
190
+ }
191
+ },
192
+ "sid": {
193
+ "label": "SID",
194
+ "default": "6581",
195
+ "values": {
196
+ "6581": {
197
+ "label": "6581 (the original SID)",
198
+ "run": {
199
+ "x64sc": [
200
+ "-sidmodel",
201
+ "0"
202
+ ]
203
+ }
204
+ },
205
+ "8580": {
206
+ "label": "8580 (the later SID)",
207
+ "run": {
208
+ "x64sc": [
209
+ "-sidmodel",
210
+ "1"
211
+ ]
212
+ }
213
+ }
214
+ }
215
+ },
216
+ "port1": {
217
+ "label": "Control port 1",
218
+ "default": "none",
219
+ "values": {
220
+ "none": {
221
+ "label": "Nothing plugged in",
222
+ "run": {
223
+ "x64sc": [
224
+ "-controlport1device",
225
+ "0"
226
+ ]
227
+ }
228
+ },
229
+ "joystick": {
230
+ "label": "Joystick",
231
+ "run": {
232
+ "x64sc": [
233
+ "-controlport1device",
234
+ "1"
235
+ ]
236
+ }
237
+ },
238
+ "paddles": {
239
+ "label": "Paddles",
240
+ "run": {
241
+ "x64sc": [
242
+ "-controlport1device",
243
+ "2"
244
+ ]
245
+ },
246
+ "facts": {
247
+ "input.paddles": true
248
+ }
249
+ },
250
+ "mouse1351": {
251
+ "label": "Commodore 1351 mouse",
252
+ "run": {
253
+ "x64sc": [
254
+ "-controlport1device",
255
+ "3",
256
+ "-mouse"
257
+ ]
258
+ },
259
+ "facts": {
260
+ "input.mouse": true
261
+ },
262
+ "detect": "@8bitscript/c64/mouse"
263
+ }
264
+ }
265
+ },
266
+ "port2": {
267
+ "label": "Control port 2",
268
+ "default": "joystick",
269
+ "values": {
270
+ "none": {
271
+ "label": "Nothing plugged in",
272
+ "run": {
273
+ "x64sc": [
274
+ "-controlport2device",
275
+ "0"
276
+ ]
277
+ }
278
+ },
279
+ "joystick": {
280
+ "label": "Joystick",
281
+ "run": {
282
+ "x64sc": [
283
+ "-controlport2device",
284
+ "1"
285
+ ]
286
+ }
287
+ },
288
+ "paddles": {
289
+ "label": "Paddles",
290
+ "run": {
291
+ "x64sc": [
292
+ "-controlport2device",
293
+ "2"
294
+ ]
295
+ },
296
+ "facts": {
297
+ "input.paddles": true
298
+ }
299
+ },
300
+ "mouse1351": {
301
+ "label": "Commodore 1351 mouse",
302
+ "run": {
303
+ "x64sc": [
304
+ "-controlport2device",
305
+ "3",
306
+ "-mouse"
307
+ ]
308
+ },
309
+ "facts": {
310
+ "input.mouse": true
311
+ },
312
+ "detect": "@8bitscript/c64/mouse"
313
+ }
314
+ }
315
+ },
316
+ "drive": {
317
+ "label": "Disk drive",
318
+ "default": "1541",
319
+ "values": {
320
+ "1541": {
321
+ "label": "1541 (170K disk)",
322
+ "facts": {
323
+ "storage.save": true,
324
+ "storage.kib": 164
325
+ },
326
+ "tag": null
327
+ },
328
+ "1571": {
329
+ "label": "1571 (340K disk)",
330
+ "facts": {
331
+ "storage.save": true,
332
+ "storage.kib": 329
333
+ },
334
+ "tag": null
335
+ },
336
+ "1581": {
337
+ "label": "1581 (800K disk)",
338
+ "facts": {
339
+ "storage.save": true,
340
+ "storage.kib": 783
341
+ },
342
+ "tag": null
343
+ },
344
+ "none": {
345
+ "label": "No drive (tape or nothing)",
346
+ "facts": {
347
+ "storage.save": false,
348
+ "storage.kib": 0
349
+ },
350
+ "tag": null
351
+ }
352
+ }
353
+ }
354
+ },
355
+ "presets": {
356
+ "stock": {
357
+ "ram": "none"
358
+ },
359
+ "reu128": {
360
+ "ram": "reu128"
361
+ },
362
+ "reu256": {
363
+ "ram": "reu256"
364
+ },
365
+ "reu512": {
366
+ "ram": "reu512"
367
+ },
368
+ "reu1m": {
369
+ "ram": "reu1m"
370
+ },
371
+ "reu2m": {
372
+ "ram": "reu2m"
373
+ },
374
+ "reu4m": {
375
+ "ram": "reu4m"
376
+ },
377
+ "reu8m": {
378
+ "ram": "reu8m"
379
+ },
380
+ "reu16m": {
381
+ "ram": "reu16m"
382
+ }
383
+ }
384
+ }
385
+ },
386
+ "files": [
387
+ "src",
388
+ "native"
389
+ ],
390
+ "publishConfig": {
391
+ "access": "public"
392
+ },
393
+ "scripts": {
394
+ "test": "node --test"
395
+ }
396
+ }