forked from slaapliedje/gem4xe
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
1463 lines (1250 loc) · 72.8 KB
/
Copy pathMakefile
File metadata and controls
1463 lines (1250 loc) · 72.8 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# gem4xe -- GEM for the Atari 8-bit (VBXE + Rapidus + U1MB)
#
# make build/hello.xex and the bootable test disk
# make test-emu Phase 0 hardware gate (VBXE / Rapidus / MEMAC / CPU switch)
# make test-m1 Milestone 1: Calypsi C running on the 65C816
# make test-m6 the far code really is in, and running from, bank $01
# make test-m7 evnt_* and form_do under host-driven input
# make test-m8 the window manager: rectangle lists, moves, WM_REDRAW
# make test-m9 menus: the bar, drop-downs, MN_SELECTED under host input
# make test-m10 native-mode interrupts: the ROM shadow, VBI, timer, keys,
# a trak-ball counted in the handler, and the way back to DOS
# make test-m11 the application ABI: a separately linked program loaded,
# relocated and run, calling GEM through COP
# make test-m26 one binary, two screens: GEM.COM with a VBXE, without
# one, and in safe mode from GEM4XE.CFG
# make check-cc the compiler bugs we work around, in the vendor's simulator
# make bench GEMBench's tests on this machine, in milliseconds (docs/bench.md)
# make test all of them
# make emu-stop kill leftover emulators (never use pkill -f: it kills the shell)
CALYPSI ?= $(HOME)/dev/toolchains/calypsi-65816
EMUTOS ?= $(HOME)/dev/emutos
# The compiler, through tools/ccdep.sh, which records what each object
# really depends on into build/*.d and is included below. The hand-written
# header lists on the rules stay: they are what makes the first build after
# a clean correct. See the top of that script for what a missing one cost.
CC65816 = $(CALYPSI)/bin/cc65816
export CC65816
CC = tools/ccdep.sh
AS = $(CALYPSI)/bin/as65816
LD = $(CALYPSI)/bin/ln65816
LIB = clib-lc-sd.a
# Large code puts every C function in `farcode`, which src/gem4xe.scm places
# in banks $01 upwards -- one linker memory per bank, filled in order, so no
# function straddles a bank -- and src/farload.s copies up as DOS loads the
# file. Data stays small -- globals and constants are addressed through the
# data bank register, so they have to remain in bank $00 (see the linker
# script).
CFLAGS = --code-model=large --data-model=small -O2 -I src
# --override lets src/sys/div16.o replace the library's _Div16/_Mod16, which
# leave the wrong flags for the compiler's own `beq` (see that file).
LDFLAGS = --rtattr exit=simplified --override _Div16 --override _Mod16
# What the compiler said each object opened, last time it was compiled.
-include $(wildcard build/*.d)
SRC_DOS ?= $(shell python3 -c "import tomllib;print(tomllib.load(open('fixtures.toml','rb'))['dos']['sd_dos2'])" 2>/dev/null)
# A double-density DOS 2 disk, [dos].dd_dos2: 720 x 256 is where the DOS 2
# product disk lives, because 707 sectors of 253 bytes hold GEM, the desktop,
# the DOS's own shell and applications besides -- and because that DOS runs
# AUTORUN.SYS, which is how the disk comes up in the desktop.
SRC_DD ?= $(shell python3 -c "import tomllib;print(tomllib.load(open('fixtures.toml','rb'))['dos']['dd_dos2'])" 2>/dev/null)
# SpartaDOS 3.2 boot disk and the SpartaDOS X cartridge, [spartados] in
# fixtures.toml -- the SpartaGEM gate (docs/phase13.md) boots the one and
# then the other, with the same program.
SRC_SP32 ?= $(shell python3 -c "import tomllib;print(tomllib.load(open('fixtures.toml','rb'))['spartados']['disk_32'])" 2>/dev/null)
SRC_SDX ?= $(shell python3 -c "import tomllib;print(tomllib.load(open('fixtures.toml','rb'))['spartados']['sdx_cart'])" 2>/dev/null)
# An Ultimate 1MB flash image carrying SpartaDOS X (test-m14u, test-m15u):
# needs the patched emulator's --u1mbrom (tools/altirra/), ALTIRRASDL=...
SRC_U1MB ?= $(shell python3 -c "import tomllib;print(tomllib.load(open('fixtures.toml','rb'))['u1mb']['flash'])" 2>/dev/null)
HELLO_OBJS = build/crt_atari.o build/farload.o build/div16.o build/clib.o build/hello.o
M2_OBJS = build/crt_atari.o build/farload.o build/div16.o build/clib.o build/m2_vbxe.o build/vbxe.o
# The context switch on its own: farmem for the parked extents, app_run
# out of abi.s for the way a context enters its program, and the runner's
# own stubs for the engine that is deliberately not linked.
M27_OBJS = build/crt_atari.o build/farload.o build/div16.o build/clib.o build/m27_ctx.o \
build/ctx.o build/ctxs.o build/farmem.o build/abis.o
# The ANTIC surface milestone: no VBXE object at all, which is the point
M24_OBJS = build/crt_atari.o build/farload.o build/div16.o build/clib.o build/m24_antic.o build/antic.o build/font8x8.o
# The VDI on the ANTIC device: the same vdi.c, compiled for the other
# side of the seam and linked against dev_antic.o.
M25_OBJS = build/crt_atari.o build/farload.o build/div16.o build/clib.o build/m25_antic_vdi.o \
build/vdi.o build/dev_antic.o build/dev_print.o build/emit.o build/antic.o build/pointer.o \
build/font8x8.o build/font6x6.o build/fillpat.o build/sintbl.o build/font.o \
build/farmem.o build/irq.o build/irqs.o build/rapidus.o \
build/cio.o build/cios.o build/dos.o build/m25_stub.o \
build/graf.o build/objc.o build/grlib.o build/event.o \
build/proc.o build/ctx.o build/ctxs.o \
build/wind.o build/ctrl.o build/menu.o build/form.o \
build/alert.o build/gemdata.o build/lang.o build/lang_rsc.o \
build/rsrc.o build/apppool.o
# The VDI on the PRINTER: the same vdi.c again, on the third device --
# a page in far memory rather than a screen -- plus the emitters, which
# are the only reason this milestone needs CIO. No AES: nothing draws an
# object tree onto paper here, so the stub answers for the call gate.
M30_OBJS = build/crt_atari.o build/farload.o build/div16.o build/clib.o build/m30_print.o \
build/vdi.o build/dev_print.o build/emit.o build/pointer.o \
build/font8x8.o build/fillpat.o build/sintbl.o build/font.o \
build/farmem.o build/irq.o build/irqs.o build/rapidus.o \
build/cio.o build/cios.o build/dos.o build/m25_stub.o \
build/graf.o build/objc.o build/grlib.o build/event.o \
build/proc.o build/ctx.o build/ctxs.o \
build/wind.o build/ctrl.o build/menu.o build/form.o \
build/alert.o build/gemdata.o build/lang.o build/lang_rsc.o \
build/rsrc.o build/apppool.o
M3_OBJS = build/crt_atari.o build/farload.o build/div16.o build/clib.o build/m3_vdi.o build/vdi.o build/dev_vbxe.o build/pointer.o build/dev_print.o build/emit.o build/objc.o build/graf.o build/event.o build/proc.o build/ctx.o build/ctxs.o build/grlib.o build/form.o build/alert.o build/wind.o build/ctrl.o build/menu.o build/farmem.o build/rapidus.o build/irq.o build/irqs.o build/abi.o build/abis.o build/app.o build/apppool.o build/cio.o build/cios.o build/dos.o build/gemdos.o build/rsrc.o build/shel.o build/app_blob.o build/font8x8.o build/fillpat.o build/sintbl.o build/vbxe.o build/antic.o build/fsel.o build/fsel_rsc.o build/gemdata.o build/lang.o build/lang_rsc.o build/font.o build/clock.o
# GEM.COM, the product (src/gem.c): the runner's objects with the runner
# itself and its compiled-in test application taken out, linked on the
# same rules with the application pool given the whole of $4000-$7FFF
# (src/gem4xe.scm, `layout`).
# GEM.COM links BOTH devices and chooses at start-up, so the ANTIC
# surface, its driver and its face come in on top of the runner's set.
GEM_OBJS = $(filter-out build/m3_vdi.o build/app_blob.o,$(M3_OBJS)) \
build/dev_antic.o build/font6x6.o \
build/config.o build/bootinfo.o build/gem.o
# A gem4xe application: its own C startup and bindings (src/app), linked
# against nothing of gem4xe's, on the application's own linker rules.
APP_OBJS = build/app/crt_gemapp.o build/app/gemabi.o build/app/gemlib.o build/app/m11_app.o
# Its near budget (src/app/gemapp.scm): the stack and data, then the
# constants; and the stack's share of the first. Decimal, because a `#`
# in a make variable starts a comment.
APP_BSS = 2048
APP_BITS = 256
APP_STACK = 256
# Everything a gate boots, and the product: a plain `make` leaves no disk
# behind its sources (a gate run by hand, rather than through its test-m*
# target, otherwise boots a stale image and compares it against a fresh
# linker map).
all: build/hello-boot.atr build/m2-boot.atr build/m3-boot.atr build/m6split-boot.atr \
build/m12-d2.atr build/m14-boot.atr build/m17-boot.atr build/gem-boot.atr build/gem-sp.atr \
build/gem-sdx.atr build/gem-cf.img
build/%.o: src/%.s
@mkdir -p build
$(AS) -o $@ $<
build/%.o: src/%.c
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
# The two device files. GEM4XE_DEV_IMPL says "this is one device's own
# translation unit", so vdidev.h gives it compile-time geometry instead
# of the pointer, and GEM4XE_DEV_PREFIX stamps its functions -- which is
# what lets BOTH be linked into one binary without a rename by hand.
build/dev_vbxe.o: src/vdi/dev_vbxe.c src/vdi/vdidev.h src/vdi/vdi.h src/vbxe/vbxe.h
@mkdir -p build
$(CC) $(CFLAGS) -DGEM4XE_DEV_IMPL -DGEM4XE_DEV_PREFIX=vbd_ \
-I src -I src/vdi -o $@ $<
build/font6x6.o: src/vdi/font6x6.c
@mkdir -p build
$(CC) $(CFLAGS) -I src/vdi -o $@ $<
src/vdi/font6x6.c: tools/fontconv6.py
python3 tools/fontconv6.py "$(EMUTOS)/bios/fnt_st_6x6.c" $@
# The page (src/vdi/dev_print.c): the third device behind the same seam,
# 640x800 at 1bpp in far memory. docs/printing.md has the geometry.
build/dev_print.o: src/vdi/dev_print.c src/vdi/vdidev.h src/vdi/vdi.h src/vdi/print.h
@mkdir -p build
$(CC) $(CFLAGS) -DGEM4XE_DEV_IMPL -DGEM4XE_DEV_PREFIX=prd_ \
-DGEM4XE_DEV_PRINT -I src -I src/vdi -o $@ $<
# The page, off the machine (src/vdi/emit.c): PCL 5 and PostScript, and
# where they go. Above the device seam -- it reads the page, it does not
# draw on it -- so no device macros.
build/emit.o: src/vdi/emit.c src/vdi/print.h src/vdi/vdi.h src/sys/cio.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I src/vdi -o $@ $<
build/dev_antic.o: src/vdi/dev_antic.c src/vdi/vdidev.h src/vdi/vdi.h src/antic/antic.h
@mkdir -p build
$(CC) $(CFLAGS) -DGEM4XE_DEV_IMPL -DGEM4XE_DEV_PREFIX=and_ \
-DGEM4XE_DEV_ANTIC -I src -I src/vdi -o $@ $<
# There is no second copy of the device-INdependent halves any more.
# build/vdi.o, build/pointer.o and build/font.o serve both screens: that
# is what the vtable bought, and it is checkable rather than claimed --
# test-m3 and test-m25 link the same vdi.o.
build/m25_antic_vdi.o: src/m25_antic_vdi.c src/vdi/vdi.h src/vdi/vdidev.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I src/vdi -o $@ $<
build/m30_print.o: src/m30_print.c src/vdi/vdi.h src/vdi/vdidev.h src/vdi/print.h
@mkdir -p build
$(CC) $(CFLAGS) -DGEM4XE_DEV_PRINT -I src -I src/vdi -o $@ $<
build/vbxe.o: src/vbxe/vbxe.c src/vbxe/vbxe.h
@mkdir -p build
$(CC) $(CFLAGS) -I src/vbxe -o $@ $<
build/antic.o: src/antic/antic.c src/antic/antic.h src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src/antic -I src -o $@ $<
build/m24_antic.o: src/m24_antic.c src/antic/antic.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/m2_vbxe.o: src/m2_vbxe.c src/vbxe/vbxe.h
build/m3_vdi.o: src/m3_vdi.c src/vbxe/vbxe.h src/antic/antic.h src/vdi/vdi.h src/vdi/vdidev.h src/sys/irq.h src/sys/abi.h src/sys/app.h src/sys/cio.h src/sys/dos.h
build/vdi.o: src/vdi/vdi.c src/vdi/vdi.h src/vdi/vdidev.h src/vdi/pointer.h src/sys/irq.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/pointer.o: src/vdi/pointer.c src/vdi/pointer.h src/vdi/vdi.h src/vdi/vdidev.h src/sys/irq.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/objc.o: src/aes/objc.c src/aes/aes.h src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/graf.o: src/aes/graf.c src/aes/aes.h src/vdi/vdi.h build/gemdata.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
build/proc.o: src/aes/proc.c src/aes/proc.h src/aes/aes.h src/sys/ctx.h src/sys/app.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/event.o: src/aes/event.c src/aes/aes.h src/aes/proc.h src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/grlib.o: src/aes/grlib.c src/aes/aes.h src/vdi/vdi.h build/gemdata.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
build/alert.o: src/aes/alert.c src/aes/aes.h src/sys/app.h build/gemdata.h build/lang_rsc.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
build/form.o: src/aes/form.c src/aes/aes.h src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/wind.o: src/aes/wind.c src/aes/aes.h src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/ctrl.o: src/aes/ctrl.c src/aes/aes.h src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/menu.o: src/aes/menu.c src/aes/aes.h src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/div16.o: src/sys/div16.s
@mkdir -p build
$(AS) -o $@ $<
# Our own memcpy/memset/str* so that no Apache-2.0 object from the
# vendor's C library is linked into a GPLv2 binary (src/sys/clib.c has
# the argument, and docs/licence.md what is still outstanding).
build/clib.o: src/sys/clib.c
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/farmem.o: src/sys/farmem.c src/sys/farmem.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/rapidus.o: src/sys/rapidus.c src/sys/rapidus.h src/vbxe/vbxe.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
# The interrupt regime: the C side installs and removes it, the assembly
# side is the handlers and the bank-$00 stubs the vectors point at.
build/irq.o: src/sys/irq.c src/sys/irq.h src/sys/rapidus.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/irqs.o: src/sys/irq.s
@mkdir -p build
$(AS) -o $@ $<
# The application ABI: the COP handler and the far-call trampoline in
# assembly, the parameter-block copy-in/out and the AES's crysbind in C,
# then the loader and the linker-reported bounds of its bank-$00 pool.
build/abi.o: src/sys/abi.c src/sys/abi.h src/vdi/vdi.h src/aes/aes.h src/sys/gemdos.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/abis.o: src/sys/abi.s
@mkdir -p build
$(AS) -o $@ $<
# The context switch: the bookkeeping in C, the three instructions C
# cannot write in assembly (src/sys/ctx.h).
build/ctx.o: src/sys/ctx.c src/sys/ctx.h src/sys/abi.h src/sys/farmem.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/ctxs.o: src/sys/ctx.s
@mkdir -p build
$(AS) -o $@ $<
build/m27_ctx.o: src/m27_ctx.c src/sys/ctx.h src/sys/farmem.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/app.o: src/sys/app.c src/sys/app.h src/sys/abi.h src/sys/cio.h src/sys/dos.h src/sys/farmem.h src/sys/gemdos.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/apppool.o: src/sys/apppool.s
@mkdir -p build
$(AS) -o $@ $<
# The file layer's floor: CIO through the OS, the IOCB side in C and the
# round trip into emulation mode in assembly.
build/cio.o: src/sys/cio.c src/sys/cio.h src/sys/irq.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/cios.o: src/sys/cio.s
@mkdir -p build
$(AS) -o $@ $<
# The DOS seam: which DOS booted, its path syntax, its listing's marks.
build/dos.o: src/sys/dos.c src/sys/dos.h src/sys/cio.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
# GEM.COM itself: it names both devices and the config, so it has to be
# rebuilt when the seam moves.
build/gem.o: src/gem.c src/vdi/vdi.h src/vdi/vdidev.h src/vdi/pointer.h \
src/vdi/font.h src/vdi/print.h src/aes/aes.h src/sys/config.h \
src/sys/bootinfo.h src/sys/clock.h src/vbxe/vbxe.h src/antic/antic.h \
build/lang_rsc.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
# GEM4XE.CFG: what the machine should be told before it has a screen.
build/config.o: src/sys/config.c src/sys/config.h src/sys/cio.h src/vdi/pointer.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
# The boot screen: what was found, on E:, before the GEM screen comes up.
# It says the version, which is the one place the C sees VERSION.
build/version.h: VERSION
@mkdir -p build
printf '#define GEM4XE_VERSION "%s"\n' "$$(cat VERSION)" > $@
build/bootinfo.o: src/sys/bootinfo.c src/sys/bootinfo.h src/sys/cio.h src/sys/irq.h \
src/sys/rapidus.h src/sys/farmem.h src/sys/dos.h src/sys/config.h \
src/sys/clock.h src/vbxe/vbxe.h src/vdi/pointer.h src/aes/aes.h \
build/lang_rsc.h build/version.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
# GEMDOS for the applications: the ST's trap #1 on CIO, through the seam.
build/gemdos.o: src/sys/gemdos.c src/sys/clock.h src/sys/gemdos.h src/sys/dos.h src/sys/cio.h src/sys/farmem.h src/sys/app.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
# The file layer proper: the resource loader and the shell library.
build/rsrc.o: src/aes/rsrc.c src/aes/aes.h src/sys/app.h src/sys/cio.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
# The AES's own artwork -- eight mouse forms, three alert icons -- from the
# one script the reference reads them from too.
build/gemdata.c build/gemdata.h: tools/gemdata.py
@mkdir -p build
python3 tools/gemdata.py build/gemdata.c build/gemdata.h
build/gemdata.o: build/gemdata.c src/aes/aes.h
$(CC) $(CFLAGS) -I src -o $@ $<
# LANG.RSC: what the system says. One description makes three things --
# the file a translator replaces, the same bytes as the far fallback, and
# the indices the C uses (tools/langrsc.py).
build/lang.rsc build/lang_rsc.c build/lang_rsc.h: tools/langrsc.py tools/rsc.py
@mkdir -p build
python3 tools/langrsc.py build/lang.rsc build/lang_rsc.c build/lang_rsc.h
build/lang_rsc.o: build/lang_rsc.c
@mkdir -p build
$(CC) $(CFLAGS) -o $@ $<
build/clock.o: src/sys/clock.c src/sys/clock.h src/sys/cio.h src/sys/dos.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/font.o: src/vdi/font.c src/vdi/font.h src/vdi/vdi.h src/vdi/vdidev.h src/sys/cio.h src/sys/farmem.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
# The character sets a translation can ship as SYSTEM.FNT, written out of
# an EmuTOS checkout in the format the VDI reads (tools/mkfnt.py). Not
# built by `all`: the product's font is the one linked in, and these are
# for whoever is translating. `make fonts` writes them.
FONTS = build/l2.fnt build/ru.fnt build/gr.fnt build/tr.fnt
fonts: $(FONTS)
build/l2.fnt: tools/mkfnt.py ; @mkdir -p build && python3 tools/mkfnt.py $(EMUTOS)/bios/fnt_l2_8x8.c $@
build/ru.fnt: tools/mkfnt.py ; @mkdir -p build && python3 tools/mkfnt.py $(EMUTOS)/bios/fnt_ru_8x8.c $@
build/gr.fnt: tools/mkfnt.py ; @mkdir -p build && python3 tools/mkfnt.py $(EMUTOS)/bios/fnt_gr_8x8.c $@
build/tr.fnt: tools/mkfnt.py ; @mkdir -p build && python3 tools/mkfnt.py $(EMUTOS)/bios/fnt_tr_8x8.c $@
# The system font as a file, and the same font inverted: what test-m21
# loads, built from the strip that is checked in so the gate needs no
# EmuTOS checkout.
build/st.fnt: tools/mkfnt.py src/vdi/font8x8.c
@mkdir -p build
python3 tools/mkfnt.py --from-strip src/vdi/font8x8.c $@
build/inv.fnt: tools/mkfnt.py build/st.fnt
python3 tools/mkfnt.py --invert build/st.fnt $@
build/lang.o: src/aes/lang.c src/aes/aes.h src/sys/cio.h src/sys/farmem.h src/vdi/font.h build/lang_rsc.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
build/fsel_rsc.c build/fsel_rsc.h: tools/fselrsc.py tools/rsc.py tools/aesref.py
@mkdir -p build
python3 tools/fselrsc.py build/fsel_rsc.c build/fsel_rsc.h
build/fsel_rsc.o: build/fsel_rsc.c
$(CC) $(CFLAGS) -o $@ $<
build/fsel.o: src/aes/fsel.c src/aes/aes.h src/sys/app.h src/sys/cio.h src/sys/dos.h src/sys/farmem.h build/fsel_rsc.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
build/shel.o: src/aes/shel.c src/aes/aes.h src/sys/app.h src/sys/cio.h src/sys/dos.h src/sys/farmem.h build/lang_rsc.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -I build -o $@ $<
# A .G4A program (src/app/*: the startup and the bindings, plus its own
# body) is linked three times -- at its placeholder addresses, with the
# near region up a page, with the far region up a bank -- so that
# tools/mkg4a.py can find every byte that depends on where it is loaded.
# $(call g4a,name,objects,near bss,near bits,stack,more mkg4a args,more targets)
# The stack is part of the near bss (src/app/gemapp.scm); its size is the
# linker's --stack-size, so the map shows what each application asked for.
# build/app/clib.o is src/sys/clib.c -- the same eight ISO C functions the
# engine uses, for the same reason: Calypsi's are Apache-2.0 and this is a
# GPLv2 tree (docs/licence.md). It is part of the LIBRARY and not of a
# program, so the kit ships it and anybody's application gets it.
G4A_LIB = build/app/crt_gemapp.o build/app/gemabi.o build/app/gemlib.o \
build/app/clib.o
# ...and the same three for an application compiled --data-model=large.
# The linker refuses to mix runtime models, so a large-data program needs
# a large-data library beside it and Calypsi's own clib-lc-ld.a rather
# than clib-lc-sd.a. The SOURCES are the same files: only the model
# differs (docs/gacs.md).
G4A_LIB_LD = build/appld/crt_gemapp.o build/appld/gemabi.o build/appld/gemlib.o \
build/appld/clib.o
LIB_LD = clib-lc-ld.a
build/app/clib.o: src/sys/clib.c
@mkdir -p build/app
$(CC) $(CFLAGS) -o $@ $<
build/appld/clib.o: src/sys/clib.c
@mkdir -p build/appld
$(CC) --code-model=large --data-model=large -O2 -I src -o $@ $<
build/appld/%.o: src/app/%.s
@mkdir -p build/appld
$(AS) -o $@ $<
build/appld/%.o: src/app/%.c src/app/gem.h
@mkdir -p build/appld
$(CC) --code-model=large --data-model=large -O2 -I src -I src/app -o $@ $<
# $(8), when given, is the runtime library: a --data-model=large program
# needs clib-lc-ld.a and the large-data half of the application library,
# because the linker refuses to mix runtime models.
#
# $(9) and $(10) are how many banks of CODE and of far VARIABLES the
# program wants, both one unless said otherwise -- which is every program
# here but m31_huge, and GACS's shell in the other repository, whose
# 102 KB of farcode and 119 KB of zfar are what made them parameters
# (src/app/gemapp.scm).
define g4a
build/$(1).elf: $(2) src/app/gemapp.scm
$$(LD) src/app/gemapp.scm $(2) $(if $(8),$(8),$$(LIB)) --rtattr exit=simplified --cstartup gemapp -o $$@ \
--list-file build/$(1).map --stack-size $(5) \
--memories-expression "(app-layout-n #x1000 #x020000 $(3) $(4) $(if $(9),$(9),1) $(if $(10),$(10),1))"
build/$(1)-near.elf: $(2) src/app/gemapp.scm
$$(LD) src/app/gemapp.scm $(2) $(if $(8),$(8),$$(LIB)) --rtattr exit=simplified --cstartup gemapp -o $$@ \
--stack-size $(5) --memories-expression "(app-layout-n #x1100 #x020000 $(3) $(4) $(if $(9),$(9),1) $(if $(10),$(10),1))"
build/$(1)-far.elf: $(2) src/app/gemapp.scm
$$(LD) src/app/gemapp.scm $(2) $(if $(8),$(8),$$(LIB)) --rtattr exit=simplified --cstartup gemapp -o $$@ \
--stack-size $(5) --memories-expression "(app-layout-n #x1000 #x030000 $(3) $(4) $(if $(9),$(9),1) $(if $(10),$(10),1))"
build/$(1).g4a build/$(1).sym $(7): build/$(1).elf build/$(1)-near.elf build/$(1)-far.elf tools/mkg4a.py
python3 tools/mkg4a.py build/$(1).elf build/$(1)-near.elf build/$(1)-far.elf \
build/$(1).g4a --syms build/$(1).sym $(6)
endef
build/app/%.o: src/app/%.s
@mkdir -p build/app
$(AS) -o $@ $<
build/app/%.o: src/app/%.c src/app/gem.h
@mkdir -p build/app
$(CC) $(CFLAGS) -I src/app -o $@ $<
build/app/%.o: src/%.c src/app/gem.h
@mkdir -p build/app
$(CC) $(CFLAGS) -I src/app -o $@ $<
# The gate application (src/m11_app.c). The .g4a is what a loader reads
# from disk; the C array is the same bytes for the runner to load from
# the image, there being no file layer yet.
$(eval $(call g4a,m11_app,$(APP_OBJS),$(APP_BSS),$(APP_BITS),$(APP_STACK),--c-array build/app_blob.c app_blob,build/app_blob.c))
build/app_blob.o: build/app_blob.c
$(CC) $(CFLAGS) -o $@ $<
# The gate accessory (src/m28_acc.c): a .G4A like any other program, on
# the disk with the extension the AES looks for. Its near region is the
# smallest of anything here -- it draws nothing and owns no window -- so
# what test-m28 measures is close to the floor an accessory costs.
ACC_OBJS = $(G4A_LIB) build/app/m28_acc.o
$(eval $(call g4a,m28_acc,$(ACC_OBJS),1152,128,384,,))
# The two accessories (src/apps): the first programs written to the
# application ABI that are not tests. Each is one C file, one resource
# built on the host, and the same three-way link every .g4a takes.
build/apps/%.o: src/apps/%.c src/app/gem.h build/calcrsc.h build/clockrsc.h
@mkdir -p build/apps
$(CC) $(CFLAGS) -I src/app -I build -o $@ $<
build/calc.rsc build/calcrsc.h: tools/calcrsc.py tools/rsc.py tools/aesref.py
@mkdir -p build
python3 tools/calcrsc.py build/calc.rsc build/calcrsc.h
build/clock.rsc build/clockrsc.h: tools/clockrsc.py tools/rsc.py tools/aesref.py
@mkdir -p build
python3 tools/clockrsc.py build/clock.rsc build/clockrsc.h
CALC_OBJS = $(G4A_LIB) build/apps/calc.o
CLOCK_OBJS = $(G4A_LIB) build/apps/clock.o build/apps/clockapp.o
$(eval $(call g4a,calc,$(CALC_OBJS),1536,256,512,,))
$(eval $(call g4a,clock,$(CLOCK_OBJS),1536,256,512,,))
# The clock AS AN ACCESSORY (src/apps/clockacc.c): the same clock.o, a
# different main, and the extension the AES looks for in the system's own
# directory. The reservations are what the map says it uses rather than
# round numbers, because an accessory is charged to the application pool
# for as long as the machine is on -- 14 KB for the desktop, its resource
# and everything resident beside it (docs/phase36.md).
CLOCKACC_OBJS = $(G4A_LIB) build/apps/clock.o build/apps/clockacc.o
$(eval $(call g4a,clockacc,$(CLOCKACC_OBJS),1152,128,384,,))
# The desktop (src/desk): a bigger near region than the gate application's,
# for the object trees a desktop keeps in bank $00, and DESKTOP.RSC beside
# it on the disk (tools/deskrsc.py; the icons from EmuTOS desk/icons.c
# through tools/iconconv.py, checked in like the font). The milestone-3
# desktop (src/m16_desk.c: a line of help, R/X/Q) stays as the stand-in
# test-m16 drives the shell loop with.
# The near region is 15 pages: the direct page, the bss, the constants.
# The bss holds the desktop's globals (GLOBES, src/desk/desk.h: the screen
# tree, the window nodes, the icon records, ~2 KB) and its stack, which
# is the gate application's 256 bytes and more: the folder window's open
# -- the button, do_open, do_dopen, do_wopen, a call to the AES on top --
# ran 256 bytes out (phase 14, milestone 5).
#
# 640 is the desktop's stack and the low-water mark says ~300 bytes of it
# are ever used; 2944 of bss is what the rest of it measures. For a
# while the stack was 896 and the bss 3200, because the honest numbers
# crashed -- which was never the desktop's doing: it is the emulator's
# SEI-shadow IRQ storm (tools/altirra/, patch 1), which paints the whole
# of bank $00, hardware registers and all, and which a couple of hundred
# bytes of layout anywhere is enough to trip or untrip. THAT IS WHY THE
# NUMBERS HERE ARE THE MEASURED ONES AND NOT A DODGE: a dodge lasts
# until the next thing that moves the code, which phase 27 demonstrated
# by moving the storm from m19 into m18. The desktop gates run against
# a patched emulator -- ALTIRRASDL=<build> -- and say so when they find
# the storm (tests/emu/m7_form.py storm_check). docs/phase26.md.
#
# The pool is shared with DESKTOP.RSC (6226 bytes) and with GEMDOS's
# work area (src/sys/gemdos.c), which is why the desktop gates run a
# runner whose staging leaves the pool the room GEM.COM leaves it
# (build/m3desk.xex, above).
DESK_OBJS = $(G4A_LIB) build/desk/desktop.o build/desk/deskobj.o build/desk/deskwin.o \
build/desk/deskfun.o
DESK_BSS = 2944
DESK_BITS = 512
DESK_STACK = 640
DESK_H = src/app/gem.h src/desk/desk.h build/deskrsc.h
build/desk/%.o: src/desk/%.c $(DESK_H)
@mkdir -p build/desk
$(CC) $(CFLAGS) -I src/app -I build -o $@ $<
$(eval $(call g4a,desktop,$(DESK_OBJS),$(DESK_BSS),$(DESK_BITS),$(DESK_STACK)))
$(eval $(call g4a,m16_desk,$(G4A_LIB) build/app/m16_desk.o,$(APP_BSS),$(APP_BITS),$(APP_STACK)))
# HELLO.G4A (src/hello_app.c): the desktop's hello-world demo, shipped in
# \APPS\ in place of the M11 gate app -- a real window a user can open and
# close, not a fixture that flashes and exits (tools/mkdist.py).
$(eval $(call g4a,hello_app,$(G4A_LIB) build/app/hello_app.o,$(APP_BSS),$(APP_BITS),$(APP_STACK)))
tools/deskicons.py: tools/iconconv.py
python3 tools/iconconv.py $(EMUTOS)/desk/icons.c $@
# VERSION is a prerequisite because the About box says it: 0.1.1 shipped
# with a resource built for 0.1, and the desktop gates found it a phase
# later, when the model (which reads VERSION) had every tree two bytes
# from where the stale file put it (docs/phase38.md).
build/desktop.rsc build/deskrsc.h: tools/deskrsc.py tools/rsc.py tools/aesref.py tools/deskicons.py VERSION
@mkdir -p build
python3 tools/deskrsc.py build/desktop.rsc build/deskrsc.h
# The GEM 8x8 system font, extracted from EmuTOS (GPL v2+) by fontconv.py.
# Checked in so the host reference reads the same bytes the target links.
build/font8x8.o: src/vdi/font8x8.c
@mkdir -p build
$(CC) $(CFLAGS) -o $@ $<
src/vdi/font8x8.c:
python3 tools/fontconv.py $(EMUTOS)/bios/fnt_st_8x8.c $@
# The standard fill patterns -- dithers, OEM patterns, hatches -- extracted
# from EmuTOS's vdi_fill.c by patconv.py, likewise checked in.
build/fillpat.o: src/vdi/fillpat.c src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
src/vdi/fillpat.c:
python3 tools/patconv.py $(EMUTOS)/vdi/vdi_fill.c $@
# The VDI's sine table, from EmuTOS's vdi_gdp.c by sinconv.py: the GDPs
# draw every curve out of it, and tools/vdiref.py reads the generated file
# so the reference and the driver cannot disagree about a circle.
build/sintbl.o: src/vdi/sintbl.c src/vdi/vdi.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
src/vdi/sintbl.c:
python3 tools/sinconv.py $(EMUTOS)/vdi/vdi_gdp.c $@
build/hello.elf: $(HELLO_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(HELLO_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/hello.map
build/m2.elf: $(M2_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(M2_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/m2.map
# _atari_entry, not __program_start: the stub must disable NMI/IRQ in emulation
# mode before the library startup's `xce`. See src/crt_atari.s.
build/hello.xex: build/hello.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry
build/m3.elf: $(M3_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(M3_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/m3.map
build/m2.xex: build/m2.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry
build/m25.elf: $(M25_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(M25_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/m25.map
build/m25.xex: build/m25.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry
build/m25-boot.atr: build/m25.xex
@test -n "$(SRC_DOS)" || { echo "no DOS fixture: set [dos].sd_dos2 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkdisk.py "$(SRC_DOS)" $< $@ M25.COM $(DISK_DENSITY)
build/m30.elf: $(M30_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(M30_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/m30.map
build/m30.xex: build/m30.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry
# The printer gate's disk (test-m30). SpartaDOS, not the DOS 2 floppy
# the other VDI milestones boot from, for one reason: the milestone
# WRITES, and a page in PostScript is 129 KB -- more than a DOS 2.5
# enhanced-density disk holds in total. 320 KB of SpartaDOS is where the
# two files fit, and it is the medium the product ships on anyway.
build/m30-boot.atr: build/m30.xex tools/mkspdisk.py tools/atr.py
@test -n "$(SRC_SP32)" || { echo "no SpartaDOS fixture: set [spartados].disk_32 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkspdisk.py "$(SRC_SP32)" $< $@ --name M30.COM $(SP_SECTORS)
build/m27.elf: $(M27_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(M27_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/m27.map
build/m27.xex: build/m27.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry --syms build/m27.sym
build/m24.elf: $(M24_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(M24_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/m24.map
build/m24.xex: build/m24.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry
build/gem.elf: $(GEM_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(GEM_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/gem.map \
--memories-expression "(layout #x010000 #x7fff)"
build/gem.xex: build/gem.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry --syms build/gem.sym
# GEMDIAG.COM: GEM.COM with a mark before every start-up step and the
# console keys bisecting the two things only Altirra has ever run
# (src/sys/diag.h) -- for a machine no emulator has been near. The same
# objects on the same layout; src/gem.c compiled once more with the marks
# in. Not part of any disk: it is copied next to GEM.COM by hand.
DIAG_OBJS = $(filter-out build/gem.o,$(GEM_OBJS)) build/gem_diag.o build/diag.o
build/gem_diag.o: src/gem.c src/sys/diag.h build/lang_rsc.h
@mkdir -p build
$(CC) $(CFLAGS) -DGEM_DIAG -I src -I build -o $@ $<
build/diag.o: src/sys/diag.c src/sys/diag.h src/sys/rapidus.h
@mkdir -p build
$(CC) $(CFLAGS) -I src -o $@ $<
build/gemdiag.elf: $(DIAG_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(DIAG_OBJS) -o $@ $(LIB) $(LDFLAGS) --list-file build/gemdiag.map \
--memories-expression "(layout #x010000 #x7fff)"
build/gemdiag.com: build/gemdiag.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry --syms build/gemdiag.sym
diag: build/gemdiag.com
# --syms lets the conformance harness find vdi_script by name instead of
# hard-coding an address that moves on every rebuild.
build/m3.xex: build/m3.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry --syms build/m3.sym
# The desktop gates' runner: the same code with the staging buffers cut
# to the few calls they stage (the prelude, the shell op, the pool
# probes) and the pool run up to where that staging starts, so the
# desktop and DESKTOP.RSC are loaded into a pool the size GEM.COM gives
# them rather than the conformance runner's half of the window. One
# object differs, so the link is the same list with it swapped in.
M3DESK_SIZES = -D SCRIPT_WORDS=128 -D SCRATCH_BYTES=512 -D MAX_RESULTS=24
M3DESK_OBJS = $(patsubst build/m3_vdi.o,build/m3desk_vdi.o,$(M3_OBJS))
build/m3desk_vdi.o: src/m3_vdi.c src/vbxe/vbxe.h src/vdi/vdi.h src/sys/irq.h src/sys/abi.h src/sys/app.h src/sys/cio.h src/sys/dos.h
@mkdir -p build
$(CC) $(CFLAGS) $(M3DESK_SIZES) -I src -o $@ $<
build/m3desk.elf: $(M3DESK_OBJS) src/gem4xe.scm
$(LD) src/gem4xe.scm $(M3DESK_OBJS) -o $@ $(LIB) $(LDFLAGS) \
--list-file build/m3desk.map \
--memories-expression "(layout #x010000 #x78ff)"
build/m3desk.xex: build/m3desk.elf
python3 tools/mkxex.py $< $@ --entry _atari_entry --syms build/m3desk.sym
# The runner outgrew a single-density disk (620 free sectors; the .xex
# alone wants more), so the fixture is converted to DOS 2.5 enhanced density
# on the way (tools/atr.py enhance()), and the program goes into the upper
# half FIRST -- the sectors a DOS 2.0 cannot reach -- so that every boot
# proves the fixture DOS reads them. The same disk build serves the small
# programs too: one disk format, not one that works until the file grows.
DISK_DENSITY = --enhanced --high
# The disk also carries what the file layer's gate reads back through CIO
# (tests/emu/m12_file.py): a text fixture and a resource file built on
# the host (tools/mkrsc.py), so rsrc_load has something to load. OUT.TXT
# is on it because the gate WRITES that name: the emulator's disk changes
# under the run while the image on the host does not, and the selector's
# listing is predicted from the image. A file that is already there is
# overwritten, so the directory the selector reads is the one the host
# read -- with the name on both sides rather than neither.
# NOT LANG.RSC. The runner's disks are what test-m12's file selector
# lists and what its far-heap accounting counts, and a tenth file
# overflows the selector's nine lines while the language resource in far
# memory moves the heap cursor by its own size -- both of which that gate
# measures. test-m20 makes its own copies of this disk with the file
# added, removed and translated, which is the point there; every other
# gate runs on the English linked into the image (src/aes/lang.c).
DISK_FILES = --add tests/fixtures/test.txt TEST.TXT --add build/test.rsc TEST.RSC \
--add tests/fixtures/out.txt OUT.TXT
# The applications the shell loop runs (docs/phase14.md, milestone 3): the
# desktop, and the gate application as the program the desktop launches.
# On the runner's disks for test-m16, on the product's because that is the
# product.
SHELL_FILES = --add build/m16_desk.g4a DESKTOP.G4A --add build/m11_app.g4a M11.G4A
SHELL_DEPS = build/m16_desk.g4a build/m11_app.g4a
DESK_FILES = --add build/desktop.g4a DESKTOP.G4A --add build/desktop.rsc DESKTOP.RSC \
--add build/m11_app.g4a M11.G4A
DESK_DEPS = build/desktop.g4a build/desktop.rsc build/m11_app.g4a
# The two accessories (src/apps), on the media with room for them: the
# SpartaDOS floppy, the CF card, and test-m22's own disk. A prerequisite
# list is expanded where it is written, so these live above every rule
# that names them.
# In a FOLDER, as the product has them: an application and its resource
# live together in \APPS\, and finding the resource from there is the
# thing test-m22 now covers (docs/phase29.md).
APP_FILES = --mkdir APPS \
--add build/calc.g4a "APPS>CALC.G4A" --add build/calc.rsc "APPS>CALC.RSC" \
--add build/clock.g4a "APPS>CLOCK.G4A" --add build/clock.rsc "APPS>CLOCK.RSC"
APP_DEPS = build/calc.g4a build/calc.rsc build/clock.g4a build/clock.rsc
# The gate accessory (src/m28_acc.c), in the system's own directory with
# the extension the AES looks for there: an accessory is not in \APPS\
# with the programs, because it is not one -- it is loaded once at
# start-up and outlives every program (src/aes/shel.c).
ACC_FILES = --add build/m28_acc.g4a M28.ACC
ACC_DEPS = build/m28_acc.g4a
# The accessory the PRODUCT ships: the clock, in the system's own
# directory rather than \APPS\, because an accessory is not a program the
# desktop launches -- the AES loads it once at start-up and it outlives
# every program (src/aes/shel.c).
ACCP_DEPS = build/clockacc.g4a build/clock.rsc
# The large-data gate application (src/m29_big.c): the ONE object in the
# tree compiled --data-model=large, which is the model GACS's engine and
# RetroWP's are written to (docs/gacs.md). Its own rule rather than the
# pattern rule, because $(CFLAGS) says small.
build/appld/m29_big.o: src/m29_big.c src/app/gem.h
@mkdir -p build/appld
$(CC) --code-model=large --data-model=large -O2 -I src -I src/app -o $@ $<
BIG_OBJS = $(G4A_LIB_LD) build/appld/m29_big.o
$(eval $(call g4a,m29_big,$(BIG_OBJS),1024,256,384,,,$(LIB_LD)))
# The application whose far IMAGE is bigger than a bank (src/m31_huge.c).
# Nothing in this tree had one until GACS's GEM shell was linked for this
# machine, so the .G4A's u16 far fixup offsets and app_load's 16-bit
# size_t both sat undisturbed -- and neither would have said so. Format 2
# and a chunked copy answer them; this is what proves it here rather than
# in another repository. Four blocks of far CONSTANTS, because only bytes
# that are in the file grow the image.
build/m31_data.c: tools/m31data.py
@mkdir -p build
python3 tools/m31data.py $@
build/app/m31_data.o: build/m31_data.c
@mkdir -p build/app
$(CC) --code-model=large --data-model=large -O2 -I src -o $@ $<
build/app/m31_huge.o: src/m31_huge.c src/app/gem.h
@mkdir -p build/app
$(CC) --code-model=large --data-model=large -O2 -I src -I src/app -o $@ $<
HUGE_OBJS = $(G4A_LIB_LD) build/app/m31_huge.o build/app/m31_data.o
$(eval $(call g4a,m31_huge,$(HUGE_OBJS),1024,256,384,,,$(LIB_LD),2,1))
build/test.rsc: tools/mkrsc.py tools/rsc.py tools/aesref.py
@mkdir -p build
python3 tools/mkrsc.py $@
# The selector's second drive: the fixture DOS disk with fifteen small
# files on it, D2: when test-m12 boots (tools/mkfsdisk.py).
build/m12-d2.atr: tools/mkfsdisk.py tools/atr.py
@test -n "$(SRC_DOS)" || { echo "no DOS fixture: set [dos].sd_dos2 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkfsdisk.py "$(SRC_DOS)" $@
# The runner's disk is DOUBLE density, and that is why the gates type an
# L before the name. The single-density fixture's DOS boots to a command
# prompt (nicer to drive) but its 1040 enhanced sectors held the runner
# with nothing to spare -- 117 KB of program on a 128 KB disk -- and the
# boot code it carries cannot read a double-density disk at all: written
# onto one, it stops at BOOT ERROR. The double-density fixture's DOS
# boots its own disk, gives the familiar DOS 2 menu, and leaves 190
# sectors free, so the runner has 48 KB to grow into. L is that menu's
# BINARY LOAD, and the file is called M3 with no extension so that the
# three keys after it are the ones every gate already typed.
# The shell gate (test-m16) runs on the SpartaDOS disk, whose size is
# ours to choose (tools/mkspdisk.py --sectors).
build/m3-boot.atr: build/m3.xex tests/fixtures/test.txt tests/fixtures/out.txt build/test.rsc
@test -n "$(SRC_DD)" || { echo "no double-density DOS fixture: set [dos].dd_dos2 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkdisk.py "$(SRC_DD)" $< $@ M3 --sweep $(DISK_FILES)
# The product disks: the system with the desktop beside it, one per DOS,
# and both of them boot into it with nothing typed.
#
# The DOS 2 one is DOUBLE density. Single density does not hold GEM.COM
# at all and enhanced holds it with three sectors to spare, which left no
# room for the DOS's own shell -- and a DOS with no shell to return to
# dies when GEM hands the machine back. 720 sectors of 253 bytes hold
# the system, DOS.SYS, DUP.SYS and the rest for applications, which is
# what makes the disk a place to keep them rather than one program.
# M11.G4A -- the demonstration program -- is NOT on this one: 180 KB is
# the tightest medium gem4xe ships on, and by the time the desktop could
# save a layout (phase 25) the demo was the difference between having
# room for somebody's own program and not. The SpartaDOS floppy and the
# CF card both carry it. The program
# is named AUTORUN.SYS because that is what the DOS runs at boot, and
# --sweep takes everything but the DOS off the fixture, which was
# somebody's magazine disk (docs/shipping.md, section 2).
build/816.com: tools/mk816.py
@mkdir -p build
python3 tools/mk816.py $@
# The DOS 2 floppy carries the SYSTEM and the clock accessory, and no
# applications: a DOS 2 disk has no directories, so \APPS\ cannot exist
# on it, and the calculator and the clock live on the install disk and
# the card (docs/shipping.md section 1). The system got a third smaller
# when its far image started travelling packed (tools/mkxex.py), which
# is what gave this disk its DOS shell back, the documented GEM4XE.CFG
# and the accessory, with a hundred-odd sectors left over --
# tests/emu/product_boot.py holds a floor of 80, so that the smallest
# disk is still somewhere a person can put a program of their own.
# GEM4XE.CFG as it ships: every setting commented out, so that finding
# the file is finding its documentation. Translated to the Atari's EOL
# ($9B) on the way to the disk -- src/sys/config.c reads CR, LF and EOL
# alike, but a file that a DOS editor opens should already be in the
# form that editor writes.
build/gem4xe.cfg: dist/gem4xe.cfg
@mkdir -p build
python3 -c "import sys; \
open(sys.argv[2],'wb').write(open(sys.argv[1],'rb').read() \
.replace(b'\r\n', b'\n').replace(b'\n', b'\x9b'))" $< $@
# ...and the safe-mode one the ANTIC gate boots with, which is the same
# file with the one line uncommented.
build/safe.cfg: dist/gem4xe.cfg
@mkdir -p build
python3 -c "import sys; \
open(sys.argv[2],'wb').write(open(sys.argv[1],'rb').read() \
.replace(b'# VIDEO=AUTO', b'VIDEO=ANTIC') \
.replace(b'\r\n', b'\n').replace(b'\n', b'\x9b'))" $< $@
# ...and the one test-cf-dosclock boots with: CLOCK=DOS, so that the
# SpartaDOS X kernel is the clock even on a machine that has the chip.
build/dosclock.cfg: dist/gem4xe.cfg
@mkdir -p build
python3 -c "import sys; \
open(sys.argv[2],'wb').write(open(sys.argv[1],'rb').read() \
.replace(b'# CLOCK=AUTO', b'CLOCK=DOS') \
.replace(b'\r\n', b'\n').replace(b'\n', b'\x9b'))" $< $@
# The DOS's own DUP.SYS stays: it is what GEM returns to when it quits.
# (It went, for a while, when the system outgrew the disk with the shell
# on it -- docs/shipping.md section 2 -- and came back with the packed
# far image.) The accessory is found in the directory GEM was started
# from, which on a DOS 2 disk is the only one there is.
DOS2_FILES = --add build/desktop.g4a DESKTOP.G4A --add build/desktop.rsc DESKTOP.RSC \
--add build/lang.rsc LANG.RSC --add build/816.com 816.COM \
--add build/clockacc.g4a CLOCK.ACC --add build/clock.rsc CLOCK.RSC
build/gem-boot.atr: build/gem.xex build/desktop.g4a build/desktop.rsc build/m11_app.g4a build/lang.rsc build/816.com build/gem4xe.cfg $(ACCP_DEPS)
@test -n "$(SRC_DD)" || { echo "no double-density DOS fixture: set [dos].dd_dos2 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkdisk.py "$(SRC_DD)" $< $@ AUTORUN.SYS --sweep \
$(DOS2_FILES) --add build/gem4xe.cfg GEM4XE.CFG
# The product's SpartaDOS floppy is an INSTALL disk: the same \GEM\ and
# \APPS\ layout the card has, so copying it onto an APT hard drive is a
# directory copy and not a decision, and none of the file layer's
# fixtures -- those belong on a gate's disk (--tree) and not on this one.
# The same shipped disk with the safe-mode line uncommented: what a user
# writes from the DOS prompt when the VBXE's output is not something
# their monitor will show (tests/emu/m26_fallback.py).
build/gem-antic.atr: build/gem.xex build/desktop.g4a build/desktop.rsc build/m11_app.g4a build/lang.rsc build/816.com build/safe.cfg $(ACCP_DEPS)
@test -n "$(SRC_DD)" || { echo "no double-density DOS fixture: set [dos].dd_dos2 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkdisk.py "$(SRC_DD)" $< $@ AUTORUN.SYS --sweep \
$(DOS2_FILES) --add build/safe.cfg GEM4XE.CFG
SP_LAYOUT = --name "GEM>GEM.COM" --boot "CD >GEM|GEM" --mkdir GEM --mkdir APPS \
--add build/desktop.g4a "GEM>DESKTOP.G4A" \
--add build/desktop.rsc "GEM>DESKTOP.RSC" \
--add build/lang.rsc "GEM>LANG.RSC" \
--add build/816.com "GEM>816.COM" \
--add build/gem4xe.cfg "GEM>GEM4XE.CFG" \
--add build/clockacc.g4a "GEM>CLOCK.ACC" \
--add build/clock.rsc "GEM>CLOCK.RSC" \
--add build/calc.g4a "APPS>CALC.G4A" --add build/calc.rsc "APPS>CALC.RSC" \
--add build/clock.g4a "APPS>CLOCK.G4A" --add build/clock.rsc "APPS>CLOCK.RSC"
SP_DEPS = build/gem.xex build/lang.rsc build/816.com build/gem4xe.cfg $(DESK_DEPS) $(APP_DEPS) $(ACCP_DEPS) tools/mkspdisk.py tools/atr.py
build/gem-sp.atr: $(SP_DEPS)
@test -n "$(SRC_SP32)" || { echo "no SpartaDOS fixture: set [spartados].disk_32 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkspdisk.py "$(SRC_SP32)" $< $@ $(SP_SECTORS) $(SP_LAYOUT) \
--add build/m11_app.g4a "APPS>M11.G4A"
# The same floppy without the gate program, for the pictures: \APPS\ is
# photographed, and M11.G4A is the tests' business, not the product's.
build/gem-shots.atr: $(SP_DEPS)
@test -n "$(SRC_SP32)" || { echo "no SpartaDOS fixture: set [spartados].disk_32 in fixtures.toml"; exit 1; }
@rm -f $@
python3 tools/mkspdisk.py "$(SRC_SP32)" $< $@ $(SP_SECTORS) $(SP_LAYOUT)
# The CF card: an APT table and two SDFS partitions, with the system in
# \GEM\ and the demonstration application in \APPS\ -- the install
# layout of docs/shipping.md section 4, on the volume it was written for.
# It needs no fixture: unlike a floppy, a card carries no DOS of its own,
# because SpartaDOS X boots from U1MB flash and the U1MB's PBI BIOS --
# from the same flash -- reads the APT table and mounts the partitions as
# D1: and D2: before any DOS runs. No SIDE.SYS, no driver on the card.
# tools/apt.py writes the table, tests/host/test_apt.py checks it against
# the rules Altirra's own parser applies, and test-cf boots it.
build/gem-cf.img: build/gem.xex build/desktop.g4a build/desktop.rsc build/hello_app.g4a \
build/lang.rsc build/gem4xe.cfg build/816.com $(APP_DEPS) $(ACCP_DEPS) tools/mkcf.py tools/apt.py tools/atr.py
@rm -f $@
python3 tools/mkcf.py $@
# The same card with CLOCK=DOS in its GEM4XE.CFG. The emulated U1MB and
# SIDE 2 both carry the chip, so on the card above the DOS is never
# asked; this one makes src/sys/clock.c ask it, which is what a machine
# with neither -- an Antonia and an IDE Plus 2 -- does on its own.
build/gem-cf-dosclock.img: build/gem-cf.img build/dosclock.cfg
@rm -f $@
python3 tools/mkcf.py $@ --cfg build/dosclock.cfg
# The same card in the shape an SD card takes in a SubCart or an AVGCART:
# a 64 MB FAT32 partition first (the cart's own browser reads it), the
# APT table and the two partitions after it. The cart's SIDE 2
# emulation hands the whole card to the U1MB's PBI BIOS, so the boot is
# test-cf's; test-sd runs it on this image. Needs mkfs.fat (dosfstools),
# so it is `make sd`, not part of `all`. GEMDIAG.COM rides along: the
# card is what goes to a real machine (docs/phase39.md).
sd: build/gem-sd.img
build/gem-sd.img: build/gem-cf.img build/gemdiag.com
@rm -f $@
python3 tools/mkcf.py $@ --fat 64 --add build/gemdiag.com "GEM>GEMDIAG.COM"
# The release floppy: the card's system partition on a double-sided