Jupiter Ace Forth (Estructura Palabras)

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 05 Ago 2022 22:31

Último mensaje de la página anterior:

Estructura de las Palabras (IX)
Estructura de las palabras tipo COMPILER(II)


La característica principal de las palabras definidas con COMPILER es que son inmediatas. Y cuando se ejecutan estando el Ace Forth en modo Compilación, lo primero que hacen es compilar el CFA de su parte Runtime y a continuación ejecutan su parte Compilante. Esta parte Compilante normalmente añade un Operand Field OF a continuación del CFA del Runtime, aunque no necesariamente.

O sea, de modo parecido a lo que dijimos con DEFINER, las palabras tipo COMPILER se componen de una cabecera y dos palabras tipo COLON a las que hemos llamado parte Compilante la primera y parte Runtime la segunda.

El conjunto Cabecera + parte Compilante equivale a una palabra tipo COLON Inmediata. Su CFA es el que lleva la cabecera.

La parte Runtime equivale a otra palabra, y su cabecera solo tiene un Code Field que apunta a la rutina que se encarga de ejecutar el Runtime. Obviamente el CFA del CF del Runtime es diferente del de la Cabecera, pues ocupa una posición de memoria diferente.

Así tenemos que las palabras tipo COMPILER tienen una Cabecera y dos palabras cada una con sus propios CFA.

Yo, como notación en mis esquemas-dibujo, cuando se compila el CFA que se corresponde con el de la Cabecera pongo que compila su CFA y cuando compila el otro, pongo que compila su CA o Compilation Address para diferenciarlos.

Ace Forth tiene muchas primitivas que son palabras Compilantes, al estilo de las tipo COMPILER pero con una estructura propia. Eso sí, al igual que las COMPILER tienen dos CFAs diferentes: El de la parte Compilante que coincide con el CFA de la Cabecera y el de la parte Runtime que es diferente. Por tanto uso CA en los esquemas cuando compilan el CFA del Runtime. Son palabras tales como:

 DOES> RUNS> ; IF ELSE THEN BEGIN UNTIL ... etc.

Volviendo a las tipo COMPILER, cuando se ejecuta la parte Runtime antes que nada, deja en la pila la dirección del Operand Field OF que compiló la parte Compilante a continuación del CA del Runtime. Esta dirección la deja incluso si NO se compiló ningún OF, pues en este caso considera que sí lo compiló pero que consta de cero bytes.

Cuando se define una palabra tipo COMPILER espera en la pila un número con el tamaño del OF que va a crear. Si el tamaño no se conoce de antemano, entonces se pone un menos uno como tamaño y es la parte Compilante la que tiene que colocarlo como un entero de 2 bytes al principio de OF (estos 2 bytes no se cuentan al calcular el tamaño del OF)

Para ver la estructura de las palabras tipo COMPILER usaremos como ejemplo la palabra 2LITERAL que toma los dos primeros números de la pila y los compila en el diccionario como su OF. Cuando se ejecuta 2LITERAL repone en la pila los dos números que compiló en su OF durante la parte compilante.

4 COMPILER 2LITERAL
SWAP , ,
RUNS>
2@
;

Vemos que las partes Compilante y Runtime de 2LITERAL son idénticas a las Definidora y Runtime de 2CONSTANT.

Esto se debe a que 2LITERAL hace lo mismo que hacía 2CONSTANT. La diferencia radica en que 2CONSTANT creaba un nuevo tipo de palabra con la que creábamos otras palabra que compilan en sus propios PFs los números que le damos. Mientras que 2LITERAL los compila dentro del PF de la palabra que se está definiendo.

Luego usaremos 2LITERAL en la definición de TEST y veremos ambas estructuras.
: TEST [ 23 18 ] 2LITERAL + ;

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 06 Ago 2022 13:09

Estructura de las Palabras (X)
Estructura de las palabras tipo COMPILER(III)


A las palabras creadas con COMPILER se les llama Palabras Compiladoras de Usuario

