EFORTH para calculadora programable

Este es el primer artículo de la serie 161eForth v0.5b, que termina aquí: habr.com/en/post/452572

¡El traductor EFORTH ahora también está en la calculadora electrónica electrónica MK-161! El 17 de mayo, la versión v0.5b superó con éxito mis pruebas, así como cinco pruebas de autoría TEST-TEST4. He logrado lo que se puede hacer solo, pero creo que esto es solo la mitad de la batalla. Es hora de presentar una nueva herramienta a la comunidad abriendo el código 161eForth para pruebas públicas. Tengo una lista de qué mejorar y dónde "trabajar en la estabilidad". Sus sugerencias y comentarios se tendrán en cuenta al completar el trabajo y la versión 1.0

Al portar la última versión de eForth a la plataforma doméstica, se superaron con éxito dos obstáculos: la velocidad relativamente baja de la máquina de 8 bits, que está programada en su propio idioma de entrada, y la modesta cantidad de memoria binaria disponible (ver 2.4.1), solo 4096 bytes.


Al escribir 161eForth, se utilizaron soluciones preparadas para Callisto, el lenguaje de entrada de próxima generación para PMK doméstico. Esta es una tecnología para implementar una máquina fuerte en la parte superior de la ALU decimal y la arquitectura "Harvard", controladores de consola y un diseño de teclado alfanumérico, así como un terminal de software basado en ellos, que funciona a través del puerto serie RS-232. Además de Electronics MK-161 y la distribución 161eForth, es posible que necesite un teclado de parche casero donde las letras de los alfabetos ruso e inglés estén firmadas en las teclas. Las letras están ordenadas alfabéticamente línea por línea, de izquierda a derecha y de arriba a abajo.


El Dr. Chen-Hanson Ting, autor de versiones modernas de eForth, enfatiza en su libro [1] la importancia de comprender los dos componentes del Fuerte. Este es un intérprete interno ("dirección") que permite que el equipo ejecute el código cosido de Fort, y un intérprete externo ("texto") responsable del diálogo con una persona.

En dos artículos, me detendré en detalle sobre las soluciones más radicales utilizadas en la implementación de cada uno de estos dos intérpretes en Electrónica. Aprender estas soluciones puede ser útil e inspirador para migrar eForth a otros dispositivos con memoria y rendimiento limitados. Comprender los artículos ayudará con una introducción inicial a los microcalculadores programables (PMC) y Fort. Explicaré momentos difíciles exclusivos de Electronics MK y el traductor eForth.

Para empezar, las palabras eForth se dividen en generales y sistémicas. El tamaño de las letras es importante. Los nombres de las palabras ordinarias se definen en letras mayúsculas y sistema - minúsculas. También hice mis innovaciones en eForth en minúsculas. El autor de eForth sugiere llevar a cabo el diálogo principal en modo CAPS. Cuando necesite usar la palabra del sistema, cambie el tiempo a letras minúsculas (combinación de teclas FP).

En el artículo, todas las palabras están escritas en mayúsculas para destacar del texto. En varias implementaciones tempranas de eForth, los encabezados de palabras del sistema se excluyeron y el comando WORDS no los generó. Esto ayudó a simplificar la apariencia de eForth y a salvar la atención de quienes usan Fort por primera vez. En 161eForth, los encabezados de estas palabras se guardaron principalmente debido a la presencia del descompilador de palabras SEE de dos puntos (ver video No. 3 al final del artículo), que no mostrará los nombres de las palabras del sistema si se eliminan sus encabezados.

Para simplificar el artículo y hacerlo útil como referencia, tuve que usar varios términos antes de definirlos. Los profesionales de Fort y PMK deben estar familiarizados con estos términos. Los principiantes a veces tienen que buscar en las secciones vecinas (pongo los enlaces en los lugares correctos) o volver a leer el artículo un par de veces.

161eForth se presenta aquí, junto con el texto fuente, un teclado gráfico en pantalla y palabras de ayuda.txt con una descripción de todas las palabras implementadas: http://the-hacker.ru/2019/161eforth0.5b.zip

También publiqué 5 videos pequeños en YouTube que ilustran el funcionamiento del 161eForth para aquellos que no tienen el MK-161. Puedes ver toda la lista de reproducción en YouTube . A continuación se muestra el primero de ellos, los 4 restantes al final del artículo.



eForth y su implementación


eForth fue diseñado como un reemplazo moderno para el conocido traductor fig-Fort. Para transferir al MK-161, elegí una versión 5.2 de 32 bits del traductor 86eForth con código indirecto cosido, escrito en 2016 en el ensamblador MASM para el sistema operativo Windows. Esta versión se describe en detalle en la tercera edición de eForth y Zen [1]. Aquellos que saben inglés, les aconsejo que encuentren y estudien este libro, es muy útil para comprender 161eForth.

En una carta personal, el autor confirmó que 86eForth502.asm de este libro es la última versión de eForth. En Internet puede encontrar mucha información en inglés sobre esto y sobre versiones anteriores de eForth.

El desarrollo de eForth siguió un camino científico enseñado por el profesor Wirth utilizando el ejemplo de su lenguaje de programación Oberon. Cada versión posterior de eForth fue una simplificación de la versión anterior. Todo lo que se puede prescindir se eliminó de la lengua. Queda un conjunto cuidadosamente pensado de construcciones de lenguaje fuerte y expresivo, cuyo poder ha sido probado en más de 40 implementaciones de eForth para varias plataformas. Ahora en la calculadora!

