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
|
assert "\"" = '"' ; check for patched fasmg
include 'tiformat.inc'
define ez80 ez80
namespace ez80
include 'ez80.inc'
end namespace
macro ?! $ : $ , \
$@ : $@ , \
$$ : $$ , \
and : and , \
assert : assert , \
at : at , \
break : break , \
define : define , \
defined : defined , \
dup : dup , \
else : else , \
emit : emit , \
end : end , \
equ : equ , \
err : err , \
esc : esc , \
ez80 : ez80 , \
from : from , \
if : if , \
include : include , \
irpv : irpv , \
iterate : iterate , \
label : label , \
lengthof : lengthof , \
load : load , \
local : local , \
macro : macro , \
match : match , \
mod : mod , \
namespace: namespace, \
not : not , \
or : or , \
purge : purge , \
rb : rb , \
repeat : repeat , \
restore : restore , \
restruc : restruc , \
rawmatch : rawmatch , \
segment : segment , \
shl : shl , \
shr : shr , \
store : store , \
struc : struc , \
used : used , \
virtual : virtual , \
while : while , \
xor : xor
local global, debug, files, segments, hex, output
global equ
segments equ
restore global, segments
macro files.libs.parse file, offset, isused, anyused*
local private
namespace private
macro library?! name, version*
end if
if anyused
emit 1: $C0, name, 0, version
end if
if 0
end macro
iterate each, export, export_pointer
macro each?! function*
end if
namespace ez80
if used global._#function
isused = 1
global._#function := $ + %-1
jp offset
virtual
local name
emit 1: '_', `function
load name: $ - $$ from $$
global equ name = global._#function
end virtual
end if
offset = offset + word + @ez80.il
end namespace
if 0
end macro
end iterate
if 0
esc include! file
end if
end namespace
end macro
macro files.libs.handle file, isused*
local offset, anyused
offset = 0
files.libs.parse file, offset, isused, anyused
anyused := isused
end macro
macro files.srcs.check file, isused*
local private
namespace private
iterate name, DEF, GLOBAL, PUBLIC, XDEF
iterate style, name, .name
macro style?! symbols*&
end if
iterate symbol, symbols
if used global.symbol
isused = 1
end if
end iterate
if 0
end macro
end iterate
end iterate
if 0
esc include! file
end if
end namespace
end macro
macro files.srcs.parse file*
local private
namespace private
virtual segments.code.area
?$ equ $
?XOR? equ xor
?AND? equ and
?OR? equ or
?SHL? equ shl
?SHR? equ shr
?NOT? equ not
iterate name, LIST, NEWPAGE, NOLIST, PAGE
macro name?
end macro
end iterate
iterate name, CPU, TITLE
macro name? arg*
end macro
end iterate
iterate name, COPY, INCLUDE
macro name?! path*
include path
end macro
end iterate
iterate name, EXTERN, EXTERNAL, REF, XREF
macro name? symbols*&
match list : space, symbols
iterate symbol, list
symbol := global.symbol
end iterate
else
iterate symbol, symbols
symbol := global.symbol
end iterate
end match
end macro
end iterate
iterate name, DEF, GLOBAL, PUBLIC, XDEF
macro name? symbols*&
iterate symbol, symbols
global.symbol := symbol
virtual
local name
emit 1: `symbol
load name: $ - $$ from $$
global equ name = global.symbol
end virtual
end iterate
end macro
end iterate
struc (symbol) EQU? expr*
local error
if ~defined error & defined symbol | error
err 'Symbol "', `symbol, '" already defined'
error = 1
else
error = 0
end if
?symbol = expr
end struc
iterate name, VAR, SET
struc (symbol) name? expr*
?symbol = expr
end struc
end iterate
macro DS? count
local c
c = count
rb c
end macro
struc DS? count
.: DS? count
end struc
iterate <def,blk,size*>, B,B,1, W,W,2, W24,P,3, L,L,4
macro D#def? vals*&
local v
iterate val, vals
v = val
emit size: v
end iterate
end macro
macro BLK#blk? count*, init
local c, i
c = count
match, init
emit size: c dup ?
else
i = init
emit size: c dup i
end match
end macro
iterate name, D#def, BLK#blk
struc name? args&
.: name? args
end struc
end iterate
end iterate
iterate <name,alias*>, TRIO,DW24, DF,DL
macro name? vals*&
alias? vals
end macro
struc name? args&
.: name? args
end struc
end iterate
macro ALIGN? val*
local v
v = val
rb v-1 - ($ + v-1) mod v
end macro
macro SEGMENT? name*
segment name
end macro
macro ASSUME? expr*
namespace ez80
assume? expr
end namespace
end macro
iterate register, B, NZ, Z, NC, C, PO, PE, P, M, D, E, \
H, IXH, IYH, L, IXL, IYL, F, A, I, R, \
MB, BC, DE, HL, IX, IY, SP, AF, AF'
register? := ez80.register?
end iterate
iterate suffix, , .s?, .l?, .is?, .il?, .sis?, .sil?, .lis?, .lil?
irpv name, ez80.@ez80.oplist
rawmatch rawname, name
define rawname rawname
macro rawname#suffix args&
namespace ez80
name#suffix args
end namespace
end macro
end rawmatch
end irpv
macro LD? d, s*
namespace ez80
@ez80.classify dst, dstind, d
@ez80.classify src, srcind, s
if ~dstind & dst eq dst element 1 & dst @ez80.is_reg @ez80.wreg \
& dst metadata 1 scale 1 and 001o & ~srcind \
& src relativeto src element 1 & src @ez80.is_reg @ez80.wreg
if src metadata 1 scale 1 = 007o
PUSH? s
POP? d
else
LEA? d, s
end if
else
LD? d, s
end if
end namespace
end macro
macro JR?#suffix args&
namespace ez80
jq?#suffix args
end namespace
end macro
end iterate
iterate <name,carry>, UEXT,<OR? A?,A>, SEXT,RLA
macro name? reg*
carry?
SBC? reg, reg
end macro
end iterate
macro COMMENT?! delim*&
end match
local inside
inside = 0
macro ?! line&
local length, text
length = 0
if inside
length = lengthof `line
text = `line
else if `line = 'end match'
inside = 1
length = lengthof `delim - 1
text = `delim shr 8
end if
repeat length
if ~text xor `delim and $FF
purge ?
break
end if
text = text shr 8
end repeat
end macro
end macro
if defined debug
debug.enabled = 0
debug.startAddr = $
iterate name, ALIAS, BASE, DEFINE, ENDREC, SPACE, TAG
macro name? str1*
if debug.enabled
virtual debug
debug.uleb128 debug.name
debug.string str1
end virtual
end if
end macro
end iterate
iterate name, BEGFUNC, ENDFUNC
macro name? str1, num1, str2*
if debug.enabled
local line, addr
line = num1
addr = $
virtual debug
debug.uleb128 debug.name
debug.string str1, str2
debug.uleb128 line - debug.line, addr - debug.addr
end virtual
debug.line = line
debug.addr = addr
end if
end macro
end iterate
macro BEGREC? str1, num1*
if debug.enabled
virtual debug
debug.uleb128 debug.BEGREC
debug.string str1
debug.uleb128 num1
end virtual
end if
end macro
iterate <name,signed>, CLASS,u, DIM,u, LENGTH,u, REG,u, SIZE,u, TYPE,s, VALUE,s
macro name? num1*
if debug.enabled
virtual debug
debug.uleb128 debug.name
debug.signed#leb128 num1
end virtual
end if
end macro
end iterate
macro DEBUG? str1*
virtual debug
debug.uleb128 debug.FILE, lengthof debug.source
emit 1: debug.source
debug.uleb128 debug.startAddr - debug.addr, debug.DEBUG
debug.string str1
end virtual
debug.enabled = 1
debug.line = 0
debug.addr = debug.startAddr
end macro
macro END?!
end if
if debug.enabled
local addr
segment code
addr = $
virtual debug
debug.uleb128 debug.END, addr - debug.addr
end virtual
debug.addr = addr
end if
if 0
end macro
macro ENDEF?
if debug.enabled
virtual debug
debug.uleb128 debug.ENDEF
end virtual
end if
end macro
macro FILE? str1*
debug.source = str1
end macro
macro LINE? num1*
local line, addr
line = num1
addr = $
if line <> debug.line | addr <> debug.addr & debug.enabled
virtual debug
debug.uleb128 debug.LINE, line - debug.line, addr - debug.addr
end virtual
debug.line = line
debug.addr = addr
end if
end macro
else
iterate name, ALIAS, BASE, BEGFUNC, BEGREC, CLASS, DEBUG, \
DEFINE, DIM, ENDEF, ENDFUNC, ENDREC, FILE, \
LENGTH, LINE, REG, SIZE, SPACE, TAG, TYPE, VALUE
macro name? args&
end macro
end iterate
macro END?!
end if
if 0
end macro
end if
struc ? def::&
. def
end struc
macro ? line&
match .rest, line
rest
else match first= .rest, line
first rest
else
line
end match
end macro
if 1
include file
end if
purge ?
restruc ?
end virtual
end namespace
end macro
macro files.srcs.handle file, isused*
if ~isused
files.srcs.check file, isused
end if
if isused
files.srcs.parse file
end if
end macro
macro symbol? args*&
iterate arg, args
rawmatch symbol == value, arg
namespace segments
global.symbol := value
virtual
local name
emit 1: `symbol
load name: $ - $$ from $$
global equ = name global.symbol
end virtual
end namespace
else
'Syntax error in symbol arguments'
end rawmatch
end iterate
end macro
iterate name, srcs, libs
macro files.name.add file, used*
local isused
rawmatch rawused, used
namespace segments
isused = rawused
end namespace
end rawmatch
if `file and $FF = "'"
files.name equ file, isused
else
files.name equ `file, isused
end if
end macro
macro name? args*&
local require
iterate arg, args
match file= =used? =if?= used, arg
files.name.add file, used
else match file= =used?, arg
files.name.add file, 1
else
files.name.add arg, 0
end match
end iterate
end macro
end iterate
macro locate? args*&
iterate arg, args
rawmatch name =at? location, arg
segments equ segments.name?
namespace segments
name? := `name
name.base? := location
end namespace
else
err 'Syntax error in locate argument'
end rawmatch
end iterate
end macro
macro range? args*&
iterate arg, args
rawmatch name lower : upper, arg
locate name at lower
namespace segments
name.high? := upper
end namespace
else
err 'Syntax error in range arguments'
end rawmatch
end iterate
end macro
macro order?: args*&
match first =, second =, rest, args
order first, second
order second, rest
else match first =, second, args
locate second at first.base + first.length
else
err 'Not enough order arguments'
end match
end macro
macro merge? args*&
match name == list, args
order list
iterate segment, list
locate name at segment.base
indx %%
namespace segments
name.top? := segment.base + segment.length
if defined segment.high
name.high? := segment.high
end if
end namespace
break
end iterate
else
err 'Syntax error in merge arguments'
end match
end macro
macro hex value*, leading: '0', digits: 6
local val, zero, digit, char
emit 1: ' '
val = value
zero = leading
repeat digits
digit = (val shr ((%% - %) shl 2)) and 0Fh
if digit < 10
char = '0' + digit
else
char = 'A' + digit - 10
end if
if digit
zero = '0'
else if % <> %%
char = zero
end if
emit 1: char
end repeat
end macro
macro map?
local longest, name
postpone ?
virtual as 'map'
longest = lengthof "Segment"
irpv segment, segments
if longest < lengthof segment
longest = lengthof segment
end if
end irpv
emit 1: "Segment", longest - lengthof "Segment" + 1 dup ' ', "Base Top High Length", 10, longest dup '-', 4 dup " ------", '-', 10
irpv segment, segments
namespace segment
if longest < lengthof segment
longest = lengthof segment
end if
emit 1: segment, longest - lengthof segment dup ' '
hex base
hex top
if defined high
hex high
else
emit 1: 7 dup ' '
end if
hex length, ' '
emit 1: 'h', 10
end namespace
end irpv
match any, global
longest = lengthof "Label"
irpv symbol, global
match name == value, symbol
if longest < lengthof name
longest = lengthof name
end if
end match
end irpv
emit 1: 10, "Label", longest - lengthof "Label" + 3 dup ' ', "Value", 10, longest dup '-', 3 dup ' ', 6 dup '-', 10
irpv symbol, global
match name == value, symbol
emit 1: name, longest - lengthof name + 1 dup ' ', '='
hex value
emit 1: 10
end match
end irpv
end match
end virtual
end postpone
end macro
macro dbg?
virtual as 'dbg'
debug::
end virtual
namespace debug
virtual at 0
iterate name, EOF, ALIAS, BASE, BEGFUNC, BEGREC, CLASS, DEBUG, DEFINE, \
DIM, END, ENDEF, ENDFUNC, ENDREC, FILE, LENGTH, LINE, \
REG, SIZE, SPACE, STRINGS, TAG, TYPE, VALUE
name rb 1
end iterate
end virtual
line = 0
addr = 0
macro uleb128 values*&
iterate value, values
local val
val = value
assert val >= 0
while val shr 7 > 0
emit 1: val and 07Fh or 080h
val = val shr 7
end while
emit 1: val
end iterate
end macro
macro sleb128 values*&
iterate value, values
local val
val = value
while val shr 6 <> 0 & val shr 6 <> -1
emit 1: val and 07Fh or 080h
val = val shr 7
end while
emit 1: val and 07Fh
end iterate
end macro
restore strings
macro string values*&
iterate value, values
local count, unfound
count = 0
unfound = 1
irpv each, debug.strings
if each = value
unfound = 0
debug.uleb128 %
break
end if
count = %%
end irpv
if unfound
debug.uleb128 count + 1
debug.strings =: value
end if
end iterate
end macro
end namespace
end macro
macro segment name*
end virtual
virtual segments.name.area
end macro
if ~defined segments
err 'No segments defined'
else
restore output.base, output.top ; forbid forward reference
irpv segment, segments
namespace segment
virtual at base
area?::
end virtual
if ~defined output.base | output.base > base & ~defined high
output.base = base
end if
end namespace
end irpv
irpv file, files.srcs
files = 0
files.srcs.handle file
end irpv
if ~defined files
err 'Please pass the input files with -i\'srcs "file1" [if require1], "file2" [if require2], ...\''
end if
irpv file, files.libs
virtual segments.libs.area
files.libs.handle file
end virtual
end irpv
if defined debug
virtual debug
if defined debug.strings
debug.uleb128 debug.STRINGS
irpv string, debug.strings
if % = 1
debug.uleb128 %%
end if
debug.uleb128 lengthof string
emit 1: string
end irpv
end if
debug.uleb128 debug.EOF
end virtual
end if
irpv segment, segments
namespace segment
virtual area
top? := $
length? := $ - $$
initlen? := $@ - $$
end virtual
if ~defined high
if ~defined output.top | output.top < top
output.top = top
end if
else if top > high
repeat 1, len: length, over: top - high, max: high - base
err 'Segment ', segment, ' is ', `len, ' bytes, ', \
`over, ' bytes larger than the maximum of ', \
`max, ' bytes'
end repeat
end if
end namespace
end irpv
org output.base
rb output.top - $
postpone ?
irpv segment, segments
namespace segment
if ~defined high
load output: initlen from area: base
store output: initlen at base
end if
end namespace
end irpv
end postpone
end if
purge ?
end macro
|