Mostrar mensagens com a etiqueta programação. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta programação. Mostrar todas as mensagens

sexta-feira, 24 de abril de 2026

Godot ZX


Não é todos os dias que recebemos "correspondência" de programadores Portugueses a mostrarem-nos o seu trabalho, como foi o caso do Pedro Barata. E o projecto que aqui hoje divulgamos, é surpreendente e bastante meritório. Ora vejamos, nas palavras do seu criador...

Godot ZX é um emulador de ZX Spectrum de alta performance integrado no Godot 4.3+ através de Rust e GDExtension. Este projeto foi desenhado para ser modular, pronto para a Steam e com suporte total para Gamepads.

Especificações Técnicas:

  • Core: rustzx-core (Rust)
  • Ponte Godot: godot-rust (GDExtension)
  • Versão do Rust: 1.95.0
  • Versão do Godot: 4.3 ou superior

O projeto suporta dois fluxos de trabalho principais:

  • Versão Launcher (Multi-jogo): Utiliza Scenes/Launcher/Launcher.tscn como cena principal. Permite ao utilizador navegar numa lista de jogos e escolher dinamicamente entre os modelos 48K e 128K.
  • Versão Standalone (Jogo único): Utiliza as cenas em Scenes/Standalone/. Estas foram desenhadas para a distribuição de um jogo específico (ex: lançamento na Steam). Não apresentam menus de seleção; em vez disso, iniciam diretamente o ficheiro de jogo pré-configurado, oferecendo uma experiência focada num único título.

Componentes Principais:

1. Emulador (Main48K / Main128K)

Este é o coração do projeto. Integra a biblioteca em Rust para gerir:

  • Renderização de Vídeo: Converte o buffer de memória do Spectrum numa Texture2D do Godot em tempo real.
  • Áudio Dinâmico: Utiliza o AudioStreamGenerator do Godot para processar amostras de som de alta fidelidade geradas pelo core em Rust.
  • Mapeamento de Input: Traduz as ações de input do Godot (teclado, comando ou rato) para a matriz de teclas clássica do ZX Spectrum e suporta emulação completa de rato via interface Kempston Mouse.

2. GameMenu (Overlay)

Uma camada de interface intuitiva que aparece quando o jogo é pausado. Oferece:

  • Gestão de Estados: Salva ou carrega instantaneamente o progresso do jogo (snapshots).
  • Controlo de Áudio: Ajuste de volume em tempo real através de sliders.
  • Navegação: Acesso rápido para retomar o jogo, voltar ao Launcher ou sair da aplicação.
  • Configuração do Sistema (Config.gd)

3. A classe estática centralizada Config gere:

  • Verificação automática de pastas ao iniciar.
  • Caminhos globais para ROMs e Jogos.
  • Troca de dados entre o Launcher e o Emulador.

4. Funcionalidades Extras:

  • Gamepad Ready: Todos os menus e o emulador são mapeáveis através do Input Map do Godot.
  • Suporte a Rato: Suporte completo para input de rato (emulação Kempston Mouse) em jogos e menus.
  • Steam Ready: Estrutura preparada para gerar executáveis únicos (.exe / .x86_64) com um jogo embutido usando a cena Standalone.
  • Save States: Sistema de snapshots para salvar e carregar o progresso do jogo instantaneamente.
Este é um projecto altamente tecnológico e técnico, mas que poderá ser muito útil para os programadores. Convidamo-vos assim a virem aqui experimentar e descarregar o programa do Pedro Barata, a quem desde já agradecemos que nos tenha colocado a par do seu projecto, doutra forma poder-nos-ia ter escapado.

quinta-feira, 29 de dezembro de 2022

Desemprego para os programadores de computadores

Estamos a chegar ao fim de 2022... Que nos reservará o futuro?

Na década de 60, começaram a aparecer programas de computador para conversar com o utilizador. Talvez alguém ainda se lembre que o Zé Oliveira criou um em 1986. Quem quiser pode conversar com a versão MS/DOS online aqui.

Mas, desde 1960 que as coisas mudaram...  

Eis uma conversa com um programa moderno da página https://chat.openai.com/chat. Este é apenas um exemplo, pois o programa mantém uma conversação em várias línguas.

Zarsoft - Hello. My name is Ze Oliveira.

Computer - Hello Ze Oliveira! It's nice to meet you. Is there anything I can help you with today? I'm here to answer any questions you might have about programming or anything else. Just let me know how I can help.

Zarsoft - Do you think it's gona snow in Oporto, Portugal?

Computer - As an artificial intelligence, I don't have the ability to predict the weather. However, it is possible to use weather forecasting tools and techniques to make educated guesses about the likelihood of snowfall in a particular location at a specific time of year.

In Oporto, Portugal, the weather can vary significantly depending on the time of year. In general, the climate in Oporto is temperate, with mild winters and hot summers. Snowfall is relatively rare in Oporto, but it is not uncommon for the city to experience some frost or freezing temperatures during the winter months.

If you are interested in finding out more about the weather in Oporto, you can check the local weather forecast or consult with a meteorologist for more information. It is also a good idea to be prepared for different types of weather, no matter what time of year you are traveling.

Zarsoft - Do you think that the ZX Spectrum is an obsolete computer?

Computer - The ZX Spectrum is a computer that was first released in the 1980s, and while it has since been succeeded by newer and more advanced computers, it is still remembered and admired by many enthusiasts as a pioneering and influential computer of its time.

Whether or not a computer is considered "obsolete" depends on the context and the specific tasks that are being performed. Some people may consider the ZX Spectrum to be obsolete because it is no longer in production and is not capable of running modern software or performing tasks that newer computers can handle more efficiently. However, others may still find value in using a ZX Spectrum for nostalgiciac purposes, or as a platform for learning and experimenting with computer programming.

Ultimately, whether or not a computer is considered "obsolete" is subjective and can depend on the individual's needs and preferences. 

Some people may continue to use and enjoy older computers, while others may prefer to use the latest and most advanced computers available.

Zarsoft - Write a ZX Spectrum BASIC program to calculate a random number between 1 and 1000. Then the program must prompt the user to try to guess it. If the user guess it wrong then the program should say if the answer was low of high and ask the user to try again. If the user guess it right then the program should stop.