Al ser un dialecto minimalista de Fort, eForth no tiene como objetivo ganar la carrera contra el Fort más pequeño. El conjunto de palabras que ofrece es bastante práctico y el programador puede ampliarlo fácilmente en la dirección necesaria para sus tareas.

La primera versión de eForth se lanzó en 1990 en el ensamblador MASM para procesadores 8086 y funcionó bajo MS-DOS. Contenía 31 palabras centrales dependientes de la máquina y 191 palabras de alto nivel. La idea era simple: traduce solo 31 palabras en su ensamblador e inmediatamente obtiene eForth en su computadora.

Este enfoque ha sido criticado en Internet, ya que la forma de minimizar la cantidad de palabras en ensamblador ha llevado a un rendimiento extremadamente bajo para los sistemas integrados. Ya en la segunda versión de eForth, el número máximo de palabras comenzó a implementarse en ensamblador, lo que enderezó la inclinación no solo hacia un sistema de programación fácil de transportar, sino también práctico.

Durante varios años, Bill Munch, el autor original de eForth, y su colega el Dr. Chen-Hanson Ting lanzaron sus lanzamientos de eForth en paralelo. Cada versión tenía sus propias características. Las opciones de eForth para diferentes plataformas también han sido implementadas por otros programadores.

La versión 5.2, lanzada en 2016, contiene 71 palabras de "código" y 110 palabras de "colon". Un cuarto de siglo de búsqueda del ideal ha llevado a una reducción significativa en el número total de palabras. Al mismo tiempo, por razones de rendimiento, aumentó el porcentaje de palabras implementadas en un nivel bajo.

El 161eForth propuesto disfruta de los generosos beneficios de este progreso, pero no pretende desarrollar más la línea troncal. Mi implementación proporciona al programador todas las herramientas presentes en la versión 5.2. Cuando la arquitectura MK-161 hace que la implementación de algunas palabras 86eForth sea imposible o no tenga sentido, en lugar de tirar el exceso, les doy a los programadores un reemplazo completo, tomándolo del estándar ANSI / ISO [4]. Aquellos que buscan el minimalismo pueden arrojar independientemente palabras "extra", porque por tradición 161eForth viene con código fuente.

Al implementar eForth, me adhirí a la comprensión del autor. Por ejemplo, en mi opinión, un bucle FOR NEXT con un valor inicial de n debería ejecutarse exactamente n veces. La misma conclusión finalmente llegó a Chuck Moore, el autor de los idiomas Forth y colorForth. Desafortunadamente, eForth usa una convención desactualizada y ejecuta dicho ciclo n + 1 veces, con un contador de n a 0. No solucioné este y muchos otros defectos, prefiriendo la compatibilidad de 161eForth con implementaciones para otras plataformas.

Dado que 161eForth es el primer sistema práctico de programación a bordo para la electrónica MK-161, con la excepción del lenguaje de fábrica, tracé la larga historia de eForth y devolví algunas palabras al lenguaje que fueron útiles en otras plataformas y que ahora pueden ser muy demandadas.

Por ejemplo, la nueva y antigua variable 'BOOT contiene el token (ver 3.1) de la palabra, que se ejecuta primero después de que se inicializa el entorno, pero antes de que comience el diálogo. Por defecto, 'BOOT contiene un token TLOAD para interpretar el código del "área de texto" (ver 2.4.2). Esto permite al programador personalizar eForth por sí mismo sin volver a compilar el entorno, que aún es imposible de producir a bordo de la "Electrónica".

Las tareas prioritarias de la implementación fueron ahorrar memoria binaria (ver 2.4.1) y mejorar el rendimiento. Su solución condujo a una disminución dramática en el número de palabras de alto nivel, porque su código ocupa esta preciosa memoria, debido a un aumento en el número de palabras rápidas del núcleo implementadas en la memoria barata del programa (ver 2.4.3).

Como resultado, 161eForth contiene 129 palabras de código, 78 palabras de alto nivel y ocupa 1816 bytes de memoria binaria MK-161, es decir, menos de la mitad. Esto da esperanza para la metacompilación de su parte de alto nivel directamente a bordo de la electrónica.

El código fuente de eForth MK-161 se divide en dos partes grandes. El núcleo escrito en el sistema de comando MK-161 está contenido en el archivo eForth0.mkl. Las palabras de alto nivel se definen en SP-Forth y se colocan en el archivo eForth.f.

La distribución también tiene un archivo de ayuda words.txt, que documenta todas las palabras 161eForth con notación de pila y una breve explicación, en una línea.

1.1 El código fuente del núcleo eForth0.mkl


El núcleo eForth contiene código ejecutable que opera en la memoria de los programas MK-161 (ver 2.4.3), que se compila en una computadora en el archivo eForth0.mkp por medios estándar, por ejemplo, el compilador MKL2MKP patentado.

El código fuente del núcleo contenido en el archivo eForth0.mkl está escrito en mnemotecnia latina . Por ejemplo, un comando IPE para leer el registro E (también conocido como R14) se escribe en esta mnemotecnia como RME. Al ser inusual para los propietarios del PMK soviético, la mnemotecnia latina es conveniente para escribir desde el teclado de una computadora. De hecho, es más fácil escribir FX ^ 2 extraño que familiar de Fx² infantil.

