EFORTH para calculadora programável

Este é o primeiro artigo da série 161eForth v0.5b, terminando aqui: habr.com/en/post/452572

O tradutor EFORTH também está agora na calculadora doméstica MK-161 Electronics! Em 17 de maio, a versão v0.5b passou nos meus testes, bem como nos cinco testes de autoria TEST-TEST4. Consegui o que pode ser feito sozinho, mas acho que isso é apenas metade da batalha. É hora de introduzir uma nova ferramenta para a comunidade, abrindo o código 161eForth para testes públicos. Eu tenho uma lista do que melhorar e onde "trabalhar com a estabilidade". Suas sugestões e comentários serão levados em consideração ao concluir o trabalho e lançar a versão 1.0

Ao transferir a versão mais recente do eForth para a plataforma doméstica, dois obstáculos foram superados com sucesso - a velocidade relativamente baixa da máquina de 8 bits, programada em seu próprio idioma de entrada, e a quantidade modesta de memória binária disponível (consulte 2.4.1), total de 4096 bytes.


Ao escrever o 161eForth, foram utilizadas soluções prontas preparadas para o Callisto, o idioma de entrada da próxima geração para o PMK doméstico. Esta é uma tecnologia para implementar uma máquina forte sobre a ALU decimal e a arquitetura "Harvard", drivers de console e um layout alfanumérico do teclado, além de um terminal de software baseado neles, operando através da porta serial RS-232. Além das distribuições Electronics MK-161 e 161eForth, você pode precisar de um teclado de patch caseiro, onde as letras dos alfabetos russo e inglês estejam assinadas nas teclas. As letras são organizadas alfabeticamente linha por linha, da esquerda para a direita e de cima para baixo.


O Dr. Chen-Hanson Ting, autor de versões modernas do eForth, enfatiza em seu livro [1] a importância de entender os dois componentes do Forte. Este é um intérprete interno ("endereço") que permite que o equipamento execute o código costurado da Fort e um intérprete externo ("texto") responsável pelo diálogo com uma pessoa.

Em dois artigos, abordarei detalhadamente as soluções mais radicais usadas na implementação de cada um desses dois intérpretes na Eletrônica. O aprendizado dessas soluções pode ser útil e inspirador para migrar o eForth para outros dispositivos com memória e desempenho limitados. A compreensão dos artigos ajudará com uma introdução inicial aos microcalculadores programáveis ​​(PMCs) e Fort. Explicarei momentos difíceis exclusivos do Electronics MK e do tradutor eForth.

Para começar, as palavras eForth são divididas em geral e sistêmica. O tamanho das letras é importante. Os nomes das palavras comuns são definidos em letras maiúsculas e sistema - minúsculas. Também fiz minhas inovações no eForth em letras minúsculas. O autor do eForth sugere conduzir o principal diálogo no modo CAPS. Quando você precisar usar a palavra do sistema, mude o horário para letras minúsculas (combinação de teclas FP).

No artigo, todas as palavras são escritas em letras maiúsculas para se destacar do texto. Em várias implementações anteriores do eForth, os cabeçalhos de palavras do sistema foram excluídos e não gerados pelo comando WORDS. Isso ajudou a simplificar a aparência do eForth e salvar a atenção de quem usa o Fort pela primeira vez. No 161eForth, os títulos dessas palavras foram salvos principalmente devido à presença do decompilador de palavras em cólon SEE (consulte o vídeo nº 3 no final do artigo), que não mostrará os nomes das palavras do sistema se os títulos forem removidos.

Para otimizar o artigo e torná-lo útil como referência, tive que usar vários termos antes de defini-los. Os profissionais de Fort e PMK devem estar familiarizados com esses termos. Os iniciantes às vezes precisam procurar nas seções vizinhas (eu coloquei os links nos lugares certos) ou reler o artigo algumas vezes.

O próprio 161eForth é apresentado aqui, juntamente com o texto fonte, um teclado gráfico na tela e help words.txt com uma descrição de todas as palavras implementadas: http://the-hacker.ru/2019/161eforth0.5b.zip

Também publiquei 5 pequenos vídeos no YouTube, ilustrando o funcionamento do 161eForth para quem não possui o MK-161. Você pode assistir a lista de reprodução inteira no YouTube . Abaixo está o primeiro deles, os 4 restantes no final do artigo.



eForth e sua implementação


O eForth foi projetado como um substituto moderno do conhecido tradutor fig-Fort. Para transferir para o MK-161, escolhi a versão 5.2 de 32 bits do tradutor 86eForth com código de costura indireto, escrito em 2016 no MASM assembler para o sistema operacional Windows. Esta versão é descrita em detalhes na terceira edição do eForth e Zen [1]. Aqueles que sabem inglês, aconselho que você encontre e estude este livro, é muito útil para entender o futuro.

Em uma carta pessoal, o autor confirmou que 86eForth502.asm deste livro é a versão mais recente do eForth. Na Internet, você pode encontrar muitas informações em inglês sobre isso e nas versões anteriores do eForth.

O desenvolvimento do eForth seguiu um caminho científico ensinado pelo professor Wirth usando o exemplo de sua linguagem de programação Oberon. Cada versão subsequente do eForth era uma simplificação da versão anterior. Tudo o que pode ser dispensado foi removido da língua. Resta um conjunto cuidadosamente pensado de construções de linguagem expressivas e fortes, cujo poder foi testado em mais de 40 implementações eForth para várias plataformas. Agora na calculadora!

