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.

Etiquetas:
Esta página muestra apuntes tomados durante el desarrollo de DZX-Forth de 2015-03 a 2015-05, que en este periodo progresó poco, debido al trabajo en Tron 0xF y Afera.

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.