El archivo eForth0.mkp es un preajuste del núcleo. Además del código de primitivas, contiene un encabezado de núcleo y una tabla de nombres tblNames, que eForth.f transfiere durante la decodificación a registros decimales (ver 2.4.4). Es sobre la base de eForth0.mkp que se creará el núcleo eForth.mkp (ver 2.4.3), por lo que eForth0.mkl debe compilarse primero.

1.2 Código fuente para palabras de alto nivel eForth.f


El archivo eForth.f se alimenta a la entrada del maravilloso compilador doméstico SP-Forth [5]. El archivo contiene definiciones de todas las palabras de alto nivel. Con el tiempo, pueden identificarse en el eForth y posiblemente compilarse directamente a bordo del Electronics MK-161.

Durante la compilación, eForth.f lee el núcleo en blanco eForth0.mkp y con su ayuda crea tres archivos en el directorio actual para su posterior carga en MK-161: eForth.mkp, eForth.mkd y eForth.mkb. Es eForth.mkb que contiene los cuerpos de las palabras de alto nivel, aunque sus encabezados se encuentran en el archivo eForth.mkd.

El cuarto archivo, eForth.mkt, se escribe manualmente en eForth y se puede editar a bordo del MK-161 utilizando el editor de texto incorporado. Analizaré cada uno de estos cuatro archivos con más detalle a continuación (ver 2.4).

2. Electrónica MK-161


Un fabricante de Novosibirsk llama al MK-161 un antiguo acrónimo. Ese era el nombre de las primeras calculadoras en la URSS. El sistema de instrucción MK-161 hereda el sistema de comando de las calculadoras soviéticas "Electrónica B3-34" y "Electrónica MK-61". Esto significa que los programas escritos para calculadoras soviéticas irán en el MK-161 sin cambios o con cambios menores.

Lo contrario no es cierto. eForth no irá a la PMK soviética, porque utiliza muchos recursos que aparecieron por primera vez en el MK-152/161 y no estaban disponibles en modelos anteriores de la serie.

Considere las características del lenguaje de entrada y la arquitectura del MK-161, que influyeron en 161eForth (en adelante, simplemente eForth) y le dieron a la implementación discutida de eForth un "acento ruso".

La primera de estas características es el acuerdo "senior at junior address", que se mantiene de manera consistente en MK-161. Por ejemplo, el número 1000 = 3 × 256 + 232 se escribirá en dos bytes consecutivos, como 3 y 232.

2.1 Direccionamiento indirecto


La programación soviética PMK escuchó sobre direccionamiento indirecto. Para el direccionamiento directo, indicamos explícitamente el número de registro al que nos referimos. Por ejemplo, P IP 44 considera el contenido del registro 44. La clave P que apareció en MK-152 se usa para acceder a los registros con el número 15 o más; estos registros estaban ausentes en el PMK soviético.

En el direccionamiento indirecto, el número del registro requerido no se conoce de antemano. Este número está en un registro diferente. Por ejemplo, si el registro 8 contiene el número 44, el comando K PI 8 considera el contenido del registro 44 (R44).

Las teclas K y P se pueden combinar. Por ejemplo, el comando R K BP 20 transferirá el control (GOTO en mnemotecnia latina) a la dirección almacenada en R20.

La característica que resultó ser importante para el intérprete interno eForth está relacionada con el aumento / disminución preliminar de registros durante el direccionamiento indirecto. Esta característica se hereda de la PMK soviética.

Por ejemplo, los comandos de lectura indirecta KI 0, KI 1, KI 2 y KI 3 reducen el contenido de los registros 0, 1, 2 o 3 en uno al registro deseado. Los comandos KI 4, KI 5 y KI 6 antes de leer, aumente el contenido de los registros 4, 5 o 6 en uno.

Esta "modificación" del registro de direcciones le permite procesar grupos enteros de registros en un bucle. Es similar a ++ R y --R en C. El número de registro es importante. Es él quien determina si aumentará (registros 4-6) o disminuirá (registros 0-3) con direccionamiento indirecto.

La arquitectura 161eForth se vio afectada por el hecho de que el aumento en los registros 4-6 con direccionamiento indirecto es preliminar . Como resultado, el puntero de interpretación (IP) ubicado en R6 siempre apunta al último byte del código cosido. En 86eForth, IP siempre indica un byte posterior que aún no se ha leído.

Esto también es cierto para el puntero de pila de retorno (RP) almacenado en el registro 2. R2 siempre apunta a la parte superior de la pila de retorno.

Una característica útil del MK-161 es la ausencia de un aumento / disminución en el registro si se produce un direccionamiento indirecto con la nueva tecla R. Por ejemplo, RKIP02 cuenta el número desde la parte superior de la pila de retorno sin cambiar el puntero. Este es un equipo Fort R @ ya hecho. De lo anterior se deduce que el valor de lectura es uno menos que la dirección del siguiente token, que se ejecutará después de regresar de la palabra "dos puntos".

Cuando tenga que desarrollar o estudiar palabras que interactúen estrechamente con el intérprete interno eForth, asegúrese de comprender completamente este punto sutil asociado con la exageración .

2.2 Tablas ordenadas y asociativas


Las tablas MK-161 se encuentran en la memoria del programa (consulte 2.4.3). Aparecieron en el Novosibirsk "Electronics MK" y son completamente desconocidos para los expertos en PMK soviético. La dirección de la tabla utilizada siempre se almacena en el registro 9042, pero el acceso a ellas es diferente.

