|
| 1 | +# SDCC |
| 2 | + |
| 3 | +(A maior parte das informações aqui foram adaptadas deste um artigo em inglês sobre como usar o SDCC para programar para o Amstrad CPC: [*Introduction to programming in C with SDCC: Compiling and testing a "Hello World"*](http://www.cpcmania.com/Docs/Programming/Introduction_to_programming_in_SDCC_Compiling_and_testing_a_Hello_World.htm).) |
| 4 | + |
| 5 | +O [SDCC (Small Device C Compiler)](http://sdcc.sourceforge.net) é um pacote de compilação da [linguagem C](https://pt.wikipedia.org/wiki/C_(linguagem_de_programa%C3%A7%C3%A3o)) que gera código para diversos processadores, dentre os quais o Z80. Este é um tutorial sobre como usá-lo para programar para o MC1000. |
| 6 | + |
| 7 | +## Pré-requisitos |
| 8 | + |
| 9 | +Instale os seguintes produtos: |
| 10 | + |
| 11 | +* [SDCC](http://sourceforge.net/projects/sdcc) — o compilador C. |
| 12 | +* [Hex2bin](http://sourceforge.net/projects/hex2bin) — um utilitário para converter arquivos em formato hexadecimal (Intel Hex) gerado pelo SDCC para binário. |
| 13 | +* [MC1000CasTools](cassete) — uma ferramenta criada em [Java](http://java.com), com o qual é possível converter o arquivo binário para .WAV. |
| 14 | + |
| 15 | +## Preparação |
| 16 | + |
| 17 | +O SDCC não sabe nada sobre o MC1000, então temos que criar alguns arquivos, o que pode ser feito com qualquer simples editor de texto ou de código: |
| 18 | + |
| 19 | +1. **crt0_mc1000_load.s** — será usado em vez do arquivo crt0 padrão para Z80 do SDCC. Implementa o truque de carregar com `LOAD` um programa em código de máquina logo após o corpo de um programa em BASIC. Como ele preserva o ambiente do interpretador BASIC (o que não acontece quando se carrega um programa com `TLOAD`), é possível voltar ao BASIC naturalmente ao final do programa em código de máquina. |
| 20 | + |
| 21 | + ``` |
| 22 | + ; crt0.s for CCE MC-1000. By Emerson José Silveira da Costa, 2017-11-10. |
| 23 | + |
| 24 | + .module crt0 |
| 25 | + .globl _main |
| 26 | + .globl l__INITIALIZER |
| 27 | + .globl s__INITIALIZED |
| 28 | + .globl s__INITIALIZER |
| 29 | + |
| 30 | + ; ================================== |
| 31 | + |
| 32 | + ; MODELO PARA PROGRAMA EM CÓDIGO DE MÁQUINA |
| 33 | + ; CARREGÁVEL NO MC-1000 VIA COMANDO LOAD. |
| 34 | + |
| 35 | + .area _HEADER (ABS) |
| 36 | + |
| 37 | + ; ================================== |
| 38 | + |
| 39 | + ; (1) Programa em BASIC que chama a porção em linguagem |
| 40 | + ; de máquina residente nos bytes após o fim do programa: |
| 41 | + |
| 42 | + ; 1 CALL 992 |
| 43 | + |
| 44 | + .org 0x03d5 |
| 45 | + |
| 46 | + .dw endlinha2 ; Endereço do próximo registro de linha do programa em BASIC. |
| 47 | + .dw 1 ; Número da linha do programa em BASIC. |
| 48 | + .db 0xa2 ; Token de "CALL". |
| 49 | + .ascii "992" |
| 50 | + .db 0 ; Fim da linha. |
| 51 | + endlinha2: |
| 52 | + .dw 0 ; Endereço do próximo registro de linha = 0, indicando fim do programa. |
| 53 | + |
| 54 | + ; ================================== |
| 55 | + |
| 56 | + ; (2) Início do programa em linguagem de máquina. |
| 57 | + ; Faz preparativos antes de pular para a função main(). |
| 58 | + |
| 59 | + ; .org 0x03e0 ; =992. |
| 60 | + |
| 61 | + ; Reativa a impressão de caracteres que é desativada |
| 62 | + ; quando um programa BASIC sem nome (autoexecutável) |
| 63 | + ; é carregado. |
| 64 | + xor a |
| 65 | + ld (0x0344),a |
| 66 | + |
| 67 | + ; Inicializa variáveis globais. |
| 68 | + call gsinit |
| 69 | + |
| 70 | + ; Executa main() (estará na área _CODE). |
| 71 | + jp _main |
| 72 | + |
| 73 | + ; ================================== |
| 74 | + |
| 75 | + ; Neste ponto estamos no endereço 0x3ea, |
| 76 | + ; endereço que deve ser usado na opção |
| 77 | + ; --code-loc do linkador. |
| 78 | + ; Aqui se iniciará o código do programa em C. |
| 79 | + |
| 80 | + .area _CODE |
| 81 | + |
| 82 | + ; .org 0x03ea ; =1002. |
| 83 | + |
| 84 | + ; ================================== |
| 85 | + |
| 86 | + ; Declara antecipadamente demais áreas usadas pelo SDCC. |
| 87 | + ; As áreas são criadas à medida que são declaradas, então |
| 88 | + ; isto define a ordem em que as áreas aparecerão no |
| 89 | + ; código final. |
| 90 | + |
| 91 | + .area _HOME |
| 92 | + .area _INITIALIZER |
| 93 | + .area _GSINIT |
| 94 | + .area _GSFINAL |
| 95 | + |
| 96 | + .area _DATA |
| 97 | + .area _INITIALIZED |
| 98 | + .area _BSEG |
| 99 | + .area _BSS |
| 100 | + .area _HEAP |
| 101 | + |
| 102 | + ; ================================== |
| 103 | + |
| 104 | + ; Inicialização de variáveis. |
| 105 | + |
| 106 | + .area _GSINIT |
| 107 | + gsinit:: |
| 108 | + ld bc, #l__INITIALIZER |
| 109 | + ld a, b |
| 110 | + or a, c |
| 111 | + jr Z, gsinit_next |
| 112 | + ld de, #s__INITIALIZED |
| 113 | + ld hl, #s__INITIALIZER |
| 114 | + ldir |
| 115 | + gsinit_next: |
| 116 | + |
| 117 | + .area _GSFINAL |
| 118 | + ret |
| 119 | + ``` |
| 120 | + |
| 121 | +2. **putchar_mc1000_load.s** — implementa a função `putchar()` do C. |
| 122 | + |
| 123 | + ``` |
| 124 | + .area _CODE |
| 125 | + |
| 126 | + _putchar:: |
| 127 | + ld hl,#2 |
| 128 | + add hl,sp |
| 129 | + |
| 130 | + ld a,(hl) |
| 131 | + jp 0xdc1c ; Rotina "PrintAPOS" da ROM. |
| 132 | + |
| 133 | + ret |
| 134 | + ``` |
| 135 | +
|
| 136 | +Compile os arquivos com o programa **sdasz80** do pacote do SDCC: |
| 137 | +
|
| 138 | +``` |
| 139 | +$ sdasz80 -o crt0_mc1000_load.s |
| 140 | +$ sdasz80 -o putchar_mc1000_load.s |
| 141 | +``` |
| 142 | +
|
| 143 | +A opção `-o` fará gerar os arquivos relocáveis **crt0_mc1000_load.rel** e **putchar_mc1000_load.rel**. |
| 144 | +
|
| 145 | +## Utilização |
| 146 | +
|
| 147 | +Eis o infame arquivo de teste **helloworld.c**: |
| 148 | +
|
| 149 | +``` |
| 150 | +#include <stdio.h> |
| 151 | + |
| 152 | +void main() { |
| 153 | + printf("HELLO, WORLD!\r\n"); |
| 154 | +} |
| 155 | +``` |
| 156 | +
|
| 157 | +Compile-o com o programa **sdcc**: |
| 158 | +
|
| 159 | +``` |
| 160 | +$ sdcc -mz80 --no-std-crt0 --code-loc 0x3ea --data-loc 0 crt0_mc1000_load.rel putchar_mc1000_load.rel helloworld.c |
| 161 | +``` |
| 162 | +
|
| 163 | +Algumas explicações: |
| 164 | +
|
| 165 | +* `-mz80` — instrui o SDCC a gerar código para o Z80. |
| 166 | +* `--no-std-crt0` — instrui o SDCC a não usar seu crt0 padrão para Z80. |
| 167 | +* `--code-loc 0x3ea` — indica o endereço onde o SDCC deve começar a área de código do programa, ou seja, após o programa em BASIC de carga e algumas instruções iniciais em linguagem de máquina constantes no nosso crt0. |
| 168 | +* `--data-loc 0` — indica o endereço onde o SDCC deve começar a área de dados do programa. O zero indica que não vai começar num endereço fixo padrão do SDCC, mas conforme a sequência de áreas especificada no nosso crt0. |
| 169 | +
|
| 170 | +O resultado da execução do programa sdcc são vários arquivos, dentre os quais **helloworld.ihx**, em formato hexadecimal da Intel. Execute agora o **hex2bin**: |
| 171 | +
|
| 172 | +``` |
| 173 | +$ hex2bin helloworld.ihx |
| 174 | +``` |
| 175 | +
|
| 176 | +O resultado será um novo arquivo **helloworld.bin**. Finalmente entra em ação o utilitário de cassete do MC1000 [MC1000CasTools](cassete): |
| 177 | +
|
| 178 | +``` |
| 179 | +$ java MC1000CasTools -b helloworld.bin -wav |
| 180 | +``` |
| 181 | +
|
| 182 | +(Se o arquivo MC1000CasTools.class não estiver no diretório atual, indique o caminho até ele com a opção `-cp caminho` logo após a palavra `java`.) |
| 183 | +
|
| 184 | +Agora que temos um arquivo **helloworld.wav**, toque-o para carregar o programa no MC1000. |
| 185 | +
|
| 186 | + |
| 187 | +
|
| 188 | +## Informações adicionais |
| 189 | +
|
| 190 | +* <http://www.cpcwiki.eu/index.php/SDCC_and_CPC> |
| 191 | +* <http://cygnus.tele.pw.edu.pl/olek/doc/np/obce/asxhtm.html> — sobre o assembler usado no SDCC. |
0 commit comments