diff --git a/src/lib/arch/zx48k/stdlib/winscroll.bas b/src/lib/arch/zx48k/stdlib/winscroll.bas index 45e5a9a4e..381f02250 100644 --- a/src/lib/arch/zx48k/stdlib/winscroll.bas +++ b/src/lib/arch/zx48k/stdlib/winscroll.bas @@ -1,8 +1,9 @@ ' ---------------------------------------------------------------- ' This file is released under the MIT License ' -' Copyleft (k) 2008 +' Copyleft (k) 2008, 2025 ' by Jose Rodriguez-Rosa (a.k.a. Boriel) +' and Conrado Badenas ' ' Use this file as a template to develop your own library file ' ---------------------------------------------------------------- @@ -19,75 +20,39 @@ REM Avoid recursive / multiple inclusion ' --------------------------------------------------------------------- ' sub WinScrollRight ' scrolls the window defined by (row, col, width, height) 1 cell right +' it works with width=1 or height=1 but it is not impressive +' nothing is done if width=0 or height=0 ' --------------------------------------------------------------------- sub fastcall WinScrollRight(row as uByte, col as uByte, width as Ubyte, height as Ubyte) asm push namespace core - LOCAL BucleChars - LOCAL BucleScans - LOCAL BucleAttrs - PROC - ld b, a - pop hl - pop de - ld c, d + LOCAL BucleRows, BucleScans, AfterLDDR, AfterLDDR2, AfterLDDR3 + +; Read parameters, return if they are bad + ld b, a ;row + pop hl ;return address pop de + ld a, d ;colLeft + pop de ;width + add a, d + dec a + ld c, a ;colRight = colLeft + width - 1 ex (sp), hl - ld e, h + ld e, h ;height ld a, e or a - ret z - or d - ret z - push bc - ld a,b - and 18h - ld h,a - ld a,b - and 07h - add a,a - add a,a - add a,a - add a,a - add a,a - add a,c - add a,d - dec a - ld l,a ;HL=top-left window address in bitmap coord - ld bc, (SCREEN_ADDR) - add hl, bc - ld b,e - -BucleChars: - push bc - ld b,8 - -BucleScans: - push bc - push de - push hl - ld c,d - dec c - ld b,0 - ld d,h - ld e,l - dec l - lddr - ; clean up latest - xor a - ld (de),a - pop hl - pop de - inc h - pop bc - djnz BucleScans - dec h - call SP.PixelDown - pop bc - djnz BucleChars - - pop bc + ret z ;height=0 + ld a, d + or a + ret z ;width=0 + +; Compute Attributes address + sub 2 ;CF=1 if width=1, CF=0 if width>1 + inc a + ex af,af' ;A' = width-1, CF'=1 if width=1, CF'=0 if width>1 + push ix + ld ixL,e ;IXl = height, iterative variable ld l,b ld h,0 add hl,hl @@ -97,33 +62,77 @@ BucleScans: add hl,hl ld a,l add a,c - add a,d - dec a - ld l,a - ld a,h - ld h,a ;HL=top-left window address in attr coord - ld bc, (SCREEN_ATTR_ADDR) - add hl, bc - ld b,e - -BucleAttrs: - push bc - push de - push hl - ld c,d - dec c - ld b,0 - ld d,h - ld e,l - dec l - lddr - pop hl - ld de,32 + ld l,a ;HL = row*32 + colRight + ld de,(SCREEN_ATTR_ADDR) add hl,de - pop de - pop bc - djnz BucleAttrs +; For each row, compute Display File address +BucleRows: + push bc ;coords = row,col + push hl ;attr address + ld a,b ;row + and %00011000 ;select third (0,1,2) + ld h,a + ld a,b + and %00000111 ;select Row In Third (0,...,7) + rrca + rrca + rrca ;A = %RIT00000 + add a,c + ld l,a ;HL = %000th000RITcolmn + ld de,(SCREEN_ADDR) + add hl,de + ld b,0 + ex af,af' ;A = width-1, CF=1 if width=1, CF=0 if width>1 + ld ixH,7 + +; For each row, transfer 8 scans +BucleScans: + push hl + jr c,AfterLDDR + ld d,h + ld e,l ;DE = to address + dec hl ;HL = from address + ld c,a + lddr ;1st-7th scan in row + ex de,hl +AfterLDDR: + ld (hl),b ;clean up leftmost + pop hl + inc h ;scan below + dec ixH + jp nz,BucleScans + + jr c,AfterLDDR2 + ld d,h + ld e,l ;DE = to address + dec hl ;HL = from address + ld c,a + lddr ;8th scan in row + ex de,hl +AfterLDDR2: + ld (hl),b ;clean up leftmost + +; For each row, transfer a line of attributes + pop hl ;attr address + jr c,AfterLDDR3 + ld d,h + ld e,l ;DE = to address + dec hl ;HL = from address + ld c,a + push de + lddr ;attrs in row + pop hl +AfterLDDR3: + ex af,af' ;A' = width-1, CF'=1 if width=1, CF'=0 if width>1 + ld de,32 + add hl,de ;row below + pop bc + inc b ;row below + dec ixL + jp nz,BucleRows + + pop ix ENDP pop namespace end asm @@ -133,74 +142,36 @@ end sub ' --------------------------------------------------------------------- ' sub WinScrollLeft ' scrolls the window defined by (row, col, width, height) 1 cell left +' it works with width=1 or height=1 but it is not impressive +' nothing is done if width=0 or height=0 ' --------------------------------------------------------------------- sub fastcall WinScrollLeft(row as uByte, col as uByte, width as Ubyte, height as Ubyte) asm push namespace core PROC - LOCAL BucleChars - LOCAL BucleScans - LOCAL BucleAttrs + LOCAL BucleRows, BucleScans, AfterLDIR, AfterLDIR2, AfterLDIR3 - ld b, a - pop hl - pop de - ld c, d +; Read parameters, return if they are bad + ld b, a ;row + pop hl ;return address pop de + ld c, d ;col + pop de ;width ex (sp), hl - ld e, h + ld e, h ;height ld a, e or a - ret z - or d - ret z - push bc - ld a,b - and 18h - ld h,a - ld a,b - and 07h - add a,a - add a,a - add a,a - add a,a - add a,a - add a,c - ld l,a ;HL=top-left window address in bitmap coord - ld bc, (SCREEN_ADDR) - add hl, bc - ld b,e - -BucleChars: - push bc - ld b,8 - -BucleScans: - push bc - push de - push hl - ld c,d - dec c - ld b,0 - ld d,h - ld e,l - inc e - ex de,hl - ldir - ; clean up latest - xor a - ld (de),a - pop hl - pop de - inc h - pop bc - djnz BucleScans - dec h - call SP.PixelDown - pop bc - djnz BucleChars - - pop bc + ret z ;height=0 + ld a, d + or a + ret z ;width=0 + +; Compute Attributes address + sub 2 ;CF=1 if width=1, CF=0 if width>1 + inc a + ex af,af' ;A' = width-1, CF'=1 if width=1, CF'=0 if width>1 + push ix + ld ixL,e ;IXl = height, iterative variable ld l,b ld h,0 add hl,hl @@ -210,31 +181,77 @@ BucleScans: add hl,hl ld a,l add a,c - ld l,a - ld a,h - ld h,a ;HL=top-left address in attr coords - ld bc, (SCREEN_ATTR_ADDR) - add hl, bc - ld b,e - -BucleAttrs: - push bc - push de - push hl - ld c,d - dec c - ld b,0 - ld d,h - ld e,l - inc e - ex de,hl - ldir - pop hl - ld de,32 + ld l,a ;HL = row*32 + col + ld de,(SCREEN_ATTR_ADDR) add hl,de - pop de - pop bc - djnz BucleAttrs + +; For each row, compute Display File address +BucleRows: + push bc ;coords = row,col + push hl ;attr address + ld a,b ;row + and %00011000 ;select third (0,1,2) + ld h,a + ld a,b + and %00000111 ;select Row In Third (0,...,7) + rrca + rrca + rrca ;A = %RIT00000 + add a,c + ld l,a ;HL = %000th000RITcolmn + ld de,(SCREEN_ADDR) + add hl,de + ld b,0 + ex af,af' ;A = width-1, CF=1 if width=1, CF=0 if width>1 + ld ixH,7 + +; For each row, transfer 8 scans +BucleScans: + push hl + jr c,AfterLDIR + ld d,h + ld e,l ;DE = to address + inc hl ;HL = from address + ld c,a + ldir ;1st-7th scan in row + ex de,hl +AfterLDIR: + ld (hl),b ;clean up rightmost + pop hl + inc h ;scan below + dec ixH + jp nz,BucleScans + + jr c,AfterLDIR2 + ld d,h + ld e,l ;DE = to address + inc hl ;HL = from address + ld c,a + ldir ;8th scan in row + ex de,hl +AfterLDIR2: + ld (hl),b ;clean up rightmost + +; For each row, transfer a line of attributes + pop hl ;attr address + jr c,AfterLDIR3 + ld d,h + ld e,l ;DE = to address + inc hl ;HL = from address + ld c,a + push de + ldir ;attrs in row + pop hl +AfterLDIR3: + ex af,af' ;A' = width-1, CF'=1 if width=1, CF'=0 if width>1 + ld de,32 + add hl,de ;row below + pop bc + inc b ;row below + dec ixL + jp nz,BucleRows + + pop ix ENDP pop namespace end asm @@ -244,107 +261,35 @@ end sub ' --------------------------------------------------------------------- ' sub WinScrollUp ' scrolls the window defined by (row, col, width, height) 1 cell up +' it works with width=1 or height=1 but it is not impressive +' nothing is done if width=0 or height=0 ' --------------------------------------------------------------------- sub fastcall WinScrollUp(row as uByte, col as uByte, width as Ubyte, height as Ubyte) asm push namespace core PROC - LOCAL BucleScans, BucleAttrs, ScrollAttrs - LOCAL CleanLast, CleanLastLoop, EndCleanScan + LOCAL BucleRows, BucleScans, AttrAddress + LOCAL CleanBottomRow, CleanBottomScans, AfterLDIR - ld b, a - pop hl - pop de - ld c, d +; Read parameters, return if they are bad + ld b, a ;row + pop hl ;return address pop de + ld c, d ;col + pop de ;width ex (sp), hl - ld e, h + ld e, h ;height ld a, e or a - ret z - or d - ret z - - push bc - push de - - ld a,b - and 18h - ld h,a - ld a,b - and 07h - add a,a - add a,a - add a,a - add a,a - add a,a - add a,c - ld l,a ;HL=top-left window address in bitmap coord - ld bc, (SCREEN_ADDR) - add hl, bc - ld a,e - ld c, d ; c = width - ld d, h - ld e, l - dec a - jr z, CleanLast - add a,a - add a,a - add a,a - ld b, a ; b = 8 * (height - 1) - - inc h - inc h - inc h - inc h - inc h - inc h - inc h - call SP.PixelDown - -BucleScans: - push bc - push de - push hl - ld b, 0 - ldir - pop hl - pop de - pop bc - call SP.PixelDown - ex de, hl - call SP.PixelDown - ex de, hl - djnz BucleScans - -CleanLast: - ex de,hl - pop de - ld b, 8 - ld c, d - push de - -CleanLastLoop: - push bc - push hl - ld (hl), 0 - dec c - jr z, EndCleanScan - ld d, h - ld e, l - inc de - ld b, 0 - ldir - -EndCleanScan: - pop hl - pop bc - inc h - djnz CleanLastLoop + ret z ;height=0 + ld a, d + or a + ret z ;width=0 -ScrollAttrs: - pop de - pop bc +; Compute TopRow Attributes address + ex af,af' ;A' = width + push ix + ld ixL,e ;IXl = height, iterative variable ld l,b ld h,0 add hl,hl @@ -354,147 +299,145 @@ ScrollAttrs: add hl,hl ld a,l add a,c - ld l,a - ld a,h - ld h,a ;HL=top-left address in attr coords - ld bc, (SCREEN_ATTR_ADDR) - add hl, bc - ld b,e - dec b - ret z - -BucleAttrs: - push bc - push de - push hl - ld b,0 - ld c,d - ex de,hl - ld hl,32 + ld l,a ;HL = row*32 + col + ld de,(SCREEN_ATTR_ADDR) add hl,de - ldir - pop hl - ld de,32 + ld (AttrAddress+1),hl + +; Compute TopRow Display File address + ld a,b ;row + and %00011000 ;select third (0,1,2) + ld h,a + ld a,b + and %00000111 ;select Row In Third (0,...,7) + rrca + rrca + rrca ;A = %RIT00000 + add a,c + ld l,a ;HL = %000th000RITcolmn + ld de,(SCREEN_ADDR) add hl,de - pop de - pop bc - djnz BucleAttrs + push hl ;HL = from address + +BucleRows: + dec ixL + jr z,CleanBottomRow +; For each row, compute Display File address + inc b ;row below + ld a,b ;row + and %00011000 ;select third (0,1,2) + ld h,a + ld a,b + and %00000111 ;select Row In Third (0,...,7) + rrca + rrca + rrca ;A = %RIT00000 + add a,c + ld l,a ;HL = %000th000RITcolmn + ld de,(SCREEN_ADDR) + add hl,de + +; For each row, transfer 8 scans + pop de ;DE = to address, obtained from last "push hl; from address" + push hl ;HL = from address, will be the next "to address" + push bc ;coords = row,col + ld b,0 + ex af,af' ;A = width + ld ixH,7 +BucleScans: + ld c,a + push de + push hl + ldir ;1st-7th scan in row + pop hl + pop de + inc h ;scan below + inc d ;scan below + dec ixH + jp nz,BucleScans + + ld c,a + ldir ;8th scan in row + +; For each row, transfer a line of attributes +AttrAddress: + ld hl,AttrAddress + ld d,h + ld e,l ;DE = to address + ld c,32 + add hl,bc ;HL = from address + ld (AttrAddress+1),hl + ld c,a + ldir ;attrs in row + ex af,af' ;A' = width + pop bc + jp BucleRows + +; Clean bottom row (Display File, not Attributes) +CleanBottomRow: + ld b,0 + ex af,af' ;A = width + ld ixH,8 ;no need to speed up code by processing scans 1-7 apart of scan 8 + pop hl +CleanBottomScans: + ld (hl),b + ld c,a + dec c + jr z,AfterLDIR + push hl + ld d,h + ld e,l + inc de + ldir + pop hl +AfterLDIR: + inc h + dec ixH + jp nz,CleanBottomScans + + pop ix ENDP pop namespace end asm - end sub ' --------------------------------------------------------------------- ' sub WinScrollDown ' scrolls the window defined by (row, col, width, height) 1 cell down +' it works with width=1 or height=1 but it is not impressive +' nothing is done if width=0 or height=0 ' --------------------------------------------------------------------- sub fastcall WinScrollDown(row as uByte, col as uByte, width as Ubyte, height as Ubyte) asm push namespace core PROC - LOCAL BucleScans, BucleAttrs, ScrollAttrs - LOCAL CleanLast, CleanLastLoop, EndCleanScan + LOCAL BucleRows, BucleScans, AttrAddress + LOCAL CleanTopRow, CleanTopScans, AfterLDIR - ld b, a - pop hl - pop de - ld c, d +; Read parameters, return if they are bad + ld b, a ;rowTop + pop hl ;return address pop de + ld c, d ;col + pop de ;width ex (sp), hl - ld e, h - ld a, e - or a - ret z - or d - ret z - + ld e, h ;height ld a, b add a, e dec a - ld b, a ; b = row + height - 1 = top most row - - push bc - push de - - ld a,b - and 18h - ld h,a - ld a,b - and 07h - add a,a - add a,a - add a,a - add a,a - add a,a - add a,c - ld l,a ;HL=bottom-left window address in bitmap coord - ld bc, (SCREEN_ADDR) - add hl, bc - ld a,e - ld c, d ; c = width - ld d, h - ld e, l - dec a - jr z, CleanLast - add a,a - add a,a - add a,a - ld b, a ; b = 8 * (height - 1) - - inc d - inc d - inc d - inc d - inc d - inc d - inc d - call SP.PixelUp - -BucleScans: - push bc - push de - push hl - ld b, 0 - ldir - pop hl - pop de - pop bc - call SP.PixelUp - ex de, hl - call SP.PixelUp - ex de, hl - djnz BucleScans - -CleanLast: - ex de,hl - pop de - ld b, 8 - ld c, d - push de - -CleanLastLoop: - push bc - push hl - ld (hl), 0 - dec c - jr z, EndCleanScan - ld d, h - ld e, l - inc de - ld b, 0 - ldir - -EndCleanScan: - pop hl - pop bc - dec h - djnz CleanLastLoop + ld b, a ;rowBottom = rowTop + height - 1 + ld a, e + or a + ret z ;height=0 + ld a, d + or a + ret z ;width=0 -ScrollAttrs: - pop de - pop bc +; Compute BottomRow Attributes address + ex af,af' ;A' = width + push ix + ld ixL,e ;IXl = height, iterative variable ld l,b ld h,0 add hl,hl @@ -504,43 +447,111 @@ ScrollAttrs: add hl,hl ld a,l add a,c - ld l,a - ld a,h - ld h,a ;HL=top-left address in attr coords - ld bc, (SCREEN_ATTR_ADDR) - add hl, bc - ld b,e - dec b - ret z - -BucleAttrs: - push bc - push de - push hl - ld b,0 - ld c,d - ex de,hl - ld hl,-32 + ld l,a ;HL = row*32 + col + ld de,(SCREEN_ATTR_ADDR) add hl,de - ldir - pop hl - ld de,-32 + ld (AttrAddress+1),hl + +; Compute BottomRow Display File address + ld a,b ;row + and %00011000 ;select third (0,1,2) + ld h,a + ld a,b + and %00000111 ;select Row In Third (0,...,7) + rrca + rrca + rrca ;A = %RIT00000 + add a,c + ld l,a ;HL = %000th000RITcolmn + ld de,(SCREEN_ADDR) add hl,de - pop de - pop bc - djnz BucleAttrs + push hl ;HL = from address + +BucleRows: + dec ixL + jr z,CleanTopRow +; For each row, compute Display File address + dec b ;row above + ld a,b ;row + and %00011000 ;select third (0,1,2) + ld h,a + ld a,b + and %00000111 ;select Row In Third (0,...,7) + rrca + rrca + rrca ;A = %RIT00000 + add a,c + ld l,a ;HL = %000th000RITcolmn + ld de,(SCREEN_ADDR) + add hl,de + +; For each row, transfer 8 scans + pop de ;DE = to address, obtained from last "push hl; from address" + push hl ;HL = from address, will be the next "to address" + push bc ;coords = row,col + ld b,0 + ex af,af' ;A = width + ld ixH,7 +BucleScans: + ld c,a + push de + push hl + ldir ;1st-7th scan in row + pop hl + pop de + inc h ;scan below + inc d ;scan below + dec ixH + jp nz,BucleScans + + ld c,a + ldir ;8th scan in row + +; For each row, transfer a line of attributes +AttrAddress: + ld hl,AttrAddress + ld d,h + ld e,l ;DE = to address + ld c,32 ;it is a "mORAcle" that CarryFlag is always 0 here + sbc hl,bc ;HL = from address + ld (AttrAddress+1),hl + ld c,a + ldir ;attrs in row + ex af,af' ;A' = width + pop bc + jp BucleRows + +; Clean top row (Display File, not Attributes) +CleanTopRow: + ld b,0 + ex af,af' ;A = width + ld ixH,8 ;no need to speed up code by processing scans 1-7 apart of scan 8 + pop hl +CleanTopScans: + ld (hl),b + ld c,a + dec c + jr z,AfterLDIR + push hl + ld d,h + ld e,l + inc de + ldir + pop hl +AfterLDIR: + inc h + dec ixH + jp nz,CleanTopScans + + pop ix ENDP pop namespace end asm - end sub #pragma pop(case_insensitive) -REM the following is required, because it defines screen start addr -#require "cls.asm" -#require "SP/PixelDown.asm" -#require "SP/PixelUp.asm" +REM the following is required, because it defines SCREEN_ADDR and SCREEN_ATTR_ADDR #require "sysvars.asm"