Una tabla ordenada es una matriz de enteros de 16 bits sin signo. eForth contiene dicha tabla tblTokens con las direcciones de primitivas (ver 3.1.1) - Fort palabras escritas en el sistema de comando MK-161. El intérprete de direcciones (ver 3.2) usa tblTokens para ejecutar rápidamente el código cosido, por lo que eForth siempre trata de contener la dirección de esta tabla en R9042.

Para acceder a una tabla ordenada, debe escribir el número del artículo deseado en R9210. El número n en el registro X será reemplazado por el valor del elemento de la tabla con el número n, el recuento comienza desde cero.

Las tablas asociativas ("búsqueda por valor") son utilizadas activamente por eForth, principalmente por la primitiva (ENCONTRAR), buscando una palabra por su nombre. Además, la tabla asociativa tblCHPUT se usa al imprimir letras en la pantalla para procesar avances de línea y otros códigos de control.

Para buscar el elemento n en la tabla asociativa, escriba n en R9212. El número n en el registro X (la administración lo llama el "índice") será reemplazado por el valor de 16 bits registrado en la tabla inmediatamente después de su "índice" n.

La presencia de esta función de búsqueda rápida, aunque simple, implementada en lenguaje ensamblador en el "firmware" MK-161 ayudó a eForth a lograr un rendimiento aceptable al reconocer nombres de palabras y compilar programas. Por supuesto, para esto no tuve que desarrollar las tablas de reconocimiento de nombres más simples, "afiladas" para esta función. Hablaremos de esto con más detalle en el segundo artículo.

2.3 Interrupciones y consola


"MK Electronics" permite a sus propietarios escribir programas en el idioma de entrada que responden a ciertos eventos, como presionar o soltar un botón, finalizando el conteo del temporizador.

eForth utiliza activamente este sistema de interrupción tanto para la entrada del teclado como para la visualización del cursor parpadeante cuando se le solicita dicha entrada y para la entrada / salida a través de un puerto serie universal (RS-232).

Las letras ingresadas desde el teclado se colocan en la cola bufKbd mientras presiona las teclas. Esto es muy conveniente y ahorra tiempo en sistemas con baja velocidad. La interrupción de KeyPress maneja el alfabeto y el cambio de mayúsculas y no ocupan espacio en la cola. Una pulsación larga en la tecla llama a la repetición automática.

Cuando la línea de 8 letras está llena y eForth aún no está listo para procesar la entrada (la situación es muy rara), el MK-161 emitirá un chirrido infeliz. Por supuesto, me gustaría no implementar todo este trabajo natural del teclado en el traductor, sino obtener el MK-161 "fuera de la caja" como un servicio del firmware (firmware). Pero lo que, como dicen, es rico.

Después del inicio del trabajo, toda la salida de eForth se dirige a la pantalla gráfica MK-161. La salida de letras en él se lleva a cabo mediante una rutina relativamente simple de la CNCut. La única dificultad aquí es la implementación del código de control de BS, el "espacio de regreso". MK-161 usa una fuente proporcional. Por lo tanto, en un búfer especial tblBS, debe recordar las posiciones de los caracteres mostrados, desde donde los toma el código de salida BS.

Durante el diálogo, el usuario puede usar la palabra IO> para redirigir todas las E / S al puerto serie RS-232, lo que permite programar el MK-161 desde un teclado de computadora familiar o desde otro MK-161 . La palabra CON> devuelve el control a la consola de la calculadora.

2.4 Áreas de memoria e instalación de eForth en el MK-161


La memoria "MK-161 Electronics" consta de memoria de programa direccionable por separado y memoria de registro de datos. A su vez, la memoria de registro es heterogénea y se divide en tres grandes áreas.

Los registros con números del 0 al 999 almacenan "números decimales". Estos son registros ordinarios, como en "Electrónica B3-34" y otras calculadoras. Simplemente son capaces de almacenar no 8, sino 12 decimales de la "mantisa".

Los registros con números del 1000 al 8167 almacenan enteros del 0 al 255. Los últimos 3 Kbytes de esta área con direcciones del 5096 al 8167 se denominan área de texto .

Los registros con números del 9000 al 9999 se denominan registros de funciones.. Esta área de servicio del espacio de direcciones se asemeja a los puertos de E / S del microprocesador. Con la ayuda de comandos de escritura y lectura, estas direcciones se utilizan para acceder a dispositivos de E / S, sistemas de interrupción, etc.

Para instalar eForth en Electronics MK-161, es suficiente transferir cuatro archivos a la calculadora, por ejemplo, utilizando el programa del fabricante MK.EXE:
  • Escriba eForth.mkp en la memoria del programa a partir de la página 0. La versión 0.5b ocupa 74 páginas.
  • Escriba eForth.mkd en la memoria de datos decimales
  • Escriba eForth.mkb en la memoria de datos binarios
  • Escriba eForth.mkt en la memoria de texto

Después de transferir a la calculadora, recomiendo guardar inmediatamente estos cuatro archivos en un directorio separado del "disco electrónico" incorporado. Como tienen el mismo nombre, puede descargar eForth de inmediato a la vez como un "paquete".

2.4.1 Memoria binaria ("byte") MK-161: eForth.mkb


Los registros de Electronics MK con números del 1000 al 5095 se utilizan para almacenar números del 0 al 255. Esta área de la memoria de registro de la calculadora se llama binaria. Se puede acceder a dos registros binarios consecutivos desde eForth como una única "celda" de 16 bits y (como en todas partes en el MK-161), los 8 bits superiores están en el registro con un número más bajo.

