Thought this would be simple... Z80

13»

Comments

  • Hi Folks,

    Found the following in the Tips section:

    ;H=Y,L=X
       LD A,H
       AND 7
       RRCA
       RRCA
       RRCA
       ADD A,L
       LD L,A
       LD A,H
       RRA
       RRA
       RRA
       AND 3
       OR #58
       LD H,A
    ;HL=address
    

    I read this as calculating the address in the bitmap of X,Y but when I tested it is actually the attriubute file. Is there a similar routine for the bitmap address?

    Many thanks

    Paddy
  • I read this as calculating the address in the bitmap of X,Y but when I tested it is actually the attriubute file. Is there a similar routine for the bitmap address?

    Can I cheat a little?

    JZBKDST.png
    Heavy on the disasm
  • edited September 2017
    Thanks Bedazzle. I thoughjt I would test this but it does not seem to work unless I am being thick. I must be as this is ROM code so must work. :-)

    org 63000
    ld b,$08
    call $0E9B
    ld (hl),$FF
    ret
    

    I was expecting this to place a bar on the 8th row?

    Manyt thanks

    Paddy
    Post edited by Paddy Coleman on
  • ;display file addressing (HL):
    ;H =010ssppp, ss=segment 0-2, ppp=pixrow 0-7;
    ;L =rrrccccc, rrr=char.row 0-7, ccccc=char.col 0-31
    Thanked by 1Paddy Coleman
  • ;display file addressing (HL):
    ;H =010ssppp, ss=segment 0-2, ppp=pixrow 0-7;
    ;L =rrrccccc, rrr=char.row 0-7, ccccc=char.col 0-31
    To make this useful, we also need to deconstruct the actual coordinates:

    Y coord = ssrrrppp
    X coord = cccccxxx, where xxx is the pixel position within a cell.

    (Note: Unlike in BASIC, the coordinates originate in the top left corner and span the entire height of the screen—192 pixels.)

    So, for example, any pixel at coordinates 0,0–7,0 will be at address 01000000 00000000, i.e. 16384 ($4000).
    Every man should plant a tree, build a house, and write a ZX Spectrum game.

    Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
    and zasm Z80 Assembler syntax highlighter.
    Member of the team that discovered, analyzed, and detailed the floating bus behavior on the ZX Spectrum +2A/+3.

    A few Spectrum game fixes.
    Thanked by 1Paddy Coleman
  • edited September 2017
    Hi Folks,

    Looking for some advice on best practice. The following wee routine simply stores the 8 bytes of a character square, replaces them with a black box and finally restores the original contents.

    The code works but seems rather long winded compared to a high level language e.g. using 8 variables to store the bytes rather than an array/loop. Is this the correct approach or am I missing a Z80 trick?

    100 CLS 
    110 PRINT AT 12,16;"X"
    120 POKE 63000,12
    130 POKE 63001,16
    140 LET A=USR 63010
    150 STOP 
    
    ; ------------------------------------------------------------------------------
                       org    63000             ; Starting address
    ; ------------------------------------------------------------------------------
    ; Variables
    
    ROW                defb   $00               ; Character row
    COL                defb   $00               ; Character column
    
    STO_B1             defb   $00               ; 8 bytes used to store current
    STO_B2             defb   $00               ; contents of the display file
    STO_B3             defb   $00               ; at row/column
    STO_B4             defb   $00
    STO_B5             defb   $00
    STO_B6             defb   $00
    STO_B7             defb   $00
    STO_B8             defb   $00
    ; ------------------------------------------------------------------------------
    
    MAIN               ld     a,(ROW)           ; Calculate display file address
                       ld     b,a               ; from the character row/column
                       ld     a,(COL)
                       ld     c,a
                       call   CALCDF_ADDR
    
                       push   hl                ; Store display file address
                       ld     a,(hl)            ; Store the current 8 bytes at
                       ld     (STO_B1),a        ; the character row/column
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B2),a
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B3),a
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B4),a
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B5),a
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B6),a
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B7),a
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B8),a
                       pop    hl                ; Restore display file address
    
                       call   WAIT_KEY          ; Wait for a key to be pressed
    
                       push   hl                ; Store display file address
                       ld     (hl),$FF          ; Draw a black box at the 
                       inc    h                 ; character row/column
                       ld     (hl),$FF
                       inc    h
                       ld     (hl),$FF
                       inc    h
                       ld     (hl),$FF
                       inc    h
                       ld     (hl),$FF
                       inc    h
                       ld     (hl),$FF
                       inc    h
                       ld     (hl),$FF
                       inc    h
                       ld     (hl),$FF
                       pop    hl                ; Restore display file address
    
                       call   WAIT_KEY          ; Wait for a key to be pressed
    
                       push   hl                ; Store display file address
                       ld     a,(STO_B1)        ; Restore the original 8 bytes
                       ld     (hl),a            ; to the character row/column
                       inc    h
                       ld     a,(STO_B2)
                       ld     (hl),a
                       inc    h
                       ld     a,(STO_B3)
                       ld     (hl),a
                       inc    h
                       ld     a,(STO_B4)
                       ld     (hl),a
                       inc    h
                       ld     a,(STO_B5)
                       ld     (hl),a
                       inc    h
                       ld     a,(STO_B6)
                       ld     (hl),a
                       inc    h
                       ld     a,(STO_B7)
                       ld     (hl),a
                       inc    h
                       ld     a,(STO_B8)
                       ld     (hl),a
                       pop    hl                ; Restore display file address
    
                       ret                      ; Return to BASIC
    ; ------------------------------------------------------------------------------
    ; Calculate display file address from character row and column
    
    CALCDF_ADDR        ld     a,b
                       and    $0F8
                       add    a,$40
                       ld     h,a
                       ld     a,b
                       and    $07
                       rrca
                       rrca
                       rrca
                       add    a,c
                       ld     l,a
                       ret
    ; ------------------------------------------------------------------------------
    ; Waits until a key is pressed
    
    WAIT_KEY           push   hl                ; Store HL as used elsewhere
                       ld     hl,23560          ; LAST K system variable
                       ld     (hl),$00          ; Put null value there
    WKLOOP             ld     a,(hl)            ; New value of LAST K
                       cp     $00               ; Is it still zero?
                       jr     z,WKLOOP          ; Yes, so no key pressed
                       pop    hl                ; Restore HL registers
                       ret                      ; No, key was pressed
    ; ------------------------------------------------------------------------------
    

    Many thanks

    Paddy
    Post edited by Paddy Coleman on
  • a quick starter...
    push   hl                ; Store display file address
                       ld     a,(hl)            ; Store the current 8 bytes at
                       ld     (STO_B1),a        ; the character row/column
                       ld     (hl),FF        ; <--- put the cursor byte in at the same time
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B2),a
                       ld     (hl),FF
                       inc    h
                       ld     a,(hl)
                       ld     (STO_B3),a
                       ld     (hl),FF
    
    

    and so on....

    use DE for STO_B1 and then INC DE it as you go along, will probably need a PUSH DE/POP DE
    Thanked by 1Paddy Coleman
  • A simpler keypress check:
    key_w	call $28e	;poll keyboard
    	inc e		;if E=FFh (no key is pressed),
    			;INC E will result in 0
    	jr z,key_w	
    

    Or, without a ROM call and using only the accumulator:
    	xor a		;zeroize A to test all address lines of keyboard
    key_w	in a,($fe)	;read port 254
    	cpl		;invert A
    	and $1f		;mask the lowest 5 bits		
    	jr z,key_w	;try again if no key is pressed
    
    
    Every man should plant a tree, build a house, and write a ZX Spectrum game.

    Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
    and zasm Z80 Assembler syntax highlighter.
    Member of the team that discovered, analyzed, and detailed the floating bus behavior on the ZX Spectrum +2A/+3.

    A few Spectrum game fixes.
    Thanked by 1Paddy Coleman
  • If you're finished with the A register, you can shave a little bit of time off by doing this instead...

                       push   hl                ; Store display file address
    
                       ld     a,$FF
    
                       ld     (hl),a            ; Draw a black box at the 
                       inc    h                 ; character row/column
                       ld     (hl),a
                       inc    h
                       ld     (hl),a
                       inc    h
                       ld     (hl),a
                       inc    h
                       ld     (hl),a
                       inc    h
                       ld     (hl),a
                       inc    h
                       ld     (hl),a
                       inc    h
                       ld     (hl),a
                       pop    hl                ; Restore display file address
    

    You can also use the stack pointer to speed up restoring the 8 bytes of the original character a touch, too.

    Something for you to ponder, perhaps. ;)

    M

    Thanked by 1Paddy Coleman
  • edited September 2017
    A simpler keypress check:
    key_w	call $28e	;poll keyboard
    	inc e		;if E=FFh (no key is pressed),
    			;INC E will result in 0
    	jr z,key_w	
    

    I tried the above but it does not seem to work... I have the following and it simply seems to loop forever.
    ; ------------------------------------------------------------------------------
    ; Waits until a key is pressed
    ; Provided by Ast_A_Moore on WOS
    
    WAIT_KEY           call   $028E             ; ROM poll keyboard
                       inc    e                 ; If E=$FF (no key pressed)
                                                ; INC E will result in 0
                       jr     z,WAIT_KEY
                       ret
    ; ------------------------------------------------------------------------------
    

    Paddy

    Post edited by Paddy Coleman on
  • I tried the above but it does not seem to work... I have the following and it simply seems to loop forever.
    Have you tried it within your code or on its own? Also, have you tried the other version (that only uses the A register)? I have a feeling something else is at play here. The code I posted is solid.
    Every man should plant a tree, build a house, and write a ZX Spectrum game.

    Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
    and zasm Z80 Assembler syntax highlighter.
    Member of the team that discovered, analyzed, and detailed the floating bus behavior on the ZX Spectrum +2A/+3.

    A few Spectrum game fixes.
    Thanked by 1Paddy Coleman
  • edited September 2017
    Hi Folks,

    The code works but seems rather long winded compared to a high level language e.g. using 8 variables to store the bytes rather than an array/loop. Is this the correct approach or am I missing a Z80 trick?
    Hi Paddy, you want some of the repetative commands
    eg DJNZ , decrement reg B ,jump on NZ of B to adres -127 to +128
       ld B, 8
    start:
      ld a,(hl)
      inc hl
      djnz start
    
    this results in DECrementin B as a counter
    when B = 0, the loop will stop
    succes,
    Post edited by Crisis on
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
    Thanked by 1Paddy Coleman
  • ld a,$FF
    ld b, 8
    start:
    ld (hl),a ; Draw a black box at the
    inc h ; character row/column
    djnz start
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
    Thanked by 1Paddy Coleman
  • The code works but seems rather long winded compared to a high level language e.g. using 8 variables to store the bytes rather than an array/loop.

    You don’t need to define a variable for each stored byte. Just label the beginning of the buffer (and its length), then copy your screen to it:
    		   ld de,STO_B1
    		   ld b,8
    to_buffer	   ld a,(hl)
    		   ld (de),a
    		   inc h
    		   inc de
    		   djnz to_buffer
    

    To draw your black square, use the same loop method:
    		   ld b,8
    		   ld a,$ff
    box		   ld (hl),a
                       inc h
    		   djnz box
    

    Finally, reuse the screen-to-buffer loop, but reverse the source/destination:
    		   ld de,STO_B1
    		   ld b,8
    from_buffer	   ld a,(de)
    		   ld (hl),a
    		   inc h
    		   inc de
    		   djnz from_buffer
    
    

    The complete section of the code will then look like this:
                       push hl          
    		   ld de,STO_B1
    		   ld b,8
    to_buffer	   ld a,(hl)
    		   ld (de),a
    		   inc h
    		   inc de
    		   djnz to_buffer
                       pop hl           
    
                       call WAIT_KEY    
    
                       push hl        
    		   ld b,8
    		   ld a,$ff
    box		   ld (hl),a
                       inc h
    		   djnz box
                       pop hl           
    
                       call WAIT_KEY    
    
                       push hl          
    		   ld de,STO_B1
    		   ld b,8
    from_buffer	   ld a,(de)
    		   ld (hl),a
    		   inc h
    		   inc de
    		   djnz from_buffer
                       pop hl           
    
                       ret              
    
    

    If you align the buffer address to a 256-byte boundary, you can speed up the code a little by replacing INC DE with INC E.
    Every man should plant a tree, build a house, and write a ZX Spectrum game.

    Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
    and zasm Z80 Assembler syntax highlighter.
    Member of the team that discovered, analyzed, and detailed the floating bus behavior on the ZX Spectrum +2A/+3.

    A few Spectrum game fixes.
    Thanked by 1Paddy Coleman
  • I tried the above but it does not seem to work... I have the following and it simply seems to loop forever.
    Have you tried it within your code or on its own? Also, have you tried the other version (that only uses the A register)? I have a feeling something else is at play here. The code I posted is solid.

    Thanks. I am sure it is me and my code. :-). I will test your routine on its own tomorrow and hopefully the reason will become apparent.

    Paddy

  • edited September 2017
    You don’t need to define a variable for each stored byte. Just label the beginning of the buffer (and its length), then copy your screen to it:

    How do you define the variable and it's length? Not seen that yet.

    Many thanks

    Paddy
    Post edited by Paddy Coleman on
  • You don’t need to define a variable for each stored byte. Just label the beginning of the buffer (and its length), then copy your screen to it:

    How do you define the variable and it's length? Not seen that yet.

    Note, I didn’t say “variable,” I said “buffer.”
    Well, it depends on the assembler. For example, the piece of code I posted above will work with what you have—the remaining labels (STO_B2, 3, etc.) will simply remain unused as labels. Many assemblers allow you to define a memory area by size with a DEFS pseudoinstruction. So in your case, you could replace your eight bytes allocated by eight DEFB statements with a single
    label	defs 8
    

    This should reserve eight bytes starting at memory location pointed to by the label label.

    If you’re still a little confused, let me copy your code and replace the relevant sections with mine.
    ; ------------------------------------------------------------------------------
                       org    63000             ; Starting address
    ; ------------------------------------------------------------------------------
    ; Variables
    
    ROW_COL		defw $0000               ; Character row/column
    STO_B1		defs 8		;Buffer (8 bytes)
    ; ------------------------------------------------------------------------------
    
    MAIN               ld     hl,(ROW_COL)
                       ld     b,h
                       ld     c,l
                       call   CALCDF_ADDR
    
                       push hl          
    		   ld de,STO_B1
    		   ld b,8
    to_buffer	   ld a,(hl)
    		   ld (de),a
    		   inc h
    		   inc de
    		   djnz to_buffer
                       pop hl           
    
                       call WAIT_KEY    
    
                       push hl        
    		   ld b,8
    		   ld a,$ff
    box		   ld (hl),a
                       inc h
    		   djnz box
                       pop hl           
    
                       call WAIT_KEY    
    
                       push hl          
    		   ld de,STO_B1
    		   ld b,8
    from_buffer	   ld a,(de)
    		   ld (hl),a
    		   inc h
    		   inc de
    		   djnz from_buffer
                       pop hl           
    
                       ret
    ; ------------------------------------------------------------------------------
    ; Calculate display file address from character row and column
    
    CALCDF_ADDR        ld     a,b
                       and    $0F8
                       add    a,$40
                       ld     h,a
                       ld     a,b
                       and    $07
                       rrca
                       rrca
                       rrca
                       add    a,c
                       ld     l,a
                       ret
    ; ------------------------------------------------------------------------------
    ; Waits until a key is pressed
    
    WAIT_KEY           push   hl                ; Store HL as used elsewhere
                       ld     hl,23560          ; LAST K system variable
                       ld     (hl),$00          ; Put null value there
    WKLOOP             ld     a,(hl)            ; New value of LAST K
                       cp     $00               ; Is it still zero?
                       jr     z,WKLOOP          ; Yes, so no key pressed
                       pop    hl                ; Restore HL registers
                       ret                      ; No, key was pressed
    ; ------------------------------------------------------------------------------
    

    Notice I also slightly optimized the bit where you pass the row/column values into B and C. Instead of multiple memory reads into the accumulator, I used a single LD HL,(**) instruction. DEFW means “define word” (a word is two bytes).
    Every man should plant a tree, build a house, and write a ZX Spectrum game.

    Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
    and zasm Z80 Assembler syntax highlighter.
    Member of the team that discovered, analyzed, and detailed the floating bus behavior on the ZX Spectrum +2A/+3.

    A few Spectrum game fixes.
    Thanked by 1Paddy Coleman
  • Looking for some advice on best practice. The following wee routine simply stores the 8 bytes of a character square, replaces them with a black box and finally restores the original contents.

    Hi Paddy,

    You don't really say why you're doing this. Is it an self-education thing? I'm trying to learn Spectrum C programming with Z88DK so I'm motivated in a similar way. So, how about a challenge?

    Take your original concept, but loop to walk the screen column by column and row by row, blanking and restoring each character cell at a time. Here's a first attempt, with no optimisation so it's hopefully clear what it's doing:
    /*
     * zcc +zx -vn -m -startup=31 -clib=sdcc_iy -O3 --max-allocs-per-node200000 blank_chars.c -o blank_chars -create-app
     */
    
    #include <z80.h>
    #include <arch/zx.h>
    
    int main()
    {
      unsigned char col;
      unsigned char row;
    
      /* Copy the ROM contents into the screen. This is just so it's easier to see it working. */
      unsigned char* rom_ptr;
      unsigned char* screen_ptr;
      for( rom_ptr=(unsigned char*)0,
           screen_ptr=(unsigned char*)0x4000; rom_ptr < (unsigned char*)6144; rom_ptr++,
                                                                              screen_ptr++ )
        {
          *screen_ptr = *rom_ptr;
        }
    
    
      /* Loop, top to bottom, left to right... */
      for ( row=0; row < 24; row++ )
        {
          for ( col=0; col < 32; col++ )
    	{
    	  unsigned char* char_address;
    	  unsigned char  char_line;
    	  unsigned char  char_lines_store[8];
    
    	  /* ...find the screen address of the character.*/
    
    	  char_address = zx_cxy2saddr(col, row);
    
    	  /* Store away the data at each line and replace with 0xFF. */
    
    	  for ( char_line=0; char_line < 8; char_line++ )
    	    {
    	      char_lines_store[char_line] = *char_address;
    	      *char_address = 0xff;
    	      char_address += 256;
    
    	      z80_delay_ms(1);
    	    }
    	  
    	  /* Now go back to the top of the character cell... */
    
    	  char_address = zx_cxy2saddr(col, row);
    
    	  /* ...and restore the cell's lines from the saved data. */
    
    	  for ( char_line=0; char_line < 8; char_line++ )
    	    {
    	      *char_address = char_lines_store[char_line];
    	      char_address += 256;
    
    	      z80_delay_ms(1); 
    	    }
    	  
    	}
        }
    
      return 0;
    }
    

    I haven't timed this. It's got little delays in so you can see the blank/restore cell sort of winking its way down the screen.

    Try it in assembly language?
    Thanked by 1Paddy Coleman
  • Hi Folks,

    The challenge continues... I now have the following which displays a hatched desktop followed by a masked sprite (8x8). You press a key between stages. I am sure to you experts this is basic stuff but I am learning a lot by going through this. Also, I now understand how you can find yourself needing more registers! :-)

    100 CLS 
    110 POKE 63000,12
    120 POKE 63001,16
    130 LET A=USR 63002
    140 STOP 
    
    ; ------------------------------------------------------------------------------
                       org    63000             ; Starting address
    ; ------------------------------------------------------------------------------
    ; Parameters
    
    ROW                defb   $00               ; Character row
    COL                defb   $00               ; Character column
    ; ------------------------------------------------------------------------------
    ; Displays the masked sprite
    
    MAIN               call   DT_DRAW           ; Create desktop pattern
    
                       ld     a,(ROW)           ; Calculate display file address
                       ld     b,a               ; from the character row/column
                       ld     a,(COL)
                       ld     c,a
                       call   CALC_DF_ADDR
    
                       push   hl                ; Store display file address
    
                       call   WAIT_KEY          ; Wait for a key to be pressed
    
    ; Copy old display file data to temporary storage (OLD_Bn)
    
                       ld     de,OLD_B1         ; Address of 1st old storage byte
                       ld     b,8               ; Loop for 8 bytes
    MAIN_LOOP1         ld     a,(hl)            ; Get byte from display file
                       ld     (de),a            ; Store dislay file byte
                       inc    h                 ; Move down 1 pixel row (256
                       inc    de                ; bytes) and next storage byte
                       djnz   MAIN_LOOP1
    
    ; Copy old data to new data
    
                       ld     de,NEW_B1         ; Destination address
                       ld     hl,OLD_B1         ; Source address
                       ld     bc,8              ; Number of bytes to copy
                       ldi                      ; INC DE/HL and DEC BC x 8
                       ldi
                       ldi
                       ldi
                       ldi
                       ldi
                       ldi
                       ldi
    
    ; Create new data by ANDing old data with the mask
    
                       ld     hl,NEW_B1         ; Address of masked sprite data
                       ld     de,MSK_B1         ; Address of mask data
                       ld     b,8               ; Loop for 8 bytes
    MAIN_LOOP2         ld     a,(de)            ; Get mask byte
                       ld     c,a               ; Store in C
                       ld     a,(hl)            ; Get sprite data
                       and    c                 ; AND A with C
                       ld     (hl),a            ; Store modified sprite byte
                       inc    hl                ; Next masked sprite byte
                       inc    de                ; Next mask byte
                       djnz   MAIN_LOOP2
    
    ; Create new data by ORing old data with the pointer
    
                       ld     hl,NEW_B1         ; Address of masked sprite data
                       ld     de,PNT_B1         ; Address of pointer data
                       ld     b,8               ; Loop for 8 bytes
    MAIN_LOOP3         ld     a,(de)            ; Get pointer byte
                       ld     c,a               ; Store in C
                       ld     a,(hl)            ; Get sprite data
                       or     c                 ; OR A with C
                       ld     (hl),a            ; Store modified sprite byte
                       inc    hl                ; Next masked sprite byte
                       inc    de                ; Next pointer byte
                       djnz   MAIN_LOOP3
    
    ; Display new sprite data
    
                       pop    hl                ; Restore display file address
                       push   hl                ; Store display file address
    
                       ld     de,NEW_B1         ; New sprite data (AND/OR)
                       ld     b,8               ; Loop for 8 bytes
    MAIN_LOOP4         ld     a,(de)            ; Get masked sprite data
                       ld     (hl),a            ; Replace display file byte
                       inc    de                ; Next masked sprite byte
                       inc    h                 ; Add 256 i.e. next pixel row
                       djnz   MAIN_LOOP4
    
                       call   WAIT_KEY          ; Wait for a key to be pressed
    
    ; Restore old screen data
    
                       pop    hl                ; Restore display file address
    
                       ld     de,OLD_B1         ; Restore the old 8 bytes
                       ld     b,8               ; Loop for 8 bytes
    MAIN_LOOP5         ld     a,(de)            ; Get old display file byte
                       ld     (hl),a            ; Replace display file byte
                       inc    de                ; Next old display file byte
                       inc    h                 ; Add 256 i.e. next pixel row
                       djnz   MAIN_LOOP5
    
                       ret                      ; Return to BASIC
    
    ; ------------------------------------------------------------------------------
    ; Draw the Desktop
    
    DT_DRAW            ld     hl,16384          ; Start of display file
                       ld     a,170             ; Hatch pattern 10101010
                       ld     c,24              ; Loop for 24 character rows
                       halt
    DT_LOOP1           ld     b,0               ; Loop for 256 bytes
    DT_LOOP2           ld     (hl),a            ; Load byte to display file
                       inc    hl                ; Next display file byte
                       djnz   DT_LOOP2
                       cpl                      ; NOT hatch pattern
                       dec    c
                       jr     nz,DT_LOOP1
                       ret
    ; ------------------------------------------------------------------------------
    ; Calculate display file address from character row and column
    
    CALC_DF_ADDR       ld     a,b
                       and    $0F8
                       add    a,$40
                       ld     h,a
                       ld     a,b
                       and    $07
                       rrca
                       rrca
                       rrca
                       add    a,c
                       ld     l,a
                       ret
    ; ------------------------------------------------------------------------------
    ; Waits until a key is pressed
    ; Provided by Ast_A_Moore on WOS
    
    WAIT_KEY           push   hl                ; Store HL as used elsewhere
                       ld     hl,23560          ; LAST K system variable
                       ld     (hl),$00          ; Put null value there
    WK_LOOP            ld     a,(hl)            ; New value of LAST K
                       cp     $00               ; Is it still zero?
                       jr     z,WK_LOOP         ; Yes, so no key pressed
                       pop    hl                ; Restore HL registers
                       ret
    ; ------------------------------------------------------------------------------
    ; Current Data
    
    OLD_B1             defb   $00               ; 8 bytes used to store current
    OLD_B2             defb   $00               ; contents of the display file
    OLD_B3             defb   $00               ; at row/column
    OLD_B4             defb   $00
    OLD_B5             defb   $00
    OLD_B6             defb   $00
    OLD_B7             defb   $00
    OLD_B8             defb   $00
    
    ; New Data
    
    NEW_B1             defb   $00               ; 8 bytes used to store the
    NEW_B2             defb   $00               ; masked sprite data
    NEW_B3             defb   $00               ; AND/OR
    NEW_B4             defb   $00
    NEW_B5             defb   $00
    NEW_B6             defb   $00
    NEW_B7             defb   $00
    NEW_B8             defb   $00
    
    ; Sprite Mask Data
    
    MSK_B1             defb   0
    MSK_B2             defb   126
    MSK_B3             defb   126
    MSK_B4             defb   126
    MSK_B5             defb   126
    MSK_B6             defb   126
    MSK_B7             defb   126
    MSK_B8             defb   0
    
    ; Sprite Pointer Data
    
    PNT_B1             defb   0
    PNT_B2             defb   126
    PNT_B3             defb   126
    PNT_B4             defb   126
    PNT_B5             defb   126
    PNT_B6             defb   126
    PNT_B7             defb   126
    PNT_B8             defb   0
    ; ------------------------------------------------------------------------------
    

    As always, comments and suggestions welcome.

    Many thanks to everyone for their help and encouragement so far.

    Paddy
  • A simpler keypress check:
    key_w	call $28e	;poll keyboard
    	inc e		;if E=FFh (no key is pressed),
    			;INC E will result in 0
    	jr z,key_w	
    

    I tried the above but it does not seem to work... I have the following and it simply seems to loop forever.
    ; ------------------------------------------------------------------------------
    ; Waits until a key is pressed
    ; Provided by Ast_A_Moore on WOS
    
    WAIT_KEY           call   $028E             ; ROM poll keyboard
                       inc    e                 ; If E=$FF (no key pressed)
                                                ; INC E will result in 0
                       jr     z,WAIT_KEY
                       ret
    ; ------------------------------------------------------------------------------
    

    Paddy

    Well tried this on its own in Basin but it just seems to ignore the key press. Wonder if this is a problem with Basin?

    Paddy
  • you can try this, it will wait for a keypress
    keyloop        RST   56                            ; checks for keypress
                   LD    A,(23557)
                   OR    A         ; CP 0
                   JP    Z,keyloop
    
              ; the rest of your program
    
  • Well tried this on its own in Basin but it just seems to ignore the key press. Wonder if this is a problem with Basin?
    I don’t think it ignores it. If you tried it on its own, it might execute too quickly, and register the key that you keep holding. For example, if you run it with RANDOMIZE USR XXXXX, then when you press ENTER, the program might execute way before you release the key.
    Every man should plant a tree, build a house, and write a ZX Spectrum game.

    Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
    and zasm Z80 Assembler syntax highlighter.
    Member of the team that discovered, analyzed, and detailed the floating bus behavior on the ZX Spectrum +2A/+3.

    A few Spectrum game fixes.
  • MatGubbins wrote: »
    Thanks for doing that thricenightly, I was about to ask if you could post the C --> asm output to compare the code, but you've provided it - cheers. It does make great reading too.

    Heh, this fun!

    I had a brainwave: unwinding the loop by one allows me to use an 8 bit count down instead of a 16 bit one:
          unsigned char scans;
    
          for( scans = 255; scans != 0; scans-- )
    	{
    	  *screen = 0xAA;
    	  screen++;
    	}
          *screen = 0xAA;
          screen++;
    

    Now the scans variable will fit in a single 8 bit register.

    The compiler now produces:
    ld	a,0xff
    l_main_00104:
    	ld	(hl),0xaa
    	inc	hl
    	dec	a
    	or	a, a
    	jr	NZ,l_main_00104
    	ld	(hl),0xaa
    	inc	hl
    

    So that's better, since it's not messing with D and E, but it's got the OR A,A in there which your code avoided by using B and DJNZ. This runs 100 times in 7.6 seconds, so halfway between the first C version and the hand crafted version.

    Hi, 2020 already,
    i dont know if it was mentioned but ' DEC A ' will interfere with the flags so ommitting 'or a,a' will save 4t per loop
    the compiler should know the flags are influenced already so that 'or' is not needed.
    ld	a,0xff
    l_main_00104:
    	ld	(hl),0xaa
    	inc	hl
    	dec	a
    	jr	NZ,l_main_00104
    	ld	(hl),0xaa
    	inc	hl
    

    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
Sign In or Register to comment.