Implementing figFORTH on SH3 assembler
Revisión | ceaa83536f598f3acf6f1870a131adc21a6c8eda (tree) |
---|---|
Tiempo | 2014-03-13 19:27:33 |
Autor | Joel Matthew Rees <reiisi@user...> |
Commiter | Joel Matthew Rees |
Mostly work on the memory map, getting the various allocation regions defined and bounded for testing.
@@ -33,8 +33,12 @@ | ||
33 | 33 | |
34 | 34 | .cpu sh3 |
35 | 35 | |
36 | -; For huge things, like U/ (USLASH) might be cut in half and repeated or something. | |
37 | -PRIORITY_SIZE: .DEFINE "1" | |
36 | +; For huge things, like U/ (USLASH), | |
37 | +; which might be cut in half and repeated or something. But probably not. | |
38 | +; PRIORITY_SIZE: .DEFINE "1" | |
39 | + | |
40 | +; Uncomment this if building for ROM: | |
41 | +; BUILD_FOR_ROM: .DEFINE "1" | |
38 | 42 | |
39 | 43 | ; Comment this out when all forward references are resolved, |
40 | 44 | ; and test stuff is no longer needed. |
@@ -94,13 +98,26 @@ BYTE_hHI_bHI: .equ MSBYTEinNAT | ||
94 | 98 | ; ****************************************************************************** |
95 | 99 | |
96 | 100 | |
101 | +; ****************************************************************************** | |
102 | +; Setting up the overall memory map: | |
103 | +; | |
97 | 104 | ; The SH-3 has modern dev tools, so we don't have to pay much attention |
98 | -; to memory layout, | |
99 | -; but we do want to keep the following virtual map in mind: | |
100 | - | |
105 | +; to memory layout. | |
106 | +; | |
107 | +; But we do need a map to work with. | |
108 | +; | |
109 | +; By tradition, the start of object code contained jumps to the initialization code: | |
110 | +; COLD entry point (4 byte jump) and | |
111 | +; WARM entry point (4 byte jump), followed by the | |
112 | +; Init constants table (about 20 natural-width entries). | |
113 | +; | |
114 | +; The init constants would be followed by the dictionary, | |
115 | +; usually starting with the inner interpreter, | |
116 | +; and proceeding to higher-level stuff: | |
117 | +; | |
101 | 118 | ; ------------ |
102 | 119 | ; low address: |
103 | -; JMP to start (But, no. Handled through the reset code.) | |
120 | +; JMP to start (But maybe handled through the reset code?) | |
104 | 121 | ; |
105 | 122 | ; Global constants table |
106 | 123 | ; |
@@ -118,7 +135,116 @@ BYTE_hHI_bHI: .equ MSBYTEinNAT | ||
118 | 135 | ; |
119 | 136 | ; high address of ROMmable part |
120 | 137 | ; ----------------------------- |
138 | +; | |
139 | +; If the object were ROMmable, at the end of the object code (ROM image) | |
140 | +; there would be a non-linked definition of "FORTH" | |
141 | +; to be copied to RAM, and the RAM part of the dictionary would link to that. | |
142 | +; | |
143 | +; In modern processors, ROM can be placed above or below RAM, | |
144 | +; so we shouldn't concern ourselves too much about where it is | |
145 | +; (or even what the map looks like within it). | |
146 | +; | |
147 | +; What concerns us is the RAM map, which is traditionally not well defined. | |
148 | +; | |
149 | +; These are the large areas of memory which we need to specify allocation for: | |
150 | +; | |
151 | +; ------------------------------------------------------------------------------ | |
152 | +; Prebuilt dictionary (potentially ROMmable). | |
153 | +; | |
154 | +; Run-time dictionary (starts with the "FORTH" entry). | |
155 | +; The un-allocated area of the run-time dictionary | |
156 | +; is used as a general purpose text buffer. | |
157 | +; | |
158 | +; Parameter stack. | |
159 | +; fig-FORTH had this growing down towards the dictionary, | |
160 | +; which we now know is an invitation for attacks. | |
161 | +; | |
162 | +; Terminal line input buffer. | |
163 | +; | |
164 | +; Return, or flow-of-control stack. | |
165 | +; fig-FORTH had this growing down toward the input buffer, | |
166 | +; which, again, we now know is a recipe for vulnerabilities. | |
167 | +; | |
168 | +; Per-USER variable table(s). | |
169 | +; | |
170 | +; Disk buffers. | |
171 | +; | |
172 | +; ****************************************************************************** | |
173 | +; The 6800 model modified the map to match customary memory use on the 6800: | |
174 | +; | |
175 | +; The bottom 128 bytes or so of memory in a 6800 were generally RAM, | |
176 | +; because of the direct-page fast-addressing mode. | |
177 | +; (ROM at the bottom might have made more sense, | |
178 | +; to deal with small integers mistakenly used as pointers.) | |
179 | +; | |
180 | +; From 0x80 to 0xff was also in the direct page range, | |
181 | +; but might be ROM, for fast access to constants. | |
182 | +; (And, beginning with the 6801, IIRC, heavily used routines.) | |
183 | +; | |
184 | +; From 0x100 to 0x1000 might not be populated, or might have RAM. | |
185 | +; | |
186 | +; The very top of memory, 0xF000 to 0xFFFF, was often populated | |
187 | +; with a monitor (debug/BIOS) ROM, to allow the reset and interupt vectors | |
188 | +; to be easily read out of ROM. | |
189 | +; | |
190 | +; The 6800 fig-FORTH model used the following map: | |
191 | +; | |
192 | +; ------------------------------------------------------------------------------ | |
193 | +; | |
194 | +; 0x00E0: Scratch pad RAM (substitute for CPU temporary registers). | |
195 | +; 0x00F0: The virtual machine registers (IP, SP, RP, W). | |
196 | +; ... | |
197 | +; 0x0100: Run-time dictionary | |
198 | +; ... | |
199 | +; Parameter stack | |
200 | +; 0x0F30: Terminal input buffer | |
201 | +; ... | |
202 | +; Return stack | |
203 | +; 0x1000: Pre-built (ROMmable) dictionary | |
204 | +; Including COLD and WARM entry jumps and initialization table at the front. | |
205 | +; ... | |
206 | +; 0x3000: disk buffers (4*128) | |
207 | +; ... | |
208 | +; 0x3210: RAM disk (very small) | |
209 | +; ... | |
210 | +; 0x3FFF: End of RAM | |
211 | +; | |
212 | +; So, .... | |
213 | +; | |
214 | +; ****************************************************************************** | |
215 | +; Some general limits to build within: | |
216 | + | |
217 | +; Small while debugging, so we don't have to hunt too far. | |
218 | +RUNTIME_DICTIONARY_SIZE: .equ h'1000 | |
219 | + | |
220 | +; Small while debugging, so we don't have to hunt too far. | |
221 | +PARAMETER_STACK_SIZE: .equ h'60 | |
121 | 222 | |
223 | +; Keep it small while debugging. | |
224 | +CONTROL_STACK_SIZE: .equ h'60 | |
225 | + | |
226 | +; Something to help avoid things bumping into things. | |
227 | +ALLOC_GAP: .equ h'10 | |
228 | + | |
229 | +; This can be bigger later. | |
230 | +TERMINAL_INPUT_BUFFER_SIZE: .equ h'100 | |
231 | + | |
232 | +; Well, maybe we'll get this far some day. | |
233 | +N_USERS: .equ 8 | |
234 | + | |
235 | +; This can be bigger later, too. | |
236 | +DISK_BUFFER_SIZE: .equ h'100 | |
237 | +DISK_BUFFER_RECORD_SIZE: .equ 2*NATURAL_SIZE+DISK_BUFFER_SIZE | |
238 | +DISK_BUFFER_COUNT: .equ 4 | |
239 | + | |
240 | +; RAM disk could be useful | |
241 | +; even after the full system is running with real (flash?) disks. | |
242 | +; So could a "ROM" disk with initial error messages. Maybe. Hmm. Anyway. | |
243 | +RAM_DISK_SIZE: .equ h'8000 | |
244 | + | |
245 | + | |
246 | +; ****************************************************************************** | |
247 | +; Mapping the virtual machine registers: | |
122 | 248 | |
123 | 249 | ; r0 must be used for many intermediate values. |
124 | 250 | ; r0 -- r7 are bank-switched on interrupt. |
@@ -146,11 +272,12 @@ fIP: .reg r5 ; virtual Instruction Pointer | ||
146 | 272 | ; Defined symbols (objects/routines) are called "WORDs" in classic FORTH. |
147 | 273 | fW: .reg r4 ; currently executing Word definition pointer |
148 | 274 | ; |
149 | -; By keeping the FORTH model in registers | |
150 | -; that the SH3 bank-switches out during interrupts, | |
275 | +; By keeping the FORTH model in banked registers | |
276 | +; that the SH3 switches out during interrupts, | |
151 | 277 | ; we can save a lot of time during interrupt processing. |
152 | 278 | |
153 | 279 | |
280 | +; ****************************************************************************** | |
154 | 281 | ; Structure of the per-USER variables table: |
155 | 282 | .section usertable, dummy |
156 | 283 | .org 0 |
@@ -215,7 +342,6 @@ IOSTAT: .equ $-UORIG | ||
215 | 342 | UTABLESZ: .equ $-UORIG |
216 | 343 | |
217 | 344 | |
218 | - | |
219 | 345 | ; Structure of the symbol table entry: |
220 | 346 | ; Length byte of the symbol name (NFA) |
221 | 347 | ; high bit set to flag the start byte |
@@ -500,6 +500,22 @@ myTOGGLE: .DEFINE "1" | ||
500 | 500 | HIHEADER PTRWIDTH, PTRWIDTH, DOCON |
501 | 501 | .data.l NATURAL_SIZE |
502 | 502 | |
503 | +; These should be linear arrays, but there is no linear array in fig-FORTH model. | |
504 | +; NBYTEORDER ( --- u ) | |
505 | +; Offsets of bytes in natural word, high byte is byte 0. | |
506 | +; Access as byte array of length NWIDTH. | |
507 | +; Not part of the fig-FORTH model, should have been. | |
508 | +; HIHEADER NBYTEORDER, NBYTEORDER, DOCON | |
509 | +; .data.l h'00010203 | |
510 | +; | |
511 | +; PBYTEORDER ( --- u ) | |
512 | +; Offsets of bytes in address/pointer, high byte is byte 0. | |
513 | +; Access as byte array of length PTRWIDTH. | |
514 | +; Not part of the fig-FORTH model, should have been. | |
515 | +; HIHEADER PBYTEORDER, PBYTEORDER, DOCON | |
516 | +; .data.l h'00010203 | |
517 | +; But we can define them high-level, so hold them off until we need them. | |
518 | + | |
503 | 519 | ; BL ( --- u ) |
504 | 520 | HIHEADER BL, BL, DOCON |
505 | 521 | .data.l " " ; ascii blank |
@@ -39,7 +39,7 @@ | ||
39 | 39 | |
40 | 40 | HEADER COLD, CENT |
41 | 41 | ; WENT will also move, eventually. |
42 | -WENT: | |
42 | +_fWENT: | |
43 | 43 | mov.l #PER_USER, fUP |
44 | 44 | ; |
45 | 45 | ; Eventually want to initialize these from the COLD_PARAMETERS table -- |
@@ -116,3 +116,46 @@ | ||
116 | 116 | |
117 | 117 | |
118 | 118 | |
119 | +; FIRST ( --- adr ) The base of the disk buffer space. | |
120 | +; Returns the address of the lowest disk block buffer. | |
121 | +; | |
122 | + HIHEADER FIRST, FIRST, DOCON | |
123 | + .data.l DISK_BUFFERS | |
124 | + | |
125 | + | |
126 | +; LIMIT ( --- adr ) The limit of the disk buffer space. | |
127 | +; Returns the address one beyond the highest disk block buffer. | |
128 | +; In many fig FORTHs, this would mark the end of system memory. | |
129 | +; Not so in this SH-3 implementation. | |
130 | +; | |
131 | + HIHEADER LIMIT, LIMIT, DOCON | |
132 | + .data.l DISK_BUFFERS_END | |
133 | + | |
134 | + | |
135 | +; B/BUF ( --- size ) The size, in bytes, of a buffer. | |
136 | +; Bytes per buffer, or the size of a disk block. | |
137 | +; | |
138 | + HIHEADER "B/BUF", BBUF, DOCON | |
139 | + .data.l DISK_BUFFER_SIZE | |
140 | + | |
141 | + | |
142 | + | |
143 | + | |
144 | +; B/SCR ( --- count ) The size, in buffers, of a screen. | |
145 | +; Blocks per screen. | |
146 | +; A screen is the traditional unit of disk space in the old FORTH. | |
147 | +; | |
148 | +; It's a good rule-of-thumb limit on the size of a word definition, | |
149 | +; named for the size of a useable small screen -- | |
150 | +; 16 lines, 64 columns in 20x80. | |
151 | +; | |
152 | +; Many traditional FORTH text editors organized the screen this way. | |
153 | +; | |
154 | + HIHEADER "B/SCR", BSCR, DOCON | |
155 | + .data.l DISK_BUFFER_COUNT | |
156 | + | |
157 | + | |
158 | + | |
159 | + | |
160 | + | |
161 | + |
@@ -33,7 +33,14 @@ | ||
33 | 33 | .include "context.inc" |
34 | 34 | |
35 | 35 | |
36 | - .section main, code, locate=h'8c000000 | |
36 | +; We may have time to move this to flash ROM at h'a0000000 ? | |
37 | + .AIFDEF BUILD_FOR_ROM | |
38 | +PREBUILT_DICTIONARY_BASE: .equ h'a0000000 | |
39 | + .AELSE | |
40 | +PREBUILT_DICTIONARY_BASE: .equ h'8c000000 | |
41 | + .AENDI | |
42 | + | |
43 | + .section main, code, locate=PREBUILT_DICTIONARY_BASE | |
37 | 44 | |
38 | 45 | .org $ |
39 | 46 |
@@ -42,16 +49,19 @@ | ||
42 | 49 | ;*************************** |
43 | 50 | ; 0 offset into the ROMmable code |
44 | 51 | ORIG: |
45 | - mov.l #_fCENT, r0 | |
46 | - jmp @r0 | |
52 | + mov.l @(_iCENT-$-NATURAL_SIZE,PC), r0 ; Cold boot, initializes everything. | |
53 | + jmp @r0 | |
54 | + nop | |
55 | + nop | |
56 | +; Wouldn't hurt to uselessly load the warm entry point as we go, | |
57 | +; but we'll assume that the offsets double for 32 bit addressing CPUs. | |
47 | 58 | ;*************************** |
48 | 59 | ;** W A R M E N T R Y ** |
49 | 60 | ;*************************** |
50 | 61 | ; |
51 | -; 4 offset into the ROMmable code | |
52 | - nop ; Conveniently left over from the COLD entry point. | |
53 | - mov.l #WENT, r0 ; warm-start code, keeps current dictionary intact | |
62 | + mov.l @(_iWENT-$-NATURAL_SIZE,PC), r0 ; warm-start code, keeps current dictionary intact | |
54 | 63 | jmp @r0 |
64 | + nop ; Can't avoid this no-op. | |
55 | 65 | nop |
56 | 66 | ; |
57 | 67 | ;* |
@@ -59,7 +69,7 @@ ORIG: | ||
59 | 69 | ;* |
60 | 70 | ; All of this is essentially place-holder values: |
61 | 71 | COLD_PARAMETERS: |
62 | - .data.l "SH-3" ; cpu | |
72 | + .data.l "SH-3" ; cpu in revision slot. | |
63 | 73 | .data.l 0 ; revision |
64 | 74 | .data.l 0 ; topmost word in FORTH vocabulary |
65 | 75 | BACKSP: |
@@ -70,19 +80,25 @@ SINIT: | ||
70 | 80 | .data.l fSP_BASE ; ORIG-$210 ; initial top of data stack |
71 | 81 | RINIT: |
72 | 82 | .data.l fRP_BASE ; ORIG-$10 ; initial top of return stack |
73 | - .data.l fSP_LIMIT-h'200 ; ORIG-$200 ; terminal input buffer | |
83 | + .data.l TERMINAL_INPUT_BUFFER ; ORIG-$200 ; terminal input buffer | |
74 | 84 | .data.l 31 ; initial name field width |
75 | 85 | .data.l 0 ; initial warning mode (0 = no disc) |
76 | 86 | FENCIN: |
77 | - .data.l fSP_LIMIT-h'400 ; REND ; initial fence | |
87 | + .data.l REND ; initial fence | |
78 | 88 | DPINIT: |
79 | - .data.l fSP_LIMIT-h'400 ; REND ; cold start value for DP | |
89 | + .data.l REND ; cold start value for DP | |
80 | 90 | VOCINT: |
81 | - .data.l fSP_LIMIT-h'400 ; FORTH+8 | |
91 | + .data.l FORTH+4*NATURAL_SIZE | |
82 | 92 | COLINT: |
83 | 93 | .data.l 132 ; initial terminal carriage width |
84 | 94 | DELINT: |
85 | 95 | .data.l 4 ; initial carriage return delay |
96 | + | |
97 | +COLD_PARAMETER_SIZE: .equ $ | |
98 | +_iCENT: | |
99 | + .data.l _fCENT | |
100 | +_iWENT: | |
101 | + .data.l _fWENT | |
86 | 102 | ;* |
87 | 103 | ;**************************************************** |
88 | 104 | ;* |
@@ -93,6 +109,7 @@ DELINT: | ||
93 | 109 | ; Thus: |
94 | 110 | ; |
95 | 111 | .include "teststuff.inc" |
112 | + | |
96 | 113 | .include "initialize.inc" |
97 | 114 | .include "primitive.inc" |
98 | 115 | .include "compiler.inc" |
@@ -104,26 +121,115 @@ DELINT: | ||
104 | 121 | .include "driver.inc" |
105 | 122 | |
106 | 123 | |
107 | - .section user, data, locate=h'8c010000 | |
124 | +; | |
125 | +; ****** Fix this later! | |
126 | +; | |
127 | + HIHEADER FORTH, ROMFORTH, DODOES, MIMM | |
128 | + .data.l h'81A0, _sTASK | |
129 | + .data.l 0 | |
130 | + .sdata "Copyright Joel Rees, 2014. Parts Copyright David Lion and Forth Interest Group, 1979" | |
131 | + | |
132 | + HIHEADER TASK, ROMTASK, DOCOL | |
133 | + .data.l NOOP, SEMIS | |
134 | +ERAM: | |
135 | + .sdata "Joel Rees" | |
136 | + | |
137 | + | |
138 | +; The memory map will depart drastically from the fig-FORTH model for many reasons. | |
139 | +; The biggest is that a buffer and a stack share allocation space is a recipe for disaster. | |
140 | +; The other biggest reason is that we are no longer nearly so memory-constrained. | |
141 | +; | |
142 | +; Also, we want to clearly mark the ROMmable portion and separate it from stuff in RAM. | |
143 | +; | |
144 | + | |
145 | + | |
146 | + .AIFDEF BUILD_FOR_ROM | |
147 | +RUNTIME_DICTIONARY_BASE: .equ h'8c000000 | |
148 | + .AELSE | |
149 | + .align 4 | |
150 | +RUNTIME_DICTIONARY_BASE: .equ $ | |
151 | + .AENDI | |
152 | + | |
153 | + | |
154 | + .section dictionary, data, locate=RUNTIME_DICTIONARY_BASE | |
155 | + | |
156 | +; ****** Fix this later! | |
157 | +; | |
158 | +;* These definitions, up through the lable 'REND', are overwritten | |
159 | +;* at time of cold load and should have the same contents | |
160 | +;* as shown here: | |
161 | +;* | |
162 | + HIHEADER FORTH, FORTH, DODOES, MIMM | |
163 | + .data.l h'81A0, _sTASK | |
164 | + .data.l 0 | |
165 | +; | |
166 | + .sdata "Copyright Joel Rees, 2014. Parts Copyright David Lion and Forth Interest Group, 1979" | |
167 | + | |
168 | + | |
169 | + HIHEADER TASK, TASK, DOCOL | |
170 | + .data.l NOOP, SEMIS | |
171 | +; | |
172 | +REND: .equ $ ; ( first empty location in dictionary ) | |
173 | +; | |
174 | + .res.b RUNTIME_DICTIONARY_SIZE-(REND-RUNTIME_DICTIONARY_BASE) | |
175 | +RUNTIME_DICTIONARY_END: .equ $ | |
176 | + .res.b ALLOC_GAP | |
177 | + .align 4 | |
178 | +RUNTIME_DICTIONARY_SPACE_END: .equ $ | |
179 | + | |
180 | + | |
181 | + .section user, data, locate=RUNTIME_DICTIONARY_SPACE_END | |
182 | + .res.b ALLOC_GAP | |
108 | 183 | PER_USER: .equ $ |
109 | - .res.b UTABLESZ | |
110 | - | |
111 | - .section pstack, stack, locate=PER_USER+h'E000 | |
184 | + .res.b UTABLESZ*N_USERS | |
185 | +PER_USER_END: .equ $ | |
186 | + .res.b ALLOC_GAP | |
187 | + .align 4 | |
188 | +PER_USER_SPACE_END: .equ $ | |
189 | + | |
190 | + | |
191 | +; Should be in per-user space, but it's not that way in the fig model: | |
192 | + .section iobuffers, data, locate=PER_USER_SPACE_END | |
193 | +IO_SPACE_BASE: .equ $ | |
194 | + .res.b ALLOC_GAP | |
195 | +TERMINAL_INPUT_BUFFER: .equ $ | |
196 | + .res.b TERMINAL_INPUT_BUFFER_SIZE | |
197 | +TERMINAL_INPUT_BUFFER_END: .equ $ | |
198 | + .res.b ALLOC_GAP | |
199 | + .align 4 | |
200 | + .res.b ALLOC_GAP | |
201 | +DISK_BUFFERS: | |
202 | + .res.b DISK_BUFFER_RECORD_SIZE*DISK_BUFFER_COUNT | |
203 | +DISK_BUFFERS_END: .equ $ | |
204 | + .res.b ALLOC_GAP | |
205 | + .align 4 | |
206 | + .res.b ALLOC_GAP | |
207 | +RAM_DISK_BASE: | |
208 | + .res.b RAM_DISK_SIZE | |
209 | +RAM_DISK_END .equ $ | |
210 | + .res.b ALLOC_GAP | |
211 | + .align 4 | |
212 | +IO_SPACE_END: .equ $ | |
213 | + | |
214 | + | |
215 | + .section pstack, stack, locate=IO_SPACE_END | |
216 | + .res.b ALLOC_GAP | |
112 | 217 | fSP_LIMIT: .equ $ |
113 | - .res.b h'1F00 | |
218 | + .res.b PARAMETER_STACK_SIZE | |
114 | 219 | fSP_BASE: .equ $ |
220 | + .res.b ALLOC_GAP | |
221 | + .align 4 | |
222 | +fSP_END: .equ $ | |
115 | 223 | |
116 | - .section rstack, stack, locate=h'8c01FF00 | |
224 | + .section rstack, stack, locate=fSP_END | |
225 | + .res.b ALLOC_GAP | |
117 | 226 | fRP_LIMIT: .equ $ |
118 | - .res.b h'100 | |
119 | -fRP_BASE: .equ $ | |
120 | - | |
121 | - .section thevoid, dummy, locate=h'8c020000 | |
122 | -OUTERSPACE: .equ $ | |
123 | - | |
124 | - | |
125 | - | |
227 | + .res.b CONTROL_STACK_SIZE | |
228 | +fRP_BASE: .equ h'8c020000-ALLOC_GAP | |
229 | + .res.b ALLOC_GAP | |
230 | + .align 4 | |
231 | +fRP_END: .equ $ | |
126 | 232 | |
127 | 233 | |
128 | 234 | |
129 | - .end | |
\ No newline at end of file | ||
235 | + .end |
@@ -56,6 +56,8 @@ COMPIL: .define "NOOP" ; used in SEMI | ||
56 | 56 | SMUDGE: .define "NOOP" ; used in SEMI |
57 | 57 | LBRAK: .define "NOOP" ; used in SEMI |
58 | 58 | COMMA: .define "NOOP" ; used in CONSTANT |
59 | +DODOES: .define "NOOP" ; used in ROMFORTH | |
60 | +DOVOC: .define "NOOP" ; used in ROMFORTH | |
59 | 61 | ; : .define "NOOP" |
60 | 62 | |
61 | 63 |