eForth utiliza esta pequeña "memoria binaria" como su principal. Las palabras funcionan con ella! y @, AQUÍ y ALLOT, solo desde aquí el intérprete de direcciones ejecuta el código cosido (ver 3.2). Aquí están las variables eForth, el búfer de entrada de texto (TIB), el diccionario y la pila de reversión tblBS para implementar el retroceso.

4096 bytes es muy modesto, según los estándares modernos. Por lo tanto, se han realizado enormes esfuerzos para llevar a otras áreas de la memoria todo lo posible.

2.4.2 Área de texto: eForth.mkt


Inmediatamente después de que la memoria binaria es un área de texto , los registros con números del 5095 al 8167. Técnicamente, son los mismos registros de bytes, pero la capacidad de escribirlos en el disco y leerlos como un archivo separado hace que esta área sea especial.

La palabra CARGAR se utiliza para trabajar con "texto" en eForth. Alimenta toda esta área a la entrada del intérprete de texto, como una cadena, 3072 letras de largo.

Existe desacuerdo sobre cómo dividir el texto en líneas. Un editor integrado en MK Electronics insiste en una longitud de línea de 24 caracteres. Callisto usa la convención Fort, donde la cadena contiene 64 caracteres. eForth ofrece al usuario la opción de contar todo el texto como una línea larga. Puede usar el editor incorporado MK-161. Puedes escribir el tuyo, compatible con Callisto.

Aquí está el contenido inicial de eForth.mkt, por conveniencia, dividido en tres líneas:

: hi ." , %user%!" CR ; ' hi 'boot ! hi \ 

La primera línea define la nueva palabra hola que saluda al usuario. La segunda línea toma el token de esta palabra (ver 3.1) y lo coloca en la variable 'BOOT (ver 1). Ahora el área de texto dejará de compilarse cada vez que se inicie eForth. En su lugar, se ejecutará el saludo ya compilado.

La última línea comienza la palabra hola, mostrando un saludo en la pantalla. La palabra \ completa la interpretación del texto, devolviendo el control a la consola.

Para compilar un archivo de texto arbitrario, debe ir a la calculadora con el comando BYE, ir al menú principal y cargar el archivo deseado en modo DOS. También puede transferir el archivo mkt desde una computadora. La tecla C / P lo regresará a eForth, luego de lo cual con el comando TLOAD puede compilar el archivo cargado en el área de texto.

2.4.3 Memoria de programa: eForth.mkp


La memoria de programa MK-161 es un espacio de direcciones aislado. También almacena bytes, pero son de solo lectura. La memoria del programa contiene 10,000 "pasos", que resultaron ser redundantes para eForth. Más de una cuarta parte de la memoria del programa resultó ser libre, lo que ofrece una buena reserva para el desarrollo del traductor.

Solo en la memoria del programa se pueden implementar "palabras de código". Además, las tablas de reconocimiento de nombres y todas las cadenas de texto conocidas se representan aquí, lo que ahorra memoria binaria.

Algunas palabras, como C @, COUNT y TYPE, pueden direccionar la memoria del programa si la dirección no es un número positivo. Por ejemplo, la frase 0 C @ cuenta como un "paso" (byte) de la dirección 0 de la memoria del programa.

2.4.4 Memoria decimal: eForth.mkd


Los registros de MK Electronics con números del 0 al 999 se denominan decimales y contienen números utilizados para cálculos ordinarios en la calculadora: 12 dígitos decimales de la "mantisa" y 2 dígitos decimales del "orden". El fuerte está diseñado para trabajar con enteros de hasta 4 bytes de longitud, un recurso de este tipo es claramente redundante para eForth.

La memoria decimal se usa para guardar una preciosa memoria binaria. Las pilas de datos y devoluciones se realizan aquí. Aquí se almacenan los encabezados de las palabras: definidas por el usuario e incrustadas, un registro por título. Este enfoque le permite redefinir incluso palabras con nombres estándar.

La pila en la memoria decimal conduce a una serie de características características del Fuerte en el MK-161. En primer lugar, el rango de valores de los elementos de la pila es enorme; puede acomodar enteros de 32 bits. La necesidad de "enteros dobles" en el MK-161 desaparece, aunque en aras de la compatibilidad, he implementado las palabras correspondientes eForth. Los "enteros dobles" se presentan en MK-161, como dos elementos de la pila que contienen números del 0 al 65535, que codifican un entero de 32 bits con un signo en el código adicional. Los 16 bits más altos de este número se colocan en la parte superior, es decir, en la dirección más baja.

Las operaciones lógicas bit a bit AND, OR, XOR y NOT tratan sus argumentos como enteros de 16 bits. Un resultado de 32768 a 65535 se convierte en números negativos de -32768 a -1. En eForth, falso se codifica con cero y la verdad menos uno. También es cierto cualquier valor que no sea cero.

La segunda característica de la pila de datos 161eForth es que contiene números con signo. Cuando la palabra @ lee el número 65535 de una "celda" de 16 bits, se convierte automáticamente a -1. Se proporciona una palabra especial "sin signo" U @ para contar directamente 65535, con un signo más.

Recuerdo que, en aras de la velocidad, los dos elementos superiores de la pila de datos no se encuentran en la memoria decimal, sino directamente en los registros X e Y.

