Jupiter Ace Forth: Utilidades

Elurdio
Mensajes: 404
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 87 veces
Agradecimiento recibido: 83 veces

Re: Jupiter Ace Forth: Utilidades

Mensajepor Elurdio » 03 Ago 2022 12:53

Último mensaje de la página anterior:

Respecto a evitar el uso de ENDGOTO al final de cada definición que usa GOTO/LABEL:

Lo de usar mis propias versiones modificadas de DOES>, RUNS> y ; lo he probado y funciona.

Pero cuando editas la palabra que las contiene, se listan la nueva y la original seguidas. Lo cual te obliga a borrar todas las instancias de la original antes de entrar la palabra editada. O sea, es más engorroso que usar el ENDGOTO.

Por lo que descarto lo de eliminar el ENDGOTO, al menos con este enfoque.

Elurdio
Mensajes: 404
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 87 veces
Agradecimiento recibido: 83 veces

Re: Jupiter Ace Forth: Utilidades

Mensajepor Elurdio » 03 Ago 2022 16:11

He hecho la versión compatible con los "nuevos" códigos marcadores de inicio (11 y 12) y que NO necesita INIGOTO. Sigue haciendo falta el ENDGOTO como en la versiones ULOOPGOT y ULOOPGOTN

Código Fuente

Código: Seleccionar todo

\ ****************************************************
\ * Conjunto de Estructuras de Control de Usuario    *
\ *                                                  *
\ *  Bucles Sin Signo: ULOOP/+ULOOP/NEXT             *
\ *     Son compatibles con DO, LEAVE, I, I' y J     *
\ *                                                  *
\ *  Salto Incondicional: GOTO/LABEL/KILLOOP/ENDGOTO *
\ ****************************************************

DECIMAL

\ Versión en código máquina de multiplicar por 2

BASE C@ DECIMAL 16 BASE C!
CREATE 2*
 DF C, CB C, 23 C, CB C, 12 C,
 D7 C, FD C, E9 C,
BASE C! 2* DUP 2- !

\ Versión en código máquina de dividir por 2

BASE C@ DECIMAL 16 BASE C!
CREATE 2/
 DF C, CB C, 2A C, CB C, 1B C,
 D7 C, FD C, E9 C,
BASE C! 2/ DUP 2- !

\ Runtime de ULOOP en código máquina

BASE C@ DECIMAL 16 BASE C!
CREATE ULOOPMC
 21 C, 04 C, 00 C, 39 C, 34 C,
 20 C, 04 C, 23 C, 34 C, 18 C,
 01 C, 23 C, 23 C, 5E C, 23 C,
 56 C, EB C, F1 C, C1 C, D1 C,
 D5 C, C5 C, F5 C, B7 C, ED C,
 52 C, 28 C, 0F C, 38 C, 0D C,
 DF C, EB C, 4E C, 23 C, 46 C,
 2B C, 09 C, C1 C, D1 C, E5 C,
 C5 C, FD C, E9 C, C1 C, D1 C,
 E1 C, E1 C, D5 C, C5 C, DF C,
 FD C, E9 C,
BASE C! ULOOPMC DUP 2- !

\ Runtime de +ULOOP en código máquina

BASE C@ DECIMAL 16 BASE C!
CREATE ULOOPMC+
 CD C, 4E C, 08 C, 21 C, 04 C,
 00 C, 39 C, 5E C, 23 C, 56 C,
 EB C, 09 C, 78 C, EB C, 72 C,
 2B C, 73 C, 23 C, 23 C, 4E C,
 23 C, 46 C, 60 C, 69 C, CB C,
 7F C, 28 C, 09 C, B7 C, ED C,
 52 C, 28 C, 18 C, 30 C, 16 C,
 18 C, 07 C, B7 C, ED C, 52 C,
 28 C, 0F C, 38 C, 0D C, DF C,
 EB C, 4E C, 23 C, 46 C, 2B C,
 09 C, C1 C, D1 C, E5 C, C5 C,
 FD C, E9 C, C1 C, D1 C, E1 C,
 E1 C, D5 C, C5 C, DF C, FD C,
 E9 C,