Sendo um dialeto minimalista de Fort, o eForth não tem como objetivo vencer a corrida contra o menor Fort. O conjunto de palavras que ele oferece é bastante prático e pode ser facilmente expandido pelo programador na direção necessária para suas tarefas.

A primeira versão do eForth foi lançada em 1990 no MASM assembler para processadores 8086 e funcionou no MS-DOS. Continha 31 palavras principais dependentes da máquina e 191 palavras de alto nível. A idéia era simples - você traduz apenas 31 palavras para o seu assembler e obtém imediatamente o eForth no seu computador.

Essa abordagem foi criticada na Internet, pois a maneira de minimizar o número de palavras no assembler levou a um desempenho extremamente baixo para sistemas embarcados. Já na segunda versão do eForth, o número máximo de palavras começou a ser implementado no assembler, o que endireitou a inclinação não apenas para um sistema facilmente portátil, mas também para um prático sistema de programação.

Por vários anos, Bill Munch, autor original do eForth, e seu colega Dr. Chen-Hanson Ting lançaram seus lançamentos eForth em paralelo. Cada versão tinha suas próprias características. As opções eForth para diferentes plataformas também foram colocadas por outros programadores.

A versão 5.2, lançada em 2016, contém 71 palavras de "código" e 110 palavras de "dois pontos". Um quarto de século de busca pelo ideal levou a uma redução significativa no número total de palavras. Ao mesmo tempo, por razões de desempenho, a porcentagem de palavras implementadas em um nível baixo aumentou.

O 161eForth proposto desfruta dos benefícios generosos desse progresso, mas não pretende desenvolver ainda mais a linha de tronco. Minha implementação fornece ao programador todas as ferramentas presentes na versão 5.2. Quando a arquitetura MK-161 torna a implementação de algumas palavras 86eForth impossível ou sem sentido, em vez de jogar fora o excesso, dou aos programadores uma substituição completa, retirando-a do padrão ANSI / ISO [4]. Quem busca o minimalismo pode, independentemente, lançar palavras “extras”, porque, por tradição, o 161eForth vem com o código-fonte.

Ao implementar o eForth, aderi ao entendimento do autor. Por exemplo, na minha opinião, um loop FOR NEXT com um valor inicial de n deve ser executado exatamente n vezes. Finalmente, chegou a mesma conclusão Chuck Moore, autor das línguas Forth e colorForth. Infelizmente, o eForth usa uma convenção desatualizada e executa esse ciclo n + 1 vezes, com um contador de n a 0. Eu não consertei isso e várias outras deficiências, preferindo a compatibilidade 161eForth com implementações para outras plataformas.

Como o 161eForth é o primeiro sistema prático de programação a bordo para o MK-161 Electronics, com exceção da linguagem de fábrica, eu tracei a longa história do eForth e retornei algumas palavras para a linguagem que eram úteis em outras plataformas e podem estar em demanda agora.

Por exemplo, a nova variável antiga 'BOOT contém o token (consulte 3.1) da palavra, que é executado primeiro após a inicialização do ambiente, mas antes do início do diálogo. Por padrão, o 'BOOT contém um token TLOAD para interpretar o código da “área de texto” (consulte 2.4.2). Isso permite que o programador personalize o eForth para si mesmo sem recompilar o ambiente, o que ainda é impossível de produzir a bordo do "Electronics".

As tarefas prioritárias da implementação foram economizar memória binária (consulte 2.4.1) e melhorar o desempenho. Sua solução levou a uma redução drástica no número de palavras de alto nível, porque seu código ocupa essa memória preciosa, devido a um aumento no número de palavras rápidas do kernel implementadas na memória de programa barata (consulte 2.4.3).

Como resultado, 161eForth contém 129 palavras de código, 78 palavras de alto nível e ocupa 1816 bytes de memória binária MK-161, ou seja, menos da metade dela. Isso dá esperança para a metacompilação de sua parte de alto nível diretamente a bordo da eletrônica.

O código fonte do eForth MK-161 está dividido em duas partes grandes. O núcleo gravado no sistema de comando MK-161 está contido no arquivo eForth0.mkl. Palavras de alto nível são definidas no SP-Forth e colocadas no arquivo eForth.f.

A distribuição também possui um arquivo de ajuda words.txt, que documenta todas as palavras 161eForth com notação de pilha e uma breve explicação, em uma linha.

1.1 O código fonte do kernel eForth0.mkl


O núcleo do eForth contém código executável que opera na memória dos programas MK-161 (consulte 2.4.3), que é compilado em um computador no arquivo eForth0.mkp por meios padrão, por exemplo, o compilador MKL2MKP proprietário.

O código fonte do kernel contido no arquivo eForth0.mkl está escrito em mnemônicos latinos . Por exemplo, um comando IPE para ler o registro E (também conhecido como R14) é escrito nesta mnemônica como RME. Sendo incomum para os proprietários do PMK soviético, os mnemônicos latinos são convenientes para digitar a partir de um teclado de computador. Na verdade, é mais fácil digitar FX ^ 2 estranho do que familiar desde a infância Fx².

