aboutsummaryrefslogtreecommitdiff
path: root/xex.inc
blob: 184b2f9cfd3fe2d450f72d699a52f1d78f46c69e (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
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
; xex.inc - easy way to generate an atari 8-bit executable with ca65,
; without dealing with ca65's linker scripts and segments.
; see xex.rst (or xex.html) for full documentation.

 .macro xex_failtarget target
  .ifdef target
   .fatal "must assemble with '-t none'"
  .endif
 .endmacro

 xex_failtarget __APPLE2__
 xex_failtarget __APPLE2ENH__
 xex_failtarget __ATARI2600__
 xex_failtarget __ATARI5200__
 xex_failtarget __ATARI__
 xex_failtarget __ATARIXL__
 xex_failtarget __ATMOS__
 xex_failtarget __BBC__
 xex_failtarget __C128__
 xex_failtarget __C16__
 xex_failtarget __C64__
 xex_failtarget __CBM__
 xex_failtarget __CBM510__
 xex_failtarget __CBM610__
 xex_failtarget __CX16__
 xex_failtarget __GEOS__
 xex_failtarget __GEOS_APPLE__
 xex_failtarget __GEOS_CBM__
 xex_failtarget __LUNIX__
 xex_failtarget __LYNX__
 xex_failtarget __NES__
 xex_failtarget __OSIC1P__
 xex_failtarget __PET__
 xex_failtarget __PLUS4__
 xex_failtarget __SIM6502__
 xex_failtarget __SIM65C02__
 xex_failtarget __SUPERVISION__
 xex_failtarget __VIC20__

 .ifndef RUNAD
  .include "atari.inc"
 .endif

 .ifndef xex_verbose
  xex_verbose=1
 .endif

 .ifndef xex_warnings
  xex_warnings=1
 .endif

 xex_api_called .set 0
 xex_segcount .set 1
 xex_old_org .set -1

 .macro xex_vprint arg
  .if xex_verbose
   .out .concat("xex.inc: ",arg)
  .endif
 .endmacro

 .macro xex_warn arg
  .if xex_verbose
   .warning .concat("xex.inc: ",arg)
  .endif
 .endmacro

 .macro xexstart startaddr, endaddr
  .if xex_api_called = 0
   .fatal "xex.inc: don't call xexstart directly, use xex_org."
  .endif
  xex_api_called .set 0
  .if xex_old_org > -1
   xex_endseg
  .endif
  .org 0 ; can be anything really...
  .ifndef xex_ffff_emitted
   .byte $ff,$ff
   xex_ffff_emitted=1
   xex_vprint .sprintf("starting segment %d at $%04x (with ffff header)", xex_segcount, startaddr)
  .else
   xex_vprint .sprintf("starting segment %d at $%04x", xex_segcount, startaddr)
  .endif
  .word startaddr
  .word endaddr-1
  .org startaddr
  ; we don't need a label here really, but define it so it shows up in
  ; the VICE label file created by -Ln.
  .ident(.sprintf("xex_startaddr_%d", xex_segcount)):
  xex_segcount .set xex_segcount + 1
 .endmacro

 .macro xex_org startaddr,limit
  xex_api_called .set 1
  xexstart startaddr,.ident(.sprintf("xex_endaddr_%d", xex_segcount))
  xex_old_org .set startaddr
  .ifblank limit
   xex_limit .set $10000 ; impossibly high
  .else
   xex_limit .set limit
  .endif
 .endmacro

 .macro xex_endseg
  .local endaddr
  endaddr = * - 1
  .if xex_old_org < 0
   xex_warn "xex_endseg called when not in a segment; harmless but redundant."
   .exitmacro
  .endif
  .if endaddr < xex_old_org
   .fatal .sprintf("cannot create an empty segment (start $%04x, end $%04x)", xex_old_org, endaddr)
  .endif
  .ident(.sprintf("xex_endaddr_%d", xex_segcount-1)):
  xex_vprint .sprintf("  ending segment %d at $%04x, length $%04x", xex_segcount-1, endaddr, endaddr-xex_old_org+1)
  xex_old_org .set -1
  .assert .not (endaddr >= xex_limit), error, .sprintf("xex.inc: segment %d exceeds user-requested limit $%04x, by $%04x bytes", xex_segcount-1, xex_limit, endaddr - xex_limit + 1)
  xex_limit .set $10000
 .endmacro

 .macro xex_run runaddr
  xex_org RUNAD
  .word runaddr
  xex_endseg
  xex_vprint .sprintf("         run address: $%04x", runaddr)
  .ifndef xex_run_addr
   xex_run_addr .set runaddr
  .else
   xex_warn .sprintf("multiple run addresses (previous was $%04x)", xex_run_addr)
   xex_run_addr .set runaddr
  .endif
 .endmacro

 .macro xex_init initaddr
  xex_org INITAD
  .word initaddr
  xex_endseg
  xex_vprint .sprintf("        init address: $%04x", initaddr)
 .endmacro

 .macro xex_incbin addr, filename, offset, length
 .local o
 .ifblank offset
  o = 0
 .else
  o = offset
 .endif
  xex_org addr
  .ifblank length
   .incbin filename, o
  .else
   .incbin filename, o, length
  .endif
  xex_endseg
 .endmacro

 ;;; THIS DOESN'T WORK!
 .if 0
 .macro xex_include addr, filename
  xex_org addr
  .out .sprintf("before include %s: %04x", filename, *)
  .include filename
  .out .sprintf("after include: %04x", *)
  xex_endseg
 .endmacro
 .endif