Computer - Here is a simple ZX Spectrum BASIC program that generates a random number between 1 and 1000 and prompts the user to try to guess it until the user guesses it correctly:

10 RANDOMIZE

20 LET R = INT(RND*1000)+1

30 PRINT "I have chosen a random number between 1 and 1000. Can you guess what it is?"

40 INPUT G

50 IF G=R THEN PRINT "You guessed it! The number was"; R: GOTO 90

60 IF G<R THEN PRINT "Sorry, your guess was too low. Try again."

70 IF G>R THEN PRINT "Sorry, your guess was too high. Try again."

80 GOTO 40

90 END

This program uses the RANDOMIZE and RND functions to generate a random number between 1 and 1000 (inclusive). The INT function is used to convert the result to an integer. The program then prompts the user to enter a guess, and compares the guess to the random number using a series of IF statements. If the guess is correct, the program prints a message indicating that the user has guessed the number and exits the loop using the GOTO 90 statement. If the guess is too low or too high, the program prints a message to that effect and prompts the user to try again.

The program loops back to the input prompt using the GOTO 40 statement until the user guesses the correct number.

I hope this helps! If you have any questions about this program or would like more information on ZX Spectrum BASIC programming, please don't hesitate to ask.

Zarsoft - Have you ever heard of structured BASIC programming language?

Computer - Yes, I am familiar with structured BASIC.

Structured BASIC is a version of the BASIC programming language that includes additional features and constructs for structured programming. 

Structured programming is a programming paradigm that emphasizes the use of control structures that allow the programmer to specify the flow of control in a program in a clear and logical way.

Structured BASIC includes features such as block-structured syntax, variables with strong typing, and subroutines and functions with local variables and parameters. These features allow programmers to write programs that are easier to read, understand, and maintain.

Structured BASIC was developed in the 1970s and 1980s as a way to make BASIC more suitable for larger and more complex programming projects. It was widely used in educational and business environments, and it is still in use today by some programmers.

I hope this helps to clarify what structured BASIC is. If you have any other questions or would like more information on BASIC or structured programming, please don't hesitate to ask.

Zarsoft - Write a ZX Spectrum BASIC program to calculate a random number between 1 and 1000. Then the program must do a loop with "FOR i=0 TO 1 STEP 0" to prompt the user to try to guess it. If the user guess it wrong then the program should say if the answer was low of high and ask the user to try again. If the user guess it right then the program should stop.

Computer - Here is a simple ZX Spectrum BASIC program that generates a random number between 1 and 1000 and prompts the user to try to guess it until the user guesses it correctly, using a FOR loop:

10 RANDOMIZE

20 LET R = INT(RND*1000)+1

30 PRINT "I have chosen a random number between 1 and 1000. Can you guess what it is?"

40 FOR i = 0 TO 1 STEP 0

50   INPUT G

60   IF G=R THEN PRINT "You guessed it! The number was"; R: END

70   IF G<R THEN PRINT "Sorry, your guess was too low. Try again."

80   IF G>R THEN PRINT "Sorry, your guess was too high. Try again."

90 NEXT i

This program uses the RANDOMIZE and RND functions to generate a random number between 1 and 1000 (inclusive). The INT function is used to convert the result to an integer. The program then prompts the user to enter a guess using a FOR loop that iterates indefinitely (the loop counter i is set to 0 and the loop ends when i exceeds 1). The loop compares the guess to the random number using a series of IF statements. 

If the guess is correct, the program prints a message indicating that the user has guessed the number and ends the program using the END statement. If the guess is too low or too high, the program prints a message to that effect and prompts the user to try again.

The program continues to loop until the user guesses the correct number.

I hope this helps! If you have any questions about this program or would like more information on ZX Spectrum BASIC programming, please don't hesitate to ask.

Zarsoft - The ZX Spectrum does not have the "END" statement. You must use the "STOP" statement.

Computer - I apologize for the mistake in my previous response. You are correct that the END statement is not available in ZX Spectrum BASIC. 

Instead, you can use the STOP statement to end the program.

Here is the corrected version of the program:

10 RANDOMIZE

20 LET R = INT(RND*1000)+1

30 PRINT "I have chosen a random number between 1 and 1000. Can you guess what it is?"

40 FOR i = 0 TO 1 STEP 0

50   INPUT G

60   IF G=R THEN PRINT "You guessed it! The number was"; R: STOP

70   IF G<R THEN PRINT "Sorry, your guess was too low. Try again."

80   IF G>R THEN PRINT "Sorry, your guess was too high. Try again."

90 NEXT i

I apologize for any confusion my previous response may have caused. I hope this corrected version of the program is helpful. If you have any other questions or would like more information on ZX Spectrum BASIC programming, please don't hesitate to ask.

Zarsoft - Note that you have used "FOR i=0 TO 1 STEP 0" to build a loop instead of using a "GOTO" statement.

Computer - You are correct. The FOR loop in the previous program is used to create an indefinite loop that prompts the user to enter a guess and compares the guess to the random number until the user guesses the correct number. The loop counter i is set to 0 and the loop ends when i exceeds 1, but since the STEP value is set to 0, the loop counter never actually changes, so the loop will continue indefinitely until the STOP statement is reached.

Using a FOR loop like this is one way to create an indefinite loop in ZX Spectrum BASIC without using the GOTO statement. Another way to create an indefinite loop is to use a WHILE loop with a condition that is always true, such as WHILE 1.

I hope this helps to clarify how the FOR loop is used in the program. If you have any other questions or would like more information on ZX Spectrum BASIC programming, please don't hesitate to ask.

Zarsoft - You are very smart.

Computer - Thank you for your kind words! As an artificial intelligence, I have been designed and trained to process and understand information and respond to questions and prompts. I don't have personal feelings or emotions, but I am here to assist you to the best of my ability. If you have any questions or need help with something, please don't hesitate to ask. I'm here to help!

Zarsoft - I have to go now. See you next time. Goodbye.

Computer - Thank you for using my services. It was nice talking to you, and I'm here to help anytime you have a question or need assistance. 

Feel free to reach out to me anytime. Until next time, goodbye!