EForth no utiliza el hecho de que los registros decimales pueden contener números fraccionarios y números de coma flotante. La máquina virtual eForth utiliza estos registros para almacenar enteros decimales de 12 bits con signo. Se accede a los registros decimales con las palabras C @ y C! - los mismos que funcionan con cualquier registro individual.

3. El intérprete interno.


El núcleo eForth es un programa escrito en el lenguaje de entrada MK-161. Su primer comando PRINCIPAL transfiere el control al código PRINCIPAL, que primero descubre las circunstancias del reinicio. Si fue causado por el token incorrecto, MK-161 chillará. En la primera puesta en marcha, y también después de encender el MK-161, la pantalla se borra. Luego, MAIN llama a la subrutina Init para inicializar el sistema de interrupción y todo lo que necesitan los controladores de consola MK-161.

Después de inicializar las pilas de datos y las devoluciones, se completa la parte de bajo nivel del inicio. Suceden cosas increíbles para las máquinas con arquitectura Harvard: eForth ejecuta el "código cableado" desde la memoria de bytes. El honor de ser el primero pertenece a una palabra cuya dirección de encabezado se registra en R43. Esta suele ser la palabra FRÍO.

¿Cómo se organizan las palabras de alto nivel (IED)? Cualquier palabra consta de dos partes, un cuerpo y un encabezado. El encabezado se almacena en decimal. Ayuda al intérprete externo y al descompilador a encontrar el nombre y el cuerpo de la palabra. El encabezado también contiene un campo de "léxico" : un conjunto de indicadores que ayudan al intérprete externo a procesar correctamente la palabra encontrada. El intérprete interno es mucho más importante para el cuerpo VCA ubicado en la memoria binaria y almacenado en el diccionario. Incluso puede ejecutar palabras que no tienen encabezado.

El cuerpo del VCA comienza con el byte del campo de código , que contiene la dirección del procesador de la palabra dada. Cuatro controladores VCA están escritos en el lenguaje de entrada MK-161 y comienzan en la primera página de la memoria del programa. Los analizaremos todos (ver 3.3), pero el principal se llama DOLST y se encuentra en la dirección 02, inmediatamente después del comando MAIN BP ya considerado. Este controlador ejecuta palabras Fort definidas con dos puntos.

Después del byte del campo de código hay un campo de parámetro de longitud arbitraria. En las "palabras de dos puntos", el campo de parámetro contiene un "código cosido", una secuencia de tokens de 16 bits, cada uno de los cuales indica una acción asignada a él.

Primero, consideraremos el token con más detalle. Luego estudiaremos el intérprete interno INEXT, que transfiere de un token a la ejecución del siguiente. EForth llama a INEXT un manejador primitivo. Concluimos este recorrido por el intérprete interno analizando los cuatro procesadores IED.

3.1 fichas


El token representa la palabra en el código cosido y la pila, lo que permite que se ejecute rápidamente. El token es un puntero al cuerpo de la palabra, pero la dura arquitectura del MK-161 hizo sus propios ajustes a esta idea simple. Analicemos todos los tipos de tokens, comenzando con el token primitivo.

3.1.1 Token primitivo


Todas las palabras incluidas en la distribución eForth están numeradas del 0 al 206. Esta numeración es de extremo a extremo, teniendo en cuenta tanto las primitivas como el VCA. Esto se hace para que por el número de la palabra sea fácil restaurar su nombre . Estos nombres se almacenan en la memoria del programa. El enlace al nombre deseado se encuentra fácilmente a través de la tabla de encabezado.

El número primitivo es su token . Como cualquier token, la primitiva toma dos bytes en el código cosido. El primero es cero. El segundo contiene su número. La tabla tblTokens le permite encontrar rápidamente la dirección del código primitivo por este número. La dirección tblTokens se almacena permanentemente en R9042 (ver 2.2), es decir, todo está siempre a mano para ejecutar la primitiva.

La palabra XT> le permite encontrar la dirección de un código primitivo por su número (token). Como el código de primitivas siempre se encuentra en la memoria del programa, la dirección recibida siempre es negativa (ver 2.4.3).

3.1.2 token VCA


VCA puede tener su propio número y nombre estándar asociado, o puede ser completamente nuevo, creado por el usuario. En todos los casos, el token VCA es la dirección de su campo de código (ver 3), es decir, un número de 1000 a 5095.

En el código cosido, el token VCA está escrito de una manera muy inusual. El número de cientos (un número del 10 al 50) se escribe en el primer byte, el resto de dividir el token por 100 (un número del 0 al 99) en el segundo byte.

Por ejemplo, el token 1234 estará representado por dos bytes 12 y 34. La compilación de este, y cualquier otro token, se lleva a cabo utilizando la palabra COMPILAR tomada del estándar ANSI. Para escribir y leer tokens VCA en el código cosido, las palabras XT! y XT @. Acceden a las direcciones (ver 3.1.4), y la palabra XT @ también puede leer el token primitivo.

3.1.3 Literales enteros


Los literales enteros son una especie de tokens primitivos. Son lo suficientemente inusuales como para considerarse por separado.

En el código cosido, los tokens DOLIT y DOLITM ocupan cuatro bytes. Los primeros dos bytes contienen el token primitivo ya considerado, es decir, 0 y el número del primitivo. Los siguientes dos bytes contienen un número entero que el literal dado colocará en la pila de datos durante la ejecución.

DOLITM difiere en que cambia el signo del número antes de colocarlo en la pila. Está diseñado para implementar números negativos.