Cuando creamos una palabra Compiladora de Usuario con COMPILER:
  1. Se crea una cabecera con el nombre suministrado
  2. COMPILER: (CF) = 1108$
  3. Al principio del PF se compila una dirección o Address (2 bytes) que apunta al tercer byte del OF de RUNS>.
  4. Se compilan los CW de las palabras que componen la parte Compilante.
  5. Se compila el CA de RUNS> (*)
  6. Se compila en el primer byte del OF de RUNS> un número con el tamaño del OF de palabra tipo COMPILER]. Si el tamaño no se sabe de antemano, se compila $FF (-1).
  7. Se compila en los dos siguiente bytes del OF de RUNS> un número entero negativo al que llamo SHIFT que sumado a la dirección de su High byte nos da la dirección de memoria del primer carácter del Nombre o NFA de la palabra
  8. Se compila en los dos últimos bytes del OF de RUNS> el CF de la parte Runtime. Luego la dirección en que esto ocurre será el CFA del Runtime
  9. Se compilan los CW de las palabras que componen la parte Runtime
  10. Se compila el CA de ; (**)

(*) RUNS> es una palabra Compilante del Ace Forth por lo que tiene dos CFA: El que está en la Cabecera y el de la parte Runtime. Cuando se pone este último lo indico usando CA en vez de CFA. Le sigue su OF de 5 bytes.
(*) ; es una palabra Compilante del Ace Forth. Ver (*)

Veamos todo lo dicho para el caso de la Compilante de Usuario 2LITERAL y la palabra tipo COLON TEST que la utiliza usando un esquema-dibujo

4 COMPILER 2LITERAL
SWAP , ,
RUNS>
2@
;

: TEST [ 12 9 ] 2LITERAL + ;

NOTA: Recordemos que [ 12 9 ] lo que hace es colocar 12 y 9 en la pila. Lo hacemos así porque Ace Forth NO permite que los números que se van a compilar en una definición estén en la pila antes que comience la definición.

COMPILER Esquema New Red.png
COMPILER Esquema New Red.png (90.62 KiB) Visto 188 veces


NOTAS del Esquema:

  • Todos los números están en Hexadecimal
  • Todas la casillas del esquema del PF son 2 bytes excepto la que contiene el n=4 que es de un byte.
  • No he puesto los valores de Address(azul) ni de Address(negro) porque dependen de la posición de 2LITERAL en el diccionario. Tampoco he puesto la del CFA de 2@ pues también depende de la posición de 2@ en el diccionario.
  • SHIFT solo depende de la definición de 2LITERAL, no depende de su posición en memoria.
  • SHIFT = $FFE5 = -27

EDITADO 20-8-2022: Corregidos varios errores. Afectan al texto y al diagrama.

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 06 Ago 2022 15:50

Estructura de las Palabras (XI)
Estructura de las palabras tipo COMPILER(IV)

La estructura cambia un poco si la palabra Compilante de Usuario NO sabe de antemano el tamaño que tendrá el OF cuando se compile.

En este caso, hemos de poner un menos uno = $FF como tamaño de OF. Además, la parte Compilante ha de compilar lo primero en el OF un entero (2 bytes) con el tamaño del OF sin contar estos 2 bytes.

Como ya he dicho, si usamos el menos uno, en el campo de un byte entre el RUNS> y el SHIFT se colocará el número $FF.

Para verlo vamos a hacer una "tontería". Vamos a definir 2LITERAL como si no supiéramos el tamaño del OF de antemano. En vez del 4 pondremos un menos uno.

-1 COMPILER 2LITERAL
4 , SWAP , ,
RUNS>
2+ 2@
;

Como vemos hemos tenido que modificar la parte Compilante para que nos compile el tamaño del OF (4) lo primero.
También hemos tenido que modificar el Runtime (ver OJO más abajo).

Definimos TEST como antes, pero usando esta nueva versión de 2LITERAL

En el siguiente esquema-dibujo se muestran las diferencias (solo muestro de 2LITERAL el trozo de interés).

Esquema COMPILER -2 New red.png
Esquema COMPILER -2 New red.png (63.21 KiB) Visto 181 veces


  • Ahora el valor de SHIFT NO lo pongo porque será otro diferente, dado que la parte Compilante es más grande. Si no me equivoco ahora SHIT=$FFDF=-33 .
  • Observa que n ahora vale $FF
  • Al inicio del PF de TEST hay un nuevo número entero (2 bytes), un 4, que indica el tamaño del OF sin contar estos dos bytes. El OF ahora son 6 bytes en total.
  • OJO: Cuando se ejecuta TEST pone el OFA en la pila antes de ejecutar el Runtime. Pero ahora el OFA no apunta al primer número almacenado, sino que apunta al 4 este al inicio del OF. Por lo que en esta versión de 2LITERAL hay que modificar el Runtime para que le sume 2 al OFA de la pila para que apunte al $000C, etc.