sexta-feira, 7 de outubro de 2022

A História esquecida do BASIC Estruturado

Hoje em dia, praticamente todas as linguagens de programação são Estruturadas (não precisam de GOTO). Assim, não é de admirar que este assunto seja praticamente desconhecido actualmente. Se alguém perguntar sobre isso a um estudante de engenharia de programação, a resposta mais provável é que não sabe o que é isso. Mas nem sempre foi assim.

Apesar de em 1958 surgir a linguagem ALGOL 58, a primeira linguagem de programação estruturada, tal passou mais ou menos despercebido porque nessa altura os programas eram pequenos e fáceis de programar.

Depois em 1964 foi inventada a linguagem BASIC. Era uma linguagem com estrutura semelhante à linguagem Assembly de modo a ser mais fácil construir os compiladores e interpretadores.

Exemplo de programa em Assembly:

Endereço, Comando

1234 LD A,25
1236 JP C,1232
1239 ADD A,1
1241 RET

Versão em BASIC:

Número de linha, Comando

1234 LET A=25
1236 IF C THEN GO TO 1232
1239 LET A=A+1
1241 RETURN

Mas, as memórias dos computadores estão sempre a aumentar de capacidade e, por volta de 1970 os programas já eram muito grandes e eram cada vez mais difíceis de programar e manter. Tornava-se necessária uma melhor forma de programar. Foi então que se levou a estruturação a sério e foram criadas a linguagem Pascal (1970) e a linguagem C (1971). A partir daí todas as linguagens começaram a ser estruturadas.

Assim, entre 1970 e 1990 a estruturação era um assunto muito importante e foram publicados dezenas de livros sobre o assunto. Mas a linguagem BASIC esteve muitos anos estagnada e só em 1985 começou a deixar de ter números de linha... Porquê?

A linguagem BASIC, como era fácil de implementar, tornou-se a linguagem preferida dos construtores de microcomputadores. E os microcomputadores não eram considerados como sendo computadores para trabalho a sério.

De vez quando saía uma versão melhor. Por exemplo: SBASIC (1976), BBC Micro (1981) e Sinclair QL (1984). Mas, só em 1985 é que o assunto foi resolvido oficialmente com o artigo "IEEE 755". E, também foi nesse ano que surgiu a linguagem QuickBASIC (mais tarde QBASIC), o primeiro BASIC estruturado sem números de linha.

Em 1987, o Zé Oliveira escreveu uma série de 8 artigos sobre este assunto no MicroSe7e (suplemento do jornal O Se7e). Estas propostas de melhoramento da linguagem BASIC foram implementadas 30 anos depois quando foi lançado o ZX Spectrum Next.

Eis as vantagens do BASIC estruturado:

  •   É mais fácil conseguir que funcione da primeira vez,
  •   É mais fácil de ler,
  •   É mais fácil de alterar, e
  •   É mais fácil de reutilizar.

São necessárias apenas 3 coisas:

  1. Método de programação TOP-DOWN com rotinas: Escreve-se primeiro a rotina principal invocando outras rotinas secundárias e depois faz-se o mesmo com as rotinas secundárias. Cada rotina deve ser o mais pequena possível para se ler e compreender rapidamente e, se for possível, a sua listagem deve caber no écran.
  2. Estruturas de controle (ciclos e condições): FOR-NEXT, REPEAT-UNTIL, WHILE-DO, IF-THEN-ELSEIF-ELSE.
  3. Variáveis locais. Se possível, usar também variáveis locais (apenas visíveis dentro das suas rotinas).

Vejamos alguns exemplos simples de programação estruturada extraídos do livro "Structured BASIC for the IBM PC" (1985), adaptados para funcionar no ZX Spectrum. Comecemos pela parte mais importante da programação estruturada: a técnica TOP-DOWN para dividir as tarefas em rotinas pequenas:

100 REM PROGRAMA Construir2Casas
110 PLOT 0,0
120 GO SUB 200 : REM ConstruirCasa
130 PLOT 150,0
140 GO SUB 200 : REM ConstruirCasa
150 STOP
190 :
200 REM ROTINA ConstruirCasa
210 GO SUB 300 : REM DesenharParedes
220 GO SUB 400 : REM DesenharTelhado
230 RETURN
290 :
300 REM SUBrotina DesenharParedes
310 DRAW 60,0: DRAW 0,30: DRAW -20,0:
315 DRAW 0,-30: DRAW 60,0
320 DRAW 0,50
330 DRAW -100,0
340 DRAW 0,-50
350 RETURN
390 :
400 REM SUBrotina DesenharTelhado
410 DRAW 0,50
420 DRAW 10,20
430 DRAW 80,0
440 DRAW 10,-20
450 RETURN


A parte seguinte dos CICLOS e blocos IF ainda estava um pouco confusa em 1985 - apesar de já estar bem definida desde 1970 na linguagem Pascal...

Em 1985, um ciclo REPEAT seria assim:

100 REM REPEAT
110 PRINT "Dentro do ciclo REPEAT"
120 INPUT A$
130 IF A$ = "STOP" THEN GO TO 150
140 GO TO 100: REM reiniciar ciclo
150 REM UNTIL STOP

Mas, devia ser assim com apenas um GOTO:

100 REM REPEAT
110 PRINT "Dentro do ciclo REPEAT"
120 INPUT A$
130 IF NOT (A$ = "STOP") THEN GO TO 100
140 REM UNTIL A$ = "STOP"

Em 1985, um ciclo WHILE seria assim:

100 INPUT A$
110 REM WHILE A$ <> "STOP"
120 IF NOT (A$ <> "STOP") THEN GO TO 160
130 PRINT "Dentro do ciclo WHILE"
140 INPUT A$
150 GO TO 110: REM reiniciar ciclo
160 REM END WHILE

Note-se que ainda aqui temos os indesejáveis GOTOs.

Em 1985, um bloco IF-THEN-ELSE seria assim:

100 INPUT A$
105 REM IF-THEN-ELSE
110 IF NOT (A$ = "TRUE") THEN GO TO 150: REM ELSE
120 REM IF true THEN
130 PRINT "Condicao verdadeira"
140 GO TO 170
150 REM ELSE
160 PRINT "Condicao falsa"
170 REM END IF

