Historia de DZX-Forth de 2015-03 a 2015-07
Descripción del contenido de la página
Historia del desarrollo DZX-Forth, un Forth para ZX Spectrum +3e, de 2015-03 a 2015-06.
2015-03-16
Primeras pruebas con el ensamblador Pleonasmo DZX.
2015-04-08
Punto de entrada adicional para arranque en caliente.
2015-04-14
Intercambio los nombres de las rutinas move_block_downwards
y move_block_upwards
; los nombres originales parecen un despiste del autor de DX-Forth. Además las documento y simplifico y acelero su funcionamiento mediante ldir
y lddr
:
move_block_downwards:
; Move block upwards
; Used by 'cmove', 'move', '-roll' and '+string'.
; hl = source
; de = destination
; bc = count
; If bc is greater than zero, copy bc consecutive characters from the data
; space starting at hl to that starting at de, proceeding
; character-by-character from higher addresses to lower addresses.
if 0
; XXX OLD
add hl,bc
ex de,hl
add hl,bc
ex de,hl
move_block_downwards.1:
ld a,c
or b
ret z
dec hl
dec de
ld a,(hl)
ld (de),a
dec bc
jp move_block_downwards.1
else
; XXX NEW
ld a,c
or b
ret z
add hl,bc
dec hl
ex de,hl
add hl,bc
dec hl
ex de,hl
lddr
ret
endif
move_block:
; Move block upwards or downwards
; Used by 'move' and 'packed'.
; hl = source
; de = destination
; bc = count
; If bc is greater than zero, copy the contents of bc consecutive address
; units at hl to the bc consecutive address units at de. After the move
; completes, the bc consecutive address units at de contain exactly what the
; bc consecutive address units at hl contained before the move.
call compare_de_hl_unsigned
jp c,move_block_downwards
move_block_upwards:
; Move block downwards
; Used by 'cmove>', 'move' and the user data init.
; hl = source
; de = destination
; bc = count
; If bc is greater than zero, copy bc consecutive characters from the data
; space starting at hl to that starting at de, proceeding
; character-by-character from lower addresses to higher addresses.
ld a,c
or b
ret z
; XXX NEW
ldir
ret
; XXX OLD
; ld a,(hl)
; ld (de),a
; inc hl
; inc de
; dec bc
; jp move_block_upwards
El punto de entrada alternativo move_block_downwards.1
era usado por la palabra roll
, por lo que es necesario hacerle una modificación. Debido a los cambios en la rutina move_block_downwards
, es más fácil y rápido que roll
haga su propio lddr
en lugar de modificar la rutina para añadirle un punto de entrada adecuado:
if 0
; XXX OLD
inc de
dec hl
call move_block_downwards.1
else
; XXX NEW
ld a,b
or c
jp z,roll_.end
dec hl
dec hl
lddr
roll_.end:
endif
Por otra parte, para probar bien el funcionamiento de las palabras que usan las rutinas modificadas, cmove
, cmove>
y move
, adapto la palabra dump
del sistema Spectrum Forth-83 de Lennart Benschop, mejor que el que provisionalmente está incluido en el propio código de DZX-Forth:
\ DUMP for DZX-Forth
\ 2015-04-14
\ Adapted from Lennart Benschop's Spectrum Forth-83 (1988)
( BS STYPE )
: bs ( -- ) 8 emit ;
: stype ( ca len -- )
\ Press the given string; the highest bit of characters
\ is ignored, and control characters are printed as a point.
bounds ?do
i c@ %01111111 and dup bl < if drop [char] . then emit
loop ;
: hexa. ( x -- )
\ Print a number as an unsigned 16-bit number in hex.
base @ swap hex s>d <# # # # # #> type space base ! ;
-->
( DUMP )
: dump ( a len -- )
7 + %1111111111111000 and 8 / 0 ?do
cr dup hexa.
8 0 do
i over + @ >< hexa.
2 +loop
dup bs 8 stype
?terminal if leave then
8 +
loop drop ;
Varias palabras necesitan tomar un parámetro de la pila para usarlo en el registro bc
, que es el registro IP
de Forth. Optimizo estas operaciones usando exx
en lugar de ex (sp),hl
. Ejemplo:
; CMOVE ( ca1 ca2 len -- )
_header _public,'CMOVE'
c_move_:
if 0
; XXX OLD
ld l,c ; 4 T
ld h,b ; 4 T
pop bc ; 10 T
pop de ; 10 T
ex (sp),hl ; 19 T
call move_block_upwards
pop bc ; 10 T
; 57 T total
else
; XXX NEW
exx ; 4 T
pop bc ; 10 T
pop de ; 10 T
pop hl ; 10 T
call move_block_upwards
exx ; 4 T
; 38 T total
endif
jp next
2015-05-13
Echo un vistazo al código después de un tiempo. El código estalla en el arranque. Rastreo el error. De paso hago dos pequeñas optimizaciones, en NIP
y 2NIP
, que reducen el tamaño y el tiempo de ejecución del código.
Tras hacer muchas pruebas y, finalmente, comparar el código con la última copia de respaldo, descubro el problema: un salto que había quedado fuera de lugar en las optimizaciones hechas el mes pasado.
2015-06-17
Corrijo rdrop
, que no preservaba su propia dirección de retorno. La nueva versión es:
; RDROP ( -- )
_header _public,'RDROP'
r_drop_:
rdrop_:
ld hl,(return_stack_pointer)
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld (return_stack_pointer),hl
ld (hl),e
inc hl
ld (hl),d
jp next
2015-06-21
El final de la definición de 0>
era reutilizado por >
, <
y d<
. Lo muevo a <
, que es una palabra más frecuente, y cambio el nombre de la etiqueta a is_de_less_than_hl
, más claro.
2015-06-23
Mejora: Un octeto de ahorro en el tampón circular de cadenas cuando la longitud es de un octeto.
2015-07-33
Nueva palabra get-1346
, correspondiente a la rutina DOS GET 1346 de +3DOS:
; GET-1346 ( -- n1 n2 n3 n4 )
; n1 = First buffer on cache
; n2 = Number of cache sector buffers
; n3 = First buffer of RAM-disk
; n4 = Number of RAM-disk sector buffers
_header _public,'GET-1346'
get_1346_:
ld ix,dos_get_1346
call do_dos
; d = First buffer on cache
; e = Number of cache sector buffers
; h = First buffer of RAM-disk
; l = Number of RAM-disk sector buffers
ld a,e
ld e,d
ld d,0
push de ; n1
ld e,a
push de ; n2
ld e,h
ld h,0
jp push_de_hl ; n3 n4
El primer objetivo es saber cuál es la distribución predeterminada de las páginas de memoria 1, 3, 4 y 6, que +3DOS usa para la caché de disco y para el disco RAM. Tras la ejecución de get-1346
el resultado en la pila es 0 8 8 120
, es decir 4 KiB se usan para la caché de disco y el resto de las cuatro páginas de memoria se usa para el disco RAM.
La intención final es usar parte de la memoria paginada para almacenar los nombres de las palabras de Forth, de la manera en que ya lo hace Solo Forth en ZX Spectrum 128K. En +3DOS, sin embargo, es necesario reservar espacio para poder seguir usando el disco RAM.