O arquivo eForth0.mkp é uma predefinição do kernel. Além do código das primitivas, ele contém um cabeçalho do kernel e uma tabela de nomes tblNames, que o eForth.f transfere durante a decodificação para registros decimais (consulte 2.4.4). É com base no eForth0.mkp que o núcleo do eForth.mkp será criado (consulte 2.4.3); portanto, o eForth0.mkl deve ser compilado primeiro.

1.2 Código fonte para palavras de alto nível eForth.f


O arquivo eForth.f é alimentado pela entrada do maravilhoso compilador doméstico SP-Forth [5]. O arquivo contém definições de todas as palavras de alto nível. Com o tempo, eles podem ser identificados no próprio eForth e possivelmente compilados diretamente a bordo do Electronics MK-161.

Durante a compilação, o eForth.f lê o eForth0.mkp em branco e com sua ajuda cria três arquivos no diretório atual para carregamento subsequente no MK-161: eForth.mkp, eForth.mkd e eForth.mkb. É eForth.mkb que contém os corpos das palavras de alto nível, embora seus cabeçalhos estejam localizados no arquivo eForth.mkd.

O quarto arquivo, eForth.mkt, é escrito manualmente no eForth e pode ser editado a bordo do MK-161 usando o editor de texto embutido. Cada um desses quatro arquivos analisarei em mais detalhes abaixo (consulte 2.4).

2. Eletrônica MK-161


Um fabricante de Novosibirsk chama o MK-161 de um acrônimo antigo. Esse era o nome das primeiras calculadoras da URSS. O sistema de instruções MK-161 herda o sistema de comando das calculadoras soviéticas "Electronics B3-34" e "Electronics MK-61". Isso significa que os programas criados para calculadoras soviéticas continuarão no MK-161 sem alterações ou com pequenas alterações.

O inverso não é verdadeiro. O eForth não irá para o PMK soviético, porque usa muitos recursos que apareceram pela primeira vez no MK-152/161 e não estavam disponíveis nos modelos anteriores da série.

Considere os recursos do idioma de entrada e da arquitetura do MK-161, que influenciaram o 161eForth (daqui em diante simplesmente eForth) e deram à implementação discutida do eForth um "sotaque russo".

O primeiro desses recursos é o contrato “senior at junior address”, que é constantemente mantido no MK-161. Por exemplo, o número 1000 = 3 × 256 + 232 será gravado em dois bytes consecutivos, como 3 e 232.

2.1 Endereçamento indireto


A programação do PMK soviético ouviu falar de endereços indiretos. Para endereçamento direto, indicamos explicitamente o número do registro ao qual estamos nos referindo. Por exemplo, P IP 44 considera o conteúdo do registro 44. A chave P que apareceu no MK-152 é usada para acessar registros com o número 15 ou mais - esses registros estavam ausentes no PMK soviético.

No endereçamento indireto, o número do registro necessário não é conhecido antecipadamente. Este número está em um registro diferente. Por exemplo, se o registro 8 contiver o número 44, o comando K PI 8 considerará o conteúdo do registro 44 (R44).

As teclas K e P podem ser combinadas. Por exemplo, o comando R K BP 20 transferirá o controle (GOTO em mnemônicos latinos) para o endereço armazenado em R20.

O recurso que se mostrou importante para o intérprete interno do eForth está relacionado ao aumento / diminuição preliminares de registros durante o endereçamento indireto. Esse recurso é herdado do PMK soviético.

Por exemplo, os comandos de leitura indireta KI 0, KI 1, KI 2 e KI 3 reduzem o conteúdo dos registros 0, 1, 2 ou 3 em um para o registro desejado.Os comandos KI 4, KI 5 e KI 6 Antes de ler, aumente o conteúdo dos registros 4, 5 ou 6 em um.

Essa "modificação" do registro de endereços permite processar grupos inteiros de registros em um loop. É semelhante a ++ R e --R em C. O número do registro é importante. É ele quem determina se aumentará (registros 4-6) ou diminuirá (registros 0-3) com endereçamento indireto.

A arquitetura 161eForth foi afetada pelo fato de que o aumento nos registros 4-6 com endereçamento indireto é preliminar . Como resultado, o ponteiro de interpretação (IP) localizado em R6 sempre aponta para o último byte do código costurado. No 86eForth, o IP sempre indica um byte subsequente que ainda não foi lido.

Isso também se aplica ao ponteiro da pilha de retorno (RP) armazenado no registro 2. O R2 sempre aponta para o topo da pilha de retorno.

Um recurso útil do MK-161 é a ausência de um aumento / redução no registro se ocorrer um endereçamento indireto com a nova chave R. Por exemplo, RKIP02 conta o número da parte superior da pilha de retorno sem alterar o ponteiro. Esta é uma equipe pronta do Fort R @. Do exposto acima, segue-se que o valor de leitura é um a menos que o endereço do próximo token, que será executado após o retorno da palavra "dois pontos".

Quando você tiver que desenvolver ou estudar palavras que interajam estreitamente com o intérprete interno do eForth, certifique-se de entender completamente esse ponto sutil associado ao exagero .

2.2 Tabelas, ordenadas e associativas


