mirror of https://github.com/falsovsky/z80.git
Remove from this branch
This commit is contained in:
parent
366a31ad41
commit
6f68a9777b
|
|
@ -1,30 +0,0 @@
|
|||
Scroller
|
||||
=========
|
||||
|
||||
Scroller é uma implementação um scroller de texto em Assembly no ZX Spectrum.
|
||||
|
||||
Requisitos
|
||||
-----------
|
||||
|
||||
O unico realmente necessário é o Assembler, mas para ver o resultado convem tambem ter um emulador, os verdadeiros podem converter o ficheiro [tap] para audio, passar para um leitor de mp3 e ligar a um Spectrum real :-D
|
||||
|
||||
* [Pasmo] - Assembler de Z80, é Open Source e Cross Platform
|
||||
* [ZX Spin] - Emulador de ZX Spectrum para Windows que inclui um Debugger
|
||||
|
||||
Instalação
|
||||
--------------
|
||||
|
||||
```sh
|
||||
git clone https://github.com/falsovsky/z80.git
|
||||
cd z80/scroller1
|
||||
pasmo -v --tapbas --err main.asm main.tap
|
||||
```
|
||||
|
||||
Licença
|
||||
----
|
||||
|
||||
BSD
|
||||
|
||||
[tap]:http://www.worldofspectrum.org/faq/reference/formats.htm
|
||||
[Pasmo]:http://pasmo.speccy.org/
|
||||
[ZX Spin]:http://www.zophar.net/sinclair/zx-spin.html
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
attr_p equ $5c8d; Endereço que contem as cores permanentes
|
||||
bordcr equ $5c48; Endereço que contem a cor da borda
|
||||
rom_limpa_ecra equ $0daf; Rotina da ROM que limpa o ecrã
|
||||
rom_define_borda equ $2294; Rotina da ROM que define a borda
|
||||
|
||||
; Cores
|
||||
; Numero | Binario | Nome
|
||||
; 0 | 000 | Preto
|
||||
; 1 | 001 | Azul
|
||||
; 2 | 010 | Vermelho
|
||||
; 3 | 011 | Roxo
|
||||
; 4 | 100 | Verde
|
||||
; 5 | 101 | Cyan
|
||||
; 6 | 110 | Amarelo
|
||||
; 7 | 111 | Branco
|
||||
|
||||
; 8 bits para definir ink, paper, brightness e flash
|
||||
; |F |B |P2|P1|P0|I2|I1|I0|
|
||||
; F Flash
|
||||
; B Brightness
|
||||
; P Paper
|
||||
; I Ink
|
||||
|
||||
; Então para definir o flash desligado, o brightness ligado com o
|
||||
; fundo a preto e o texto a amarelo fica-se com:
|
||||
; 01000110 = 70 = $46
|
||||
; 01000000 = 64 = $40 - Tudo preto
|
||||
; 01000111 = 71 = $47 - Fundo preto Texto Branco
|
||||
screen_attribute equ $47
|
||||
|
||||
; Valor de 0 a 7
|
||||
border_color equ $0
|
||||
|
||||
clear_screen
|
||||
ld a, screen_attribute
|
||||
ld (attr_p), a ; Variavel de sistema que permite definir
|
||||
; o ink, paper, brightness e flash
|
||||
call rom_limpa_ecra ; Clear screen
|
||||
|
||||
ld a, border_color ; Cor do border
|
||||
call rom_define_borda+$7
|
||||
; Chama a rotina da ROM para actualizar a borda, mas salta 7
|
||||
; bytes à frente, porque são para ler o valor da borda do
|
||||
; BASIC. O valor fica guardado em 23624.
|
||||
ret
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
; Rotina de delay variavel, conforme o valor definido em A antes de a chamar
|
||||
; Ripada do Paradise Café
|
||||
delay
|
||||
push bc
|
||||
delay_start
|
||||
ld c, 10
|
||||
delay_loop2
|
||||
ld b, 0
|
||||
delay_loop1
|
||||
djnz delay_loop1 ; b--, se b != 0 corre novamente o loop1
|
||||
dec c ; c--
|
||||
jr nz, delay_loop2 ; Se c != 0 corre o loop2
|
||||
dec a ; a--
|
||||
jr nz, delay_start ; Se a != 0 volta ao inicio da rotina
|
||||
pop bc
|
||||
ret
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
org 30000
|
||||
|
||||
tv_flag equ $5c3c ; Endereço que contem flags da tv
|
||||
last_k equ $5c08 ; Contem a ultima tecla pressionada
|
||||
|
||||
k_cur equ $5c5b ; Contem a posição do cursor - TODO: Usar isto
|
||||
; Depois de meter a 10,6 (y,x) fica com
|
||||
; $5d16
|
||||
|
||||
; Video RAM
|
||||
LINHA9 equ $4820
|
||||
LINHA10 equ $4840
|
||||
LINHA11 equ $4860
|
||||
|
||||
; 16 é para definir o INK
|
||||
; 17 é para definir o PAPER
|
||||
; 22 é para definir as Cordenadas Y,X
|
||||
; 255 Marcador de fim da string
|
||||
mystr db 22,10,0, 16,1, " ", 16,6, ".o0O0o. LOL GORDOS .o0O0o.", 16,1, " ", 255
|
||||
|
||||
start
|
||||
xor a ; O mesmo que LD a, 0
|
||||
ld (tv_flag), a ; Directs rst 10h output to main screen.
|
||||
|
||||
push bc ; Parece que é algum standard guardar o BC
|
||||
; na stack, e tirar no fim do programa.
|
||||
|
||||
call clear_screen ; Limpa o ecrã
|
||||
|
||||
; Flood de numeros em todas as linhas
|
||||
ld a, $0 ; Começa na linha 0
|
||||
ld b, $16 ; Repete nas 22 linhas
|
||||
lol_flood
|
||||
ld c, a ; Guarda o A em C e o B em D porque
|
||||
ld d, b ; são alterados no call
|
||||
call printnumbers
|
||||
ld a, c ; Le o A de volta
|
||||
inc a ; Proxima linha
|
||||
ld b, d ; Le o B de volta
|
||||
djnz lol_flood ; B-- , se for != 0 salta
|
||||
|
||||
ld hl, mystr ; Le para HL o endereço da string a printar
|
||||
printa_ate_255
|
||||
ld a,(hl) ; Le para A o valor que esta no endereço em HL
|
||||
cp $ff ; Se for 255...
|
||||
jr z, mainloop ; então já se imprimiu tudo e é para sair
|
||||
rst $10 ; Syscall para imprimir o no ecrã o que estiver em A
|
||||
inc hl ; Incrementa o valor de HL
|
||||
; Passa a ter o endereço do proximo caracater da str
|
||||
jr printa_ate_255 ; Volta ao inicio da rotina
|
||||
|
||||
mainloop
|
||||
ld a, $0
|
||||
ld (last_k), a ; Limpa o valor da ultima tecla pressionada
|
||||
|
||||
ld hl, LINHA9
|
||||
call scroll_direita
|
||||
ld hl, LINHA10
|
||||
call scroll_esquerda
|
||||
ld hl, LINHA11
|
||||
call scroll_direita
|
||||
|
||||
ld a, $1
|
||||
call delay ; Chama a rotina de delay(1)
|
||||
|
||||
ld a, (last_k) ; Se o valor da ultima tecla pressionada ainda
|
||||
cp $0 ; for 0, é porque ainda não se pressionou nenhuma
|
||||
jr z, mainloop ; tecla, por isso... repete
|
||||
|
||||
exit
|
||||
pop bc ; Tira o BC da Stack
|
||||
ret ; Sai para o BASIC
|
||||
|
||||
INCLUDE "scroll_esquerda.asm"
|
||||
INCLUDE "scroll_direita.asm"
|
||||
INCLUDE "delay.asm"
|
||||
INCLUDE "clear.asm"
|
||||
INCLUDE "printnumbers.asm"
|
||||
|
||||
end start
|
||||
Binary file not shown.
|
|
@ -1,24 +0,0 @@
|
|||
; printa numeros de 0 a 9 na linha definida em A
|
||||
printnumbers
|
||||
ld b, a ; guarda o valor de A em B
|
||||
ld a, $16 ; AT
|
||||
rst $10
|
||||
ld a, b ; Y = B
|
||||
rst $10
|
||||
ld a, $0 ; X = 0
|
||||
rst $10
|
||||
|
||||
ld b, $20 ; 32 colunas
|
||||
ld h, $30 ; chr "0"
|
||||
|
||||
printnumbers_loop
|
||||
ld a, h ; printa o chr em H
|
||||
rst $10
|
||||
inc h ; Incrementa
|
||||
ld a, h ; Guarda o valor em A
|
||||
cp $3a ; Compara com chr ":" (a seguir ao "0")
|
||||
jr nz, printnumbers_continue
|
||||
ld h, $30 ; Volta a meter a "0"
|
||||
printnumbers_continue
|
||||
djnz printnumbers_loop
|
||||
ret
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
;videoAddr2 equ 4820h ; Linha 9
|
||||
;videoAddr2 equ 4920h ; Faz o mesmo, tenho de entender porque
|
||||
|
||||
addractual2 db 0,0
|
||||
primeiroaddr db 0,0
|
||||
|
||||
; Rotina de scroll de texto da esquerda para a direita pixel a pixel
|
||||
; O endereço inicial tem de vir em HL
|
||||
scroll_direita
|
||||
; ld hl, videoAddr2 ; Endereço de Memoria Video a ser manipulado
|
||||
ld c, $8 ; Numero de vezes que a rotina vai correr
|
||||
; 8 é o numero de linhas de pixeis a scrollar
|
||||
|
||||
; Loop1
|
||||
scroll_direita_0
|
||||
ld (addractual2), hl ; Guarda o valor de HL em tmp1
|
||||
call scroll_direita_1 ; Scrolla
|
||||
ld hl, (addractual2) ; Le o valor de tmp1 para HL
|
||||
|
||||
inc h ; Incrementa H, mas como estamos a trabalhar com um
|
||||
; endereço de 16bits, na realidade vai adicionar
|
||||
; $100 a HL
|
||||
; Isto vai fazer com que a segunda rotina seja
|
||||
; chamada com os seguintes endereços em tmp1
|
||||
; videoAddr, videoAddr+$100 videoAddr+$200,
|
||||
; ..., videoAddr+$700
|
||||
|
||||
dec c ; Decrementa o contador C
|
||||
jr nz, scroll_direita_0 ; Se C != 0 corre novamente o Loop1
|
||||
ret
|
||||
|
||||
; Segunda rotina
|
||||
scroll_direita_1
|
||||
ld hl, (addractual2) ; Le o argumento tmp1 para HL
|
||||
ld (primeiroaddr), hl
|
||||
ld b, $20 ; Numero de vezes que vai correr
|
||||
; Loop2
|
||||
scroll_direita_2
|
||||
ld a, (hl) ; Faz um rotate right aos 8 pixels no
|
||||
rra ; endereço de video ram em HL, o bit
|
||||
; perdido fica na carry
|
||||
ld (hl), a ; Actualiza
|
||||
inc hl ; Anda uma coluna para a direita
|
||||
djnz scroll_direita_2 ; Se ainda nao chegou ao fim, repete
|
||||
|
||||
ld hl, (primeiroaddr) ; Le o valor do endereço da coluna
|
||||
ld a, (hl) ; mais à esquerda, em A
|
||||
|
||||
jr nc, scroll_direita_sem_carry ; Não tem carry? vai para o fim
|
||||
or $80 ; bit 7 = 1
|
||||
scroll_direita_sem_carry
|
||||
ld (hl), a ; Actualiza
|
||||
ret
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
;videoAddr equ 4840h ; Endereço de Memoria Video da Linha 10
|
||||
;videoAddr equ 4940h ; Faz o mesmo, tenho de entender porque
|
||||
|
||||
addractual1 db 0,0
|
||||
ultimoaddr db 0,0
|
||||
|
||||
; Rotina de scroll de texto da direita para a esquerda pixel a pixel
|
||||
; O endereço inicial tem de vir em HL
|
||||
scroll_esquerda
|
||||
; ld hl, videoAddr ; Endereço de Memoria Video a ser manipulado
|
||||
ld c, $8 ; Numero de vezes que a rotina vai correr
|
||||
; 8 é o numero de linhas de pixeis a scrollar
|
||||
|
||||
; Loop1
|
||||
scroll_esquerda_0
|
||||
ld (addractual1), hl ; Guarda o valor de HL em tmp1
|
||||
call scroll_esquerda_1 ; Scrolla
|
||||
ld hl, (addractual1) ; Le o valor de tmp1 para HL
|
||||
|
||||
inc h ; Incrementa H, mas como estamos a trabalhar com um
|
||||
; endereço de 16bits, na realidade vai adicionar
|
||||
; $100 a HL
|
||||
; Isto vai fazer com que a segunda rotina seja
|
||||
; chamada com os seguintes endereços em tmp1
|
||||
; videoAddr, videoAddr+$100 videoAddr+$200,
|
||||
; ..., videoAddr+$700
|
||||
|
||||
dec c ; Decrementa o contador C
|
||||
jr nz, scroll_esquerda_0; Se C != 0 corre novamente o Loop1
|
||||
ret
|
||||
|
||||
; Segunda rotina
|
||||
scroll_esquerda_1
|
||||
ld hl, (addractual1) ; Le o argumento tmp1 para HL
|
||||
|
||||
push bc
|
||||
ld bc, $1f ; Soma $1f ao endereço para começar
|
||||
adc hl, bc ; no fim da linha, tudo à direita
|
||||
; Cada linha tem 32 bytes
|
||||
|
||||
ld (ultimoaddr), hl ; Guarda o endereço do fim da linha
|
||||
pop bc
|
||||
|
||||
ld b, $20 ; Numero de vezes que vai correr
|
||||
|
||||
; Vai começar por fazer um rotate left à coluna mais à direita, e
|
||||
; guarda o bit que se perde na carry, que vai ser usado como o
|
||||
; bit 0 do proximo rotate left que for executado.
|
||||
|
||||
; Se no rotate da coluna mais à esquerda se perdeu alguma coisa,
|
||||
; então é para passar para a coluna mais a direita.
|
||||
; Se depois do ultimo rotate o carry estiver definido, faz-se um
|
||||
; OR ao bit 0 da coluna mais à direita.
|
||||
|
||||
; Loop2
|
||||
scroll_esquerda_2
|
||||
ld a, (hl) ; Faz um rotate left aos 8 pixels no
|
||||
rla ; endereço de video ram em HL, o bit
|
||||
; perdido fica na carry
|
||||
ld (hl), a ; Actualiza
|
||||
dec hl ; Anda uma coluna para a esquerda
|
||||
djnz scroll_esquerda_2 ; Se ainda nao chegou ao fim, repete
|
||||
|
||||
ld hl, (ultimoaddr) ; Le o valor do endereço da coluna
|
||||
ld a, (hl) ; mais à direita, em A
|
||||
|
||||
; Se não tem carry significa que não perdeu pixel nenhum
|
||||
; no ultimo rotate, então não é preciso passar nada para
|
||||
; a coluna mais à direita porque já tem o bit 0 a 0 devido
|
||||
; ao rotate inicial.
|
||||
jr nc, scroll_esquerda_sem_carry ; Não tem carry? vai para o fim
|
||||
|
||||
; Se tem carry é porque se perdeu um pixel no ultimo
|
||||
; rotate, então tem de se settar o bit 0 do coluna mais
|
||||
; à direita a 1
|
||||
or $1 ; bit 0 = 1
|
||||
scroll_esquerda_sem_carry
|
||||
ld (hl), a ; Actualiza
|
||||
ret
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
Scroller
|
||||
=========
|
||||
|
||||
Scroller é uma implementação um scroller de texto em Assembly no ZX Spectrum.
|
||||
|
||||
Requisitos
|
||||
-----------
|
||||
|
||||
O unico realmente necessário é o Assembler, mas para ver o resultado convem tambem ter um emulador, os verdadeiros podem converter o ficheiro [tap] para audio, passar para um leitor de mp3 e ligar a um Spectrum real :-D
|
||||
|
||||
* [Pasmo] - Assembler de Z80, é Open Source e Cross Platform
|
||||
* [ZX Spin] - Emulador de ZX Spectrum para Windows que inclui um Debugger
|
||||
|
||||
Instalação
|
||||
--------------
|
||||
|
||||
```sh
|
||||
git clone https://github.com/falsovsky/z80.git
|
||||
cd z80/scroller2
|
||||
pasmo -v --tapbas --err main.asm main.tap
|
||||
```
|
||||
|
||||
Licença
|
||||
----
|
||||
|
||||
BSD
|
||||
|
||||
[tap]:http://www.worldofspectrum.org/faq/reference/formats.htm
|
||||
[Pasmo]:http://pasmo.speccy.org/
|
||||
[ZX Spin]:http://www.zophar.net/sinclair/zx-spin.html
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
; Rotina de delay variavel, conforme o valor definido em A antes de a chamar
|
||||
; Ripada do Paradise Café
|
||||
delay
|
||||
push bc
|
||||
delay_start
|
||||
ld c, 15
|
||||
delay_loop2
|
||||
ld b, 0
|
||||
delay_loop1
|
||||
djnz delay_loop1 ; b--, se b != 0 corre novamente o loop1
|
||||
dec c ; c--
|
||||
jr nz, delay_loop2 ; Se c != 0 corre o loop2
|
||||
dec a ; a--
|
||||
jr nz, delay_start ; Se a != 0 volta ao inicio da rotina
|
||||
pop bc
|
||||
ret
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
attr_p equ $5c8d; Endereço que contem as cores permanentes
|
||||
bordcr equ $5c48; Endereço que contem a cor da borda
|
||||
rom_limpa_ecra equ $0daf; Rotina da ROM que limpa o ecrã
|
||||
rom_define_borda equ $2294; Rotina da ROM que define a borda
|
||||
|
||||
; Cores
|
||||
; Numero | Binario | Nome
|
||||
; 0 | 000 | Preto
|
||||
; 1 | 001 | Azul
|
||||
; 2 | 010 | Vermelho
|
||||
; 3 | 011 | Roxo
|
||||
; 4 | 100 | Verde
|
||||
; 5 | 101 | Cyan
|
||||
; 6 | 110 | Amarelo
|
||||
; 7 | 111 | Branco
|
||||
|
||||
; 8 bits para definir ink, paper, brightness e flash
|
||||
; |F |B |P2|P1|P0|I2|I1|I0|
|
||||
; F Flash
|
||||
; B Brightness
|
||||
; P Paper
|
||||
; I Ink
|
||||
|
||||
; Então para definir o flash desligado, o brightness ligado com o
|
||||
; fundo a preto e o texto a amarelo fica-se com:
|
||||
; 01000110 = 70 = $46
|
||||
; 01000000 = 64 = $40 - Tudo preto
|
||||
; 01000111 = 71 = $47 - Fundo preto Texto Branco
|
||||
screen_attribute equ $47
|
||||
|
||||
; Valor de 0 a 7
|
||||
border_color equ $0
|
||||
|
||||
limpa_ecra
|
||||
ld a, screen_attribute
|
||||
ld (attr_p), a ; Variavel de sistema que permite definir
|
||||
; o ink, paper, brightness e flash
|
||||
call rom_limpa_ecra ; Clear screen
|
||||
|
||||
ld a, border_color ; Cor do border
|
||||
call rom_define_borda+$7
|
||||
; Chama a rotina da ROM para actualizar a borda, mas salta 7
|
||||
; bytes à frente, porque são para ler o valor da borda do
|
||||
; BASIC. O valor fica guardado em $5c48.
|
||||
ret
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
org 30000
|
||||
|
||||
tv_flag equ $5c3c ; Variavel das flags da tv
|
||||
last_k equ $5c08 ; Variavel que contem a ultima tecla usada
|
||||
LINHA10 equ $4840 ; Endereço da linha 10 na Memoria Video
|
||||
|
||||
o_barbas db 22,9,0, 16,6, "o_barbas disse:", 255
|
||||
scroll_udg db $8 ; Numero de pixeis já scrollados no UDG#1
|
||||
; Inicializado a 8 para "pedir" uma nova
|
||||
; letra quando corre pela primeira vez.
|
||||
|
||||
start
|
||||
xor a ; O mesmo que LD a, 0
|
||||
ld (tv_flag), a ; Faz com que o rst $10 envie output pra tv
|
||||
push bc ; Guarda BC na stack
|
||||
|
||||
call limpa_ecra ; Limpa o ecrã
|
||||
|
||||
ld hl, o_barbas ; Le para HL o endereço da string a printar
|
||||
printa_string
|
||||
ld a,(hl) ; Le para A o valor que esta no endereço em HL
|
||||
cp $ff ; Se for 255...
|
||||
jr z, main_loop ; então já se imprimiu tudo e é para sair
|
||||
rst $10
|
||||
inc hl ; Incrementa a posição na string
|
||||
jr printa_string ; Volta ao inicio da rotina
|
||||
|
||||
main_loop
|
||||
ld a, $0
|
||||
ld (last_k), a ; Limpa o valor da ultima tecla pressionada
|
||||
|
||||
ld a, (scroll_udg) ; Le o numero de pixeis já scrollados no UDG#1
|
||||
cp $8 ; São 8?
|
||||
jr nz, main_loop_scroll ; Não? salta
|
||||
call obtem_proxima_letra ; Sim, manda meter uma nova letra em UDG#1
|
||||
ld a, 0
|
||||
ld (scroll_udg), a ; Reseta o numero de pixeis scrollados no UDG#1
|
||||
|
||||
main_loop_scroll
|
||||
ld hl, LINHA10
|
||||
call scroll_esquerda ; Scrolla a linha 10
|
||||
|
||||
ld a, (scroll_udg)
|
||||
inc a ; Incrementa o numero de pixeis já scrollados
|
||||
ld (scroll_udg), a
|
||||
|
||||
ld a, $1
|
||||
call delay ; Chama a rotina de delay(1)
|
||||
|
||||
ld a, (last_k) ; Se o valor da ultima tecla pressionada ainda
|
||||
cp $0 ; for 0, é porque ainda não se pressionou nenhuma,
|
||||
jr Z, main_loop ; por isso... repete
|
||||
|
||||
exit
|
||||
pop bc ; Tira o BC da stack
|
||||
ret ; Sai para o BASIC
|
||||
|
||||
INCLUDE "delay.asm"
|
||||
INCLUDE "limpa.asm"
|
||||
INCLUDE "texto.asm"
|
||||
INCLUDE "scroll.asm"
|
||||
|
||||
end start
|
||||
Binary file not shown.
|
|
@ -1,24 +0,0 @@
|
|||
; printa numeros de 0 a 9 na linha definida em A
|
||||
printnumbers
|
||||
ld b, a ; guarda o valor de A em B
|
||||
ld a, $16 ; AT
|
||||
rst $10
|
||||
ld a, b ; Y = B
|
||||
rst $10
|
||||
ld a, $0 ; X = 0
|
||||
rst $10
|
||||
|
||||
ld b, $20 ; 32 colunas
|
||||
ld h, $30 ; chr "0"
|
||||
|
||||
printnumbers_loop
|
||||
ld a, h ; printa o chr em H
|
||||
rst $10
|
||||
inc h ; Incrementa
|
||||
ld a, h ; Guarda o valor em A
|
||||
cp $3a ; Compara com chr ":" (a seguir ao "0")
|
||||
jr nz, printnumbers_continue
|
||||
ld h, $30 ; Volta a meter a "0"
|
||||
printnumbers_continue
|
||||
djnz printnumbers_loop
|
||||
ret
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
scroll_addr db 0,0 ; Endereço da linha a scrollar - na coluna 0
|
||||
linha_actual db 0 ; Linha actual
|
||||
ultima_addr db 0,0 ; Endereço da coluna mais à direita da linha actual
|
||||
|
||||
; O endereço inicial tem de vir em HL
|
||||
scroll
|
||||
ld c, $8 ; Numero de vezes que a rotina vai correr
|
||||
; 8 é o numero de linhas de pixeis a scrollar
|
||||
|
||||
ld a, $0
|
||||
ld (linha_actual), a ; Começa na linha 0
|
||||
|
||||
; Loop1
|
||||
scroll_loop
|
||||
ld (scroll_addr), hl ; Guarda o valor de HL (argumento da rotina)
|
||||
call scrolla_linha ; Scrolla uma linha
|
||||
ld hl, (scroll_addr) ; Le o valor de tmp1 para HL
|
||||
|
||||
inc h ; Incrementa H, mas como estamos a trabalhar com um
|
||||
; endereço de 16bits, na realidade vai adicionar
|
||||
; $100 a HL
|
||||
; Isto vai fazer com que a segunda rotina seja
|
||||
; chamada com os seguintes endereços em tmp1
|
||||
; videoAddr, videoAddr+$100 videoAddr+$200,
|
||||
; ..., videoAddr+$700
|
||||
|
||||
ld a, (linha_actual) ; Incrementa a linha actual
|
||||
inc a
|
||||
ld (linha_actual), a
|
||||
|
||||
dec c ; Decrementa o contador C
|
||||
jr nz, scroll_loop ; Se C != 0 corre novamente o Loop1
|
||||
ret
|
||||
|
||||
; Scrolla a linha que estiver em scroll_addr
|
||||
scrolla_linha
|
||||
push bc
|
||||
ld hl, (scroll_addr) ; Le linha a scrollar
|
||||
ld bc, $1f ; Soma $1f ao endereço para começar
|
||||
add hl, bc ; no fim da linha, tudo à direita
|
||||
; Cada linha tem 32 bytes
|
||||
|
||||
ld (ultima_addr), hl ; Guarda o endereço do fim da linha
|
||||
ld b, $20 ; Numero de vezes que vai correr
|
||||
|
||||
; Vai começar por fazer um rotate left à coluna mais à direita, e
|
||||
; guarda o bit que se perde na carry, que vai ser usado como o
|
||||
; bit 0 do proximo rotate left que for executado.
|
||||
|
||||
; Depois faz-se um rotate left à mesma linha do UDG#1 guardado na
|
||||
; rotina do "scroll_text.asm".
|
||||
; Se a carry estiver definida faz-se um OR ao bit 0 da coluna mais
|
||||
; à direita da linha.
|
||||
|
||||
; Loop2
|
||||
scrolla_linha_loop
|
||||
ld a, (hl) ; Faz um rotate left aos 8 pixels no
|
||||
rla ; endereço de video ram em HL, o bit
|
||||
; perdido fica na carry
|
||||
ld (hl), a ; Actualiza
|
||||
dec hl ; Anda uma coluna para a esquerda
|
||||
djnz scrolla_linha_loop ; Se ainda nao chegou ao fim, repete
|
||||
; Já processou tudo ate à esquerda, vamos passar o resto do
|
||||
; UDG#1
|
||||
ld a, (linha_actual) ; Le a linha actual para A
|
||||
ld d, $0 ; D = $0
|
||||
ld e, a ; E = A
|
||||
ld hl, udg_start ; Endereço onde começa o UDG#1
|
||||
add hl, de ; Soma a linha actual
|
||||
|
||||
ld a, (hl) ; Le o valor da linha do #UDG#1
|
||||
rla ; Rotate
|
||||
ld (hl), a ; Actualiza
|
||||
|
||||
ld hl, (ultima_addr) ; Le o valor do endereço da coluna
|
||||
ld a, (hl) ; mais à direita em A
|
||||
|
||||
; Se não tem carry significa que não perdeu pixel nenhum
|
||||
; no ultimo rotate, então não é preciso passar nada para
|
||||
; a coluna mais à direita porque já tem o bit 0 a 0 devido
|
||||
; ao rotate inicial.
|
||||
jr nc, scrolla_linha_fim ; Não tem carry? vai para o fim
|
||||
|
||||
; Se tem carry é porque se perdeu um pixel no ultimo
|
||||
; rotate, então tem de se settar o bit 0 do coluna mais
|
||||
; à direita a 1
|
||||
or $1 ; bit 0 = 1
|
||||
scrolla_linha_fim
|
||||
ld (hl), a ; Actualiza
|
||||
pop bc
|
||||
ret
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
text db "\"SEM QUERER MAGOAR O MEU BENFICA SO SABE GANHAR VIVA O BENFICA\" \"DA TRAFARIA ATE AO JAMOR O MEU BENFICA MOSTRA SEMPRE O SEU ESPLENDOR VIVA O BENFICA\" \"MANHA DE NEVOEIRO TARDE DE SOL SOALHEIRO BENFICA SEMPRE O PRIMEIRO VIVA O BENFICA\" \"DUAS VIAGENS SEGUIDAS PARA A ITALIA DAQUI A BOCADO MAIS VALE ABRIR UM BARBAS EM TURIM VIVA O BENFICA\" ", 0
|
||||
|
||||
chars equ $5c36 ; Endereço 256 ($100) bytes abaixo da fonte (2 bytes)
|
||||
; Contem $3c00 inicialmente
|
||||
|
||||
font_start equ $3c00 ; Endereço onde começa a fonte, acaba em $3fff
|
||||
; Começa com o espaço e acaba no ©
|
||||
; http://en.wikipedia.org/wiki/ZX_Spectrum_character_set
|
||||
|
||||
udg equ $5c7b ; Endereço do primeiro user-defined graphics (2 bytes)
|
||||
; Contem $ff58 inicialmente
|
||||
|
||||
udg_start equ $ff58 ; User-defined characters, vai até $ffff
|
||||
; São acessiveis com o caracter $90 até $a4
|
||||
|
||||
posicao_addr db 0,0 ; Contem o endereço da posição actual na string
|
||||
reset_posicao db 1 ; Se estiver a 1 a posição é resetada a 0
|
||||
|
||||
obtem_proxima_letra
|
||||
ld a, (reset_posicao)
|
||||
cp $1 ; Se não for para meter a posição a 0 salta
|
||||
jr nz, proxima_letra_sem_reset
|
||||
; o reset_posicao está a 1, meter a posicao na string a 0
|
||||
ld a, 0
|
||||
ld (reset_posicao), a ; reset_posicao = 0
|
||||
ld hl, text ; Endereço do primeiro chr
|
||||
jr proxima_letra_loop
|
||||
proxima_letra_sem_reset
|
||||
; Usa a posição guardada em posicao_addr
|
||||
ld hl, (posicao_addr)
|
||||
|
||||
proxima_letra_loop
|
||||
; Por exemplo, a primeira letra é um L. No ASCII do
|
||||
; Spectrum o valor dela é $4C e com esse valor pretendo
|
||||
; chegar a $3E60 que é onde está a font dela
|
||||
|
||||
ld a, (hl) ; Le chr da string - $4C inicialmente
|
||||
push hl ; Guarda a posição na string na stack
|
||||
|
||||
ld h,$0 ; H = $0
|
||||
ld l,a ; L = A
|
||||
|
||||
add hl, hl ; $4C + $4C = $98
|
||||
add hl, hl ; $98 + $98 = $130
|
||||
add hl, hl ; $130 + $130 = $260
|
||||
|
||||
ld d, h
|
||||
ld e, l ; DE = HL
|
||||
|
||||
ld hl, font_start
|
||||
add hl, de ; $3C00 + $260 = $3E60
|
||||
|
||||
call proxima_letra_udg ; Copia a letra para o UDG#1
|
||||
; O argumento para a rotina é o valor em HL
|
||||
|
||||
pop hl ; Tira a posição na string da stack
|
||||
inc hl ; Anda para a frente
|
||||
ld a, (hl) ; Le o proximo valor
|
||||
cp $0 ; Se for 0 estamos no fim da string
|
||||
jr z, proxima_letra_sem_reset ; Manda fazer reset à posição
|
||||
jr proxima_letra_fim ; Senão continua
|
||||
proxima_letra_sem_reset
|
||||
ld a, $1 ; Manda meter a posicao a 0 na proxima
|
||||
ld (reset_posicao), a ; iteração
|
||||
proxima_letra_fim
|
||||
ld (posicao_addr), hl ; Guarda a posição
|
||||
ret
|
||||
|
||||
; copia a letra para o UDG#1
|
||||
proxima_letra_udg
|
||||
; Está a contar que o endereço de origem esteja em HL
|
||||
ld b, $8 ; Copiar 8 bytes, cada letra são 8x8
|
||||
ld de, udg_start ; Destino
|
||||
proxima_letra_udg_loop
|
||||
ld a, (hl) ; Le origem
|
||||
ld (de), a ; Copia para destino
|
||||
inc hl ; Incrementa ambos
|
||||
inc de
|
||||
djnz proxima_letra_udg_loop ; b--, se b != 0 salta
|
||||
ret
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
zx-brainfuck
|
||||
=========
|
||||
|
||||
ZX-Brainfuck é um interpretador de [Brainfuck] em Assembly no ZX Spectrum.
|
||||
|
||||
Requisitos
|
||||
-----------
|
||||
|
||||
O unico realmente necessário é o Assembler, mas para ver o resultado convem tambem ter um emulador, os verdadeiros podem converter o ficheiro [tap] para audio, passar para um leitor de mp3 e ligar a um Spectrum real :-D
|
||||
|
||||
* [Pasmo] - Assembler de Z80, é Open Source e Cross Platform
|
||||
* [ZX Spin] - Emulador de ZX Spectrum para Windows que inclui um Debugger
|
||||
|
||||
Instalação
|
||||
--------------
|
||||
|
||||
```sh
|
||||
git clone https://github.com/falsovsky/z80.git
|
||||
cd z80/zx-brainfuck
|
||||
pasmo -v --tapbas --err main.asm main.tap
|
||||
```
|
||||
|
||||
Licença
|
||||
----
|
||||
|
||||
BSD
|
||||
|
||||
[Brainfuck]:http://en.wikipedia.org/wiki/Brainfuck
|
||||
[tap]:http://www.worldofspectrum.org/faq/reference/formats.htm
|
||||
[Pasmo]:http://pasmo.speccy.org/
|
||||
[ZX Spin]:http://www.zophar.net/sinclair/zx-spin.html
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
org 30000
|
||||
|
||||
tv_flag equ $5c3c ; Variavel das flags da tv
|
||||
last_k equ $5c08 ; Contem a ultima tecla pressionada
|
||||
|
||||
OP_INC_DP equ ">"
|
||||
OP_DEC_DP equ "<"
|
||||
OP_INC_VAL equ "+"
|
||||
OP_DEC_VAL equ "-"
|
||||
OP_OUT equ "."
|
||||
OP_IN equ ","
|
||||
OP_JMP_FWD equ "["
|
||||
OP_JMP_BCK equ "]"
|
||||
|
||||
;brainfuck db "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.", 0
|
||||
brainfuck db "+++++++++++++++++++++++++++++++++.", 0
|
||||
memory_pos db $0,$80
|
||||
|
||||
start ; Começa em $75a2
|
||||
xor a ; O mesmo que LD a, 0
|
||||
ld (tv_flag), a ; Faz com que o rst $10 envie output pra tv
|
||||
push bc ; Guarda BC na stack
|
||||
|
||||
main
|
||||
ld hl, brainfuck
|
||||
read_bf
|
||||
ld a,(hl)
|
||||
push hl
|
||||
|
||||
; EOF
|
||||
cp $0
|
||||
jr z, end_main
|
||||
|
||||
; >
|
||||
cp OP_INC_DP
|
||||
jr z, F_INC_DP
|
||||
|
||||
; <
|
||||
cp OP_DEC_DP
|
||||
jr z, F_DEC_DP
|
||||
|
||||
; +
|
||||
cp OP_INC_VAL
|
||||
jr z, F_INC_VAL
|
||||
|
||||
; -
|
||||
cp OP_DEC_VAL
|
||||
jr z, F_DEC_VAL
|
||||
|
||||
; .
|
||||
cp OP_OUT
|
||||
jr z, F_OUT
|
||||
|
||||
; ,
|
||||
cp OP_IN
|
||||
jr z, F_IN
|
||||
|
||||
continue
|
||||
pop hl
|
||||
inc hl
|
||||
jr read_bf
|
||||
|
||||
end_main
|
||||
pop bc ; Tira o BC da stack
|
||||
ret ; Sai para o BASIC
|
||||
|
||||
F_INC_DP
|
||||
ld hl, (memory_pos)
|
||||
inc hl
|
||||
ld (memory_pos), hl
|
||||
jr continue
|
||||
|
||||
F_DEC_DP
|
||||
ld hl, (memory_pos)
|
||||
dec hl
|
||||
ld (memory_pos), hl
|
||||
jr continue
|
||||
|
||||
F_INC_VAL
|
||||
ld hl, (memory_pos)
|
||||
ld a, (hl)
|
||||
inc a
|
||||
ld (hl), a
|
||||
jr continue
|
||||
|
||||
F_DEC_VAL
|
||||
ld hl, (memory_pos)
|
||||
ld a, (hl)
|
||||
dec a
|
||||
ld (hl), a
|
||||
jr continue
|
||||
|
||||
F_OUT
|
||||
ld hl, (memory_pos)
|
||||
ld a, (hl)
|
||||
rst $10
|
||||
ld (hl), a
|
||||
jr continue
|
||||
|
||||
F_IN
|
||||
ld a, $0
|
||||
ld (last_k), a ; Limpa o valor da ultima tecla pressionada
|
||||
F_IN_LOOP
|
||||
ld a, (last_k) ; Se o valor da ultima tecla pressionada ainda
|
||||
cp $0 ; for 0, é porque ainda não se pressionou nenhuma
|
||||
jr z, F_IN_LOOP ; tecla, por isso... repete
|
||||
ld hl, (memory_pos)
|
||||
ld (hl), a
|
||||
jr continue
|
||||
|
||||
|
||||
|
||||
end start
|
||||
Binary file not shown.
Loading…
Reference in New Issue