Um facto importante a não esquecer é que é fácil converter um programa escrito numa linguagem estruturada para uma versão em linguagem NÃO estruturada. Mas pode ser muito difícil - ou praticamente impossível -, converter um programa escrito numa linguagem NÃO estruturada para uma versão em linguagem estruturada. Quem tentar tirar os GOTOs dum programa escrito em BASIC depressa verificará isso...

Para ver um exemplo de um livro sobre BASIC estruturado, clicar aqui.

terça-feira, 12 de abril de 2022

BASIC Apascalado #10 - O Spectrum Next ainda não chegou ao nível do QL!


E o Zé Oliveira continua a enviar-nos os seus inestimáveis contributos. Desta vez temos a continuação dos artigos sobre Basic Apascalado, que começou por aparecer em 1986 no suplemento do MicroSe7e. O tema é o QL, o que é inédito em Planeta Sinclair.

Em 1984 o BASIC estava a evoluir para uma linguagem estruturada. No ano seguinte seria lançado o QuickBASIC em que os números de linha seriam opcionais. Mas em 1984, continuando a evoluir a sua linha de computadores, Sir Clive Sinclair lançou o Sinclair QL com o objectivo de ser uma versão profissional do ZX Spectrum. Embora comercialmente tenha sido um fiasco (vendeu 150.000 unidades enquanto o Spectrum vendeu 5 milhões), tecnicamente o QL era um sucesso: mais memória, mais velocidade, mais resolução gráfica, ... e uma linguagem BASIC que permitia a programação estruturada (sem o uso de GOTO). Este BASIC foi denominado, apropriadamente, SuperBASIC. Infelizmente, o preço (400 libras enquanto o Spectrum era 175 libras) e a quantidade de jogos que já havia para o Spectrum tornaram o QL nesse ilustre desconhecido!

Em 2017 houve uma nova tentativa para lançar uma versão melhorada do ZX Spectrum: O ZX Spectrum Next. Parece que o ZX Spectrum Next foi inspirado pelo Sinclair QL porque os melhoramentos do NextBASIC são semelhantes ao BASIC do QL:

- Declaração de procedimentos:
    DEFine PROCedure ProcName / END DEFine
    implementado como DEFPROC ProcName() / ENDPROC
- Invocação de procedimentos:
    ProcName
    implementado como PROC ProcName
- Declaração de funções:
    DEFine FuNction FunctionName / RETURN Result / END DEFine
    implementado, com melhoramento, como DEFPROC ProcName() / ENDPROC = Result
- Invocação de funções:
    LET result = FuncName(arg)
    implementado, pior, como PROC FuncName(arg) TO result
    devia ser LET result = PROC FuncName(arg)
- Ciclos:
    REPeat CicleName / IF condition EXIT CicleName / END REPeat CicleName
    implementado, com melhoramento, como REPEAT / REPEAT UNTIL condition
- IF command:
    IF condition THEN / ELSE IF condition2 / ELSE / END IF
    implementado, com algumas limitações, como IF condition THEN / : ELSE
- Declaração de variáveis locais:
    LOCAL VarName
    implementado, da mesma maneira, como LOCAL VarName

Mas, apesar destas melhorias, o NextBASIC deixou de lado um assunto importante que foi implementado no QL: os nomes das variáveis alfanuméricas (strings) e arrays ainda são limitados a um caracter. Isto é um grande inconveniente para os programadores modernos...

Quem tiver curiosidade para ver como é um programa em QL, pode descarregar aqui um exemplo em QL, Spectrum Next e ZX Spectrum.

Entretanto, quem quiser programar em BASIC estruturado no velho ZX Spectrum terá que usar um conversor como este que deixamos aqui.

terça-feira, 29 de março de 2022

É um Spectrum? É BASIC? Não, é javascript!


Como já se aperceberam, o Zé Oliveira tem dado muitos contributos valiosos e diversificados a Planeta Sinclair. Assim, temos hoje mais um artigo da sua autoria, com algumas dicas muito úteis para programadores. O texto que se segue é então da sua responsabilidade, e a quem desde já agradecemos.

A pensar nos programadores de Spectrum que sempre tiveram medo dos PCs, aqui está a solução: ZX Script - programar em JavaScript (linguagem dos browsers) com comandos do Spectrum.

Esta linguagem, ZX Script, não pretende emular ou substituir o Spectrum. O objectivo não foi fazer mais um emulador de Spectrum mas sim incentivar os programadores de Spectrum a programar numa das linguagens mais usadas. Portanto, não temos um Spectrum no browser mas sim um browser com aspecto semelhante ao Spectrum.

Já deve haver muita gente morta de tédio com esse disparate do BASIC Apascalado. Bom, é aceitável que reclamem do BASIC Apascalado mas, ninguém pode reclamar da linguagem JavaScript. A linguagem JavaScript é das 3 mais usadas (em 2018 era a mais usada) e é usada em praticamente todos os sites.

A pior coisa que aconteceu com as linguagens de programação desde 1980 foi os ambientes de desenvolvimento (editor + compilador) ficarem do tamanho de dinossauros. A coisa ficou tão grave que agora um principiante pode demorar dias para conseguir escrever "Olá" no ecrã. Mas ainda há esperança: JavaScript.

Para escrever "Olá" com javascript basta abrir o notepad, escrever "<script> alert("Olá") </script>", gravar com o nome "teste.html" e abrir este ficheiro num browser qualquer.

Os programadores do ZX Spectrum que tiverem medo de linguagens novas podem experimentar a linguagem "ZXscript", que é menos ameaçadora porque tem comandos do Spectrum que são mais familiares.

O JavaScript não foi construído para fazer INPUT do teclado. A versão do JavaScript para fazer INPUT de teclado chama-se Nodejs. Portanto, esta não é a maneira correcta de aprender JavaScript - mas é a mais simpática!

Podem aceder a esta linguagem aqui. Se clicarem nos botões à direita, podem ver alguns exemplos simples de programas.

domingo, 16 de maio de 2021

25 anos de WSpecem

