• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Implementing figFORTH on SH3 assembler


Commit MetaInfo

Revision9b5a66bd60ec110a45576f8b46600fa8b2a0dd70 (tree)
Time2014-03-07 14:01:56
AuthorJoel Matthew Rees <reiisi@user...>
CommiterJoel Matthew Rees

Log Message

Making sure stuff will work like it should, maybe?

Change Summary

Incremental Difference

--- a/context.inc
+++ b/context.inc
@@ -34,7 +34,8 @@
3434 .cpu sh3
3535
3636 NATURAL_SIZE: .equ 4 ; 4 byte word
37-ALL_BITS: .equ H'FFFFFFFF
37+ALIGN_MASK: .equ ( H'FF & ~(NATURAL_SIZE - 1) )
38+ALL_BITS8: .equ ( H'FF & -1 )
3839
3940
4041 ; The SH-3 has modern dev tools, so we don't have to pay much attention
@@ -94,12 +95,42 @@ fW: .reg r4 ; currently executing Word definition pointer
9495 ; we can save a lot of time during interrupt processing.
9596
9697
98+; Structure of the symbol table entry:
99+; Length byte of the symbol name (NFA)
100+; high bit set to flag the start byte
101+; next bit is MIMM
102+; next bit is MHID
103+; 5 bits of length, 0 really does mean zero.
104+; Length - 1 bytes of name, 7 bit characters. (Woe unto ye who use UTF-8, shift-JIS, etc.)
105+; Last byte, high bit set to flag the end byte.
106+; In alignment sensitive architectures, 0 to alignment - 1 padding. (SH3 has 0 to 3.)
107+; Link to the previous name in the vocabulary. (LFA)
108+; Link to the (machine language level) characteristic definition for the symbol table entry.
109+; With "low-level words", this just links to the code that follows. (CFA)
110+; Parameter field(s). (PFA)
111+; For "low-level words", this is machine code.
112+; For global constants and variables, this contains the value.
113+; For per-USER (task) constants and variables, the offset into
114+; the current per-USER table.
115+; For "high-level words", this is a list of virtual instruction pointers,
116+; in other words, pointers to the characterictics (CFA) of the symbols
117+; compiled into the definition.
118+;
119+
120+
97121 ; mode flags (to go with the length byte):
98-MIMM .equ H'40 ; precedence is IMMEDIATE execution (in length byte -- NFA)
99-MHID .equ H'20 ; SMUDGEd definition (in length byte -- NFA)
122+CTFLAG: .equ H'80 ; Count byte in dictionary has high bit set.
123+MIMM: .equ H'40 ; precedence is IMMEDIATE execution (in length byte -- NFA)
124+MHID: .equ H'20 ; SMUDGEd definition (in length byte -- NFA)
125+CTMASK: .equ ( H'FF & ~( CTFLAG | MIMM ) ) ; MHID hides SMUDGEd definitions this way.
126+; MHID limits length to 31
127+;
128+TAILFLAG: .equ H'80 ; Trailing character in dictionary has high bit set.
129+TAILMASK: .equ ( H'FF & ~TAILFLAG ) ; Expose the tail character.
130+
100131
101132
102-_LASTNAME: .assign 0 ; allocation/dictionary link (terminated by zero)
133+_PREVNAME: .assign 0 ; allocation/dictionary link (terminated by zero)
103134
104135 .macro HEADER name, characteristic, mode=0
105136 ; Symbol name length and mode (Too much stuff in one byte, really.)
@@ -111,10 +142,10 @@ _s\characteristic: .sdata .substr("\name", 0, .len("\name")-1)
111142 ; Symbol names float, yes this is a bit awkward.
112143 .align NATURAL_SIZE
113144 ; Link to previously defined symbol's header.
114- .data.l _LASTNAME
145+ .data.l _PREVNAME
115146 ; Use the SH-3 assembler to track the last symbol.
116147 ; (This is not always a good idea.)
117-_LASTNAME: .assign _s\characteristic
148+_PREVNAME: .assign _s\characteristic
118149 ; Point to the characteristic code for this Word (symbol) to execute.
119150 \characteristic .equ $
120151 .data.l _p\characteristic
@@ -143,3 +174,18 @@ exit\@:
143174 .endm
144175
145176
177+; Convenience macros:
178+; *** Use these instead of stealing code.
179+; Branch to address is limited to +- 4k,
180+; and stolen code is easy to lose track of.
181+; Or, maybe you can let an optimizer move the code more reliably for you!
182+
183+; See xPALIGN
184+; Immediate masks are only available for r0!
185+ .macro mALIGNr0
186+ add #NATURAL_SIZE-1, r0 ; Only works where NATURAL_SIZE is a power of 2.
187+ and #ALIGN_MASK, r0 ; SH3's NATURAL_SIZE is 4, or 2^2, so it works.
188+ .endm
189+
190+
191+
--- a/evaluator.inc
+++ b/evaluator.inc
@@ -11,6 +11,20 @@
1111 ;
1212 ; .section evaluator, code
1313
14+
15+; Not in the 6800 fig model, I've just re-factored it for fun.
16+; (ALIGN) ( ptr1 --- ptr2 )
17+; Adjust ptr1 to the nearest aligned address not lower.
18+; In other words, if ptr1 is aligned at a NATURAL_SIZE boundary, do nothing.
19+; Otherwise, adjust it up until it is aligned.
20+;
21+ HEADER ALIGN, xPALIGN
22+ mov.l @fSP, r0
23+ mALIGNr0
24+ rts
25+ mov.l r0, @fSP
26+
27+
1428
1529 ; It's tempting to put I in a dedicated register,
1630 ; but we don't want to optimize too early.
--- a/parser.inc
+++ b/parser.inc
@@ -23,14 +23,14 @@
2323 mov.b #"0", r1
2424 cmp/ge r1, r0 ; character (r0) >= "0"
2525 bf xDIGITno
26- add.l #-"0", r0
26+ add #-"0", r0
2727 mov.b #9, r1
2828 cmp/gt r1, r0 ; digit (r0) > 9
2929 bf xDIGITbase
3030 mov.b #"A"-"0", r1
3131 cmp/ge r1, r0 ; was it between "9" and "A"?
3232 bf xDIGITno
33- add.l #"9"-"A"+1, r0
33+ add #"9"-"A"+1, r0
3434 xDIGITbase:
3535 mov.l @fSP, r1
3636 cmp/ge r1, r0 ; digit (r0) >= base
@@ -42,10 +42,113 @@ xDIGITbase:
4242 ;
4343 xDIGITno:
4444 mov.b #0, r0
45- add.l #NATURAL_SIZE, fSP
45+ add #NATURAL_SIZE, fSP
4646 rts
4747 mov.l r0, @fSP ; set the flag on our way out
48-
49-
50-
48+
49+
50+; ENCLOSE ( buffer c --- buffer off1 off2 off3 )
51+; Scan buffer for a symbol delimited by c or ASCII NUL;
52+; return the offsets to the first character of the symbol,
53+; the last character of the symbol,
54+; and the next character after the symbol.
55+;
56+ HEADER ENCLOSE, xENCLOSE
57+ mov.l @fSP, r2 ; delimiter
58+ mov.b #0, r3 ; start the count at zero
59+ mov.l @(NATURAL_SIZE,fSP), r1
60+xENCLOSEloopwhite:
61+ mov.b @r1+, r0
62+ cmp/eq #0, r0 ; NUL character before symbol?
63+ bt xENCLOSEnone
64+ cmp/eq r2, r0 ; leading delimiter? (Usually SPACE.)
65+ bt xENCLOSEloopwhite
66+ add #1, r3 ; Count it as we go.
67+;
68+ add #-1, r3 ; Counted too far.
69+ mov.l r3, @fSP ; Save offset to symbol or NUL.
70+ add #-1, r1 ; Back up to what stopped us.
71+xENCLOSEloopword:
72+ cmp/eq #0, r0 ; NUL?
73+ bt xENCLOSEnul
74+ ****
75+ add #1, r3
76+ bra xENCLOSEloopword
77+ mov.l @r1+, r0
78+;
79+
80+; found NUL before non-delimiter, therefore there is no word
81+xENCLOSEnone:
82+ mov.l r3, @fSP
83+ add #1, r3
84+ mov.l r3, @-fSP
85+ add #-1, r3
86+ rts
87+ mov.l r3, @-fSP
88+; delimited by NUL
89+xENCLOSEnul:
90+ mov.l r3, @-fSP
91+ rts
92+ mov.l r3, @-fSP
93+
94+
95+
96+;* ######>> screen 20 <<
97+;* ======>> 12 <<
98+; FCB $87
99+; FCC 6,ENCLOSE
100+; FCB $C5
101+; FDB PFIND-9
102+;* NOTE :
103+;* FC means offset (bytes) to First Character of next word
104+;* EW " " to End of Word
105+;* NC " " to Next Character to start next enclose at
106+;ENCLOS FDB *+2
107+; INS
108+; PUL B now, get the low byte, for an 8-bit delimiter
109+; TSX
110+; LDX 0,X
111+; CLR N
112+;* wait for a non-delimiter or a NUL
113+;ENCL2 LDA A 0,X
114+; BEQ ENCL6
115+; CBA CHECK FOR DELIM
116+; BNE ENCL3
117+; INX
118+; INC N
119+; BRA ENCL2
120+;* found first character. Push FC
121+;ENCL3 LDA A N found first char.
122+; PSH A
123+; CLR A
124+; PSH A
125+;* wait for a delimiter or a NUL
126+;ENCL4 LDA A 0,X
127+; BEQ ENCL7
128+; CBA ckech for delim.
129+; BEQ ENCL5
130+; INX
131+; INC N
132+; BRA ENCL4
133+;* found EW. Push it
134+;ENCL5 LDA B N
135+; CLR A
136+; PSH B
137+; PSH A
138+;* advance and push NC
139+; INC B
140+; JMP PUSHBA
141+;
142+;ENCL6 LDA B N found NUL
143+; PSH B
144+; PSH A
145+; INC B
146+; BRA ENCL7+2
147+;* found NUL following the word instead of SPACE
148+;ENCL7 LDA B N
149+; PSH B save EW
150+; PSH A
151+;ENCL8 LDA B N save NC
152+; JMP PUSHBA
153+;
51154
--- a/primitive.inc
+++ b/primitive.inc
@@ -25,7 +25,7 @@ next:
2525 nop
2626 bra next
2727 nop
28-; Note that, since jumps to absolute addresses have limits on constant-width instruction sets,
28+; Note that, since jumps to absolute addresses have limits in constant-width instruction sets,
2929 ; using the subroutine call mode for the virtual machine is not as much a penalty as it might seem.
3030 ; It also has the advantage of being more compatible with more conventional code.
3131 ; Ways to make an absolute jump work might include
@@ -61,12 +61,12 @@ next:
6161
6262 ; BRANCH ( --- ) C
6363 ; Add the following word from the instruction stream to the
64-; instruction pointer (Y++). Causes a program branch.
64+; instruction pointer (postincrement). Causes a program branch.
6565 ;
6666 HEADER BRANCH, BRANCH
6767 mov.l @fIP+, r0
6868 BRANCHgo:
69- add.l r0, fIP
69+ add r0, fIP
7070 rts
7171 nop
7272
@@ -103,14 +103,14 @@ BRANCHgo:
103103 ;
104104 HEADER (LOOP), xLOOP
105105 mov.l @fRP, r0 ; I (loop counter)
106- add.l #1, r0
106+ add #1, r0
107107 mov.l r0, @fRP ; update I
108108 mov.l @(NATURAL_SIZE,fRP), r1 ; limit
109109 cmp/ge r1, r0 ; r0 >= r1 ?
110110 bf/s BRANCHgo ; not yet
111111 mov.l @fIP+, r0
112112 rts
113- add.l #2*NATURAL_SIZE, fRP
113+ add #2*NATURAL_SIZE, fRP
114114
115115
116116 ; (+LOOP) ( n --- ) ( limit index *** limit index+n ) C
@@ -124,7 +124,7 @@ BRANCHgo:
124124 HEADER (+LOOP), xPLOOP
125125 mov.l @fSP+, r1 ; increment
126126 mov.l @fRP, r0 ; I (loop counter)
127- add.l r1, r0
127+ add r1, r0
128128 mov.l r0, @fRP ; update I
129129 shal r1 ; increment negative or positive?
130130 bt/s xPLOOPminus
@@ -156,10 +156,10 @@ xPLOOPminus:
156156 HEADER (DO), xPDO
157157 mov.l @fSP+, r0
158158 mov.l @fSP+, r1
159- add.l #-2*NATURAL_SIZE, fRP
159+ add #-2*NATURAL_SIZE, fRP
160160 mov.l r1, @(NATURAL_SIZE,fRP)
161- mov.l r0, @fRP
162161 rts
162+ mov.l r0, @fRP
163163
164164
165165
--- a/symbol.inc
+++ b/symbol.inc
@@ -9,22 +9,115 @@
99 ; .include "context.inc"
1010 ;
1111 ; .section evaluator, code
12-
13-
14-; (FIND) ( name vocptr --- locptr f )
15-; Search vocabulary for a symbol called name. Name is a pointer
16-; to a NUL terminated string of characters without count, vocptr
17-; is a pointer to a pointer to a definition (the length byte of a
18-; symbol table entry). Locptr is also a pointer to a pointer to a
19-; definition, such that, if the flag is false, a symbol with the
20-; name searched for may be inserted in proper order at that point.
21-; Vocptr and locptr may point to either the right or left entry of
22-; the order-parent entry in the symbol table, or to pointer to the
23-; root of a vocabulary. HIDDEN (smudged) definitions are
24-; lexically less than their name strings. Searches only the local
25-; vocabulary, from the order-parent node passed. Uses (REFIND).
26-;
27-; vocptr is a pointer to the parameter field of a vocabulary
28-; header.
12+
13+
14+; Not in the 6800 fig model, I've just re-factored it for fun.
15+; (NAME-SCAN) ( ptr1 --- ptr2 )
16+; Scan ptr1 to a byte with the high bit set,
17+; leave ptr2 pointing to the next byte.
18+; Walks all over r0 and r1. Must leave fW untouched.
19+;
20+ HEADER (NAME-SCAN), xNAMESCAN
21+ mov.l @fSP, r1
22+ mov.b @r1+, r0
23+xNAMESCANloop:
24+ and #CTFLAG, r0
25+ cmp/eq #CTFLAG, r0
26+xNAMESCANstart:
27+ bf/s xNAMESCANloop
28+ mov.b @r1+, r0
29+;
30+ add #-1, r1
31+ mov r1, r0
32+ mALIGNr0
33+ rts
34+ mov.l r0, @fSP
35+
36+
37+
38+; Not in the 6800 fig model, I've just re-factored it for fun.
39+; (CHK-NAME) ( name nfa --- name link f )
40+; Compare a name in a buffer to a name in the symbol table.
41+; Leave an equality flag and a pointer to the link field for the next name.
42+; Names in the dictionary are terminated with the high bit set.
43+; (Names only save 3 significant characters in some FORTHs.)
44+; Walks all over r0 - r3. Must leave fW untouched.
45+;
46+ HEADER (CHK-NAME), xCHKNAME
47+ sts.l pr, @-fRP ; so we can call stuff
48+ mov.l @fSP, r2 ; name in dictionary
49+ mov.l @(NATURAL_SIZE, fSP), r3 ; name in buffer
50+ mov.b @r2+, r0 ; count byte in dictionary, plus flags
51+ and #CTMASK, r0 ; Extract the actual count.
52+ mov.b @r3+, r1 ; count byte in buffer
53+ cmp/eq r0, r1
54+ bf xCHKNAMEno
55+xCHKNAMEloop:
56+ mov.b @r2+, r0 ; character in dictionary
57+ tst #TAILFLAG, r0
58+ bt xCHKNAMElast
59+ mov.b @r3+, r1 ; character in buffer
60+ cmp/eq r0, r1
61+ bt xCHKNAMEloop
62+;
63+xCHKNAMEno:
64+ mov #0, r3 ; r3 is not touched by xNAMESCAN
65+xCHKNAMEret:
66+ bsr xNAMESCAN
67+ mov.l r2, @fSP ; save it as we go
68+ lds.l @fRP+, pr ; Gotta have that return address!
69+ rts
70+ mov.l r3, @-fSP ; flag it as we go
71+;
72+xCHKNAMElast:
73+ mov.b @r3+, r1 ; last character in buffer
74+ and #TAILMASK, r0
75+ cmp/eq r0, r1
76+ bf xCHKNAMEno
77+;
78+ bra xCHKNAMEret
79+ mov #ALL_BITS8, r3 ; Set the flag as we go.
80+
81+
82+; (FIND) ( name nfa --- pfa b tf )
83+; ( name nfa --- ff )
84+; Search vocabulary for a symbol called name.
85+; name is a pointer to a counted string.
86+; nfa is the NFA of the last entry in the vocabulary to be searched.
87+; Walks all over r0 - r3, and fW.
2988 ;
3089 HEADER (FIND), xPFIND
90+ sts.l pr, @-fRP ; so we can call stuff
91+ mov.l @fSP, r0
92+xPFINDloop:
93+ mov.b @r0, fW ; We aren't using fW anyway, and it doesn't get walked in.
94+ bsr xCHKNAME
95+ mov.l @fSP+, r0 ; Did we find it?
96+ cmp/eq #0, r0
97+ bf/s xPFINDfound ; Use the true flag in r0
98+ mov.l @fSP, r1 ; LFA needed either way
99+;
100+ mov.l @r1, r0
101+ cmp/eq #0, r0
102+ bt xPFINDnot
103+ bra xPFINDloop
104+ mov.l r0, @fSP ; Store the next one to check as we go.
105+;
106+xPFINDnot:
107+; mov #0, r0 ; use the NULL pointer as a false flag
108+ bra xPFINDret
109+ add #2*NATURAL_SIZE, fSP ; bump as we go
110+;
111+xPFINDfound:
112+ add #2*NATURAL_SIZE, r1 ; pfa
113+ mov.l r1, @(NATURAL_SIZE,fSP)
114+ mov.l fW, @fSP ; Store the saved count byte, with mode bits.
115+; mov #ALL_BITS8, r0 ; We can reuse the flag that sent us here.
116+xPFINDret:
117+ lds.l @fRP+, pr ; Gotta have that return address!
118+ rts
119+ mov.l r0, @-fSP ; Flag it as we go.
120+
121+
122+; *** Sometime check whether there are extra (unused) instructions in the 6800 code about here.
123+