BASE C! ULOOPMC+ DUP 2- !

\ Runtime de NEXT en código máquina
\ y también es el Runtime de GOTO

BASE C@ DECIMAL 16 BASE C!
CREATE MCNEXT
 DF C, 62 C, 6B C, 4E C, 23 C,
 46 C, EB C, 09 C, D1 C, C1 C,
 E5 C, D5 C, FD C, E9 C,
BASE C! MCNEXT DUP 2- !

10 VARIABLE MRK     \ Contiene el marcador usado por al definición:
                    \ 10 si COLON o Runtime de DEFINER/COMPILER
                    \ 11 si COMPILER antes de RUNS>
                    \ 12 si DEFINER  antes de DOES>
                   
0 COMPILER INIGOTO  \ Chequea cual es el valor del marcador usado por la definición en curso.
                    \ Esta palabra ha de ser la primera de la definición cuando se usa GOTO/LABEL
                    \ Si GOTO/LABEL se usan en una DEFINER o COMPILER tiene que ir al principio de la
                    \ parte compilante si se usan allí y/o de la parte Runtime si se usan allí. O sea se
                    \ tratan por separado las dos zonas como si fueran dos definiciones distintas (que de hecho
                    \ lo son, de ahí los marcadores diferentes para cada zona):
 
 DUP MRK !
RUNS>
 DROP
;

: DEPTH ( - n)
\ Coloca en la pila el tamaño de la misma (sin contar n)

 15419 @ HERE 12 +
 - 2/
;
 
: ERROR ( n - )
\ Aborta el programa con el mensaje "ERROR n"
 
 15421 C! ABORT
;
 
: ROLLD ( n - )
\ Como ROLL pero en sentido contrario: Saca n de la pila y la rota colocando el elemento top en la posición n y
\ subiendo todos los que están por encima de él una posición.
\ e.g. < 6 5 3 8 21 4 ROLLD > -> < 6 21 5 3 8 >

 DUP 2 <
 IF
  DROP EXIT
 THEN
 DUP DEPTH 2- >
 IF
  2 ERROR
 THEN
 SWAP >R DEPTH OVER -
 2* HERE + 12 +
 DUP >R OVER 1- 2*
 + DUP ROT 1- 0
 DO
  DUP 2- SWAP OVER @
  SWAP !
 LOOP
 DROP R> R> SWAP !
;
 
: ENCRUST
 ( n,i - )
\ Dada la posición i de la pila (sin contar ni a n ni a i), incrusta n justo debajo de dicha posición.
\ e.g. < 50 40 30 20 10 88 4 ENCRUST > -> < 50 88 40 30 20 10 >

 1+ ROLLD
;

: CHKMRK ( - ) 
\ Busca el marcador de inicio de definición en curso.
\ Almacena en la variable MRK el primer valor que encuentra en la pila que sea un 10 o un 11 o un 12.

 DEPTH 1+ 1
 DO
  I PICK DUP 10 =
  IF
   LEAVE
  ELSE
   DUP 11 =
   IF
    LEAVE
   ELSE
    DUP 12 =
    IF
     LEAVE
    ELSE
     DROP
    THEN
   THEN
  THEN
 LOOP
 MRK !
;

: SEARCH>10 ( n - n2)
 \ n es el número a buscar antes de encontrar un 10.
 \ n2 es la posición que ocupa en el stack (1->top, 0->no encontrado)
 
 DEPTH 1+ 2
 DO
  I PICK 10 =
  IF
   DROP 0 LEAVE
  ELSE
   I PICK OVER =
   IF
    DROP I 1- LEAVE
   THEN
  THEN
 LOOP
;


: SEARCHMRK ( - n)
\ n es dos posiciones antes del valor de la varibale MRK en la pila.
\ ENCRUST incrusta justo debajo de la posición dada, pues así lo necesita NEXT
\ Pero GOTOF necesita incrustar justo encima de la posición dada.
\ Para poder aprovechar ENCRUST añadimos el "2-" y así, cuando usemos ENCRUST incrustará justo encima.
 
 DEPTH 1+ 1
 DO
  I PICK MRK @ =
  IF
   I LEAVE
  THEN
 LOOP
 2-