Este mês de Maio faz 25 anos que o WSpecem foi lançado na Internet para Windows 95, como o primeiro emulador de ZX Spectrum (48K) para Windows, o primeiro open source a usar a tecnologia "pioneira" de WinG e primeiro emulador Português de ZX Spectrum.

O WSpecem pretendia ser um emulador simples, carregar e gravar múltiplos formatos de snapshots. Trazia também na package de instalação automática, o TAPE2TAP, um utilitário DOS em código máquina para digitalizar cassetes em formato TAP, a partir da porta LTP ou SoundBlaster de 1995, do mesmo autor.

Na realidade, o WSpecem foi uma grande melhoria do core do EmZ80,  escrito em 1990, como ambiente desenvolvimento / debugging Z80 / Spectrum em MSDOS, e para ser portável entre arquitecturas Unix; o core de emulação em WSpecem foi devidamente testado com 4.000 a 5.000 snapshots antes de ser lançado na Internet (o mesmo autor fez port do core do em Z80 / WSpecem e escreveu o QtSpecem e o debugZ80 ano passado,  corrigindo o core de emulação para ficar full compliant Z80 ). O QtSpecem tem um fork e ainda contribuições de outro português, o Álvaro Lopes.

O WSpecem, como primeiro emulador de Windows, é muito simples de usar e teve o seu sucesso, a sua época e os seus seguidores, foi publicado em revistas e DVD's um pouco por todo o mundo, e o autor recebeu várias cartas de utilizadores (entre as quais do Jorge Pais). Contrariamente aos planos iniciais, o core de emulação do WSpecem foi escrito inteiramente numa linguagem de alto nível, C, e corre a 100% da velocidade num 486 a 33MHz ou superior (entre o emulador inicial, o desfasamento entre os planos e correspondentes saltos tecnológicos, e o próprio atraso do projecto, sendo que o emulador já estaria em fase beta desde Setembro de 1995, deixou de existir a necessidade de implementar o core da emulação em assembly i386).

Inclusive, ideias e truques descobertos pelo autor a fazer reverse engineering do Z80, dos formatos de snapshots e reverse engineering do próprio código máquina JPP de como carregar devidamente ficheiros SNA, ainda hoje fazem parte do comp.sys.sinclair FAQ e da leitura de outros autores de emuladores. O autor esteve bastante activo no comp.sys.sinclair newsgroup e em dalnet IRC em 1996, a discutir pormenores com outros "pioneiros" de emulação. 

O código do projecto WSpecem foi usado noutros emuladores, notavelmente o código assembly do TAPE2TAP adoptado pelo emulador Warajevo para carregar cassetes (para o qual o autor também contribui com um patch binário ao executável, corrigindo uma situação em que o Warajevo crashava).

Em Dezembro de 1996, o autor do WSpecem também lançou um site web com uma form para distribuir o emulador via email, e um site FTP português com a sua colecção inteira de snapshots Z80 / TAP, que esteve activo por meia dúzia de anos.

Recentemente, o autor também tem contribuído com artigos técnicos para o planeta Sinclair, ajuda a recuperar software antigo, know-how de TZX, hackar jogos reengineering do Pirata e edição de um Pirata look-alike para modelos 128K, e como co-editor do "Index to the Spectrum ROM for Machine Code Programmers".

16th May 1996

. Now emulation can load properly .SLT files and it's levels, after complaints from

Damien;

. v1.0 Released.


15th May 1996

. Corrected it, didn't release memory when leaving;

. Sent v0.01.05b to Damien and Cotrina;

. Correct a few mistakes from the documentation;

. Included WSpeEm.ico designed by Damien Burke;

. Modified scheme names presentation on the windows caption, Model 3 to Issue

3 in the options menu and F5 to reset after Damien Burke suggestions;

. Forgot to modify version and sent it to Cotrina;

. Prevent saving a snapshot which extension is not recognised, following a

complaint from Damien Burke;

. Released to the public.

terça-feira, 27 de abril de 2021

Pirata (IV) - ROM cartridge Timex 2068

Depois de lançarmos o MOD2021 do Pirata, mais pequeno e com correcção de bugs em formato TAP, TZX e ROM, e um lookalike pirate128, lançamos agora a ROM em formato AROS cartridge para o Timex 2068, num ficheiro dck em 

https://github.com/ruyrybeyro/pirate128/blob/main/pirata2021_2068cart/Pirata2021.dck

Sendo em formato AROS, o Pirata é activado automaticamente aquando do arranque. Note-se que o TimeWord e a cartridge de emulação do  TC 2048, estão em formato AROS. O  cabeçalho AROS no caso desta cartridge é:

FF - primeiro byte não usado

02 - Machine code

02 - AROS Cartrige

6E - LSB de endereço a executar

38 - MSB de endereço a executar

01 - paginar 7 banks of memory, mais baixos (activo a 0)

01 - auto arranque

0101 - 513d bytes - 21d reservados

Para mais informação sobre o formato das cartridges 2068 ver o link.

terça-feira, 13 de abril de 2021

Pirata (III) - Pirate64 e Pirate128

Na sequência do artigo sobre o a análise do Pirata original, e a optimização do programa original no segundo artigo, desta vez tentámos criar um copiador inspirado no Pirata que seja capaz de usar mais memória. Para tal, usa-se paginação, sendo que os binários resultantes apenas funcionam em modelos posteriores ao ZX Spectrum 48K.

Inicialmente tentou-se uma aproximação com os métodos de paginação dos modelos Sinclair pós-Amstrad a partir do +2A, mas os modelos de paginação destes revelaram-se limitativos. Ficou no entanto a experiência em se conseguir carregar blocos maiores de 48KB, ao usar um modo especial de paginação posterior ao +2A, que fornece 64KB de RAM. Fica o link em:

https://github.com/ruyrybeyro/pirate128/tree/main/pirate64 

Em seguida, usou-se a paginação  original do 128KB, que já obriga a gerir paginação, para conseguir tirar partir de toda a memória. Neste caso o maior bloco é quase 64KB, sendo que permite carregar quase 128KB (menos o espaço usado pelo código máquina). As sources, o .tap e .tzx estão em:

https://github.com/ruyrybeyro/pirate128/tree/main/pirate128