As tabelas MK-161 estão localizadas na memória do programa (consulte 2.4.3). Eles apareceram no Novosibirsk "Electronics MK" e são completamente desconhecidos dos especialistas em PMK soviético. O endereço da tabela usada é sempre armazenado no registro 9042, mas o acesso a eles é diferente.

Uma tabela ordenada é uma matriz de números inteiros de 16 bits não assinados. O eForth contém uma tabela tblTokens com os endereços das primitivas (consulte 3.1.1) - Fort palavras escritas no sistema de comando MK-161. O intérprete de endereço (consulte 3.2) usa tblTokens para executar rapidamente o código costurado, portanto o eForth tenta sempre conter o endereço desta tabela no R9042.

Para acessar uma tabela ordenada, é necessário escrever o número do item desejado no R9210. O número n no registro X será substituído pelo valor do elemento da tabela pelo número n, a contagem começa em zero.

As tabelas associativas ("pesquisa por valor") são ativamente usadas pelo eForth, principalmente pelo primitivo (FIND), procurando uma palavra por seu nome. Além disso, a tabela associativa tblCHPUT é usada ao imprimir letras na tela para processar feeds de linha e outros códigos de controle.

Para procurar o elemento n na tabela associativa, escreva n em R9212. O número n no registro X (a gerência chama de “índice”) será substituído pelo valor de 16 bits registrado na tabela imediatamente após o seu “índice” n.

A presença dessa função de busca rápida, embora simples, implementada na linguagem assembly no “firmware” do MK-161, ajudou a eForth a alcançar um desempenho aceitável ao reconhecer nomes de palavras e compilar programas. É claro que, para isso, tive que desenvolver não as tabelas de reconhecimento de nome mais simples, "aprimoradas" para essa função. Falaremos sobre isso em mais detalhes no segundo artigo.

2.3 Interrupções e console


O “MK Electronics” permite que seus proprietários gravem programas no idioma de entrada que respondem a determinados eventos - como pressionar ou soltar um botão, encerrando a contagem do temporizador.

O eForth usa ativamente esse sistema de interrupção tanto para a entrada do teclado quanto para a exibição do cursor piscante quando solicitada, e para entrada / saída através de uma porta serial universal (RS-232).

As letras digitadas no teclado ficam na fila bufKbd à medida que você pressiona as teclas. Isso é muito conveniente e economiza tempo em sistemas com baixa velocidade. A troca de alfabeto e maiúsculas e minúsculas é tratada pela interrupção do KeyPress e não ocupa espaço na fila. Um toque longo na tecla chama a repetição automática.

Quando a linha de 8 letras estiver cheia, e o eForth ainda não estiver pronto para processar a entrada (a situação é muito rara), o MK-161 emitirá um chiado infeliz. Obviamente, eu gostaria de não implementar todo esse trabalho natural do teclado no tradutor, mas tirar o MK-161 "pronto da caixa" como um serviço do programa embutido (firmware). Mas o que, como dizem, é rico.

Após o início dos trabalhos, toda a saída eForth é direcionada para a tela gráfica MK-161. A saída das letras é realizada por uma rotina relativamente simples do CNCut. A única dificuldade aqui é a implementação do código de controle BS, o “espaço de volta”. O MK-161 usa uma fonte proporcional. Portanto, em um buffer especial tblBS, é necessário lembrar as posições dos caracteres exibidos, de onde o código de saída BS mais tarde os leva.

Durante o diálogo, o usuário pode usar a palavra IO> para redirecionar toda a E / S para a porta serial RS-232, o que possibilita programar o MK-161 a partir de um teclado de computador familiar ou de outro MK-161 . A palavra CON> retorna o controle ao console da calculadora.

2.4 Áreas de memória e instalação do eForth no MK-161


A memória “MK-161 Electronics” consiste em memória de programa endereçável separadamente e memória de registro de dados. Por sua vez, a memória do registro é heterogênea e é dividida em três grandes áreas.

Registros com números de 0 a 999 armazenam "números decimais". Estes são registros comuns, como em "Eletrônica B3-34" e outras calculadoras. Eles são simplesmente capazes de armazenar não 8, mas 12 casas decimais da "mantissa".

Registros com números de 1000 a 8167 armazenam números inteiros de 0 a 255. Os últimos 3 Kbytes desta área com endereços de 5096 a 8167 são chamados de área de texto .

Registros com números de 9000 a 9999 são chamados de registradores de funções. Essa área de serviço do espaço de endereço se assemelha às portas de E / S do microprocessador. Com a ajuda de comandos de gravação e leitura, esses endereços são usados ​​para acessar dispositivos de E / S, interromper sistemas etc.

Para instalar o eForth no "Electronics MK-161", basta transferir quatro arquivos para a calculadora, por exemplo, usando o programa do fabricante MK.EXE:
  • Escreva eForth.mkp na memória do programa, começando na página 0. A versão 0.5b ocupa 74 páginas.
  • Escreva eForth.mkd na memória de dados decimal
  • Grava eForth.mkb na memória de dados binários
  • Escreva eForth.mkt na memória de texto

Após a transferência para a calculadora, recomendo salvar imediatamente esses quatro arquivos em um diretório separado do “disco eletrônico” incorporado. Como eles têm o mesmo nome, você pode fazer o download do eForth imediatamente de cada vez como um "pacote".

2.4.1 Memória binária ("byte") MK-161: eForth.mkb


