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 fake forward referencing:
39 BYTESZ EQU 8 ; bit count in byte
41 ADRWDSZ EQU 2 ; bytes per address word
43 * If at all possible, a CELL should be able to contain an address.
44 * Otherwise, fetch and store become oddities.
46 CELLBSZ EQU (CELLSZ*BYTESZ) ; bit count in CELL
48 DBLBSZ EQU (DBLSZ*BYTESZ) ; bit count in DOUBLE
50 GAPCT EQU 2 ; address words for the gaps
51 ALLOGAP EQU (GAPCT*CELLSZ) ; For crude checks, gaps always zero.
54 * Declare initial Return Stack (flow-of-control stack):
55 RSTKBND EQU $8000 ; Bound: one beyond
56 RSTKINI EQU (RSTKBND-1) ; Init: next available byte on 6800
57 RSTKSZ EQU (62*CELLSZ) ; Size: Safe for most purposes.
58 RSTKLIM EQU (RSTKBND-RSTKSZ) ; Limit: Last useable
59 * Kibitzing -- CPUs really should have automatic stack bounds checking.
60 * Don't forget gaps for CPUs that don't automatically check.
61 * Crude guard rails is better than none?
63 * Declare initial Parameter Stack (data stack):
64 SSTKBND EQU (RSTKLIM-ALLOGAP)
65 SSTKINI EQU (SSTKBND-CELLSZ) ; Also post-dec on 6800, but on address word boundary.
66 SSTKSZ EQU (126*CELLSZ) ; Size: CELL addressing, small stacks.
67 SSTKLIM EQU (SSTKBND-SSTKSZ)
69 * The paramater stack and heap at opposite ends of the same region
72 * The initial per-user allocation heap:
73 UPGBND EQU (SSTKLIM-ALLOGAP)
74 UPGSZ EQU (64*CELLSZ) ; This will need adjusting in many cases.
75 UPGBASE EQU (UPGBND-UPGSZ)
79 * ORG directives in older assemblers can get tangled up
80 * if they are convoluted. Keep the ORGs in assending order.
85 * Internal registers --
86 * (When switching contexts, these must be saved and restored.):
88 * RP RMB ADRWDSZ ; the return/flow-of-control stack pointer is 6800 S
89 PSP RMB ADRWDSZ ; the parameter/data stack pointer (Forth SP)
90 UP RMB ADRWDSZ ; pointer to the per-task heap
91 TEMP RMB 2*CELLSZ ; for general math
92 GCOUNT RMB CELLSZ ; general counter
93 IXDEST RMB ADRWDSZ ; destination index pointer
94 IXSRC RMB ADRWDSZ ; source index pointer
95 IXTERM RMB ADRWDSZ ; terminator for moves
107 * _LOWORD_ Move 256 bytes or less going up:
108 * 0=256, do not enter without pretesting for 0 count!
109 * source in IXSRC, destination in IXDEST, count in B:
110 * Overlaps only work if source is higher than dest.
124 * _LOWORD_ Move 256 bytes or less going down:
125 * 0=256, do not enter without pretesting for 0 count!
126 * source in IXSRC, destination in IXDEST, count in B, A is overwritten:
127 * Overlaps only work if source is higher than dest.
132 CLRA ; 1# 2~ -- BCC takes 2#, 4~; INC IXSRC takes 3# & 6~
138 CLRA ; 1# 2~ -- BCC takes 2#, 4~; INC IXDEST takes 3# & 6~
154 * _WORD_ Move up to 32K bytes ( src dest count --- ):
155 * Copies zero when count >= 2^15
156 * Compare CMOVE in Forth.
158 LDX PSP ; get paramaters
160 BEQ DEALL3 ; bail now if zero
161 BMI DEALL3 ; also if greater than 32K
165 LDAA 0,X ; SRC, going to do math
169 SUBB CELLSZ+ADRWDSZ+1,X ; DEST
170 SBCA CELLSZ+ADRWDSZ,X
184 LDAB GCOUNT+1 ; Get low byte for partial block
185 CLR GCOUNT+1 ; To avoid debugging confusion.
186 BMOVEL BSR SMOVE ; partial block and full blocks
187 DEC GCOUNT ; count high byte down (blocks)
188 BPL BMOVEL ; This limits the count.
189 * Rob point to deallocate 3 on stack, as long as CELLSZ == ADRWDSZ.
192 ADDB #(CELLSZ+2*ADRWDSZ) ; 2# 3~
195 INC PSP ; 3# 6~ Unaries have no direct page version. => 11# 20~
199 * ADDB #(CELLSZ+2*ADRWDSZ) ; 2# 3~
202 * ADCA #(CELLSZ+2*ADRWDSZ) ; 2# 3~
203 * STAA PSP ; 2# 4~ => 12# 20~
206 * LDX PSP ; 6 INXs is around the breakover point in the 6800.
207 * INX ; 2 + 6 + 2 bytes => 11#
208 * INX ; 4 + 24 + 5 cycles => 33~
217 * _LOWORD_ Subtract byte in B from cell pointed to by X:
218 * Not really all that useful when you can CLRA and SUBCELL?
227 * _LOWORD_ Add byte in B to cell pointed to by X:
228 * Not really all that useful when you can CLRA and ADDCELL?
245 * Or doing as subroutine would would add 4 bytes and about ten cycles?
246 * How useful would it be?
249 * _WORD_ Take logical AND of top two on stack ( n1 n2 --- n3 ):
258 * _WORD_ Take logical OR of top two on stack ( n1 n2 --- n3 ):
267 * _WORD_ Take logical OR of top two on stack ( n1 n2 --- n3 ):
276 * _WORD_ Add top two cells on stack ( n1 n2 --- sum ):
278 LDX PSP ; MACRO GETAB
283 * _LOWORD_ Add cell in A:B to cell pointed to by X:
287 * Keep rob point for storing over 2nd and deallocating top.
296 * _WORD_ Subtract top cell on stack from second ( n1 n2 --- difference(n1-n2) ):
298 LDX PSP ; MACRO GETAB
303 * !xxx _LOWORD_ Subtract cell pointed to by 2,X from cell in A:B (not useful?):
315 * _WORD_ Fetch byte only pointed to by top cell on stack ( adr --- b(at adr) ):
316 * (Refer to Forth's C@, but byte is not character!)
323 STAB 1,X ; Not worth robbing.
326 * _WORD_ Store low byte of cell at 2nd at address on top of stack, deallocate both ( n adr --- ):
327 * (Refer to Forth's C!, but byte is not character!)
330 LDAB ADRWDSZ+1,X ; n low byte only
332 STAB 0,X ; Store only byte, do not clear high byte!
333 BRA DEALL2 ; Rob code to deallocate.
335 * ASSERT CELLSZ == ADRWDSZ
336 * _WORD_ Fetch cell pointed to by top cell on stack ( adr --- n(at adr) ):
347 * _WORD_ Store cell at 2nd at address on top of stack, deallocate both ( n adr --- ):
355 * Rob point to deallocate 2 on stack.
365 * _WORD_ Unsigned multiply of top two on stack ( n1 n2 --- uproduct(n1*n2) ):
368 LDAA #CELLBSZ ; bits/cell
372 USTARL ROR CELLSZ,X ; shift multiplier
380 RORB ; shift result in
382 USTARX STAB 1,X ; store more significant 16 bits
386 * _WORD_ swap top two cells on stack ( n1 n2 --- n2 n1 ):
400 * _WORD_ Unsigned divide of unsigned double dividend in 2nd:3rd on stack by top unsigned divisor
401 * ( ud u --- uremainder uquotient )
402 * Dividend should be range of product of 16 by 16 bit unsigned multiply,
403 * divisor should be the multiplier or multiplicand:
406 LDAA #CELLBSZ+1 ; one more than bits/cell
408 LDAA CELLSZ,X ; dividend
410 USLLUP CMPA 0,X ; divisor
411 BHI USLSUB ; Make sure carry from LSB would carry over
414 BCC USLSUB ; CC = HS (High or Same)
415 USLNSUB CLC ; For shifting
420 USLNEXT ROL 1+2*CELLSZ,X
427 BRA USLSUB ; Catch the excess.
428 USLX INX ; Drop high cell.
431 STAA 0,X ; High cell now empty, save remainder.
432 STAB 1,X ; But remainder is now top.
433 BRA SWAPROB ; PSP in X, reverse quotient & remainder.
437 * _WORD_ Save top cell on stack to return stack ( n --- ) { --- n }:
444 INX ; Not worth robbing code.
449 * _WORD_ Pop top of return stack to parameter stack ( --- n ) { n --- }:
455 * _WORD_ Retrieve, do not pop top of return stack to parameter stack ( --- n ) { n --- n }:
469 * Should true be set as 1 or -1?
470 * _WORD_ Test top cell on stack for zero ( n --- f(top==0) ):
483 * _LOWORD_ Duplicate (count in B) bytes on stack:
490 * _WORD_ Execute the address on the stack:
497 JSR 0,X ; For debugging and flattening, no early optimizations.