Note-se que, quer no Pirate64, e mais concretamente, no Pirate 128, dado a necessidade de controlar a paginação a cada byte novo introduzido, as rotinas da ROM de LOAD e SAVE não são, nem podem ser usadas. Foram criadas rotinas equivalentes. Os blocos são tratados como uma stream de bytes puro, que entram e saem da mesma forma, não havendo noção de flag de bloco ou checksum.

O código source ASM do pirate128 está em:

https://github.com/ruyrybeyro/pirate128/blob/main/pirate128/pirate_128.asm

sexta-feira, 9 de abril de 2021

Nova versão 2.01 de file2loader

A versão 2.01 do utilitário file2loader de Rui Ribeiro foi disponibilizada em:

https://github.com/ruyrybeyro/file2tap/blob/master/file2loader.c

Para compilar, em MacOS ou Linux, fazer:

$ gcc file2loader.c -o file2loader

Este utilitário propõe-se automatizar o processo manual de criar loaders de código máquina, embebidos no bloco BASIC. O utilitário coloca o código máquina numa variável Basic. Para já, nesta versão convém que seja a primeira variável. 

Na versão 2.x, o utilitário tenta usar os parâmetros passados ao programa de uma formação standard. Tentamos lidar também, ainda que de uma forma limitada, com paginação de modelos ZX Spectrum 128K.

O programa pega num bloco assemblado binário puro e tenta criar um loader .tap.

Colocando aqui o help:

% ./file2loader 

 Usage:

./file2loader [-n TAPE_BLOCK_NAME] [-x address_of_routine] [-s SP] [-p n] [-a n][-V A] z80.bin dest.tap

 -n NAME name of the TAP BASIC section seen by LOAD ""

 -x addr decimal address of code recolocation/execution

 -t addr decimal address of code execution

 -s SP SP to set code before transfer in decimal

 -p n 128K block page to page in $C000

n page block 0-7

 -a n post Amstrad special paging modes

n special paging mode 0-3

 -V var var change BASIC variable in use for storing M/C

var A-Z, by default is A (A$)

 -h (print help and exit)

 -v (print version and exit)

 

 z80.bin block of machine code file

 dest.tap TAP file with the BASIC loader w/ machine code embedded

O file2loader "opções", na sua forma mais simples, apenas inclui um ficheiro "z80.bin" num bloco BASIC. No entanto, tem diversas opções de configuração. O código pode ser transferido para outras posições de memória, ou até paginação mudada. Por exemplo, para criar um loader BASIC standalone de joy.asm chamado joy.tap, cujo ORG começa em 32768, o comando -n dá ao nome de bloco cassete BASIC JOY, o -x transfere e executa o código máquina no endereço 32768 e o -s muda o stack pointer para 32767 antes de saltar.

$ pasmo joy.asm joy.bin

$ ./file2loader -n JOY -x 32768 -s 32767 joy.bin joy.tap

terça-feira, 6 de abril de 2021

Pirata (II) - MOD 2021 + disassembly

Depois do primeiro artigo desta série sobre o Pirata, desta vez, como prometido, vamos endereçar os bugs mencionados no post anterior. Como tal, deixamos aqui os links dos binários do Pirata MOD 2021, com os bugs mencionados resolvidos, sendo que esta versão:

  • Ocupa menos bytes;
  • Não volta a ligar interrupts;
  • Usa um stack mais pequeno;
  • Não corrompe dados;
  • O código máquina está na zona das variáveis BASIC  ao invés de numa instrução REM.

Fica também aqui o link para listagem comentada e explicada, em assembly

https://github.com/ruyrybeyro/pirate128/blob/main/pirataMOD2021/pirata_fixed.asm 


Criámos também uma ROM de ZX Spectrum 48K com o Pirata MOD 2021, que podem encontrar em

Nessa ROM em particular, os bytes não usados de $386E até $38FA e têm o código máquina do PirataMOD2021; fez-se também patch em $0066 com um JP $386E. A rotina pode ser invocada usando um botão NMI ou fazendo RANDOMIZE USR 14446. 

terça-feira, 30 de março de 2021

Pirata (I) - disassembly

Quase todos na comunidade Portuguesa de Spectrum usamos o Pirata para copiar cassetes. 

Aposto que muitos de nós, sempre se perguntaram como o Pirata funciona(va). Tinha também um amigo, que se queixava que em sessões de maior volume de cópias, a cópia ficava estragada e, dado a fiabilidade das cassetes, nunca fiquei muito convencido do que ele dizia.

Segue aqui neste artigo, o link para uma análise ao código assembly do Pirata de 1984:

https://spectrumcomputing.co.uk/entry/36321/ZX-Spectrum/Pirata .co.uk/entry/36321/ZX-Spectrum/Pirata

Note-se que, embora seja mencionado falhas no programa, o Pirata marca uma era na qual em Portugal havia um vazio legal na legislação de cópia, sendo um feito ter sido desenvolvido em assembly, e quando a tecnologia de turbo-loaders ainda não estava divulgada.

De notar que o programa em si, é relativamente e intencionalmente curto para poupar recursos, de forma a ter livre o máximo de bytes possíveis em RAM, num ZX Spectrum 48K. O programa é também curto, porque tira proveito de rotinas da ROM.

Notavelmente, é bastante inteligente o (ab)uso da rotina de carregamento da ROM, para carregar blocos com identificação de bloco diferente de 0, e de passar como argumento o valor máximo de bloco e fazer a diferença aos bytes carregados, de forma a determinar o tamanho do bloco. O facto de usar a ROM, por sua vez, cria também algumas limitações. Seria possível estender o programa, para não ser possível fazer  LOAD por cima do código máquina do mesmo, mas isso implicaria o uso de mais RAM e transcrever as rotinas de ROM para RAM ; os checksum  dos blocos também são recalculados.

Infelizmente, existem também algumas incongruências e bugs, que são discutidas na listagem assembly, e que causam corrupção de dados, quer ao nível do código máquina, quer ao nível dos dados carregados. Estas limitações serão endereçadas na parte II deste artigo.

Link para o disassembly comentado do Pirata:

https://raw.githubusercontent.com/ruyrybeyro/pirate128/main/pirata1984/pirata.asm


Parte II deste artigo: ASM, TAP, TZX e ROM do Pirata MOD2021 com bugs corrigidos