;

: GETNUM ( - n)
\ Busca el número compilado como LITERAL que está al final del diccionario justo antes de la compilante de usuario
\ que contiene al GETNUM y lo pone en la pila.
\ Comprueba se sea mayor que 100 (menor número de etiqueta válido)

 HERE 4 - @  \ El número de etiqueta está 4 bytes antes del HERE al ejecutarse el GOTO/LABEL que contiene a GETNUM.
 DUP 100 < OVER 199 > OR
 IF
  100 ERROR
 THEN
;

: DELPICK ( n - )
\ Elimina el elemento en la posición n del stack (sin contar n mismo)

 ROLL DROP
;

: SEARCH>MRK<P ( n,p - m)
\ Busca un número n en la pila de arriba hacia abajo empezando en la posición p (p=1 es top).
\ Termina si encuentra el valor de la variable MRK
\ Devuele m=0 si no la encuentra o m=posición de n si la encuentra.

 DEPTH 1+ SWAP 1+
 DO
  I PICK MRK @ =
  IF
   DROP 0 LEAVE
  ELSE
   I PICK OVER =
   IF
    DROP I 1- LEAVE
   THEN
  THEN
 LOOP
;

: SEARCHLABEL ( n - m)
\ Busca una etiqueta con número n en la pila. Si la encuentra m=posición, si no, m=0
\ La etiquetas tienen como código primero un 25. Luego viene el número de etiqueta y luego el HERE

 25 1
 BEGIN
  SEARCH>MRK<P ?DUP 0=
  IF
   DROP 0 EXIT
  THEN
  OVER OVER 3 + PICK =
  IF
   SWAP DROP EXIT
  THEN
  25 SWAP 1+ 0
 UNTIL
;

: SEARCHGOTO ( n - m)
\ Busca un GOTO con número de etiqueta n en la pila. Si la encuentra m=posición, si no, m=0
\ Los GOTO (adelante) tienen como código primero un 30. Luego viene el número de etiqueta y luego el HERE
\ Los GOTO (atrás) se resuelven al momento (la etiqueta tiene que existir previamente).

 30 1
 BEGIN
  SEARCH>MRK<P ?DUP 0=
  IF
   DROP 0 EXIT
  THEN
  OVER OVER 3 + PICK =
  IF
   SWAP DROP EXIT
  THEN
  30 SWAP 1+ 0
 UNTIL
;

2 COMPILER ULOOP
\ Igual que LOOP pero trata los límites como enteros sin signo.

 3 = 0=
 IF
  5 ERROR
 THEN
 HERE - ,
 BEGIN
  DUP 5 =
 WHILE
  DROP DUP HERE SWAP -
  4 - SWAP !
 REPEAT