Os registradores Electronics Electronics com números de 1000 a 5095 são usados ​​para armazenar números de 0 a 255. Essa área da memória de registro da calculadora é chamada de binário. Dois registradores binários consecutivos podem ser acessados ​​do eForth como uma única célula de 16 bits e (como em todo o MK-161), os 8 bits superiores estão no registrador com um número menor.

O eForth usa essa pequena "memória binária" como principal. Palavras trabalham com ela! e @, HERE e ALLOT, somente a partir daqui o interpretador de endereço executa o código costurado (consulte 3.2). Aqui estão as variáveis ​​eForth, o buffer de entrada de texto (TIB), o dicionário e a pilha de reversão tblBS para implementar o backspace.

4096 bytes é muito modesto, para os padrões modernos. Portanto, enormes esforços foram gastos para trazer para outras áreas da memória tudo o que é possível.

2.4.2 Área de texto: eForth.mkt


Imediatamente depois que a memória binária é uma área de texto , registra-se com números de 5095 a 8167. Tecnicamente, esses são os mesmos registradores de bytes, mas a capacidade de gravá-los no disco e ler como um arquivo separado torna essa área especial.

A palavra TLOAD é usada para trabalhar com "texto" no eForth. Alimenta toda essa área à entrada do intérprete de texto, como uma sequência de 3072 letras.

Há desacordo sobre como dividir o texto em linhas. Um editor incorporado à MK Electronics insiste em um comprimento de linha de 24 caracteres. Callisto usa a convenção Fort, onde a string contém 64 caracteres. O eForth oferece ao usuário a opção de contar todo o texto como uma linha longa. Você pode usar o editor embutido MK-161. Você pode escrever o seu próprio, compatível com o Callisto.

Aqui está o conteúdo inicial do eForth.mkt, por conveniência, dividido em três linhas:

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

A primeira linha define a nova palavra oi que cumprimenta o usuário. A segunda linha pega o símbolo desta palavra (veja 3.1) e coloca-o na variável 'BOOT (veja 1). Agora a área de texto irá parar de compilar sempre que o eForth for iniciado. Em vez disso, a saudação já compilada será executada.

A última linha inicia a palavra oi, exibindo uma saudação na tela. A palavra \ conclui a interpretação do texto, retornando o controle ao console.

Para compilar um arquivo de texto arbitrário, você precisa ir para a calculadora com o comando BYE, acessar o menu principal e carregar o arquivo desejado no modo DOS. Você também pode transferir o arquivo mkt de um computador. A tecla C / P retornará você ao eForth, após o qual com o comando TLOAD você poderá compilar o arquivo carregado na área de texto.

2.4.3 Memória de programa: eForth.mkp


A memória do programa MK-161 é um espaço de endereço isolado. Ele também armazena bytes, mas eles são somente leitura. A memória do programa contém 10.000 "etapas", que acabaram sendo redundantes para o eForth. Mais de um quarto da memória do programa ficou livre, o que oferece uma boa reserva para o desenvolvimento do tradutor.

Somente na memória do programa as "palavras de código" podem ser implementadas. Além disso, tabelas de reconhecimento de nome e todas as seqüências de texto conhecidas são renderizadas aqui, o que economiza memória binária.

Algumas palavras, como C @, COUNT e TYPE, podem endereçar a memória do programa se o endereço não for um número positivo. Por exemplo, a frase 0 C @ conta como um “passo” (byte) do endereço 0 da memória do programa.

2.4.4 Memória decimal: eForth.mkd


Os registros da MK Electronics com números de 0 a 999 são chamados decimais e contêm números usados ​​para cálculos comuns na calculadora - 12 dígitos decimais da "mantissa" e 2 dígitos decimais da "ordem". O forte foi projetado para trabalhar com números inteiros de até 4 bytes, esse recurso é claramente redundante para o eForth.

A memória decimal é usada para economizar preciosa memória binária. Pilhas de dados e devoluções são feitas aqui. Os títulos das palavras são armazenados aqui - definidos pelo usuário e incorporados, um registro por título. Essa abordagem permite redefinir palavras pares com nomes padrão.

A pilha na memória decimal leva a vários recursos característicos do Fort no MK-161. Primeiramente, o intervalo de valores dos elementos da pilha é enorme; ele pode acomodar números inteiros de 32 bits. A necessidade de "números inteiros duplos" no MK-161 desaparece, embora por razões de compatibilidade eu tenha implementado as palavras correspondentes eForth. “Inteiros duplos” são apresentados no MK-161, como dois elementos de pilha contendo números de 0 a 65535, codificando um número inteiro de 32 bits com um sinal no código adicional. Os 16 bits altos desse número são colocados no topo, ou seja, no endereço mais baixo.

As operações lógicas bit a bit AND, OR, XOR e NOT tratam seus argumentos como números inteiros de 16 bits. Um resultado de 32768 a 65535 é convertido em números negativos de -32768 em -1. No eForth, false é codificado com zero e verdade menos um. Também verdadeiro é qualquer valor diferente de zero.

O segundo recurso da pilha de dados 161eForth é que ele contém números assinados. Quando a palavra @ lê o número 65535 de uma “célula” de 16 bits, é automaticamente convertida em -1. Uma palavra especial “não assinada” U @ é fornecida para contar diretamente 65535, com um sinal de adição.