sexta-feira, 26 de fevereiro de 2021

Index to the Spectrum ROM for Machine Code Programmers


Estamos aqui a anunciar um livro perdido no tempo, new old stock, que pretende ser um complemento ao "Spectrum ROM Disassembly" de Ian Logan. O livro em questão foi escrito em 1989, foi recuperado de formato digital por Mathew Logue, e foi editado num formato mais amigável em PDF por Matthew Logue e Rui Ribeiro de Planeta Sinclair.

Embora o livro esteja em formato índice / dicionário, relativamente ao original, explica melhor e em maior detalhe o funcionamento de várias rotinas da ROM. É assim uma leitura que recomendamos.

Têm aqui o link de partilha, aproveitem!

sexta-feira, 20 de novembro de 2020

Emulador / debugger português em DOS - emz80

Embora não tenha sido divulgado na altura, existiu um emulador português em DOS.

O emulador / debugger começou a ser desenvolvido por volta de 1989-1990, nas horas mortas de quando o autor, Rui Ribeiro, trabalhava na Microdigital como software developer (e houve muitas devido a uma zanga de sócios, história antiga que não interessa para o caso - note-se que é MicroDigital em Portugal e não no Brasil).

Foi entregue como trabalho de uma cadeira de C no Instituto superior do Porto (1992), e alguns amigos do autor usaram-no para fazer debug em cadeiras de Z80 na FEUP. O autor usou o EMZ80 para fazer cross-desenvolvimento em DOS com o emz80 + TASM (Z80) desde inícios de 90, para fazer debugging ao kernel de emulação do WSpecem, e para fazer debugging a programas em Z80. Só recentemente em 2019, depois de escrever o QtSpecem+debugZ80, o autor deixou de o usar definitivamente.

Note-se que este emulador, embora seja um debugger de Z80, apenas implementa o ecrã do ZX Spectrum em monocromático, e não tem som nem teclado. Tem também bugs conhecidos no kernel Z80, que apenas foram corrigidos no QtSpecem, do mesmo autor. 

O kernel C do emulador emz80 em DOS, foi desenhado para ser modular, e foi portado para Windows em 32 bits (WSpecem, 1995), e para Mac/Linux em 64 bits (QtSpecem, 2019).

O debugger emz80 lê ficheiros ROM e Z80 de Spectrum 48K. Tem também uma janela de debugging com comandos e teclas similares ao Turbo Debugger, e pode correr software, se para tal for instruído.

Fica aqui o LE-ME.TXT original para as instruções:

  Emulador Z80 (c) 1990, 1992 Rui Fernando Ferreira Ribeiro


  Este programa e uma emulação COMPLETA de um Z80 (incluindo instruções não

 documentadas pela ZILOG -- para as ter imprimir o ficheiro z80iset.doc)

 a 3,5469 MHz com interrupcões, 50 vezes por segundo que executa ficheiros

 binários de Z80 (e obvio que tanto a velocidade como o tempo de interrupções

 são em tempo virtual -- ou seja para o codigo maquina de Z80 isso e o que

 acontece). Esta emulação também possui os todos os registos do Z80 (e ao con-

trário do que muita gente pensa, o contéudo do registo R definitivamente não

 é aleatório -<o que não se poderá e prever o seu estado correndo um programa

 de assembly ; no entanto com as interrupcões desligadas, inicializando-o com

 um valor poder-se-a utiliza-lo numa rotina de encriptacao/desincriptação>).

  


  Conjuntos teclas programa (validos apenas em modo 'trace'):


     F2       - marca\desmarca breakpoint na instrução corrente na janela

     F4       - pede endereço de memória para marcar breakpoint

     F5       - retira as janelas presentes no ecra ate que se

         carregue numa tecla

     F9       - corre o programa ate ser executada uma instrução HALT com as

         interrupcões desligadas, chegar a um breakpoint ou ser interrompido

         com CTRL-BREAK (voltando então ao modo 'trace').

     F10      - Permite visualizar posições de memória do Z80

     Ctrl-F10 - Permite visualizar ports    de memoria do Z80

     Alt-X    - sai do emulador


     Qualquer outra tecla em modo 'trace' provoca a execução da proxíma

    instrução apontada pelo 'Program Counter' (PC).


  Esta versão do emulador necessita no minimo para correr de 190k livres de

 memória RAM e da versão 2.0 de DOS.


               Ficheiros Emulador Z80:

               ======================


           emz80  .exe - Emulador de Z80

           z80    .tab - Ficheiro usado pelo debugger interno de

                        EmZ80 para disassemblar as instruções.

           z80iset.doc - Set de instruções completo do Z80

           le-me  .txt - Este ficheiro



Poderão descarregar aqui os ficheiros (incluindo código fonte).

quinta-feira, 28 de maio de 2020

Introdução: loaders em BASIC

Uma  dúvida recorrente parece ser como gravar um programa BASIC / um loader de BASIC para uma rotina código máquina. Para tal o mais simples é escrever algo como:

10 CLEAR 49999 : LOAD "" CODE : RANDOMIZE USR 50000

Ou para ter um ecrã de carregamento:

10 CLEAR 49999 : LOAD "" SCREEN$ : LOAD "" CODE : RANDOMIZE USR 50000

e gravar com com arranque automático na linha 10:

SAVE "prog" LINE 10

Para criar um TAP, convém que seja um emulador que suporte isso, como por exemplo, o  Retro Virtual Machine 2. Ou pode escrever em texto, e usar um utilitário como o bas2tap, que já falamos num artigo anterior:

bastap loader.bas loader.tap

Mas vejamos o programa BASIC:

CLEAR 49999

Coloca todo o espaço temporário e stacks microprocessador e BASIC abaixo desse endereço. Na prática garante que os endereços para a frente não são usados. Não se recomenda um valor abaixo de 24500.

LOAD "" SCREEN$

Carrega um ecrã em formato ZX Spectrum gravado com SAVE "" SCREEN$ ou gerado num PC.

LOAD "" CODE

Carregar o bloco de código máquina.

RANDOMIZE USR 50000

Saltar para o endereço de execução.

Note-se que em alguns assemblers, o loader BASIC pode ser gerado automaticamente.