RUNS>
 ( R> R> 1+ >R >R I' J U< 0= DUP  ) \ Versión Forth
 ( IF                             )
 ( R> R> R> DROP DROP             )
 ( >R                             )
 ( THEN                           )
 ULOOPMC                            \ Versión Código Máquina
;
 
2 COMPILER +ULOOP
\ Igual que +LOOP pero trata los límites como enteros sin signo

 3 = 0=
 IF
  5 ERROR
 THEN
 HERE - ,
 BEGIN
  DUP 5 =
 WHILE
  DROP DUP HERE SWAP -
  4 - SWAP !
 REPEAT
RUNS>
 SWAP ULOOPMC+
;
 
2 COMPILER NEXT
\ Salta directamente al ULOOP/+ULOOP

 3 SEARCH>10 DUP 0=
 IF
  5 ERROR
 THEN
 1+ DUP >R 5 SWAP
 ENCRUST HERE R> 1+ ENCRUST
 0 ,
RUNS>
 ( DUP @ + R> DROP >R ) \ Versión Forth
 MCNEXT                 \ Versión Código Máquina
;

2 COMPILER GOTO ( - )
\ Salto incondicional adelante o atrás.
\ Los datos que deja en la pila son: El código 30 de GOTO + número de etiqueta + HERE (solo GOTO adelante)
\ Si encuentra un LABEL con su número de etiqueta    => Salto hacia atrás (lo resuelve)
\ Si NO encuentra un LABEL con su número de etiqueta => Salto hacia adelante -> Pone datos en pila (lo deja pendiente)

 CHKMRK                                 \ Hace la variable MRK = marcador en curso (10, 11 o 12)
 GETNUM SEARCHLABEL ?DUP 0=
 IF   
  \ Etiqueta aún no existe -> Es un salto hacia adelante -> Deja datos en la pila para ser resueltos por la
  \ etiqueta con el mismo número cuando se compile.
  30 SEARCHMRK ENCRUST GETNUM SEARCHMRK ENCRUST HERE SEARCHMRK ENCRUST 0 ,
 ELSE
  \ Etiqueta ya existe -> Es un salto hacia atrás -> Resolvemos el GOTO hacia atrás sin poner nada en la pila.
  1+ PICK HERE - ,
 THEN
RUNS>
  ( SWAP DROP) ( DUP @ + R> DROP >R )   \ Versión Forth
  SWAP DROP MCNEXT                      \ Versión Código Máquina.
;

0 COMPILER LABEL ( - )
\ Etiqueta destino del GOTO correspondiente.
\ Los datos que deja en la pila son: El código 25 de LABEL + número de etiqueta + HERE
\ Los datos de una etiqueta NO se borran cuando se resuelve, pues un LABEL puede corresponder a varios GOTOs.
\ Lo primero que hace es comprobar que el número de etiqueta no esté repetido.
\ Luego busca si existe un GOTO pendiente con el mismo número de etiqueta y si lo encuentra -> lo resuelve (adelante)
\ Si no encuentra ningún GOTO pendiente, NO hace nada.

 GETNUM SEARCHLABEL 0= 0=       \ Etiqueta repetida -> ERROR 101
 IF   
  101 ERROR
 THEN

 CHKMRK                         \ Hace la variable MRK = marcador en curso (10, 11 o 12)
 \ Coloca sus datos en la pila
 25 SEARCHMRK ENCRUST GETNUM SEARCHMRK ENCRUST HERE SEARCHMRK ENCRUST

 \ Resuelve cualguier GOTO pendiente con el mismo número de etiqueta.
 BEGIN
  GETNUM SEARCHGOTO ?DUP 0= 0=
 WHILE
  DUP DELPICK DUP DELPICK 1- ROLL
  DUP HERE SWAP - SWAP !
 REPEAT
RUNS>
 DROP DROP
;

: KILLOOP ( n - )
\ n es el número de bucles DO/LOOP/+LOOP/ULOOP/+ULOOP que hay que "cerrar" cuando se ejecute el GOTOF.
\ e.g. Si el GOTOF está dentro de 3 bucles anidados y salta al interior del más externo habrá que
\      cerrar 2 bucles (el más externo sigue en uso).
\ OJO: Si hay >R/R> pendientes de cerrar, hay que cerrarlos también, pero tienes que hacerlo tú.
\      Pero es muy peligroso. No se recomienda usar GOTOF/LABELF si se están usando pares >R/R>
\ IMPORTANTE: KILLOOP ha de ir justo antes del GOTOF/B (sin nada entre ambas) e.g. KILLOOP 100 GOTOF

 DUP 1 <
 IF
  DROP EXIT
 THEN
 R>
 SWAP
 BEGIN
  R> DROP R> DROP 1- ?DUP 0=
 UNTIL
 >
;

0 COMPILER ENDGOTO ( - )
\ Si en una palabra se usa GOTO/LABEL hay que terminarla con ENDGOTO para que elimine los datos de etiquetas de
\ la pila. Esto implica que pueden haber etiquetas que no las use nadie y gasten memoria y tiempo de ejecución.

 BEGIN
  25 1 SEARCH>MRK<P ?DUP 0=
  IF
   EXIT
  THEN
  1+ DUP DELPICK DUP DELPICK 1- DELPICK
  0
 UNTIL
RUNS>
 DROP
;

uloopgotf.TZX
(1.66 KiB) Descargado 1 vez

Elurdio
Mensajes: 404
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 87 veces
Agradecimiento recibido: 83 veces

Re: Jupiter Ace Forth: Utilidades

Mensajepor Elurdio » 03 Ago 2022 22:27

Comentar respecto a las estructuras de control que todas, incluso las sencillas, pueden fallar según lo que se haga.

Pongo un ejemplo de como puede fallar la estructura IF/THEN haciendo algo que, en principio, no es incorrecto aunque sí algo poco habitual.

Defino la palabra TEST de esta manera:

: TEST IF [ 3 ] THEN LITERAL ;

Cuando la entre me dará ERROR 5.

En teoría, TEST definido así, al listarlo (si no hubiera fallado) debería dar:

: TEST
IF
THEN
3
;

Lo normal es cargar el 3 en la pila justo antes del LITERAL y no como lo hemos hecho.

Si lo hubiéramos hecho así:
: TEST IF  THEN [ 3 ] LITERAL ;

El resultado sería el listado de arriba, como era de esperar.

Si en vez de un 3 hubiéramos usado, por casualidad, un 2, la palabra se compila sin error pero la listarla vemos que NO es lo que se pretendía que fuera:

: TEST IF [ 2 ]  THEN LITERAL ;

Si la listas:

: TEST
IF
THEN
24083
;

NOTA: El 24083 puede ser otro número, depende del tamaño del diccionario en el momento de definir TEST.

Si ejecutamos:
1 TEST .

nos imprime 24083. Bien.

Pero si ejecutamos:
0 TEST .

en mi caso se reinició el Ace Forth (se borró el diccionario). Es porque el IF ante un valor falso, ejecuta el salto y éste se programó mal...

El porqué tiene que ver con los códigos de control que pone IF y lo que hay en la pila en el momento de cerrar el IF con el THEN. El IF pone un 2 y el THEN espera ese 2 en el top de la pila.

Dejo la explicación detallada de lo que ha pasado en los diferentes casos al lector del post.

En general, hay que vigilar un poco lo que hacemos con la pila cuando se compilan estructuras de Control, tanto si son las que vienen con Ace Forth como las que podamos hacer nosotros.

Elurdio
Mensajes: 404
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 87 veces
Agradecimiento recibido: 83 veces

Re: Jupiter Ace Forth: Utilidades

Mensajepor Elurdio » 05 Ago 2022 13:01

Solo aclarar un dato incorrecto que di hablando de los "nuevos" códigos 11 y 12:

Dije que son marcadores de inicio de definición. Como el 10 en el caso de las COLON. Pero hay que añadir que también se usan como marcadores para cálculos durante la compilación de la palabra. Me explico:

Por ejemplo, el par DEFINER/DOES>. Cuando se ejecuta DEFINER, NO solo coloca el 12 en la pila, sino que justo debajo coloca el valor de HERE en ese momento para que luego DOES> pueda calcular valores que ha de compilar. Y algo parecido con COMPILER/RUNS> y el 11. En ambos casos es en la compilación de la parte primera, no así en la parte segunda (Runtime), que pone un 10 y nada más (marcador de inicio de definición puro y duro)

Elurdio
Mensajes: 404
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 87 veces
Agradecimiento recibido: 83 veces

Re: Jupiter Ace Forth: Utilidades

Mensajepor Elurdio » 08 Ago 2022 12:22

En este este post comentaba que la versión de SIN del paquete Mathematical & Trigonometrical Functions era, en modo FAST, casi 2.5 veces más rápido que la misma función definida según las páginas 92 y 93 de Manual de Jupiter Ace.

Hoy he encontrado esto sobre la versión usando solo números enteros para calcular SIN y COS. Ya se ha hablado mucho del tema en libros/artículos de la época pues Forth, en general, carece de números en coma flotante. Me he decidido a probarlo. Pensaba que la diferencia sería abismal, pero, aunque significativa, no es para tanto.

La idea es poder utilizar estos senos en aplicaciones que usen gráficos que no requieren mucha precisión.

Pongo aquí los resultados obtenidos comparando los resultados del Seno versión números enteros con el Seno versión Manual del JA:

Primero van los grados (en grados sexagesimales), luego el resultado entero (1 = 10000) y por último el resultado en coma flotante.
sinustest.png
sinustest.png (16.81 KiB) Visto 58 veces

Como se ve, la precisión es aceptable para ser enteros.

En cuanto a la velocidad de ejecución, estos son los resultados:
1 - Tiempo en segundos para 0 a 90 grados en incrementos de 1 grado. (91 senos) (Slow/Fast)
2 - Senos por segundo (Slow/Fast)

.                               SIN/s
Versión Slow Fast Slow Fast
----------------------------------------
JA 24.9 22.3 3.5 4.0
M&T 13.6 9.4 6.7 9.7
INT 10.2 6.6 8.9 13.8

Elurdio
Mensajes: 404
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 87 veces
Agradecimiento recibido: 83 veces

Re: Jupiter Ace Forth: Utilidades

Mensajepor Elurdio » 14 Ago 2022 16:57

Mirándome el desensamblado de la ROM del Jupiter Ace he visto varias cosas interesantes.

1- Hay una subrutina en $084E que te pone en el par de registros BC el entero que hay en el top de la pila. Esto ya hace tiempo que lo sé, pero creo que no lo he comentado nunca.

2- Hay muchas Palabras de uso interno. Supongo que para ahorrar espacio las han hecho "Headerless" (sin cabecera). No es que no tengan cabecera, sino que tienen una cabecera con solo del Code Field, nada más.

El punto 1 puede ser de utilidad en assembler.

El punto 2 es interesante porque algunas de esas palabras "Headerless" pueden ser útiles.

A modo de ejemplo, voy a comentar una en concreto:

La que tiene su CFA en $0688. En el desemsamblado la han llamado "stk-zero". Simplemente coloca un cero en la pila. Además, es una primitiva, pues el contenido de su CFA apunta al inicio de su PF.

; ----------------------------
; The 'stk-zero' Internal Word
; ----------------------------
; ( -- 0 )

L0688: DEFW L068A ; headerless 'code field'

; ---

L068A: LD DE,$0000 ; load DE with the value zero.
RST 10H ; stack Data Word DE

JP (IY) ; to 'next'.

Lo que se me ha ocurrido es crear palabras que nos permitan usar estas "palabras internas" como una palabra más del Ace Forth. Lo que hago es crear un nuevo tipo de palabra. Las llamaré tipo "Internas".

Vienen a ser un tercer caso de primitivas: Las normales en las que (CFA) = PFA. Las "raras" de BoldField en las que (CFA) apunta dentro del PF pero no precisamente al inicio y ésta en las que (CFA) apunta a la ROM y no tienen PF.

En el caso del stk-zero voy a crear la palabra CERO así:

CREATE CERO

Ahora solo hemos de colocar en su CF el contenido del CF de stk-zero que vale $068A (1674)

1674 CERO 2- !

Y ya tenemos nuestra palabra CERO de tipo "Interno" y sin PF (Parameter Field).

CERO no es ni listable ni editable.

Vamos a ver que tal se porta:

: TEST1 0 ;
: TEST2 CERO ;

Mido los tiempos de ejecución en segundos para 10.000 veces.

Slow Fast
TEST1 1.7 0.9
TEST2 1.5 0.6


Vemos que en modo FAST la palabra CERO es un 50% más rápida que poner en la pila un cero compilado.

Hasta ahora he encontrado seis casos de palabras Headerless que pueden ser útiles:

  • stk_zero $068A Coloca un cerro en la pila
  • stk_digit $07BA Toma un número de la pila y si es el ascii de un carácter válido en la base actual devuelve el dígito correspondiente. En el top de la pila pone un flag: 1 si correcto 0 si inválido
  • stk-char $0A09 Parece la inversa de la anterior, pero solo lo he mirado por encima.
  • branch $1278 Unconditional branch.
  • ?branch $128F Conditional branch
  • check-for $12DA Check internal marker for control structure.

La que me interesan sobremaner son las tres últimas. Pues serían útiles en la creación de estructuras de control de usuario. Pero me temo que van a dar problemas. Ya lo estudiaré más adelante.

La pega está en que algunos de mis programas, como por ejemplo WLIST y el Extractor de Fuentes Semiautomático EXTRACTSOU fallarán si se encuentran con este tipo de palabras "Internas" al estilo CERO.

De momento, dado que, por un lado, no me he encontrado nunca con este tipo de palabras, y por otro lado no veo que valgan la pena por los tres primeros casos, no modificaré nada.

En cambio, si los tres últimos, sobre todo el branch y el ?branch se pudieran aprovechar, sí me veo entonces dispuesto a crear las seis (y cualquier otra que vea) y modificar mis programas para este nuevo tipo de palabra "Interna".

Elurdio
Mensajes: 404
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 87 veces
Agradecimiento recibido: 83 veces

Re: Jupiter Ace Forth: Utilidades

Mensajepor Elurdio » 15 Ago 2022 16:49

Uno de mi muchos defectos es que tengo tendencia a aceptar lo que me parece que debería ser con cuatro comprobaciones, sin comprobarlo a fondo.

Hace poco hablaba, en otro hilo, de las palabras originales del del Ace Forth (las que hay cuando lo acabas de arrancar) que están escritas en código máquina (primitivas) y las que están escritas internamente como definiciones COLON, COMPILER, etc

En general, cuando importa que se ejecuten rápido serán primitivas. Cuando no es tan crítica la velocidad de ejecución, se harán como COLON, etc.

Pues bien, probé con unas cuantas de las palabras manipuladoras del STACK y como me salieron que eran primitivas, pues di por supuesto que lo eran todas, pues sería lo lógico al ser palabras de las que se espera que todas sean lo más rápidas posible.

Pues NO -banghead

Hoy viendo que un programa usaba sus propias versiones de OVER y ROT pensé que era porque habrían hecho versiones del código máquina más efectivas. Cual fue mi sorpresa cuando vi que esas dos palabras en el Ace Forth NO son primitivas, está escritas como definiciones COLON internas.

Volví a comprobar las palabras de manejo de la PILA (STACK) del JA y veo que todas son primitivas menos esas dos:

Primitivas: DROP, DUP, SWAP, ROLL y PICK
NO-primitivas: OVER y ROT

Entonces supuse que sería por una cuestión de espacio. Que tanto OVER como ROT serían más cortas así que en código máquina. Pero esta vez, recién escaldado, me dije: "compruébalo".

Y NO, no es por cuestión de espacio. De hecho, las versiones en código máquina de esas dos palabras que lleva el programa en cuestión (TURTLE.TAP) ocupan 19 bytes cada una (38 bytes en total). Las versiones del Ace FORTH ocupan 18 y 20 bytes respectivamente (38 en total).

Son iguales, pero si las pusiéramos en la ROM, al ser las cabeceras de la palabras originales del JA 2 bytes más cortas, tendríamos que ocuparían solo 34 bytes frente a los 38 que ocupan las actuales.

Creo, y es solo una idea, que se les pasó hacerlo al modo que lo han hecho los del TURTLE.TAP. No han hecho unas versiones código máquina desde cero, sino que han aprovechado las rutinas en código máquina del ROLL del JA. Por un lado sabemos que 3 ROLL es lo mismo que ROT. Por otro lado han hecho un uso parcial de las rutinas del ROLL para hacer un OVER. Todo muy ingenioso.

Y la cosa es seria, pues las versiones nuevas son mucho más rápidas que las del JA. El ROT unas 3 veces y el OVER 4-5 veces más rápidos.

Es que incluso, usando las versiones que vienen con el JA, es más rápido (casi el doble) hacer un 3 ROLL que ROT...


Volver a “Jupiter Ace”

¿Quién está conectado?

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