Autor Wątek: Konkurs dla programistów ;)  (Przeczytany 21547 razy)

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Konkurs dla programistów ;)
« dnia: 2013.09.13, 17:00:33 »
Każdy programujący w asemblerze zna taką procedurkę:

inc h
ld a,h
and 7
ret nz
ld a,l
add a,32
ld e,l
ret c
ld a,h
sub 8
ld h,a
       ret

Zdaniem jest napisanie odpowiednika w języku C.

Dodam, że ja znam rozwiązanie ;-). Jestem ciekaw waszych sposobów.

pear

  • *****
  • Wiadomości: 5511
  • Miejsce pobytu:
    Będzin
  • Z80 only
Odp: Konkurs dla programistów ;)
« Odpowiedź #1 dnia: 2013.09.14, 09:00:36 »
Nie to, żebym się czepiał, ale wypadałoby podać co jest wejściem, a co wyjściem.
ZX/Enterprise/CPC/Robotron/C128D

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Konkurs dla programistów ;)
« Odpowiedź #2 dnia: 2013.09.14, 11:58:52 »
To jest standardowa procedura przejścia o jedną linię niżej w pamięci ekranu Spectrum.

Argument: HL, zwracana wartość:HL.

A w C pisał nie będę bo pomysłu nie mam,  przepisałbym operacja po operacji kod z asemblera ;)

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Konkurs dla programistów ;)
« Odpowiedź #3 dnia: 2013.09.14, 17:33:42 »
pear, dzięki za uwagę, Fakt, nie każdy musi kojarzyć tą procedurę.

Tak jak napisał Rafał, wejściem jest adres pamięci VIDEO w rejestrze HL. Wynikiem działania jest adres pamięci dla linii poniżej. Działanie na zasadzie y=y+1

Co do języków programowania, to w sumie może być każdy inny wysokiego poziomu, jak chociażby BASIC.

Po rozwiązaniu tego zadania, będzie kolejne. Mam nadzieję, że inni również się przyłączą do zabawy ;)

Gryzor

  • *****
  • Wiadomości: 2010
  • Miejsce pobytu:
    Warszawa
Odp: Konkurs dla programistów ;)
« Odpowiedź #4 dnia: 2013.09.14, 18:38:01 »
Za malo danych wejsciowych do rozwiazania zadania :-)
To ma byc w C na ZXa czy w generycznie w Ansi C np.
unsigned int func(unsigned int x);
ja bym uzyl #def i przepisal w assemblerze :-)


pear

  • *****
  • Wiadomości: 5511
  • Miejsce pobytu:
    Będzin
  • Z80 only
Odp: Konkurs dla programistów ;)
« Odpowiedź #5 dnia: 2013.09.14, 19:37:24 »
C znam raczej słabo, ale to tak jakoś magicznie wychodzi (uprościłem sobie rozbijając operację na oddzielne zmienne do połówek rejestrów, ale to chyba nie jest dyskwalifikacja :) )

h++;
if ((h & 7) == 0) && (l < 224) h-=8;
ZX/Enterprise/CPC/Robotron/C128D

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Konkurs dla programistów ;)
« Odpowiedź #6 dnia: 2013.09.14, 20:04:27 »
Gryzor: nie mędrkuj ;)

pear: fajnie że kombinujesz ;) Masz racje, w tym zadaniu jest pewne wyzwanie. To co w asemblerze jest 'naturalne', w językach wysokiego problemu może stanowić pewne wyzwanie.

Rozwiązanie podesłał już UB880D (ten sam, który stworzył MNI Browser dla ESXDOS), dzięki! ;)

Aby nie psuć zabawy, opublikuję to co podesłał dopiero w poniedziałek popołudniu. Dodam również swoje rozwiązanie.

Spróbujcie swoich sił ;)

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Konkurs dla programistów ;)
« Odpowiedź #7 dnia: 2013.09.15, 00:29:59 »
Cytuj
h++;
if ((h & 7) == 0) && (l < 224) h-=8;

To nie jest dobre, w ogóle nie wykonuje L=L+32 w niektórych przypadkach.