3.1.4 Literales de dirección


Al igual que los literales completos, los tres literales de dirección BRANCH,? BRANCH y DONXT ocupan 4 bytes cada uno en el código cosido. Los primeros 2 bytes contienen el token primitivo, los dos últimos bytes son la dirección de salto.

La dirección se registra en el mismo formato que el token VCA (consulte 3.1.2). El primer byte contiene el número de cientos, el segundo contiene el resto de dividir la dirección por 100. Recuerdo que debido a la exageración (ver 2.1), la dirección de transición no contiene la dirección del token deseado, sino un número menos por uno.

El token DONXT ayuda a implementar el "ciclo final" FOR-NEXT (ver 1). El salto incondicional BRANCH es necesario para implementar el ciclo infinito BEGIN-AGAIN. Rama condicional? BRANCH transfiere el control si cero está en la parte superior de la pila de datos (falso). Sirve para implementar la instrucción condicional IF-THEN, salidas de "bucles indefinidos" BEGIN-UNTIL y BEGIN-WHILE-REPEAT.

3.1.5 Literales de cadena


Los literales de cadena son un tipo de tokens VCA. En el código cosido de un literal de cadena, después de un token, hay un byte con una longitud de cadena, después de lo cual es la cadena en sí, desde el primer byte hasta el último.

EForth tiene tres literales de cadena: $ "| ,." | y abortar "|. Se definen en el archivo eForth0.mkl como tokens STRQP, DOTQP y ABORQ, respectivamente. El trabajo" literal "principal se realiza para ellos con la palabra do $, el token DOSTR.

Para que el tamaño del artículo sea razonable, no puedo detenerme demasiado en este interesante tema, pero es bueno saber acerca de su disponibilidad en eForth.

3.2 Intérprete de direcciones


Es hora de considerar el intérprete de tokens , cuya dirección siempre se escribe en el registro 9. La mayoría de las primitivas terminan su trabajo con el comando K BP 9, que transfiere el control a la etiqueta INEXT.

 INEXT: 6 Fx≠0 NPrime NData:  2 6 + 7 F⟳ 7 8 F⟳ 8 

Primero, el intérprete de direcciones lee el primer byte del siguiente token con el comando KIP6. Si es cero, este es un primitivo y el código bajo la etiqueta NPrime manejará el token.

La etiqueta NData denota el procesamiento del token VCA. El primer byte se multiplica por cien por el comando VP 2, después de lo cual KIP6 + agrega el segundo byte del token al resultado (ver 3.1.2). El equipo P7 ingresa el token de lectura en el WP "registro de trabajo" (R7).

Sabemos que el token VCA es la dirección de su campo de código, que contiene la dirección del procesador. Los comandos KIP7 P8 leen el byte del campo de código en R8, y el comando KBP8 transfiere el control al procesador VCA. El controlador sabe que R7 contiene un número uno menos que la dirección del campo de parámetro de la palabra que se procesa.

Las instrucciones F⟳ con el código 25 están "ordenadas" en la pila. El hecho es que eForth almacena los dos elementos superiores de la pila de datos directamente en los registros X e Y de la pila MK-161. Tal solución acelera el trabajo, pero hace que sea necesario asegurarse de que estos datos importantes no se pierdan.

Queda por comprender cómo el intérprete de direcciones ejecuta las primitivas.

 NPrime: F⟳ 6 9210 8 F⟳ 8 

El comando KIP6 lee el segundo byte del token primitivo. Los comandos RRP9210 P8 leen la dirección de esta primitiva de la tabla tblTokens (ver 2.2 y 3.1.1), y KBP8 transfiere el control a esta primitiva.

Como anteriormente, F⟳ elimina el exceso de la pila, restaurando el contenido de los registros X e Y.

El intérprete de direcciones eForth es tan pequeño que se duplica varias veces en la memoria del programa. La copia principal se ejecuta mediante el comando K BP 9, que completa la mayoría de las primitivas.

Como ejercicio, recomiendo estudiar la implementación de la palabra EJECUTAR, colocada después de la etiqueta EXECU. Esta es una variante INEXT, que lee el token no del código cosido, sino que lo toma de la pila de datos.

3.3 controladores VCA


Cuatro variedades de VCA tienen cuatro controladores diferentes: DOLST, DOVAR, DOCON y DOCONM. Ya hemos visto anteriormente que el intérprete de direcciones antes de llamar al controlador deja en R7 la dirección del campo de código de la palabra que se está procesando.

eForth.f aprende las direcciones de estos manejadores leyendo el encabezado del núcleo del archivo eForth0.mkp. Esto le ayuda a compilar el VCA para la Electrónica MK-161 correctamente colocando el resultado en el archivo eForth.mkb.

3.3.1 Palabras de dos puntos: DOLST y EXIT


El siguiente tema importante después de INEXT es lo que hace el intérprete interno cuando encuentra el token de una palabra definida a través de dos puntos. El campo de código de dicha palabra contiene el número 2, por lo que INEXT transfiere el control al controlador DOLST, que hace el trabajo necesario para comenzar a interpretar la nueva lista de tokens.

 DOLST: 6 2 F⟳ 7 6 F⟳ INEXT: 

El registro 2, como ya hemos discutido (ver 2.1), contiene un puntero de pila de retorno RP. Los comandos IP6 KP2 escriben el valor de R6, el puntero de interpretación (IP), en la pila de retorno. Más tarde, esto ayudará a recordar la posición actual en la antigua lista de tokens, donde INEXT encontró una palabra de dos puntos. Ahora IP7 P6 reorganiza IP al comienzo de una nueva lista.

