1: \ numref.fs
2:
3: \ Copyright (C) 1998,2001,2003,2007 Free Software Foundation, Inc.
4:
5: \ This file is part of Gforth.
6:
7: \ Gforth is free software; you can redistribute it and/or
8: \ modify it under the terms of the GNU General Public License
9: \ as published by the Free Software Foundation, either version 3
10: \ of the License, or (at your option) any later version.
11:
12: \ This program is distributed in the hope that it will be useful,
13: \ but WITHOUT ANY WARRANTY; without even the implied warranty of
14: \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: \ GNU General Public License for more details.
16:
17: \ You should have received a copy of the GNU General Public License
18: \ along with this program. If not, see http://www.gnu.org/licenses/.
19:
20: 0 [IF]
21:
22: This is a generic solution for doing labels (forward and backward
23: references) in an assembler program.
24:
25: How to use local labels
26: =======================
27:
28: Example:
29:
30: Label 10pause
31: 10 # ldy,
32: 1 $: dey,
33: 1 $ bne,
34: rts,
35: End-Label
36:
37: "n $:" defines an address reference. "n $" returns the address of the
38: reference defined with "n $:".
39:
40:
41: How to embed local labels in your assembler
42: ===========================================
43:
44: At the moment all references are forward references, meaning all
45: references are resolved at the end of the definition.
46:
47: The Simple Resolver
48: -------------------
49:
50: The only special thing is how a label is resolved. Numref does this by
51: executing a resolver-word. For example, consider a two byte opcode
52: with the second byte as branch-offset. The resolver-word would look
53: like this:
54:
55: : doresolve ( iaddr -- )
56: dup ref-addr @ - swap 1+ X c! ;
57:
58: iaddr is the address of the instruction with the reference that must
59: be resolved. The destination address of the reference is stored at ref-addr.
60:
61: The resolver-word must be registered like this:
62:
63: "' doresolve TO std-resolver"
64:
65: This is not a deferred word!
66:
67: Complex Resolving
68: -----------------
69:
70: To support different cpu-instruction with different operand formats it
71: is possible to find out the type of opcode by accessing the target's
72: memory in doresolve. This works for very simple processors, e.g. for
73: 6502 it is very easy to find out whether we have a 2-byte absolute
74: address or a 1-byte relative address.
75:
76: If this method is too difficult, it is possible to store additional
77: information in the resolve structure.
78:
79: When assembling an opcode you should find out whether the address is a
80: reference and then store the xt of a special resolver word in the
81: resolve structure by "ref-resolver !", or store some additional data
82: in the resolve structure by "ref-data !", if one data field is not
83: enough, allocate memory and use ref-data as pointer to it.
84:
85: Internal structure
86: ==================
87:
88: There is a heap buffer to store the references. The structure of one
89: entry is:
90:
91: 1 cell ref-link
92: 1 cell ref-flag \ mixture of tag-number
93: \ and tag type
94: 1 cell ref-resolver \ xt of resolver
95: 1 cell ref-addr \ pointer to destination or on reference
96: \ instruction
97: \ (start of the instruction)
98: 1 cell ref-data \ additional information for resolver
99:
100: [THEN]
101:
102: require ./basic.fs
103:
104: also assembler definitions
105:
106: hex
107:
108: 0 value ref-marker \ tells us that address is an reference
109:
110: 0 value ref-now \ points to the reference we are working on
111:
112: : ref-link ref-now ;
113: : ref-flag ref-now cell+ ;
114: : ref-resolver ref-now 2 cells + ;
115: : ref-adr ref-now 3 cells + ;
116: : ref-addr ref-now 3 cells + ;
117: : ref-data ref-now 4 cells + ;
118: : ref-tag-len 5 cells ;
119:
120: : ref-resolve ref-resolver @ execute ;
121:
122: : ref? ( -- )
123: ref-marker
124: false TO ref-marker ;
125:
126: : forward? ( target-addr -- target-addr false | true )
127: dup there = ref? and dup
128: IF nip THEN ;
129:
130: :noname false TO ref-marker ; propper8 chained
131:
132: variable ref-heap 0 ref-heap !
133:
134: ' drop value std-resolver
135:
136: : ref! ( flags/nr -- )
137: \G stores a reference tag
138: \ get mem for tag
139: ref-tag-len allocate throw to ref-now
140: \ build link
141: ref-heap @ ref-link ! ref-link ref-heap !
142: there ref-adr !
143: std-resolver ref-resolver !
144: ref-flag ! ;
145:
146: : $ ( num -- address )
147: \G makes a reference source with the next instruction
148: 01ff and 0200 or ref! there ;
149:
150: : $: ( num -- )
151: \G makes a reference target
152: 01ff and 0a00 or ref! ;
153:
154: : g$: ( num -- )
155: \G makes a reference target for a global label
156: 01ff and 0e00 or ref! ;
157:
158: : g$ ( num -- addr )
159: \G searches a global label and gets its address
160: 01ff and 0e00 or
161: ref-heap BEGIN dup >r @ dup WHILE 2dup cell+ @ =
162: IF nip to ref-now
163: ref-link @ r> !
164: ref-adr @
165: ref-now free throw EXIT THEN
166: r> drop
167: REPEAT 2drop -1 ABORT" could not resolve G label!" ;
168:
169: : kill$: ( -- )
170: \G deallocs the complete reference heap
171: ref-heap @ BEGIN dup WHILE dup @ swap free throw REPEAT drop
172: 0 ref-heap ! ;
173:
174: : find$: ( adr nr -- )
175: 0800 or
176: ref-heap
177: BEGIN dup >r @ dup WHILE 2dup cell+ @ =
178: IF nip to ref-now
179: r> drop
180: ref-resolve EXIT
181: THEN
182: r> drop
183: REPEAT 2drop -1 ABORT" could not resolve label!" ;
184:
185: : solve$
186: ref-heap dup >r @
187: BEGIN dup WHILE dup cell+ @ 0E00 and 0200 =
188: IF to ref-now
189: ref-link @ r@ !
190: ref-now >r
191: ref-adr @ ref-flag @ ( 01ff and ) find$:
192: r> to ref-now
193: ref-link ( dup >r ) @
194: ref-now free throw
195: ELSE
196: r> drop
197: dup >r @
198: THEN
199: REPEAT r> drop drop kill$: ;
200:
201: ' solve$ end-code8 chained
202:
203: previous definitions
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>