Tak chyba jest poprawnie:
h++;

if ((h & 7) == 0)
{
l+=32;
h-=8;
}

if (l==256)
{
l=0;
h+=8;
}

Szuwarek

  • **
  • Wiadomości: 80
  • Miejsce pobytu:
    Rabka-Zdrój
    • http://xxl.atari.pl/
Odp: Konkurs dla programistów ;)
« Odpowiedź #8 dnia: 2013.09.15, 10:36:33 »
inc h
ld a,h
and 7
ret nz
ld a,l
add a,32
ld e,l
ret c
ld a,h
sub 8
ld h,a
       ret

ta literowka jest po to zeby "zmylic przeciwnika"?

powinno byc raczej tak:
inc h
ld a,h
and a,$07
ret nz
ld a,l
add a,$20
ld l,a ;----------------- L
ret c
ld a,h
sub a,$08
ld h,a
ret

i do kompletu linijka wyzej:
ld a,h
dec h
and a,$07
ret nz
ld a,l
sub a,$20
ld l,a
ret c
ld a,h
add a,$08
ld h,a
ret

pear

  • *****
  • Wiadomości: 5511
  • Miejsce pobytu:
    Będzin
  • Z80 only
Odp: Konkurs dla programistów ;)
« Odpowiedź #9 dnia: 2013.09.15, 16:38:41 »
Cytuj
h++;
if ((h & 7) == 0) && (l < 224) h-=8;

To nie jest dobre, w ogóle nie wykonuje L=L+32 w niektórych przypadkach.

Tak chyba jest poprawnie:
h++;

if ((h & 7) == 0)
{
l+=32;
h-=8;
}

if (l==256)
{
l=0;
h+=8;
}
Nie dodawałem 32 do L, bo wynik lądował w nieznaczącym rejestrze E. Chyba, że to rzeczywiście błąd w assemblerze ?
Jeśli tak, to wyjdzie taki kod:
h++;
if ((h & 7) == 0) {
  if (l < 224) h-=8;
  l+=32;
}
ZX/Enterprise/CPC/Robotron/C128D

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Konkurs dla programistów ;)
« Odpowiedź #10 dnia: 2013.09.15, 18:09:22 »
Faktycznie, w listingu asm jest błąd, aczkolwiek ten, kto wie do czego procedura służyła, nie miał z nią problemów.

Dzięki za nadesłane propozycje, to dobra wprawka do kolejnych wyzwań ;)

Moja procedura wygląda tak:
int linianizej(int addr)
{
int newaddr = addr;
newaddr += 256;
if ( ((newaddr>>8) & 7) == 0)
{
int h = newaddr & 0xff;
newaddr += 32;
h += 32;
if( h < 255) {
newaddr -= 8*256;
}
else
{
newaddr-=256;
}
}
return newaddr;
}

Rozwiązanie nadesłane przez UB880D jest następujące:
#include <stdio.h>

//010t tyyy YYYx xxxx

//linearize, increment, delinearize
int downhl(int hl) {
  int tmp;
 
  tmp=((hl&0xf81f)|((hl&0x0700)>>3)|((hl&0xe0)<<3))+0x0020;
  if ((tmp&0x1800)==0x1800) tmp&=0xe7ff;
  return (tmp&0xf81f)|((tmp&0x0700)>>3)|((tmp&0xe0)<<3);
}

//idea by book "ZX Spectrum a Assembler"
int downhl2(int hl) {
  hl+=0x0100;
  if (!(hl&0x0700)) {
    hl-=0x07e0;
    if (!(hl&0x00e0)) hl+=0x0700;
    if ((hl&0x1800)==0x1800) hl&=0xe7ff;
  }
  return hl;
}

//oneliner
int downhl3(int hl) {
  return hl + (((hl&0x07e0)==0x07e0) ? 0x0020 : (((hl&0x0700)==0x0700) ? -0x06e0 : 0x0100)) - (((hl&0x1fe0)==0x17e0) ? 0x1800 : 0);
}