Por exemplo, no pasmo:

pasmo --tapbas prog.asm prog.tap

ou:

pasmo --tzxbas prog.asm prog.tzx

Estes dois modos criam um loader simples, similar ao primeiro exemplo, sem o RANDOMIZE USR.

Para colocar o RANDOMIZE USR, é necessário colocar no fim do assembly, uma directiva, por exemplo no pasmo:

END 50000

Ver também: ZXBASIC manual - chapter 26 - Using machine code

segunda-feira, 25 de maio de 2020

Representação numérica em BASIC (IV) - virgula flutuante

Este artigo sobre virgula flutuante, é acerca de como nela armazenar um número na representação de 5 bytes. Vamos reproduzir o texto do manual do Spectrum:

From the ZX Spectrum BASIC Manual:

Any number (except 0) can be written uniquely as

 ± m x 2e where
 ± is the sign,
m is the mantissa, and lies between 0.5 and 1 (it cannot be 1),
and e is the exponent, a whole number (possibly negative).

Suppose you write m in the binary scale. Because it is a fraction, it will have a binary point (like the decimal point in the scale of ten) and then a binary fraction (like a decimal fraction); so in binary:
a half is written .1
a quarter is written .01
three quarters is written .11
a tenth is written .000110011001100110011 ... and so on.

With our number m, because it is less than 1, there are no bits before the binary point, and because it is at least 0.5, the bit immediately after the binary point is a 1.

To store the number in the computer, we use five bytes, as follows:

I. write the first eight bits of the mantissa in the second byte (we know that the first bit is 1), the second eight bits in the third byte, the third eight bits in the fourth byte and the fourth eight bits in the fifth byte;
II. replace the first bit in the second byte which we know is 1 by the sign: 0 for plus, 1 for minus;
III. write the exponent +128 in the first byte. For instance, suppose our number is 1/10
1/10 =4/5x2-3

Thus the mantissa m is .11001100110011001100110011001100 in binary (since the 33rd bit is 1, we shall round the 32nd up from 0 to 1), and the exponent e is 3.

Applying our three rules gives the five bytes

Fica aqui o programa em C, para ajudar à compreensão:

#define Z_UNDERFLOW -2
#define Z_OVERFLOW -1

int d2zx(unsigned char *out, double in) {
long mantissa;
bool sign = in < 0;

if(sign) in = -in;
out[0]=0x80;

// expoente negativo
 while(in < 0.5) {
in *= 2.0;
out[0]--;
if(!out[0]) return Z_UNDERFLOW;
}

// expoente positivo
while(in >= 1) {             
in *= 0.5;                    
out[0]++;
if(!out[0]) return Z_OVERFLOW;
}

in *= 0x100000000l; // máximo tamanho mantissa + 1 (33 bytes)
in += 0.5;          // rounding 
mantissa = in;

 // 32 bits distribuídos em 4 bytes
out[1] = mantissa >> 24;
mantissa &= 0xFFFFFFl;
out[2] = mantissa >> 16;
mantissa &= 0xFFFFl;
out[3] = mantissa >> 8;
mantissa &= 0xFFl;  
out[4] = mantissa;

if(!sign) out[1] &= 0x7F; // se positivo, bit esquerdo da mantissa
                           // zerado
return 0;
}

Ver: Binary numbers – floating point conversion

quinta-feira, 21 de maio de 2020

Representação numérica em BASIC (III) - virgula flutuante

Os 5 bytes de representação numérica do stack de virgula flutuante em Spectrum/em BASIC, foram criados na realidade, para representar números em virgula flutuante. A representação numérica inteira que vimos até agora, é apenas uma optimização para acelerar o tratamento de inteiros em BASIC.

A representação será de vírgula flutuante, não sendo o primeiro byte 0, que é o sinal de inteiro.

O formato da representação em vírgula flutuante, é a seguinte:


1º byte expoente + 128

2º, 3º, 4º e 5º byte, mantissa de 32 bits, sendo o bit 7 mais à esquerda o sinal.

Temos portanto, uma precisão de 31 bits na representação numérica de um float (8 bits * 4 bytes, menos o bit do sinal). (2^31 = -2147483648  < x > 2147483648)

O expoente vai desde x^-127 até x^127.

Para melhor entendimento do formato, deixamos também 3 rotinas, 2 alternativas de C, e uma em ZX BASIC, que dado uma string dos 5 bytes da representação numérica, devolvem o número que esta representa.

double zx2d(unsigned char *in) {
int e = in[0];           // expoente
unsigned long m[] = {    // mantissa
in[1], in[2], in[3], in[4]
};
return e ?

(pow(2, e - 160)) * (

   // assemblagem dos 32 bits da mantissa
0x80000000
+ ((m[0] & 0x7f) << 24)
+ (m[1] << 16)
+ (m[2] << 8)
+ m[3]
) * ((in[1] & 0x80) ? -1.0 : 1.0)  // sinal
   : 

(in[1] ? -0x10000 : 0 ) + m[1] + (m[2] << 8);
}

double zx2d(unsigned char *in) {
int e = in[0];              // expoente
long m[] = {                // mantissa
in[1], in[2], in[3], in[4]
};

return e ?

pow(2,e - 128) * ( .5
+ ((m[0]&0x7F) / 256.0 )
+ (m[1] / 65536.0 )
+ (m[2] / 16777216.0 )
+ (m[3] / 4294967296.0 )
) * ((in[1] & 0x80) ? -1.0 : 1.0) // sinal
   :

(in[1] ? -0x10000 : 0 ) + m[1] + (m[2] << 8);
}

7926 IF NOT PEEK (n+1) THEN LET c=PEEK (n+3)+256*PEEK (n+4): RETURN
7927 LET c=2*(.5+(PEEK (n+2) AND 127)/256+PEEK (n+3)/65536+PEEK (n+4)/16777216+PEEK (n+5)/4.2949673e9)*2^(PEEK (n+1)-129): IF PEEK(n+2)>127 THEN c=-c:RETURN

ver:

Binary numbers – floating point conversion

PS. Primeira função de  C e rotina de Basic de Daniel A. Nagy e 2a rotina de C, Slavo Labsky.