Exibindo números grandes no Z80

z80_large_number

Programa originalmente escrito por Miguel Angel Rodriguez Jodar, o IdeaFix, com o objetivo de exibir números grandes em um ZX Spectrum e, consequentemente, qualquer outro computador baseado em Z80. E o maior número que esta rotina consegue formatar é um sujeito com tamanho de 255 bytes, este aqui:

22040-1

Mas se você for daqueles fanáticos por números e só acredita nos dígitos que pode contar com os dedos…

12623830496605862226841748706511699984548477605357610950050916182626
81841362026988015515680137613807175340545348511641386489045279316051
60527688095259563605939964364716019515983399209962459578542172100149
93776393858121960407273342250718005600967254090070955410951681657377
95933263322883148732515590778530684449778648033919625808006827600178
49589281937637993445539366428356761821065267423102149447628375691862
21071720202524163030311855918867830431407694380169252824698095970590
16414442388949286208254823034318069556902263087734268295039009305293
95181208739591967195841536053143145775307050594328881077553168201547
775

…chame familiares, vizinhos, gato, cachorro, papagaio, periquito, cidade inteira se precisar para ajudar.

O código para o Speccy está disponível na página dele, na ZX Projects. Este aqui é minha adaptação para rodar em computadores MSX com a mudança no endereço de execução e um complemento para escrever o número na tela logo de uma vez:


; This source code is regulated under the GNU license. Original division
; routine (c)Milos "baze" Bazelides, ( b…@stonline.sk ).
; Rest of code (c)Miguel Angel Rodriguez Jodar ( rodri…@atc.us.es )
;
; Adaptated to run in MSX from Giovanni Nunes
;
CHPUT equ 0x00a2
org 0xc000 ; The BASIC program is stored
; in 0x8000 (32768) address
; org 32768
Main proc
ld de,CADENA
otro_digito push de
call Obtener_Resto ; Get next remainder
pop de
add a,'0' ; Convert to an ASCII digit
ld (de),a ; and store it
inc de
call Check_Cero ; Is it the new dividend null?
jr nz,otro_digito ; Go to get another digit if not null
dec de ; Fix end address
; ld b,d ; And copy it to BC register
; ld c,e
;
; MSX
;
escribe ld a,(de) ; Read number
cp 0
ret z ; If A is zero, return to BASIC
call CHPUT ; write number on screen
dec de
jr escribe
;
; MSX
;
endp
Obtener_Resto proc
ld a,(NBYTES) ; A = number of bytes of the original
; number. We need number of bits, so we
; multiply it by 8.
ld l,a
ld h,0
add hl,hl
add hl,hl
add hl,hl
ex de,hl ; DE = number of bits of the original
; number
ld c,10 ; C holds the divisor.
ld hl,NUMERO ; HL points to the dividend/quotient
xor a ; Reset remainder
buc_div push hl ; This is, esencially, the same
; algorithm from Milos Bazelides, with
; the changers detailed above.
call Mult_2 ; The "old" ADD HL,HL
pop hl
rla
cp c
jr c,no_incr
sub c
call Increm ; The "old" INC L
no_incr dec de
push af
ld a,d
or e
jr z,fin_div
pop af
jr buc_div
fin_div pop af
ret
endp
Increm proc
ld hl,NUMERO
inc (hl)
ret
endp
Mult_2 proc
ld hl,NBYTES
ld b,(hl)
ld hl,NUMERO
sla (hl)
inc hl
dec b
ret z
buc_desplaza rl (hl)
inc hl
djnz buc_desplaza
ret
endp
Check_Cero proc
ld hl,NUMERO
ld a,(NBYTES)
ld b,a
check_byte ld a,(hl)
or a
jr nz,no_cero
inc hl
djnz check_byte
xor a
no_cero ret
endp
; Variables
NUMERO ds 255,255 ; 255 bytes filled with the value 255. Little
; endian notation. This is the largest number this routine can manage
; (although it's possible that it can deal with 256 byte-wide numbers
NBYTES db 255 ; how many bytes comprises our number
db 0 ; NULL byte to mark end of the converted number
CADENA equ $ ; here will be the ASCII code of the least
; significant digit of the converted number.

view raw

large.asm

hosted with ❤ by GitHub

Ele pode ser ser montado com o Pasmo,  a sintaxe é:

pasmo -d -v --msx large.asm large.bin

Mas ainda precisa de um programa em BASIC para combinar.


100 DEF FN SC(K$)=(60*VAL(LEFT$(K$,2))+VAL(MID$(K$,4,2)))*60+VAL(RIGHT$(K$,2))
110 BLOAD "LARGE.BIN":DEFUSR0=&HC000
120 GET TIME T$:T1#=FN SC(T$)
130 I%=USR0(0)
140 GET TIME T$:T2#=FN SC(T$)
150 PRINT:PRINT"Conversion took";(T2#T1#);"seconds."
160 END

view raw

large.bas

hosted with ❤ by GitHub

Porém, como o MSX não tem um contador de 24-bit como o ZX Spectrum que armazenaria quase 4 dias de operação e a variável de sistema JIFFY com 16-bit só registraria pouco mais de 18 minutos minha alternativa foi recorrer ao circuito de relógio do MSX — ou seja MSX2 e superiores, MSX1 fica de fora da brincadeira desta vez. 🙁

A única ressalva deste programa é de não rodá-lo perto de meia noite, ou a contagem ficará negativa — mas se você quiser pode usar o GET DATE para acrescentar dia, mês ou ano às variáveis T1# e T2#.

large_z80

Para os que gostam de comparações o tempo para formatar o número no ZX Spectrum foi de cerca de 3.214 segundos (~53’30”) enquanto que em um MSX turbo R em modo Z80 foi de 3.656 segundos (~60’55”) e em modo R800 de apenas 632 segundos (~10’30”).

large_r800

Aliás, curiosa a diferença de pouco mais de 7 minutos entre os Z80, não?

4 pensou em “Exibindo números grandes no Z80

  1. O MSX gera um wait cycle para cada ciclo M1, por isso é mais lento que o Spectrum para fazer o mesmo cálculo.
    Já o Turbo R (R800) roda as instruções do Z80 usando menos menos ciclos de máquina por instrução, por isso ele é mais rápido do que um Z80 com o clock multiplicado (ou, é por isso que as placas MSX ‘turbo’ são mais lentas que o R800 para o mesmo clock).
    Para fazer no MSX 1 basta criar seu próprio jiffy usando o hook HTIMI ($FD9F).

  2. Você pode implementar um contador de 24 bits assim (ou até maior)

    org od9fh:
    jp my_jiffy
    ret

    my_jiffy: ; contador de 24 bits
    ld hl,(mycounter)
    inc (hl) ; incrementa lsb
    ret nz ; retorna se não estourou
    inc hl ; estourou? incrementa proximo byte
    inc (hl) ; e por aí vai
    ret nz
    inc (hl) ; retorna apos incrementar o mais significativo
    ret

    mycounter: db 0,0,0

  3. Só faltou avisar que seria interessante colocar um ventilador do lado do seu MSX para realizar o calculo, o Z80 deve fritar para realizar toda a tarefa. Interessante a comparação entre as duas arquiteturas (MSX e ZX).

  4. Interessante senão fosse velho XD

    Em 2013 quando lancei o MSXDUMP, precisei implementar na minha biblioteca em Turbo Pascal, toda uma aritmética para trabalhar com numeros grandes uma vez que as IDE’s no MSX suportam operações em setores de 24bits. Essa biblioteca que chamei de BigInt.

    http://sourceforge.net/p/oldskooltech/code/HEAD/tree/msx/trunk/msxdos/pascal/bigint.pas

    Nela você consegue trabalhar com numero de qualquer tamanho e no caso hoje tenho 2 typedefs 1 para numeros de 24Bits e outra para 32Bits, entretanto a biblioteca é genérica e suporta quantos bits vc quiser e couber na memória do MSX.

    Na BigInt.pas você tem funções de comparação, soma, subtração, multiplicação, só faltou mesmo divisão que colocarei em breve.

    Não medi o tempo mas é bem performática, principalmente porque como ela foi criada para o MSXDUMP, que é um software que faz uso extensivo do disco, sua performance não é o gargalo.

    Penso um dia em mudar as funções para Assembly, não pela performance mas sim pelo uso de memória.

Os comentários estão fechados.