int main() {
  int i;
  int hl, hl2, hl3;
 
  printf("\nstandard vram @ 0x4000\n");
  hl=0x4000;
  hl2=hl;
  hl3=hl;
  for (i=0;i<193;i++) {
    printf("%04X %04X %04X (%s) (%s) \n", hl, hl2, hl3, ((hl==hl2) ? "ok" : "bad"), ((hl==hl3) ? "ok" : "bad"));
    hl=downhl(hl);
    hl2=downhl2(hl2);
    hl3=downhl3(hl3);
  }

  printf("\nvram mapped to 0xc000\n");
  hl=0xc000;
  hl2=hl;
  hl3=hl;
  for (i=0;i<193;i++) {
    printf("%04X %04X %04X (%s) (%s) \n", hl, hl2, hl3, ((hl==hl2) ? "ok" : "bad"), ((hl==hl3) ? "ok" : "bad"));
    hl=downhl(hl);
    hl2=downhl2(hl2);
    hl3=downhl3(hl3);
  }

  return 0;
}


RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Konkurs dla programistów ;)
« Odpowiedź #11 dnia: 2013.09.15, 22:59:59 »
Tak jak na to patrzę, to wszystkie te procedury to jest własciwie jedno i to samo.

ZbyniuR

  • *****
  • Wiadomości: 3333
  • Miejsce pobytu:
    Carlisle w UK
  • CPC AGA PSX
Odp: Konkurs dla programistów ;)
« Odpowiedź #12 dnia: 2013.09.16, 07:22:06 »
Amen. ;)
- Jeśli masz w domu światło i wodę, tzn. że masz światłowód. ;)

Gryzor

  • *****
  • Wiadomości: 2010
  • Miejsce pobytu:
    Warszawa
Odp: Konkurs dla programistów ;)
« Odpowiedź #13 dnia: 2013.09.16, 10:13:18 »
Poczatek mialem dobry, reszty nie daliscie mi dopisac :-)

W sumie na ZX przy operacjach na ekranie nie da sie przeskoczyc tego co jest HW,
znajac liczniki i logike w ULA, mozna napisac optymalne operacje.

Ciekawsze teraz jaki kod wygeneruje z tego C, SDCC.

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Konkurs dla programistów ;)
« Odpowiedź #14 dnia: 2013.09.16, 10:28:19 »
Zrobiłem szybki test SDCC z moją procedurką.

Parametry kompilacji:  sdcc -mz80 --opt-code-speed --max-allocs-per-node 100000 -c test.c

Oto co otrzymałem:

_linianizej_start::
_linianizej:
push ix
ld ix,#0
add ix,sp
;__test_decHL.c:3: int newaddr = addr;
ld e,4 (ix)
ld d,5 (ix)
;__test_decHL.c:4: newaddr += 256;
ld hl,#0x0100
add hl,de
ex de,hl
;__test_decHL.c:5: if ( ((newaddr>>8) & 7) == 0)
ld h, d
ld a,h
rlc a
sbc a, a
ld a,h
and a, #0x07
jr NZ,00105$
;__test_decHL.c:7: int h = newaddr & 0xff;
ld l,e
ld h,#0x00
;__test_decHL.c:8: newaddr += 32;
ld a,e
add a, #0x20
ld e,a
ld a,d
adc a, #0x00
ld d,a
;__test_decHL.c:9: h += 32;
ld bc,#0x0020
add hl,bc
;__test_decHL.c:10: if( h < 255) {
ld bc, #0x80FF
add hl, hl
ccf
rr h
rr l
sbc hl, bc
jr NC,00102$
;__test_decHL.c:11: newaddr -= 8*256;
ld a,d
add a,#0xF8
ld d,a
jr 00105$
00102$:
;__test_decHL.c:15: newaddr-=256;
ld a,d
add a,#0xFF
ld d,a
00105$:
;__test_decHL.c:18: return newaddr;
ex de,hl
pop ix
ret

Nie spodziewałem się nic rewolucyjnego, ponieważ posługiwałem się 16bitowymi danymi.
Jakby pear dokończył swoją procedurę, to mogę również ją skompilować i zobaczyć co będzie wynikiem.