summaryrefslogtreecommitdiff
path: root/frontends/calculator/CEdev/include/fasmg-ez80/ld.fasmg
blob: e7bdbf865c64197036e99224ca3685e93cceadb6 (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
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