Lembro que, por uma questão de velocidade, os dois elementos superiores da pilha de dados não estão localizados na memória decimal, mas diretamente nos registros X e Y.

O fato de os registros decimais poderem conter números fracionários e números de ponto flutuante não é usado pelo eForth. A máquina virtual eForth usa esses registradores para armazenar números inteiros decimais de 12 bits assinados. Registradores decimais são acessados ​​pelas palavras C @ e C! - os mesmos que funcionam com um único registro.

3. O intérprete interno


O núcleo do eForth é um programa escrito na linguagem de entrada MK-161. Seu primeiro comando MAIN transfere o controle para o código MAIN, que primeiro descobre as circunstâncias da reinicialização. Se foi causado pelo token errado, o MK-161 irá chiar. Na primeira inicialização, e também depois de ligar o MK-161, a tela é limpa. Em seguida, MAIN chama a sub-rotina Init para inicializar o sistema de interrupção e tudo o que os drivers do console MK-161 precisam.

Depois de inicializar as pilhas e os retornos de dados, a parte de baixo nível da partida está concluída. Coisas incríveis acontecem para máquinas com arquitetura de Harvard - o eForth continua executando o "código com fio" da memória de bytes. A honra de ser o primeiro pertence a uma palavra cujo endereço de cabeçalho está registrado em R43. Geralmente é a palavra FRIO.

Como as palavras de alto nível (IEDs) são organizadas? Qualquer palavra consiste em duas partes, um corpo e um cabeçalho. O cabeçalho é armazenado em decimal. Ajuda o intérprete e o decompilador externos a encontrar o nome e o corpo da palavra. O cabeçalho também contém um campo "léxico" - um conjunto de sinalizadores que ajudam o intérprete externo a processar corretamente a palavra encontrada. O intérprete interno é muito mais importante para o corpo do VCA localizado na memória binária e armazenado no dicionário. Ele é capaz de executar palavras que não têm título.

O corpo do VCA começa com o byte do campo de código , que contém o endereço do processador da palavra especificada. Quatro manipuladores VCA são gravados no idioma de entrada do MK-161 e começam na primeira página da memória do programa. Vamos analisar todos eles (ver 3.3), mas o principal é chamado DOLST e está localizado no endereço 02, imediatamente após o comando MAIN BP já considerado. Este manipulador executa palavras Fort definidas com dois pontos.

Após o byte do campo de código , há um campo de parâmetro de comprimento arbitrário. Nas "palavras em dois pontos", o campo de parâmetro contém um "código costurado" - uma sequência de tokens de 16 bits, cada um dos quais indica uma ação atribuída a ele.

Primeiro, consideraremos o token com mais detalhes. Em seguida, estudaremos o intérprete interno INEXT, que transfere de um token para a execução do próximo. EForth chama INEXT de manipulador primitivo. Concluímos esse tour do intérprete interno analisando todos os quatro processadores IED.

3.1 Tokens


O token representa a palavra no código e na pilha costurados, permitindo que seja executado rapidamente. O token é um ponteiro para o corpo da palavra, mas a arquitetura severa do MK-161 fez seus próprios ajustes nessa idéia simples. Vamos analisar todos os tipos de tokens, começando com o token primitivo.

3.1.1 Token primitivo


Todas as palavras incluídas na distribuição eForth são numeradas de 0 a 206. Essa numeração é de ponta a ponta, levando em consideração tanto as primitivas quanto a VCA. Isso é feito para que, pelo número da palavra, fosse fácil restaurar o nome dele. Esses nomes são armazenados na memória do programa. O link para o nome desejado é facilmente encontrado na tabela de cabeçalho.

O número primitivo é o seu token . Como qualquer token, o primitivo ocupa dois bytes no código costurado. O primeiro é zero. O segundo contém o número dele. A tabela tblTokens permite que você encontre rapidamente o endereço do código primitivo por esse número. O endereço tblTokens é armazenado permanentemente no R9042 (consulte 2.2), ou seja, tudo está sempre à mão para executar a primitiva.

A palavra XT> permite descobrir o endereço de um código primitivo por seu número (token). Como o código das primitivas sempre está localizado na memória do programa, o endereço recebido é sempre negativo (consulte 2.4.3).

3.1.2 Token VCA


O VCA pode ter seu próprio número e nome padrão associado ou pode ser completamente novo, criado pelo usuário. Em todos os casos, o token VCA é o endereço do seu campo de código (consulte 3), ou seja, um número de 1000 a 5095.

No código costurado, o token VCA é escrito de uma maneira muito incomum. O número de centenas (um número de 10 a 50) é gravado no primeiro byte, e o restante da divisão do token por 100 (um número de 0 a 99) no segundo byte.

Por exemplo, o token 1234 será representado por dois bytes 12 e 34. A compilação desse e de qualquer outro token é realizada usando a palavra COMPILE, obtida do padrão ANSI. Para escrever e ler tokens VCA no código costurado, as palavras XT! e XT @. Eles acessam endereços (consulte 3.1.4), e a palavra XT @ também é capaz de ler o token primitivo.

3.1.3 Literais inteiros


Literais inteiros são uma espécie de tokens primitivos. Eles são incomuns o suficiente para serem considerados separadamente.