Luego hacerlo así, si no es a título demostrativo, es una "tontería", pues es más complicado y gasta más memoria. Este método solo debería usarse cuando realmente no sabemos el tamaño del OF a priori.

¿Como hallar el CFA de la palabra Compilante de Usuario que corresponde a un CFA compilado dado?

Pues de un modo parecido al del caso DEFINER se llega a:
CFA 2- DUP @ + 1+ = NFA

Una vez tenemos el NFA sabiendo que el último carácter del nombre tiene 128 sumado, lo buscamos y sabemos que, por la estructura de la Cabecera de una palabra, el CFA de la definidora señala 6 bytes más adelante.

Otro cáculo útil: CFA -> Runtime

A partir del CFA de una palabra compiladora de usuario podemos obtener fácilmente el valor del CFA de su Runtime (su CA)
CFA 2+ @ = CA


NOTA: La fórmula del NFA es muy parecida al caso DEFINER pero NO es igual. En nuestro caso hay un @ menos.

EDIT (21-08-2022): Corregidos errores en Texto y Diagrama.

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 06 Ago 2022 23:12

Estructura de las Palabras (XII)

Palabras Primitivas del Ace Forth

Las palabras que ya vienen con Ace Forth las acostumbro a llamar palabras Primitivas. Pero esto NO es correcto. Las palabras que vienen de fábrica con el Ace Forth las podríamos llamar palabras Básicas o palabras Originales o palabras Predefinidas... pero NO primitivas, pues NO todas lo son.

Ace Forth viene con 142 palabras predefinidas. Pero solo algunas son primitivas.

¿Qué es una palabra primitiva?

Una palabra primitiva es la que está definida en Código Máquina. Ace Forth tiene muchas de éstas entre sus palabras predefinidas, pero otras están definidas a partir de primitivas de modo similar a como definimos nosotros nuestra propias palabras. Ahora mismo desconozco cuales, entre todas las predefinidas, son primitivas.

A nivel de su estructura, las Palabras Primitivas del Ace Forth cumplen este requisito:

El contenido de su CF, o sea, (CF) o (CFA) apunta al primer byte de su PF.

Precisamente el esquema de Cabecera+Parameter Field de la palabra STAR del primer post del hilo coincide con el de una palabra primitiva (aunque pretendía ser el de una definición COLON)

Así, si queremos saber si una palabra es una primitiva, nos basta comprobar que el contenido de su CFA apunta al inicio de su PF

Por ejemplo, veamos si SWAP es una primitiva:
FIND SWAP DUP @ 2- - 
Si es una primitiva el resultado será cero.

Recordemos que el (CFA) de una palabra apunta a la rutina en código máquina que se ha de ejecutar cuando se ejecute la palabra.
Ya hemos visto que el (CFA) de una definición tipo COLON es siempre $0EC3. Esto es así porque en esa dirección de memoria empieza la rutina en código máquina que se encarga de "interpretar" y ejecutar el PF de cualquier palabra tipo COLON

Como acabamos de decir, en la Primitivas, lo que se va a ejecutar es la rutina en código máquina almacenada en su propio PF.

Nosotros también podemos crear nuestras propias palabras Primitivas de Usuario. Y les añado la coletilla de Usuario porque hay una diferencia importante con las primitivas del Ace Forth, a saber:

Todas las palabras predefinidas del Ace Forth están en la ROM del Jupiter Ace, por lo que NO se pueden mover. La única excepción es la palabra FORTH que se copia al principio de la RAM, pero también es inamovible.

Esto hace que el código máquina de las palabras primitivas del Ace Forth NO tiene que ser relocalizable.

En cambio, las primitivas de Usuario, como puede que se muevan en el diccionario, su código máquina tiene que ser relocalizable. Si no es relocalizable tenemos que estar seguros que NO se van a mover, lo cual es difícil de asegurar.

Recordemos que las palabras de Usuario pueden cambiar de posición en el diccionario (por ende, en la memoria) por varios motivos:

  • Cuando cargamos con LOAD el diccionario que la contiene y ya había otro diccionario previamente cargado.
  • Cuando usamos REDEFINE siendo nuestra primitiva la última palabra del diccionario
  • Cuando usamos REDEFINE sobre una palabra que está por debajo de nuestra primitiva en el diccionario y es de tamaño diferente del que tiene la que la sobreescribe.
