O Agon Light e outras revisões da Plataforma Agon são baseados no processador Zilog eZ80. O eZ80 possui um espaço de endereço de 24 bits que suporta 16 megabytes de memória, em comparação com os 64 kilobytes do Z80 original. O eZ80 possui dois modos de operação: o modo padrão Z80, que possui registradores de 16 bits facilitando o endereçamento de 64k de memória, mas exigindo o uso de “banking” para acessar mais de 64k de memória; e modo de operação ADL (address data long), que estende os registradores para 24 bits, tornando todo o espaço de endereço prontamente acessível.
Quando consideramos linguagens de programação de alto nível, há várias disponíveis para o Z80, mas elas são limitadas a 64k de memória ou possuem métodos complicados de troca de banco para acessar mais memória.
Considerando as linguagens de programação C, há vários compiladores Z80 C disponíveis. Até o momento, a comunidade Agon se concentrou em dois:
Ambiente de desenvolvimento Zilog ZDS II que pode produzir código ADL eZ80. Este foi o conjunto original de ferramentas usado pelos desenvolvedores do Agon, mas é de código fechado, roda apenas em Windows e suporta apenas o padrão de dados C89
SDCC (compilador C para pequenos dispositivos) , uma escolha popular para computadores de 8 bits, e adaptá-lo para Agon tem sido o foco de várias pessoas no computador Agon. Este é um bom compilador para Z80, mas suporta apenas Z80 e não o modo ADL.
Como alternativa, o conjunto de ferramentas CEdev C/C++ é um compilador de código aberto que pode produzir código ADL. Ele é direcionado à calculadora TI-84 Plus CE (baseada no processador eZ80) e possui uma comunidade de tamanho razoável. CEdev é baseado nas versões eZ80 do compilador LLVM e do montador fasmg. Ele produz código ADL com ponteiros de 24 bits, números inteiros de 24 bits, comprimentos de 32 bits, curtos de 16 bits e pontos flutuantes de 32 bits. Há também uma biblioteca bastante extensa para programas C e C++ (embora não seja compatível com ISO... ainda).
AgDev é o resultado de um esforço para modificar o CEdev para acomodar o conjunto de recursos e o design de hardware da Plataforma Agon. O resultado é um conjunto de ferramentas mais poderoso e compatível com C++, em comparação com outras opções do Agon.
Baixe você mesmo uma versão de lançamento ou uma versão do código-fonte. Coloque a compilação em um diretório de sua escolha.
Depois, certifique-se de que a pasta /bin
possa ser encontrada em PATH
; se você estiver no Windows, siga este guia ou execute cedev.bat e execute comandos a partir daí. No Linux, execute export PATH=/<insert path here>/bin:$PATH
em uma janela de terminal.
Isso segue a mesma abordagem do CE Toolchain original (veja a parte inferior da página de introdução do CEdev). O processo de construção foi modificado para parar na geração do arquivo .bin
. Este é o executável do Agon Light.
Eu recomendo usar:
fazer limpo faça V = 1
O comando make clean
pode ser usado para excluir os resultados de compilações anteriores e, assim, forçar uma recompilação.
O processo de construção passa pelas seguintes etapas:
Compilação de arquivos de origem .c para bitcode LLVM (.bc) usando ez80-clang
Vinculação de bitcode LLVM usando ez80-link
. Isso inclui otimização do tempo de link
Geração de código assembly eZ80 (.src) para os programas fonte usando ez80-clang
Montagem e vinculação do código assembly gerado (da etapa 3) com as bibliotecas e o tempo de execução do compilador usando fasmg
- isso inclui a construção do executável direcionado a um local de memória específico. Esta é a parte principal do processo de construção que precisa ser ajustada.
Consulte a nota de aplicação do Zilog "Chamando C de asm.pdf".
Apenas o registro e a pilha IX precisam ser preservados pelas funções chamadas.
Os argumentos são empurrados do último para o primeiro, correspondendo ao protótipo C. No eZ80, 3 bytes são sempre colocados na pilha, independentemente do tamanho real. No entanto, a função assembly deve ter cuidado para usar apenas os bytes válidos que são enviados. Por exemplo, se um tipo curto for usado, o byte superior do valor colocado na pilha conterá dados arbitrários. Esta tabela lista os locais relativos a sp dentro da função chamada. Observe que sp + [0,2]
contém o endereço de retorno.
Tipo C/C++ | Tamanho | Localização da pilha |
---|---|---|
personagem | 1 byte | esp + [3] |
curto | 2 bytes | esp + [3,4] |
interno | 3 bytes | esp + [3,5] |
longo | 4 bytes | esp + [3,6] |
muito longo | 8 bytes | esp + [3,10] |
flutuador | 4 bytes | esp + [3,6] |
dobro | 4 bytes | esp + [3,6] |
ponteiro | 3 bytes | esp + [3,5] |
Observe que eZ80 é little endian – ou seja, o byte menos significativo é armazenado primeiro.
Esta tabela lista quais registros são usados para valores de retorno de uma função. O sinal do tipo não afeta os registros utilizados, mas pode afetar o valor retornado. O LSB está localizado no registrador mais à direita da expressão, por exemplo E:UHL
indica que o registrador L
armazena o LSB.
Tipo C/C++ | Registro de devolução |
---|---|
personagem | UM |
curto | HL |
interno | UHL |
longo | E:UHL |
muito longo | BC:UDE:UHL |
flutuador | E:UHL |
dobro | E:UHL |
ponteiro | UHL |
Não é compatível com ISO!
Consiste no seguinte:
Arquivo IO:
fopen()
, freopen(),
fclose()
fputc()
, fputs()
fgetc()
, ungetc()
, fgets()
feof()
, ferror()
, fflush()
fread()
, fwrite()
fseek()
, rewind()
, ftell()
clearerr()
remove()
E/S stdin/stdout:
putchar()
, puts()
getchar()
, gets_s()
Saída formatada
printf()
(e vprintf()
)
sprintf()
(e vsprintf()
)
snprintf()
(e vsnprintf()
)
Entrada formatada
scanf()
sscanf()
Há algumas outras coisas aqui - como stdint
e outras - mas devem corresponder principalmente às expectativas da biblioteca padrão normal. Majoritariamente.
stdio
Pode redirecionar a saída usando freopen()
em stdout
ou stderr
:
putchar()
- envia para outchar()
a menos que a saída seja redirecionada, nesse caso envia para fputc()
puts()
- chama putchar()
printf()
(e vprintf()
) - chama npf_putc_std()
, que chama putchar()
em nanoprintf.c
fputc()
- chama mos_fputc()
a menos que seja chamado em stdout
quando chama outchar()
- evita chamar putchar()
para que não haja risco de loops de chamada de função
Pode redirecionar a entrada usando freopen()
em stdin
:
getchar()
- chama inchar()
para obter o caractere e outchar()
para ecoar o caractere (mesmo que a saída tenha sido redirecionada). Se a saída não tiver sido redirecionada, chama fgetc()
e não ecoa o caractere.
gets_s()
- chama getchar()
se a entrada não foi redirecionada (as linhas terminam com CR). As chamadas fgets()
de input foram redirecionadas (as linhas terminam com o par CR/LF).
scanf()
- chama getchar()
em uscan.c
(não precisa de atualização)
fgetc()
- chama mos_fgetc()
a menos que seja chamado em stdin quando chama inchar()
e echos com outchar()
- evita chamar getchar()
para que não haja risco de loops de chamada de função
Requer FILE *
, que é um ponteiro para um identificador de arquivo retornado por fopen
e passado para as rotinas de E/S do arquivo para indicar em qual arquivo a ação deve ser executada.
Outros arquivos relacionados:
stdio.h
- arquivos de cabeçalho normais, que definem as várias funções e o typedef para FILE
files.c
- instancia o armazenamento para identificadores de arquivos, incluindo: stdout, stderr, stdin.
Os seguintes identificadores de arquivo padrão são definidos:
stdout
– saída padrão
stderr
– saída padrão para mensagem de erro
stdin
- entrada padrão
O MOS não implementa redirecionamento de entrada/saída, portanto, por padrão, todos eles usam o console.
Duas opções estão disponíveis para processamento de linha de comando.
Isso é incluído automaticamente se a função principal for definida como
int principal(int argc, char* argv[] )
o divide a linha de comando usando espaço como delimitador. As opções de linha de comando estão disponíveis no array argv[]
normalmente.
Isto é incluído opcionalmente se o makefile do aplicativo incluir:
LDHAS_ARG_PROCESSING = 1
Isto suporta
Citando com aspas duplas
Redirecionamento de entrada/saída
>out_file.txt
- redireciona stdout para out_file.txt
, criando um novo arquivo
>>out_file.txt
- redireciona stdout para out_file.txt
, anexando ao final do arquivo
<in_file.txt
- redireciona stdin para in_file.txt
Para obter a documentação atual sobre comandos MOS, consulte a documentação do Agon Console8.
O MOS (sistema operacional da máquina) fornece uma interface para o sistema de arquivos Agon e alguns periféricos de hardware, como o mouse. Ele mantém informações sobre variáveis do sistema em uma grande estrutura SYSVAR
que pode ser acessada no lado Z80. Geralmente seu código C irá declarar um ponteiro para esta estrutura, inicializada assim:
estático volátil SYSVAR* sv; sv = vdp_vdu_init();
Para obter mais informações, consulte <mos_api.h>
.
Para obter a documentação atual sobre comandos VDU, consulte a documentação do Agon Console8.
O VDP (processador de exibição de vídeo) aceita um fluxo de texto do MOS, agindo como um terminal de texto/gráfico. O fluxo de texto pode conter:
Texto normal
Sequências de escape/comandos para controlar a exibição e enviar comandos gráficos/som/etc.
Quando os resultados são retornados pelo MOS como resultado do envio de um comando, eles são armazenados nos SYSVAR
e não retornados diretamente em resposta ao comando. A resposta é assíncrona – para verificar se um resultado foi retornado:
Defina vdp_pflags
em SYSVAR
como zero
Emita o comando VDU
Aguarde até que o bit relevante em vdp_pflags
seja definido - consulte <mos_api.h>
para as máscaras de bits
Os comandos podem ser enviados por:
putch()
- caractere único (não faz parte da biblioteca padrão C)
mos_puts()
- string com vários caracteres
Ambos saem diretamente para MOS/VDP - observe que eles não fazem parte da biblioteca STDIO e não estão sujeitos à tradução ou redirecionamento CR/LF.
Funções de conveniência para muitos comandos VDU são fornecidas no AgDev. Por exemplo, para alterar a tela MODE para 3, o C chama vdp_mode(3);
enviará 22,3
como bytes únicos para a saída, equivalente a putch(22); putch(3);
Para obter uma lista dessas funções, consulte <vdp_vdu.h>
. Funções adicionais relacionadas ao manuseio do teclado são encontradas em <vdp_key.h>
.