No código costurado, os tokens DOLIT e DOLITM ocupam quatro bytes. Os dois primeiros bytes contêm o token primitivo já considerado, ou seja, 0 e o número do primitivo. Os próximos dois bytes contêm um número inteiro que o literal fornecido colocará na pilha de dados durante a execução.

O DOLITM difere no fato de alterar o sinal do número antes de colocá-lo na pilha. Ele foi projetado para implementar números negativos.

3.1.4 Literais de endereço


Como literais inteiros, os três literais de endereço BRANCH ,? BRANCH e DONXT ocupam 4 bytes cada no código costurado. Os 2 primeiros bytes contêm o token primitivo, os dois últimos bytes são o endereço de salto.

O endereço é gravado no mesmo formato que o token VCA (consulte 3.1.2). O primeiro byte contém o número de centenas, o segundo contém o restante da divisão do endereço por 100. Lembro que, devido ao exagero (consulte 2.1), o endereço de transição não contém o endereço do token desejado, mas um número a menos um.

O token DONXT ajuda a implementar o "ciclo final" FOR-NEXT (consulte 1). O salto incondicional de FILIAL é necessário para implementar o loop BEGIN-AGAIN infinito. Ramificação condicional? BRANCH transfere o controle se zero estiver na parte superior da pilha de dados (false). Serve para implementar a instrução IF-THEN condicional, sai de "loops indefinidos" BEGIN-UNTIL e BEGIN-WHILE-REPEAT.

3.1.5 Literais de string


Literais de sequência são um tipo de tokens VCA. No código costurado de uma literal de sequência, após o token, há um byte com o comprimento da sequência, após o qual é a própria sequência, do primeiro até o último.

O EForth possui três literais de string: $ "| ,." | e abortam "|. Eles são definidos no arquivo eForth0.mkl como tokens STRQP, DOTQP e ABORQ, respectivamente. O principal trabalho" literal "é feito pela palavra do $, o token DOSTR.

Para tornar o tamanho do artigo razoável, não posso insistir muito nesse tópico interessante, mas é bom saber sobre a disponibilidade deles no eForth.

3.2 Intérprete de endereço


É hora de considerar o intérprete do token , cujo endereço é sempre escrito no registro 9. A maioria das primitivas termina seu trabalho com o comando K BP 9, que transfere o controle para o rótulo INEXT.

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

Primeiro, o interpretador de endereço lê o primeiro byte do próximo token com o comando KIP6. Se for zero, isso é primitivo e o código sob o rótulo NPrime manipulará o token.

O rótulo NData indica o processamento do token VCA. O primeiro byte é multiplicado por cem pelo comando VP 2, após o qual o KIP6 + adiciona o segundo byte do token ao resultado (consulte 3.1.2). O token de leitura é inserido pela equipe P7 no WP "registro de trabalho" (R7).

Sabemos que o token VCA é o endereço do seu campo de código, que contém o endereço do processador. Os comandos KIP7 P8 leem o byte do campo de código em R8 e o comando KBP8 transfere o controle para o processador VCA. O manipulador sabe que R7 contém um número um a menos que o endereço do campo de parâmetro da palavra que está sendo processada.

Os comandos F⟳ com o código 25 são "ordenados" na pilha. O fato é que o eForth armazena os dois principais elementos da pilha de dados diretamente nos registros X e Y da pilha MK-161. Essa solução acelera o trabalho, mas torna necessário garantir que esses dados importantes não sejam perdidos.

Resta entender como o interpretador de endereço executa as primitivas.

 NPrime: F⟳ 6 9210 8 F⟳ 8 

O comando KIP6 lê o segundo byte do token primitivo. Os comandos RRP9210 P8 leem o endereço dessa primitiva na tabela tblTokens (consulte 2.2 e 3.1.1) e o KBP8 transfere o controle para essa primitiva.

Como acima, F⟳ remove o excesso da pilha, restaurando o conteúdo dos registradores X e Y.

O intérprete de endereço eForth é tão pequeno que é duplicado várias vezes na memória do programa. A cópia principal é executada pelo comando K BP 9, que completa a maioria das primitivas.

Como exercício, recomendo estudar a implementação da palavra EXECUTE, colocada após o rótulo EXECU. Essa é uma variante INEXT, que lê o token não do código costurado, mas o extrai da pilha de dados.

3.3 Manipuladores VCA


Quatro variedades de VCA têm quatro manipuladores diferentes: DOLST, DOVAR, DOCON e DOCONM. Já vimos acima que o intérprete de endereço antes de chamar o manipulador deixa em R7 o endereço do campo de código da palavra que está sendo processada.

O eForth.f aprende os endereços desses manipuladores lendo o cabeçalho do kernel no arquivo eForth0.mkp. Isso o ajuda a compilar o VCA para o Electronics MK-161 corretamente, colocando o resultado no arquivo eForth.mkb.

3.3.1 Palavras do cólon: DOLST e EXIT


O próximo tópico importante após INEXT é o que o intérprete interno faz quando encontra o token de uma palavra definida por dois pontos. O campo de código dessa palavra contém o número 2, portanto INEXT transfere o controle para o manipulador DOLST, que faz o trabalho necessário para começar a interpretar a nova lista de tokens.

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

