The following warnings occurred:
Warning [2] Undefined array key 0 - Line: 1677 - File: showthread.php PHP 8.2.31 (Linux)
File Line Function
/inc/class_error.php 157 errorHandler->error
/showthread.php 1677 errorHandler->error_callback
/showthread.php 916 buildtree




Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Stack Bug in ZXB 1.2.5-r1489 ?
#1
I was updating fourspriter to use SUBs as opposed to gotos. Probably slower, but a little cleaner on the interface to the user.

Anyway, as it stands the main program:

Calls initialize for the first sprite
which calls a dummy "data" routine (which is really just for asm. The first line is return. It only calls it to make sure it's not peephole optimized out)
Comes back to main
calls coords for the first sprite
comes back to main
calls initialize for the second sprite
which calls the dummy data routine again......

and then it goes wrong. It never comes back from this data routine this second time, even though it should return immediately. In fact, it restarts the main program again. Over and over - and then after a few cycles, crashes.


I confirmed the code does the same thing with 1.23 and 1.22; and I didn't think they had the stack bugs, so it could be something I'm doing wrong, I suppose. I can't really see what could go wrong with "return" being the only statement, though.

The code is a bit complex, and is unfinished; but hopefully you can see where I'm going. It has testing PRINTs in it. Just copy and paste and see if it behaves the same way for you.

Code:
SUB fspInitialize (n as uByte, a as uByte, b as uByte, c as uByte, d as uByte) 'Initialize Sprite: n (sprite number 0-3);a,b,c,d (UDG number 0-20,99 means the sprite won't be printed) PRINT AT 0,0;"Initialize" : PAUSE 1: PAUSE 0 fspData() : REM call the data sub to make sure it isn't optimized out of the compile. That call just returns. PRINT AT 2,0;"FSPData came back to Initialize" : PAUSE 1: PAUSE 0 IF n>3 OR a>20 or b>20 or c>20 or d>20 then return : END IF : REM Bounds checking - so a bad function call doesn't poke all over memory. DIM targetAddr as uInteger targetAddr=@fspDataStart+(48*n) POKE targetAddr,a targetAddr=targetAddr+1 POKE targetAddr,b targetAddr=targetAddr+1 POKE targetAddr,c targetAddr=targetAddr+1 POKE targetAddr,d PRINT AT 3,0;"We're at the end of Initialize" PAUSE 1:PAUSE 0 END SUB SUB fspDisable (n as UByte) IF n>3 then return : END IF POKE @fspDataStart+48*n,99 end SUB SUB fspCoord (n as uByte, x as uByte, y as uByte) 'Set sprite coords: n (sprite number);x,y (vertical,horizontal coords) IF n>3 then return : END IF DIM targetAddr as uInteger targetAddr=@fspDataStart+4+48*n POKE targetAddr,x targetAddr=targetAddr+1 POKE targetAddr,y rem targetAddr=targetAddr+1 rem POKE targetAddr,x rem targetAddr=targetAddr+1 rem POKE targetAddr,y END SUB SUB fspAttrs (n as uByte, attra as uByte, attrb as uByte, attrc as uByte, attrd as uByte) 'Set sprite attrs: n (sprite number);a,b,c,d (UDG attrs) IF n>3 then return : END IF DIM targetAddr as uInteger targetAddr=@fspDataStart+40+48*n POKE targetAddr,attra targetAddr=targetAddr+1 POKE targetAddr,attrb targetAddr=targetAddr+1 POKE targetAddr,attrc targetAddr=targetAddr+1 POKE targetAddr,attrd END SUB FUNCTION fspAttrByte(fspInk as uByte,fspPaper as uByte,fspBright as uByte, fspFlash as uByte) as uByte if fspInk > 7 OR fspPaper > 7 OR fspBright > 1 or fspFlash >1 then return 0: END IF: Rem bounds check return (fspFlash shl 7) + (fspBright shl 6) + (fspPaper shl 3) + fspInk END FUNCTION SUB fspAttr(n as uByte,fspInk as uByte,fspPaper as uByte,fspBright as uByte, fspFlash as uByte) if fspInk > 7 OR fspPaper > 7 OR fspBright > 1 or fspFlash >1 then return : END IF: Rem bounds check DIM attrByte as uByte attrByte=fspAttrByte(fspInk,fspPaper,fspBright,fspFlash) fspAttrs(n,fspAttrByte,fspAttrByte,fspAttrByte,fspAttrByte) END SUB SUB fspData() fspDataStart: RETURN : REM if called we should return immediately. This sub is for data and ASM only. REM This routine contains Fourspriter data and code that is called by other routines. In effect, it's a dummy subroutine. REM It is called by fspInitialize in order to ensure it is included in the build. ASM ;; 16x16 Sprites moving a character each frame ;; Copyleft 2009 The Mojon Twins. ;; Pergreñado por na_th_an ;; Uses UDGs (it reads the address from the system variables). ;; It moves up to 4 sprites, preserving the backgrounds. datap: ; each block is 48 bytes long. [This comment originally said 40 bytes, and it's clearly 48] ;; Sprite 1 udgs1: defb 0,0,0,0 ; Four UDGs of the first sprite. x_pos1: defb 0 ; X position in chars. y_pos1: defb 0 ; Y position in chars. cx_pos1: defb 0 ; Previous X position in chars. cy_pos1: defb 0 ; Previous Y position in chars. buffer1: defb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; Background Gfx buffer. attrs1: defb 7,7,7,7 ; Sprite ATTRs buffatrs1: defb 0,0,0,0 ; Background Attr's buffer ;; Sprite 2 udgs2: defb 0,0,0,0 x_pos2: defb 0 y_pos2: defb 0 cx_pos2: defb 0 cy_pos2: defb 0 buffer2: defb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 attrs2: defb 7,7,7,7 buffatrs2: defb 0,0,0,0 ;; Sprite 3 udgs3: defb 0,0,0,0 x_pos3: defb 0 y_pos3: defb 0 cx_pos3: defb 0 cy_pos3: defb 0 buffer3: defb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 attrs3: defb 7,7,7,7 buffatrs3: defb 0,0,0,0 ;; Sprite 4 udgs4: defb 0,0,0,0 x_pos4: defb 0 y_pos4: defb 0 cx_pos4: defb 0 cy_pos4: defb 0 buffer4: defb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 attrs4: defb 7,7,7,7 buffatrs4: defb 0,0,0,0 ;; General use coordinates xpos: defb 0 ypos: defb 0 cxpos: defb 0 cypos: defb 0 ;; Sprite control is done writing a certain number ;; in the Sprite's first UDG ;; If the first UDG is 99, it won't be printed docopy: call get_scr_address ; Dirección (xpos, ypos) en BC ld l, c ld h, b ; Dirección (xpos, ypos) en HL ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ret ;; Esta función devuelve en bc la dirección de memoria ;; de la posición (xpos, ypos) en carácteres. Extraído de código ;; por BloodBaz. get_scr_address: push de ld a, (xpos) and 31 ld c, a ld a, (ypos) ld d, a and 24 add a, 64 ld b, a ld a, d and 7 rrca rrca rrca or c ld c, a pop de ret ;; Esta función devuelve en bc la dirección de memoria ;; de la posición (xpos, ypos) dentro del archivo de atributos. ;; Adaptado de código por Jonathan Cauldwell. ;; 010110YY YYYXXXXX get_attr_address: ld a, (ypos) ; Cogemos y rrca rrca rrca ; La multiplicamos por 32 ld c, a ; nos lo guardamos en c and 3 ; ponemos una mascarita 00000011 add a, 88 ; 88 * 256 = 22528, aquí empieza el tema ld b, a ; Hecho el bite superior. ld a, c ; Nos volvemos a traer y * 32 and 224 ; Mascarita 11100000 ld c, a ; Lo volvemos a poner en c ld a, (xpos) ; Cogemos x add a, c ; Le sumamos lo que teníamos antes. ld c, a ; Listo. Ya tenemos en BC la dirección. ret spare: defb 85,85,85,85,85,85,85, 85 END ASM END SUB SUB fspErase() asm ;; Routine to save the background to the buffer ;borra_sprites: ; pointer = datap ; for (i = 0; i < 4; i ++) { ; CX = *(pointer + 6) ; CY = *(pointer + 7) ; scr_address = get_scr_address (CX, CY); ; for (j = 0; j < 8; j ++) { ; *scr_address = *(pointer + 8 + j); ; scr_address += 256; ; } ; scr_address = get_scr_address (CX+1, CY); ; for (j = 0; j < 8; j ++) { ; *scr_address = *(pointer + 16 + j); ; scr_address += 256; ; } ; scr_address = get_scr_address (CX, CY+1); ; for (j = 0; j < 8; j ++) { ; *scr_address = *(pointer + 24 + j); ; scr_address += 256; ; } ; scr_address = get_scr_address (CX+1, CY+1); ; for (j = 0; j < 8; j ++) { ; *scr_address = *(pointer + 32 + j); ; scr_address += 256; ; } ; pointer += 40; ; } ld de, datap ; ld b, 4 ; i4chars2: push bc ;; ld a, (de) cp 99 jr z, nxt2 ;; A inc de inc de inc de inc de inc de inc de ; Obtenemos xpos = CX ld a, (de) ld hl, xpos ld (hl), a inc de ; Obtenemos ypos = CY ld a, (de) ld hl, ypos ld (hl), a inc de ;; B ; Pintamos el primer char call borra_char ; xpos++ ld hl, xpos inc (hl) ;; C ; Pintamos el segundo char call borra_char ; xpos -- ld hl, xpos ld a, (hl) dec a ld (hl), a ; ypos ++ ld hl, ypos inc (hl) ;; D ; Pintamos el tercer char call borra_char ; xpos++ ld hl, xpos inc (hl) ;; E ; Pintamos el cuarto char call borra_char ;; attr inc de inc de inc de inc de ;; ; xpos -- ld hl, xpos ld a, (hl) dec a ld (hl), a ; ypos -- ld hl, ypos ld a, (hl) dec a ld (hl), a ; call get_attr_address ; call copyattrs ; nxt2: pop bc djnz i4chars2 jp fspErase_end borra_char: call get_scr_address ; ld l, c ld h, b ; ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ld a, (de) ld (hl), a inc h inc de ret fspErase_end: end asm END SUB SUB fspBufferBackground() asm init_sprites: ; pointer = datap ; for (i = 0; i < 4; i ++) { ; X = *(pointer + 4); // A ; Y = *(pointer + 5); ; scr_address = get_scr_address (X, Y); // B ; for (j = 0; j < 8; j ++) { ; *(pointer + 8 + j) = *scraddress; ; scraddress += 256; ; } ; scr_address = get_scr_address (X+1, Y); // C ; for (j = 0; j < 8; j ++) { ; *(pointer + 16 + j) = *scraddress; ; scraddress += 256; ; } ; scr_address = get_scr_address (X, Y+1); // D ; for (j = 0; j < 8; j ++) { ; *(pointer + 24 + j) = *scraddress; ; scraddress += 256; ; } ; scr_address = get_scr_address (X+1, Y+1); // E ; for (j = 0; j < 8; j ++) { ; *(pointer + 32 + j) = *scraddress; ; scraddress += 256; ; } ; pointer = pointer + 40; ; } ld de, datap ; ld b, 4 ; i4chars: push bc ;; ld a, (de) cp 99 jr z, nxt1 ;; A inc de inc de inc de inc de ; ld a, (de) ld hl, xpos ld (hl), a inc de ; ld a, (de) ld hl, ypos ld (hl), a inc de inc de inc de ;; B ; call copia_char ; xpos++ ld hl, xpos inc (hl) ;; C ; call copia_char ; xpos -- ld hl, xpos ld a, (hl) dec a ld (hl), a ; ypos ++ ld hl, ypos inc (hl) ;; D ; call copia_char ; xpos++ ld hl, xpos inc (hl) ;; E ; call copia_char ;; Now we point to the ATTR buffer,adding 4: inc de inc de inc de inc de ;; ; xpos -- ld hl, xpos ld a, (hl) dec a ld (hl), a ; ypos -- ld hl, ypos ld a, (hl) dec a ld (hl), a ; call get_attr_address ; ld l, c ld h, b ld bc, 31 ld a, (hl) ld (de), a ; Primer carácter inc hl inc de ld a, (hl) ld (de), a ; Segundo carácter add hl, bc inc de ld a, (hl) ld (de), a ; Tercer carácter inc hl inc de ld a, (hl) ld (de), a ; Cuarto carácter inc de ; Fin del bucle nxt1: pop bc djnz i4chars ;ret jp fspBufferBackground_end copia_char: call get_scr_address ; ld l, c ld h, b ; ld a, (hl) ld (de), a inc h inc de ld a, (hl) ld (de), a inc h inc de ld a, (hl) ld (de), a inc h inc de ld a, (hl) ld (de), a inc h inc de ld a, (hl) ld (de), a inc h inc de ld a, (hl) ld (de), a inc h inc de ld a, (hl) ld (de), a inc h inc de ld a, (hl) ld (de), a inc h inc de ret ; Subroutines don't need to return themselves. fspBufferBackground_end: ;; Routine to move the sprites: end asm END SUB SUB fspRedraw() asm halt end asm ';call borra_sprites ; Erase the sprites fspErase() ';call init_sprites ; Save background fspBufferBackground() ';call draw_sprites ; print sprites fspDraw() ';call update_coordinates ; update coordinates :) fspUpdate() ';ret END SUB SUB fspDraw() asm ;; Print sprites routine ;; UDGs are labeled from 0 to 21. The addres of the UDG is: ;; *(23675) + 256 * *(23676) + 8 * N draw_sprites: ld de, datap ; ld b, 4 ; i4chars3: push bc ld a, (de) cp 99 jr z, nxt3 ;; copiar aquí "de" a un buffer call charsabuff ; Obtenemos xpos ld a, (de) ld hl, xpos ld (hl), a inc de ; Obtenemos ypos ld a, (de) ld hl, ypos ld (hl), a inc de inc de inc de push de ld hl, bufchars call getde call docopy ; xpos++ ld hl, xpos inc (hl) ; Dirección del gráfico ld hl, bufchars inc hl call getde ; Pintamos el segundo char call docopy ; xpos-- ld hl, xpos ld a, (hl) dec a ld (hl), a ; ypos ++ ld hl, ypos inc (hl) ; Dirección del gráfico ld hl, bufchars inc hl inc hl call getde ; Pintamos el tercer char call docopy ; xpos ++ ld hl, xpos inc (hl) ; Dirección del gráfico ld hl, bufchars inc hl inc hl inc hl call getde ; Pintamos el cuarto char call docopy pop de ; de = de + 32 ld bc, 32 ld h, d ld l, e add hl, bc ld d, h ld e, l ;; attr ; xpos -- ld hl, xpos ld a, (hl) dec a ld (hl), a ; ypos -- ld hl, ypos ld a, (hl) dec a ld (hl), a ; call get_attr_address ; call copyattrs inc de inc de inc de inc de ; nxt3: pop bc djnz i4chars3 ;ret jp fspDraw_end ;; Esta función calcula la posición en memoria del UDG apuntado por ;; el número que está en la dirección hl. getde: ld a, (hl) ld d, a ld hl, 23676 ld a, (hl) ld e, a ld hl, 23675 ld a, (hl) ld l, a ld a, e ld h, a ;; HL = *(23675) + 256 * *(23676) ld a, d rlca rlca rlca ; a = N * 8 ld d, 0 ld e, a add hl, de ld d, h ld e, l ret bufchars: defb 0,0,0, 0 ; charsabuff: ld hl, bufchars ld a, (de) ld (hl), a inc de inc hl ld a, (de) ld (hl), a inc de inc hl ld a, (de) ld (hl), a inc de inc hl ld a, (de) ld (hl), a inc de inc hl ret copyattrs: ld l, c ld h, b ld bc, 31 ld a, (de) ld (hl), a ; Primer carácter inc hl inc de ld a, (de) ld (hl), a ; Segundo carácter add hl, bc inc de ld a, (de) ld (hl), a ; Tercer carácter inc hl inc de ld a, (de) ld (hl), a ; Cuarto carácter inc de ; Ahora de apunta a datap+48, o sea, al siguiente sprite. ret fspDraw_end: END ASM END SUB SUB fspUpdate() asm update_coordinates: ld de, datap ; Apuntamos a la zona de datos ld hl, datap ; idem ld b, 4 ; 4 iteraciones i4chars4: push bc ;; Para cada sprite hay que hacer: ;; *(datap + 6) = *(datap + 4) ;; *(datap + 7) = *(datap + 5) inc de inc de inc de inc de ld a, (de) ; a = X inc hl inc hl inc hl inc hl inc hl inc hl ld (hl), a ; CX = a inc de ld a, (de) ; a = Y inc hl ld (hl), a ; CY = a inc hl ;; hl = hl + 40 ld bc, 40 add hl, bc ;; de = hl ld d, h ld e, l pop bc djnz i4chars4 ;ret END ASM END SUB #include <sinclair.bas> #include <memcopy.bas> #include <keys.bas> 100 DIM gentle (0 to 3,0 to 7) AS uByte => { { 15, 15, 15, 15, 15, 15, 13, 15} , _ { 240, 144, 208, 208, 240, 240, 176, 240} , _ { 15, 14, 63, 0, 0, 12, 26, 30} , _ { 176, 112, 252, 0, 0, 48, 104, 120}} 110 POKE Uinteger 23675, @gentle(0,0) memcopy (0,16384,4092) LET gx=10:LET gy=10:let dx=3:let dy=3:let tx=6:let ty=6:let cx=18:let cy=18 let dmx=1:let dmy=1:let tmx=-1:let tmy=-1:let cmx=1:let cmy=-1 fspInitialize (0,0,1,2,3) PRINT AT 5,0;"We came back from Initialize the first time" : PAUSE 1: PAUSE 0 fspCoord (0,gy,gx) PRINT AT 6,0;"We came back from fspCoord the first time": PAUSE 1: PAUSE 0 CLS fspInitialize (1,0,1,2,3) PRINT AT 7,0;"We came back from Initialize the second time" : PAUSE 1: PAUSE 0 fspCoord (1,dy,dx) fspInitialize (2,0,1,2,3) fspCoord (2,ty,tx) fspInitialize (3,0,1,2,3) fspCoord (3,cy,cx) fspAttrs (0,31,31,31,31) fspAttrs (1,12,12,12,12) fspAttrs (2,26,26,26,26) fspAttrs (3,6,6,6,6) DO IF MULTIKEYS(KEYO)<>0 and gx>0 THEN LET gx=gx-1: END IF IF MULTIKEYS(KEYP)<>0 and gx<30 THEN LET gx=gx+1:END IF IF MULTIKEYS(KEYQ)<>0 and gy>0 THEN LET gy=gy-1 :END IF IF MULTIKEYS(KEYA)<>0 and gy<22 THEN LET gy=gy+1: END IF let dx=dx+dmx:if dx=0 or dx=30 then let dmx=-dmx : END IF let dy=dy+dmy:if dy=0 or dy=22 then let dmy=-dmy: END IF let tx=tx+tmx:if tx=0 or tx=30 then let tmx=-tmx: END IF let ty=ty+tmy:if ty=0 or ty=22 then let tmy=-tmy: END IF let cx=cx+cmx:if cx=0 or cx=30 then let cmx=-cmx: END IF let cy=cy+cmy:if cy=0 or cy=22 then let cmy=-cmy: END IF pause 2 fspCoord (0,gx,gy) fspCoord (1,dx,dy) fspCoord (2,tx,ty) fspCoord (3,cx,cy) fspRedraw() loop
Reply


Messages In This Thread

Forum Jump:


Users browsing this thread: 1 Guest(s)