No es tema de este hilo explicar cómo crear/hacer palabras Primitivas de Usuario. Baste decir que, por ejemplo, cuando usas el Ensamblador/Desensamblador de BOLDFIED, las palabras las genera como Primitivas de Usuario (*). Eso sí, que sean relocalizables o no, depende de ti.

En el manual del Jupiter Ace, las palabras en código máquina definidas por el usuario se hacen de otra manera. Se crea un nuevo tipo de Palabras, las CODE con DEFINER y con CODE se crean las distinta palabras en código máquina. Aquí también es fundamental que el código máquina que creas sea relocalizable.

(*) Existe un tipo muy concreto e inusual de palabras Primitivas de Usuario que en vez de apuntar al primer byte del PF apunta a otra posición del mismo. Ver este post. en este mismo hilo.

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 07 Ago 2022 15:46

Estructura de las Palabras (XIII)
Palabras Compilantes del Ace Forth (I)

Nos queda por ver la estructura de las palabras Compilantes del Ace Forth al compilarse en el PF de una palabra de Usuario.

La lista completa es:

;
DOES>
RUNS>
LITERAL
FLITERAL
ASCII
."
(
IF THEN ELSE
BEGIN UNTIL
BEGIN WHILE REPEAT
DO LOOP +LOOP

Vamos a verlas una por una en detalle, pero primero haré unos

Comentarios Generales

La palabras Compilantes del Ace Forth son muy parecidas a las Compilantes de Usuario.

Al igual que las Compilantes de Usuario, las Compilantes del Ace Forth cumplen:

  1. (CFA) = $1108 = 4360 (*)
  2. El tamaño del OF compilado es (CA es el CFA que compila, el del Runtime)
    CA 3 - C@
  3. A partir del CFA compilado se calcula su NFA->Cualquier otro Campo:
    CFA 2- DUP @ + 1+ (**)
  4. A partir del CFA de la Compiladora del Ace Forth obtenemos el CFA de su Runtime (su CA) así:
    CFA 2+ @ = CA

(*) La única excepción es ASCII que su CFA contiene $0EC3 -> es tipo COLON. Ya entraremos en detalles cuando veamos la estructura de lo que compila.
(**) LITERAL y FLITERAL no cumplen esto.

Como vemos, solo el procedimiento #2 es de aplicación general. En cambio, el #1 y el #2 tienen alguna excepción.

Por este motivo, en el desarrollo del "Analizador de Palabras" (una rutina que utilizan mis programas Extractor de Fichero Fuente, Extractor de Dicccionarios y el Extractor de Palabras) en lugar de usar estos métodos para detectar si un CFA compilado es de una Compilante del Ace Forth, opté por chequear si el CFA en cuestión es uno de los posibles valores de todos los Runtime de la lista de palabras Compilantes del Ace.

Hubiera sido mejor usar le método #3 general y a continuación comprobar las 3 excepciones en vez de tratarlos todos como excepciones.

Pero podía haber usado el método #2 para obtener el tamaño del OF ya que funciona sin excepciones. No sé por qué no lo hice (quizás supuse que también tendría excepciones) y opté por agrupar los Runtime por tamaño de su OF y chequearlos.

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 08 Ago 2022 00:12

Estructura de las Palabras (XIV)
Palabras Compilantes del Ace Forth (II)

; (Punto y coma)

Marca el final de una palabra y de la definición.
CFA = $04A1 = 1185
(CFA) = $1108 = 4360 COMPILER
CA = $04B6 = 1206 Runtime
Size[OF] = 0

----------------------------------------------
DOES>

Marca el final de la "palabra" parte Definidora
CFA = $10B4 = 4276
(CFA) = $1108 = 4360 COMPILER
CA = $10E8 = 4328 Runtime
Size[OF] = 5

Ver el esquema-dibujo de DEFINER aquí.
Size[OF] = 5 = 2 bytes del SHIFT más 3 bytes del CALL $0FF0
----------------------------------------------
RUNS>

Marca el final de la "palabra" parte Compilante
CFA = $1125 = 4389
(CFA) = $1108 = 4360 COMPILER
CA = $1140 = 4416 Runtime
Size[OF] = 5

Ver el esquema-dibujo de COMPILER aquí.
Size[OF] = 5 = 1 byte del Size[OF] + 2 bytes del SHIFT más 2 bytes del CF Runtime
----------------------------------------------
LITERAL

Su OF contiene un número entero
CFA = $1006 = 4102
(CFA) = $1108 = 4360 COMPILER
CA = $1011 = 4113 Runtime
Size[OF] = 2

NOTA: Falla el proceso estándar CA->NFA
Ver el esquema-dibujo de PF de TEST aquí. El número compilado allí es $0109 = 265
----------------------------------------------
FLITERAL Nombre puesto por mí, pues es una palabra sin Cabecera (solo tiene CFA)

Su OF contiene un número decimal (coma flotante)
CFA = $1055 = 4181
(CFA) = $1108 = 4360 COMPILER
CA = $1064 = 4196 Runtime
Size[OF] = 4

NOTA: Falla el proceso estándar CA->NFA
Esquema-dibujo FLITERAL
Esquema FLITERAL.jpg
Esquema FLITERAL.jpg (24.58 KiB) Visto 353 veces

----------------------------------------------

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 08 Ago 2022 15:54

Estructura de las Palabras (XV)
Palabras Compilantes del Ace Forth (III)


Vamos con el caso "especial" de ASCII

ASCII

Su OF contiene un byte (un carácter)
CFA = $1028 = 4136
(CFA) = $0EC3 = 3779 COLON
CA = $104B = 4171 Runtime
Size[OF] = 1

NOTA: No es tipo COMPILER

ASCII se ha definido de tipo COLON y además se ha hecho Inmedita.

Al ser tipo COLON puede usarse en modo interactivo: Deja en la pila el código ASCII del carácter que sigue en el búfer de entrada (o del primer carácter si es una palabra).

Al ser Inmediata se ejecuta en modo compilación. En este modo opera diferente: Compila el CFA de un Runtime y en su OF de un byte compila el código ASCII del carácter que le sigue (o el primero de la palabra que le sigue). Cuando se ejecuta coloca el contenido de su OF en la pila

En ambos casos, detecta en qué modo estamos ("ejecución" o "compilación") chequeando el bit #6 de la variable del sistema FLAGS $3C3E (15422) el cual vale 1 si estamos en modo "compilación". Así puede obrar de una u otra manera según el caso.

Todas las demás palabras Compilantes del Ace, precisamente por ser Compilantes, NO se pueden ejecutar en modo interactivo. Si se intenta darán ERROR 4 (Compile only word).

Esta técnica también la podríamos usar nosotros en nuestras propias palabras, pero tendríamos problemas al listar/editar palabras que la contengan en su definición (tema ya tratado en el hilo del "JA un Forth muy particular") a menos que el Runtime que compilemos corresponda al de una palabra Compilante (de Usuario o del Ace Forth).

Un ejemplo de aplicación de esta técnica a una palabra de Usuario lo tenemos en la palabra ' (Tick) que en su versión completa (NO la del manual del JA, sino la del estándar Forth-79):

  • En modo ejecución pone en la pila el PFA de la siguiente palabra
  • En modo compilación compila el PFA de la siguiente palabra

: STATE
15422 C@ 64 AND
;

: '
FIND ?DUP 0=
IF
13 ERROR
THEN
2+ STATE
IF
4113 , ,
THEN
;

La palabra STATE pone en la pila el bit #6 de la variable del sistema FLAGS (1 si modo es "Compilación") .

Cuando se utilice la palabra ' (Tick) en la definición de otra palabra, se compila el CA que es el CFA del Runtime de LITERAL por lo que no tendremos ningún problema al listar/editar la palabra que haya utilizado ' (Tick) en su definición.

Veamos la estructura de lo que compila ASCII al usarse en la definición de una palabra. Usamos ASCII A como ejemplo:

Esquema-dibujo ASCII
Esquema ASCII.jpg
Esquema ASCII.jpg (16.37 KiB) Visto 331 veces

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 08 Ago 2022 23:18

Estructura de las Palabras (XV)
Palabras Compilantes del Ace Forth (III)

."

Su OF contiene un número variable de caracteres.
CFA = $1388 = 5000
(CFA) = $1108 = 4360 COMPILER
CA = $1396 = 5014 Runtime
Size[OF] = $FF = menos uno.

Esquema dibujo de ." del ejemplo ." Saludos"
Esquema comillas_red..png
Esquema comillas_red..png (30.86 KiB) Visto 317 veces

----------------------------------------------
(

Su OF contiene un número variable de caracteres.
CFA = $1361 = 4961
(CFA) = $1108 = 4360 COMPILER
CA = $1379 = 4985 Runtime
Size[OF] = $FF = menos uno.

Esquema dibujo de ( del ejemplo ( Saludos)
Esquema parentesis_red.png
Esquema parentesis_red.png (31.87 KiB) Visto 317 veces

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 09 Ago 2022 11:45

Estructura de las Palabras (XVI)
Palabras Compilantes del Ace Forth (IV)


IF
 
Su OF contiene un número entero con el tamaño del salto a realizar si el test es falso:
Salta detrás del OF de ELSE si lo hay. Si no hay ELSE salta detrás del THEN.
El salto se cuenta desde el High byte del OF de IF. (*)
CFA = $11C0 = 4544
(CFA) = $1108 = 4360 COMPILER
CA = $1283 = 4739 Runtime
Size[OF] = 2

----------------------------------------------
ELSE
 
Su OF contiene un número entero con el tamaño del salto si el test fue cierto:
Salta detrás del THEN.
El salto se cuenta desde el High byte del OF de ELSE.
CFA = $11EC = 4588
(CFA) = $1108 = 4360 COMPILER
CA = $1271 = 4721 Runtime
Size[OF] = 2

----------------------------------------------
THEN
 
CFA = $1207 = 4615
(CFA) = $1108 = 4360 COMPILER
CA = $12A4 = 4772 Runtime
Size[OF] = 0

----------------------------------------------
Esquema: Dos ejemplos, con ELSE y sin ELSE
NOTA: En las casillas de 1 byte ahora solo pongo el primer campo para mostrar el orden (Low byte, High byte). Solo si fuera necesario pondría algunas más.
Esquema IF THEN ELSE red.png
Esquema IF THEN ELSE red.png (56.08 KiB) Visto 308 veces


(*) Cuando digo "Los saltos se cuentan desde el High byte del OF" significa que:
Se le suma el tamaño del salto a la dirección de memoria del High byte del mismo

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 09 Ago 2022 12:46

Estructura de las Palabras (XVII)
Palabras Compilantes del Ace Forth (V)


BEGIN
 
CFA = $121A = 4634
(CFA) = $1108 = 4360 COMPILER
CA = $129F = 4767 Runtime
Size[OF] = 0

----------------------------------------------
UNTIL
 
Su OF contiene un número entero NEGATIVO con el tamaño del salto si el flag es falso:
Salta detrás del BEGIN.
El salto se cuenta desde el High byte del OF de UNTIL.
CFA = $1263 = 4707
(CFA) = $1108 = 4360 COMPILER
CA = $128D = 4749 Runtime
Size[OF] = 2

----------------------------------------------
Esquema: Un ejemplo
Esquema BEGIN red2.png
Esquema BEGIN red2.png (21.34 KiB) Visto 295 veces

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 09 Ago 2022 16:12

Estructura de las Palabras (XVII)
Palabras Compilantes del Ace Forth (V)


BEGIN (Ya visto)
 
CFA = $121A = 4634
(CFA) = $1108 = 4360 COMPILER
CA = $129F = 4767 Runtime
Size[OF] = 0

----------------------------------------------
WHILE
 
Su OF contiene un número entero con el tamaño del salto si el test fue falso:
Salta detrás del REPEAT.
El salto se cuenta desde el High byte del OF de WHILE.
CFA = $11D5 = 4565
(CFA) = $1108 = 4360 COMPILER
CA = $1288 = 4744 Runtime
Size[OF] = 2

----------------------------------------------
REPEAT
 
Su OF contiene un número entero NEGATIVO con el tamaño del salto:
Salta detrás del BEGIN.
El salto se cuenta desde el High byte del OF de REPEAT.
CFA = $124C = 4684
(CFA) = $1108 = 4360 COMPILER
CA = $1276 = 4726 Runtime
Size[OF] = 2

----------------------------------------------
Esquema: Ejemplo
Esquema WHILE red.png
Esquema WHILE red.png (38.76 KiB) Visto 288 veces

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 10 Ago 2022 12:25

Estructura de las Palabras (XVIII)
Palabras Compilantes del Ace Forth (VI)


DO
 
CFA = $12AB = 4779
(CFA) = $1108 = 4360 COMPILER
CA = $1323 = 4899 Runtime
Size[OF] = 0

----------------------------------------------
LOOP
 
Su OF contiene un número entero NEGATIVO con el tamaño del salto:
Salta detrás del DO.
El salto se cuenta desde el High byte del OF de LOOP.
CFA = $12BD = 4797
(CFA) = $1108 = 4360 COMPILER
CA = $1332 = 4914 Runtime
Size[OF] = 2

----------------------------------------------
+LOOP
 
Su OF contiene un número entero NEGATIVO con el tamaño del salto:
Salta detrás del DO.
El salto se cuenta desde el High byte del OF de +LOOP.
CFA = $12D0 = 4816
(CFA) = $1108 = 4360 COMPILER
CA = $133C = 4924 Runtime
Size[OF] = 2

----------------------------------------------
Esquema:
Solo hago el caso DO LOOP, pues el caso DO +LOOP es igual, solo cambia el CA de +LOOP que es $133C en vez del $1332 del LOOP.
Esquema DOLOOP red.png
Esquema DOLOOP red.png (28.97 KiB) Visto 278 veces

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 11 Ago 2022 00:15

Ya hemos visto la estructura de todos los tipos de palabras.

Voy a ahondar más en el tema de la palabras Primitivas del Ace Forth

Unos posts más arriba afirmé:

Elurdio escribió:····
Así, si queremos saber si una palabra es una primitiva, nos basta comprobar que el contenido de su CFA apunta al inicio de su PF

Por ejemplo, veamos si SWAP es una primitiva:
FIND SWAP DUP @ 2- - 
Si es una primitiva el resultado será cero.
····


Lo cual es cierto pero con matices.

Veamos unos casos:

LITERAL

Si hacemos:
FIND LITERAL DUP @ 2- -
nos da un valor distinto de cero -> LITERAL NO es una palabra primitiva.

Recuerda que 4113=$1011=CFA del Runtime de LITERAL
Si hacemos esto:
4113 DUP @ 2- -
nos da cero -> Runtime de LITERAL SI es una palabra primitiva.


Vemos que de las dos palabras que componen la Compilante del Ace Forth LITERAL, la parte Compilante NO es una primitiva, pero la parte Runtime sí que lo es.

Esto es bastante general con las palabras Compilantes del Ace Forth. Lo cual tiene sentido, pues que la parte Compilante se ejecute rápido NO es importante. Lo importante es que se ejecute rápido la parte Runtime.

Operaciones aritméticas

Si hacemos la prueba con las operaciones aritmética +, -, *, /, MOD, /MOD, */, */MOD, U* y U/MOD vemos que solo + y U*son primitivas, pero todas las demás salen NO primitivas. -shock

Lo cual choca bastante, pues interesa que sean rápidas. Vamos por partes.

La Resta

Si miramos el desensamblado de la ROM, vemos que la resta la han definido como una palabra tipo COLON así:
: - NEGATE + ;

O sea, en vez de restar, hace negativo al número top de la pila y realiza una suma. Tanto NEGATE como + (suma) son ambas Primitivas por lo que el conjunto es una, digamos, pseudo-primitiva.

Si medimos estas operaciones (FAST) me sale: Tiempo en segundos que tarda en realizar 10.000 operaciones.

+ 1.2 s
NEGATE 0.7 s
- 2.6 s

Se ve que si fuera 100% primitiva tardaría sobre los 1.2+0.7=1.9 s mientras que programada como pseudo-primitiva nos tarda 2.6 s. Hay un OVERHEAD de 0.7 s por hacerlo como COLON.
1.9 frente a 2.6 es un aumento en el tiempo de ejecución del 37%, lo cual es bastante, por lo que hubiera valido la pena hacerla Primitiva en vez de pseudo-primitiva.

La Multiplicación

De nuevo, mirando el desensamblado de la ROM vemos que la multiplicación está definida como tipo COLON así:
: * U* DROP ;

Tanto U* como DROP son primitivas, así que también podríamos decir que la multiplicación es una pseudo-primitiva
Recordemos que U* multiplica dos enteros de la pila dando como resultado un entero de doble precisión. El DROP nos convierte el resultado de nuevo en un entero sencillo al eliminar el High Word, con lo que nos quedamos el Low Word.

Al ser la multiplicación bastante más lenta que la suma, el OVERHEAD del COLON (0.7 s) pesa menos y la opción pseudo-primitiva es más aceptable:

Tiempo 10.000 multiplicaciones 6.2 s


División
Aquí, tras mirar la ROM, la división se programa como COLON y utiliza /MOD descartando el resto. Pero /MOD es también tipo COLON y usa U/MOD el cual, a su vez, también es tipo COLON y utiliza una rutina interna de división que, por fin, está en código máquina.

Pero si se mira, por ejemplo, la definición COLON de /MOD pues vemos que es:

: /MOD SWAP >R I ABS stk_data(0) ROT DUP I XOR >R ABS U/MOD >R pos SWAP >R pos SWAP ;
(Donde la palabras en minúsculas son de uso interno.)

Ya no son dos palabritas...

Tiempo 10.000 divisiones 43.3 s

En fin, que no me extraña que el JA sea tan lento en las comparativas de velocidad de operaciones aritméticas respecto a otros Forth de la época.

Y ya no me explayo más con las otras operaciones, ya vemos por dónde van los tiros.

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 20 Ago 2022 16:30

Me acabo de dar cuenta que he cometido un error al describir las estructura interna de las palabras Tipo DEFINER (y posiblemente las COMPILER también).

Cuando dije (y dibujé) que Address(azul) apunta a SHIFT me equivoqué, apunta al primer byte del CALL (el que contiene $CD).

Voy a tener que repasar todas la fórmulas y, lo peor de todo, retocar los esquemas-dibujo.

Cuando esté todo arreglado, pondré un post aquí indicándolo.

EDIT: Lo mismo con las tipo COMPILER.

Me he quedado "a cuadros" que haya pasado desapercibido tan garrafal error hasta la fecha. He vuelto a mirar el primer post que publiqué sobre la estructura de las palabras tipo DEFINER (éste) y allí sí esta bien descrito. El fallo ha sido reciente, al volver a tocar el tema para masticarlo y "corregir errores"... -banghead

Elurdio
Mensajes: 510
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 115 veces
Agradecimiento recibido: 95 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 21 Ago 2022 10:29

.
Corregido el error(y algunos nuevos menores que he detectado en el proceso)

En total he tenido que corregir 4 posts (2 sobre DEFINER y 2 sobre COMPILER). Todos tienen la marca "EDIT (fecha): motivo" al final.

Comentarios

El post Original sobre la estructura de las palabras tipo DEFINER (el primero, de hace 7 meses) está correcto sobre a dónde apunta el contenido de los dos primeros bytes del PF (Address), pero falla "conceptualmente" (que no "operativamente") con respecto al OF de DOES>, que por aquél tiempo no lo tenía muy claro, la verdad.

Gracias a Dios todavía conservo los esquemas-dibujos originales, que son "vectoriales", por lo que la edición de los mismos ha sido relativamente fácil.

En cuanto a las fórmulas, para mi sorpresa, no he tenido que modificarlas. Ha cambiado la forma "conceptual" de llegar a ellas, pero el resultado es el mismo. Unas porque no usaban directamente el valor Address(azul) y otras porque debí copiarlas de posts anteriores que sí estaban bien.

Un ejemplo en el que hubiera fallado el tema sería éste:

Supongamos que quiero hacer un programa que me liste el nombre de todas la palabras tipo 2CONSTANT que hay en el diccionario (ejemplo que es aplicable a cualquier palabra definidora de usuario, no solo a 2CONSTANT).

El núcleo del programa es encontrar un dato que compartan todas esas palabras y que no tengan otro tipo de palabras. Lo demás (buscar en el diccionario, etc.) es accesorio.

Ese dato no es otro que el CF=(CFA): Todas las palabras tipo 2CONSTANT tienen el mismo CF que es igual la dirección del tercer byte del OF de DOES> en 2CONSTANT.

Según el esquema "erróneo" esa dirección es Address_azul + 2 que en Ace Forth sería:
FIND 2CONSTANT 2+ @ 2+

Según el esquema "correcto" esa dirección es Addres_azul que en Ace Forth sería:
FIND 2CONSTANT 2+ @


Como vemos, si aplicara el esquema "erróneo" obtendría la dirección del 5º byte del OF en vez de la esperada dirección del tercer byte.


Volver a “Jupiter Ace”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado