4 * Joel Matthew Rees April 2020
6 * Borrowing some concepts from fig-Forth.
9 * ------------------------------------LICENSE-------------------------------------
11 * Copyright (c) 2009, 2010, 2011 Joel Matthew Rees
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this software and associated documentation files (the "Software"), to deal
15 * in the Software without restriction, including without limitation the rights
16 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 * copies of the Software, and to permit persons to whom the Software is
18 * furnished to do so, subject to the following conditions:
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 * --------------------------------END-OF-LICENSE----------------------------------
35 * These must be edited for target runtime:
37 * Necessary here for forward referencing:
43 BYTESZ EQU 8 ; bit count in byte
45 ADRWDSZ EQU 2 ; bytes per address word
47 * If at all possible, a CELL should be able to contain an address.
48 * Otherwise, fetch and store become oddities.
50 CELLBSZ EQU (ADRWDSZ*BYTESZ) ; bit count in CELL
52 DBLBSZ EQU (DBLSZ*BYTESZ) ; bit count in DOUBLE
54 GAPCT EQU 2 ; address words for the gaps
55 ALLOGAP EQU (GAPCT*ADRWDSZ) ; For crude checks, gaps always zero.
58 * Declare initial Return Stack (flow-of-control stack):
59 RSTKBND EQU $8000 ; Bound: one beyond
60 RSTKINI EQU (RSTKBND-1) ; Init: next available byte on 6800/6801
61 RSTKSZ EQU (62*ADRWDSZ) ; Size: Safe for most purposes.
62 RSTKLIM EQU (RSTKBND-RSTKSZ) ; Limit: Last useable
63 * Kibitzing -- CPUs really should have automatic stack bounds checking.
64 * Don't forget gaps for CPUs that don't automatically check.
65 * Crude guard rails is better than none?
67 * Declare initial Locals Stack (temporaries stack):
68 LSTKBND EQU (RSTKLIM-ALLOGAP)
69 LSTKINI EQU (LSTKBND-CELLSZ) ; Pre-dec, even on 6801, but on address word boundary.
70 LSTKSZ EQU (30*CELLSZ) ; Size: CELL addressing, small stacks.
71 LSTKLIM EQU (LSTKBND-LSTKSZ)
73 * Declare initial Parameter Stack (data stack):
74 SSTKBND EQU (LSTKLIM-ALLOGAP)
75 SSTKINI EQU (SSTKBND-ADRWDSZ) ; Pre-dec, even on 6801, but on address word boundary.
76 SSTKSZ EQU (126*ADRWDSZ) ; Size: CELL addressing, small stacks.
77 SSTKLIM EQU (SSTKBND-SSTKSZ)
79 * The paramater stack and heap at opposite ends of the same region
82 * The initial per-user allocation heap:
83 UPGBND EQU (SSTKLIM-ALLOGAP)
84 UPGSZ EQU 30*ADRWDSZ ; This will need adjusting in many cases.
85 UPGBASE EQU (UPGBND-UPGSZ)
89 * ORG directives in older assemblers can get tangled up
90 * if they are convoluted.
91 * Keep the ORGs in assending order.
96 * Internal registers --
97 * (When switching contexts, these must be saved and restored.):
99 * RP RMB ADRWDSZ ; the return/flow-of-control stack pointer is 6801 S
100 * A software locals stack would require thrashing X,
101 * so we'll take the unwise expedient of using the return stack.
102 LSP RMB ADRWDSZ ; the locals stack pointer (for locals, i. e., instead of RP)
103 PSP RMB ADRWDSZ ; the parameter/data stack pointer (Forth SP)
104 UP RMB ADRWDSZ ; pointer to the per-task heap
105 TEMP RMB 2*CELLSZ ; for general math
106 GCOUNT RMB CELLSZ ; general counter
107 IXDEST RMB ADRWDSZ ; destination index pointer
108 IXSRC RMB ADRWDSZ ; source index pointer
109 IXTERM RMB ADRWDSZ ; terminator for moves
121 * See runt6800.68c for consideration of byte operators and a GETAB routine.
123 * _WORD_ AND Take logical AND of top two on stack ( n1 n2 --- n3 ):
131 * See runt6800.68c for more discussion of the following.
135 * Might replace the first two instructions with
144 * But that only saves two bytes each,
145 * at a cost of some eleven cycles on the 6801
146 * in code that we assume will become a bottleneck.
148 * The number of places it would be used are less than ten, I think.
149 * Less than 20 bytes saved.
151 * Tail-stealing the STDEALL code costs enough to throw that into question as it is,
152 * but that's six bytes saved at a cost of three cycles.
154 * We will assume that auto-in-lining for the 6801 will be not be in this version.
156 * _WORD_ OR Take logical OR of top two on stack ( n1 n2 --- n3 ):
164 * _WORD_ XOR Take logical OR of top two on stack ( n1 n2 --- n3 ):
172 * _WORD_ + Add top two cells on stack ( n1 n2 --- sum ):
174 LDX PSP ; MACRO GETAB
178 * _LOWORD_ Add cell in A:B to cell pointed to by X:
181 * Keep rob point for storing over 2nd and deallocating top.
189 * _WORD_ - Subtract top cell on stack from second ( n1 n2 --- difference(n1-n2) ):
191 LDX PSP ; MACRO GETAB
195 * !xxx _LOWORD_ Subtract cell pointed to by CELLSZ,X from cell in A:B (not useful?):
206 * ASSERT CELLSZ == ADRWDSZ
208 * _WORD_ B@ Fetch byte only pointed to by top cell on stack ( adr --- b(at adr) ):
209 * (Refer to Forth's C@, but byte is not character!)
216 STAB 1,X ; Not worth robbing.
219 * _WORD_ B! Store low byte of cell at 2nd at address on top of stack, deallocate both ( n adr --- ):
220 * (Refer to Forth's C!, but byte is not character!)
223 LDAB 1+ADRWDSZ,X ; n low byte only
225 STAB 0,X ; Store only byte, do not clear high byte!
226 BRA DEALL2 ; Rob code to deallocate, assumes CELLSZ == ADRWDSZ.
228 * _WORD_ @ Fetch cell pointed to by top cell on stack ( adr --- n(at adr) ):
237 * _WORD_ ! Store cell at 2nd at address on top of stack, deallocate both ( n adr --- ):
243 * Rob point to deallocate 2 on stack.
246 ADDD #(CELLSZ+ADRWDSZ)
250 * _WORD_ U* Unsigned multiply of top two on stack ( n1 n2 --- udproduct(n1*n2) ):
253 * LDAA #CELLBSZ ; bits/cell
255 * CLRA ; Clear Carry, too. LDD #0 does not clear carry.
257 * USTARL ROR CELLSZ,X ; shift multiplier
259 * DEC 1+GCOUNT ; done?
264 * RORB ; shift result in
266 * USTARX STD 0,X ; store more significant 16 bits
269 * _WORD_ U* Unsigned multiply of top two on stack ( n1 n2 --- udproduct(n1*n2) )
270 * Using 6801's MUL for speed -- more code less time:
300 * _WORD_ SWAP swap top two cells on stack ( n1 n2 --- n2 n1 ):
301 * Use TEMP for speed and code size, since we're using it anyway.
312 * To compare the 6800 way with (avoids TEMP):
326 * _WORD_ U/MOD Unsigned divide of unsigned double dividend in 2nd:3rd on stack by top unsigned divisor
327 * ( ud u --- uremainder uquotient )
328 * Dividend should be range of product of 16 by 16 bit unsigned multiply,
329 * divisor should be the multiplier or multiplicand:
332 LDAA #1+CELLBSZ ; one more than bits/cell
334 LDD CELLSZ,X ; dividend
335 USLLUP SUBD 0,X ; divisor
336 BCC USLSUBD ; CC = HS (High or Same)
338 CLC ; shouldn't ever get set?
340 USLSUBD SEC ; For shifting
341 USLNEXT ROL 1+2*CELLSZ,X
345 ROLB ; No, the 6801 does not have ROLD.
348 SUBD 0,X ; Catch the excess.
350 USLX INX ; Drop high cell.
353 STAA 0,X ; High cell now emptu, save remainder.
354 STAB 1,X ; But remainder is now top.
355 BRA SWAPROB ; PSP in X, reverse quotient & remainder.
358 * _WORD_ >L Save top cell on stack to locals stack ( n --- ) { --- n }:
372 * _WORD_ >R Save top cell on stack to return stack ( n --- ) { --- n }:
379 PULX ; Get the return address
384 * _WORD_ L> Pop top of parameter stack to locals stack ( --- n ) { n --- }:
387 LDD 0,X top cell on locals stack
398 * _WORD_ R> Pop top of locals stack to parameter stack ( --- n ) { n --- }:
401 LDD ADRWDSZ,X top cell on R stack -- dodge return address
406 STD 0,X ; save it first
407 PULX ; return address
408 INS ; drop top from return stack
412 * _WORD_ L Retrieve, do not pop top of locals stack to parameter stack ( --- n ) { n --- n }:
415 LDD ADRWDSZ,X top cell on locals stack
423 * _WORD_ R Retrieve, do not pop top of return stack to parameter stack ( --- n ) { n --- n }:
426 LDD ADRWDSZ,X top cell on R stack -- dodge return address
434 * _WORD_ DUP Duplicate top cell on stack ( n --- n n ):
444 * _WORD_ DROP Remove a cell from the parameter stack ( n --- )
447 INX ; LDAB #2 1 more byte, 1 less cycle
448 INX ; ABX same cycles
452 * _WORD_ 2DROP Remove a cell from the parameter stack ( n --- )
461 * Should true be set as 1 or -1?
462 * Going with all bits False (0)
463 * or all bits True (-1) as the flag to set.
464 * D really doesn't help here. (Compare 6800 code.)
465 * _WORD_ 0= Test top cell on stack for zero ( n --- f(top==0) ):
476 * True as 1 is obvious.
480 * _LOWORD_ Duplicate (count in B) bytes on stack:
487 * _LOWORD_ Move 256 bytes or less, going up:
488 * 0=256, do not enter without pretesting for 0 count!
489 * source in IXSRC, destination in IXDEST, count in 1+GCOUNT:
490 * Overlaps only work if source is higher than dest.
506 * _LOWORD_ Move 256 bytes or less, going down:
507 * 0=256, do not enter without pretesting for 0 count!
508 * source in IXSRC, destination in IXDEST, count in 1+GCOUNT:
509 * Overlaps only work if source is lower than dest.
512 DECB ; adjust to offset
523 * _WORD_ Move up to 32K bytes ( src dest count --- ):
524 * Copies zero when count >= 2^15
525 * Compare CMOVE in Forth.
527 ****** Working in here to make it go both ways.
528 ****** Also need to check multiply and divide.
534 BEQ BMOVEX ; Do nothing if zero.
535 BMI BMOVEX ; Do nothing if too big.
540 LDAB 1+GCOUNT ; Get low byte for partial block.
541 CLR 1+GCOUNT ; To avoid debugging confusion.
542 BMOVEL BSR SMOVE ; partial block and full blocks
543 DEC GCOUNT ; count high byte down (blocks)
544 BPL BMOVEL ; This limits the count.
551 * LDB #3*ADRWDSZ ; ADDD #3*ADRWDSZ is probably faster. Byte count is same.
556 * _WORD_ Execute the address on the stack:
563 JSR 0,X ; For debugging and flattening, no early optimizations.