O registro 2, como já discutimos (consulte 2.1), contém um ponteiro de pilha de retorno RP. Os comandos IP6 KP2 gravam o valor de R6, o Interpretation Pointer (IP), na pilha de retorno. Mais tarde, isso ajudará a lembrar a posição atual na lista antiga de tokens, onde INEXT encontrou uma palavra em dois pontos. Agora, o IP7 P6 reorganiza o IP no início de uma nova lista.

Imediatamente após o código DOLST, é inserido o código INEXT, que executará a primeira palavra da nova lista de tokens. Como em outros lugares, os comandos F ajudam a manter os dois principais elementos da pilha de dados.

As palavras de dois pontos geralmente terminam com um token EXITT, que faz o oposto em comparação com DOLST - ele pega o antigo valor de IP da pilha de retorno e retorna à interpretação da lista de tokens antigos.

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

Os comandos RKIP02 P6 leem o valor IP antigo da parte superior da pilha de retorno (consulte 2.1). Depois disso, os comandos Cx 1 IP2 + P2 corrigem o valor de RP, aumentando em um. O comando F⟳ restaura a pilha, após o que INEXT executa a próxima palavra da lista antiga de tokens.

Obviamente, o INEXT não pode ir tanto após DOLST quanto após EXITT ao mesmo tempo. Para fazer isso, apliquei um truque antigo dos tempos da URSS. Você também pode dominá-lo examinando as linhas correspondentes no arquivo eForth0.mkl.

3.3.2 DOVAR, manipulador de variável e matriz


Palavras geradas pelas palavras CREATE e VARIABLE usam o mesmo manipulador DOVAR. Esse manipulador envia na pilha o endereço da variável localizada no campo de parâmetro, que segue imediatamente após o byte do campo de código. As variáveis ​​VARIABLE ocupam 2 bytes e as matrizes criadas usando CREATE contêm quantos bytes o programador deseja.

 DOVAR: ⇔ 3 x 1 7 + 9 

Comandos ⇔ KP3 salva o conteúdo do registro Y na pilha de dados. Ao mesmo tempo, o número da parte superior da pilha é inserido em RY, liberando RX para o novo valor. Após os comandos Cx 1 IP7 +, esse novo valor na parte superior da pilha se torna o endereço do campo de parâmetro da palavra executável. O KBP9 transfere o controle para INEXT, sem truques, passando para a próxima palavra.

3.3.3 Manipuladores constantes: DOCON e DOCONM


Diferentemente do DOVAR, o manipulador constante acessa o campo de parâmetro de sua própria palavra. O DOCON lê um valor constante de 16 bits a partir dele. Este valor é sempre positivo.

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

Os comandos ⇔ KP3 ⇔ salvam RY na pilha de dados. Mas desta vez, o antigo topo da pilha de dados retorna ao RX. Os comandos IP7 P5 o forçam a voltar para RY, enquanto preparam o registrador de ponteiro R5 para ler o valor da constante. Em seguida, Cx 256 substitui o lixo no registrador X pelo número 256.

Instrumentos KIP5 × KIP5 + leem uma constante do campo de parâmetro até o topo da pilha de dados, ou seja, no RX. Como lembramos, no MK-161 o primeiro byte é sempre alto. É multiplicado por 256, após o qual o byte menos significativo da constante é adicionado ao produto. Todo o trabalho está concluído, o KBP9 transfere o controle para a próxima palavra.

O DOCONM funciona exatamente da mesma maneira, apenas o sinal constante após a leitura muda para o oposto. As constantes negativas são implementadas no MK-161 como um processador separado por uma questão de velocidade:

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

Agora, descobrimos completamente como o eForth executa seu código no MK-161 Electronics a partir da área de dados, inclusive abordando um tópico mais profundo dos literais de strings (consulte 3.1.5).

No segundo artigo da série, falarei sobre o intérprete externo de “texto” 161eForth, analisarei a estrutura das tabelas de cabeçalho e o reconhecimento de nomes. Esta parte do tradutor exigiu que eu desenvolvesse soluções muito mais radicais, tendo como pano de fundo o discutido acima: o forte tradicional, antigo e bom.

Feliz Fort programação!

Literatura


  1. Dr. Chen-Hanson Ting. eForth and Zen - 3rd Edition, 2017. Disponível no Amazon Kindle.
  2. Baranov S.N., Nozdrunov N.R. Linguagem Fort e sua implementação. - L.: Engenharia mecânica. Leningrado Departamento, 1988.
  3. Semenov Yu.A. Programação na linguagem FORT. - M.: Rádio e comunicações, 1991.
  4. ANS Quarto padrão. X3.215-1994. Tradução
  5. Documentação SP-Forth .
  6. Loja Externa (Procedimentos do Dr. Chen-Hanson Ting) , onde é possível fazer o download do 86eForth v5.2 para Windows, documentação em inglês.


Ilustrações em vídeo


Esses quatro pequenos vídeos do 161eForth continuam. O primeiro vídeo no início do artigo.

Parte 2 de 5. Testes TEST-TEST4 do livro "eForth and Zen", 3ª edição, no MK-161.



Parte 3 de 5. VER descompilador.



Parte 4 de 5. Ponto de interrupção BYE, terminal RS-232 e acesso remoto ao MK-161.



Parte 5 de 5. Palavras finais.

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


All Articles