Inmediatamente después del código DOLST, se coloca el código INEXT, que ejecutará la primera palabra de la nueva lista de tokens. Como en otros lugares, los comandos F ayudan a mantener los dos elementos superiores de la pila de datos.

Las palabras de dos puntos generalmente terminan con un token EXITT, que hace lo contrario, en comparación con DOLST: toma el antiguo valor de IP de la pila de retorno y vuelve a la interpretación de la lista de tokens anterior.

 EXITT: 02 6 x 1 2 + 2 F⟳ INEXT: 

Los comandos RKIP02 P6 leen el antiguo valor de IP desde la parte superior de la pila de retorno (ver 2.1). Después de eso, los comandos Cx 1 IP2 + P2 corrigen el valor de RP, incrementándolo en uno. El comando F⟳ restaura la pila, después de lo cual INEXT ejecuta la siguiente palabra de la lista de tokens anterior.

Por supuesto, INEXT no puede ir después de DOLST y EXITT al mismo tiempo. Para hacer esto, apliqué un antiguo truco de la época de la URSS. También puede dominarlo examinando las líneas correspondientes en el archivo eForth0.mkl.

3.3.2 DOVAR, variable y controlador de matriz


Las palabras generadas por las palabras CREATE y VARIABLE usan el mismo controlador DOVAR. Este controlador empuja en la pila la dirección de la variable ubicada en el campo de parámetro, que va inmediatamente después del byte del campo de código. Las variables VARIABLES ocupan 2 bytes, y las matrices creadas usando CREATE contienen tantos bytes como el programador quiera.

 DOVAR: ⇔ 3 x 1 7 + 9 

Los comandos ⇔ KP3 guardan el contenido del registro Y en la pila de datos. Al mismo tiempo, el número desde la parte superior de la pila se ingresa en RY, liberando RX al nuevo valor. Después de los comandos Cx 1 IP7 +, este nuevo valor en la parte superior de la pila se convierte en la dirección del campo de parámetro de la palabra ejecutable. KBP9 transfiere el control a INEXT, sin ningún truco, pasando a la siguiente palabra.

3.3.3 Manejadores constantes: DOCON y DOCONM


A diferencia de DOVAR, el controlador constante accede al campo de parámetros de su propia palabra. DOCON lee un valor constante de 16 bits. Este valor siempre es positivo.

 DOCON: ⇔ 3 ⇔ 7 5 x 256 5 × 5 + 9 

Los comandos ⇔ KP3 ⇔ guardan RY en la pila de datos. Pero esta vez, la parte superior de la pila de datos vuelve a RX. Los comandos IP7 P5 lo obligan a regresar a RY, mientras preparan el registro de puntero R5 para leer el valor de la constante. A continuación, Cx 256 reemplaza la basura en el registro X con el número 256.

Los instrumentos KIP5 × KIP5 + leen una constante desde el campo de parámetros hasta la parte superior de la pila de datos, es decir, en RX. Como recordamos, en MK-161 el primer byte siempre es alto. Se multiplica por 256, después de lo cual el byte menos significativo de la constante se agrega al producto. Todo el trabajo está hecho, KBP9 transfiere el control a la siguiente palabra.

DOCONM funciona exactamente de la misma manera, solo el signo constante después de leer cambia a lo opuesto. Las constantes negativas se implementan en el MK-161 como un procesador separado en aras de la velocidad:

 DOCONM: ⇔ 3 ⇔ 7 5 x 256 5 × 5 + /-/ 9 

Ahora hemos descubierto completamente cómo eForth ejecuta su código en la electrónica MK-161 desde el área de datos, incluso tocando un tema más profundo de los literales de cadena (ver 3.1.5).

En el segundo artículo de la serie, hablaré sobre el intérprete externo de "texto" 161eForth, analizaré la estructura de las tablas de encabezado y el reconocimiento de nombres. Esta parte del traductor me exigió que desarrollara soluciones mucho más radicales, en cuyo contexto lo mencionado anteriormente es el Fuerte tradicional, antiguo y bueno.

¡Programación Happy Fort!

Literatura


  1. Dr. Chen-Hanson Ting. eForth and Zen - 3rd Edition, 2017. Disponible en Amazon Kindle.
  2. Baranov S.N., Nozdrunov N.R. Fuerte lenguaje y su implementación. - L .: Ingeniería mecánica. Leningrado Departamento, 1988.
  3. Semenov Yu.A. Programación en el lenguaje FORT. - M .: Radio y comunicaciones, 1991.
  4. ANS Cuarto estándar. X3.215-1994. Traducción
  5. Documentación SP-Forth .
  6. Offete Store (Actas del Dr. Chen-Hanson Ting) , donde puede descargar 86eForth v5.2 para Windows, documentación en inglés.


Ilustraciones de video


Estos cuatro pequeños videos 161eForth continúan. El primer video al comienzo del artículo.

Parte 2 de 5. Pruebas TEST-TEST4 del libro "eForth and Zen", tercera edición, en el MK-161.



Parte 3 de 5. VER descompilador.



Parte 4 de 5. Breakpoint BYE, terminal RS-232 y acceso remoto a MK-161.



Parte 5 de 5. Palabras finales.

Source: https://habr.com/ru/post/452398/


All Articles