;;####################################################################
;;# GNU Free Documentation License                                   #
;;# Version 1.3, 3 November 2008                                     #
;;#                                                                  #
;;# Copyright (C) 2021 Lumina                                        #
;;# (Paula Garcia Morales, Laura Gil Lopez, Jorge Perez Dominguez)   #
;;#                                                                  #
;;# Everyone is permitted to copy and distribute verbatim copies     #
;;# of this license document, but changing it is not allowed.        #
;;####################################################################


.include "cpctelera.h.s"
.include "renderfunctions.h.s"

mydrawsolidbox20x32::
 ;; COPY2HL_n_INC Macro 
    ;;  Copy Register To (HL) and Increment HL
    ;; INPUT:
    ;;    reg8 - any 8-bits register
    ;;
    .macro COPY2HL_n_INC reg8
        ld   (hl), reg8         ;; [2] (HL) = reg8
        inc   hl                ;; [2] HL++  
    .endm

    ;; DrawSolidBox code starts here (immediately after getting parameters from stack)
    ld     h, d             ;; [1] / HL = DE  
    ld     l, e             ;; [1] \ HL Points to Video Memory, and DE holds a copy which won't be modified
    ld     e, a             ;; [1] E=A (Colour pattern)
    
    ;; Modify code using width to jump to ensure
    ;; that only width bytes are copied each line 
    ld     a, #128          ;; [2] We need to jump 128 bytes (64 COPY2HL_n_INC*2 bytes) minus the width of the sprite * 2 (2B)
    sub    c                ;; [1]  to do as much COPY2HL_n_INC as bytes the Sprite is wide
    sub    c                ;; [1]
    ld (_jr_offset), a      ;; [4] Modify JR data to create the jump we need
    
    ld     c, e             ;; [1] C=E (Colour pattern)
    ld     e, l             ;; [1] Restore DE = HL

    _next_line:
    _jr_offset = .+1
   jr__0                   ;; [3] Self modifying instruction: the '00' will be substituted by the required jump forward. 
                           ;; ... (Note: Writting JR 0 compiles but later it gives odd linking errors)  

    ;; 64 COPY2HL_n_INC c, which are able to copy up to 64 bytes each time.
    ;; That means that each Sprite line should be 64 bytes width at most.
    ;; The JR instruction at the start makes us ignore the COPY2HL_n_INC we don't need 
    ;; (jumping over them) That ensures we will be doing only as much COPY2HL_n_INC 
    ;; as bytes our sprite is wide.
    .rept 64
        COPY2HL_n_INC c         ;; [4] (HL) = c, ++HL { Repeated 64 times }
    .endm
    
    dec    b                ;; [1] Another line finished: we discount it from D
    ret    z                ;; [2/4] If that was the last line, we safely return

    ;; Jump destination pointer to the start of the next line in video memory
    ld     a, #0x8          ;; [2] / HL = DE = DE + 0x800
    add    d                ;; [1] | DE holds the pointer to the start of this line
    ld     h, a             ;; [1] | Adding 0x800 makes HL point to the start of
    ld     d, a             ;; [1] | the next line to be filled in with values
    ld     l, e             ;; [1] \ DE holds a copy which won't be modified
    ;; We check if we have crossed video memory boundaries (which will happen every 8 lines). 
    ;; ... If that happens, bits 13,12 and 11 of destination pointer will be 0
    and   #0x38             ;; [2] leave out only bits 13,12 and 11 from new memory address (00xxx000 00000000)
    jp    nz, _next_line    ;; [3] If any bit from {13,12,11} is not 0, we are still inside 
                            ;; ... video memory boundaries, so proceed with next line

    ;; Every 8 lines, we cross the 16K video memory boundaries and have to
    ;; reposition destination pointer. That means our next line is 16K-0x50 bytes back
    ;; which is the same as advancing 48K+0x50 = 0xC050 bytes, as memory is 64K 
    ;; and our 16bit pointers cycle over it
    ld    hl, #0xC028       ;; [3] We advance destination pointer to next line
    add   hl, de            ;; [3] HL = DE + 0xC050
    ld     d, h             ;; [1] / DE = HL
    ld     e, l             ;; [1] \
    jp   _next_line         ;; [3] Continue copying   
ret




mydrawSprite_20x32::
   ;; Modify code using width to jump in drawSpriteWidth
      ld    a, #126   ;; [2] We need to jump 126 bytes (63 LDIs*2 bytes) minus the width of the sprite * 2 (2B)
      sub   c                 ;; [1]    to do as much LDIs as bytes the Sprite is wide
      sub   c                 ;; [1]
      ld (ds_drawSpriteWidth+#4), a ;; [4] Modify JR data to create the jump we need

      ld    a, b              ;; [1] A = Height (used as counter for the number of lines we have to copy)
      ex   de, hl             ;; [1] Instead of jumping over the next line, we do the inverse operation because 
                              ;; .... it is only 4 cycles and not 10, as a JP would be)

   ds_drawSpriteWidth_next:
      ;; NEXT LINE
      ex   de, hl             ;; [1] HL and DE are exchanged every line to do 16bit maths with DE. 
                              ;; .... This line reverses it before proceeding to copy the next line.
   ds_drawSpriteWidth:
      ;; Draw a sprite-line of n bytes
      ld   bc, #0x800  ;; [3] 0x800 bytes is the distance in memory from one pixel line to the next within every 8 pixel lines
                       ;; ... Each LDI performed will decrease this by 1, as we progress through memory copying the present line
      jr__0            ;; [3] Self modifying instruction: the '00' will be substituted by the required jump forward. 
                       ;; ... (Note: Writting JR 0 compiles but later it gives odd linking errors)
      ldi              ;; [5] <| 63 LDIs, which are able to copy up to 63 bytes each time.
      ldi              ;; [5]  | That means that each Sprite line should be 63 bytes width at most.
      ldi              ;; [5]  | The JR instruction at the start makes us ignore the LDIs we don't need 
      ldi              ;; [5] <| (jumping over them) That ensures we will be doing only as much LDIs 
      ldi              ;; [5] <| as bytes our sprite is wide.
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
      ldi              ;; [5] <|
      ldi              ;; [5] <|
      ldi              ;; [5]  |
      ldi              ;; [5]  |
    
      dec   a          ;; [1] Another line finished: we discount it from A
      ret   z          ;; [2/4] If that was the last line, we safely return

      ;; Jump destination pointer to the start of the next line in video memory
      ex   de, hl      ;; [1] DE has destination, but we have to exchange it with HL to be able to do 16bit maths
      add  hl, bc      ;; [3] We add 0x800 minus the width of the sprite (BC) to destination pointer 
      ld    b, a       ;; [1] Save A into B (B = A)
      ld    a, h       ;; [1] We check if we have crossed video memory boundaries (which will happen every 8 lines). 
                       ;; .... If that happens, bits 13,12 and 11 of destination pointer will be 0
      and   #0x38      ;; [2] leave out only bits 13,12 and 11 from new memory address (00xxx000 00000000)
      ld    a, b       ;; [1] Restore A from B (A = B)
      jp   nz, ds_drawSpriteWidth_next ;; [3] If any bit from {13,12,11} is not 0, we are still inside 
                                       ;; .... video memory boundaries, so proceed with next line

      ;; Every 8 lines, we cross the 16K video memory boundaries and have to
      ;; reposition destination pointer. That means our next line is 16K-0x50 bytes back
      ;; which is the same as advancing 48K+0x50 = 0xC050 bytes, as memory is 64K 
      ;; and our 16bit pointers cycle over it
      ld   bc, #0xC028 ;; [3] We advance destination pointer to next line
      add  hl, bc                ;; [3]  HL += 0xC050
      jp ds_drawSpriteWidth_next ;; [3] Continue copying

ret


mygetScrPrt_20x32::

    ;; Add up X coordinate to screen_memory, so that DE = (screen_start + x)
    ;; (DE += C, as DE = screen_memory, and C = x coordinate) 
    ld    a, e     ;; [1] / E = E + x   (As C = x)
    add   c        ;; [1] |   ( If E + x > 0xFF, Carry is set. We must Add it to D )
    ld    e, a     ;; [1] |
    adc   d        ;; [1] | D = D + (C + A) + Carry   (E = C + A)
    sub   e        ;; [1] | D = D + Carry
    ld    d, a     ;; [1] |   (If E + x did set carry, this will do D += 1, else D += 0)

    ;; Let y' = [ y / 8 ] = int(y / 8) (Integer division by 8)
    ;; Calculate 40y' = (32 + 8)y' (0x28 * y')
    ld    a, b     ;; [1] A = y coordinate (which is stored in b)
    and   #0xF8    ;; [2] A = 8y'   ( and 0xF8 is the same as 8 * int(y / 8) = 8y' )
    ld    l, a     ;; [1] | HL = 8y'  (H = 0, L = 8y')
    ld    h, #0    ;; [2] |
    ld    a, b     ;; [1] A = y coordinate (Save for later use, freeing BC)
    ld    b, h     ;; [1] | BC = 8y'
    ld    c, l     ;; [1] |
    add  hl, hl    ;; [3] HL = 8y' + 8y'   = 16y'
    add  hl, hl    ;; [3] HL = 16y' + 16y' = 32y'
    add  hl, bc    ;; [3] HL = 32y' + 8y'  = 40y'

    ;; Calculate 2048 * (y % 8)  (0x800 * (y % 8))
    and   #0x07    ;; [2]  A = y % 8  (A had y coordinate)
    rlca           ;; [1]  A = 2 (y % 8)
    rlca           ;; [1]  A = 4 (y % 8)
    rlca           ;; [1]  A = 8 (y % 8)
    ;; Now [A 0x00] (Using a as HSB) would be 0x100 * A = 0x100 * 8 (y % 8 )
    ;; So, we only have to add A to H in order to have HL += 0x100 * 8 (y % 8)
    add   h        ;; [1]  | HL += 0x100 * 8 (y % 8)
    ld    h, a     ;; [1]  |

    ;; Add up everything and return
    add  hl, de    ;; [3] HL = 40 * [y / 8] + 2048 * (y % 8) + (screen_start + x)

ret            ;; [3] Return



mysetdrawtilemap::
   ;; Declare global symbols used here

   .globl pp_tilesetPtr 
   .globl pp_widthHeightSet
   .globl pp_restoreWidth
   .globl pp_updateWidth
   .globl pp_incrementHL
   .globl pp_restoreI

      ;; Set (tilesetPtr) placeholder
      ld (pp_tilesetPtr), hl     ;; [5] Save HL into tilesetPtr placeholder

      ;; Set all Width values required by drawTileMap4x8_ag. First two values
      ;; (heightSet, widthSet) are values used at the start of the function for
      ;; initialization. The other one (restoreWidth) restores the value of the
      ;; width after each loop, as it is used as counter and decremented to 0.
      ld (pp_widthHeightSet), bc ;; [6]
      ld     a, c                    ;; [1]
      ld (pp_restoreWidth), a    ;; [4] Set restore width after each loop placeholder
      
      ;; In order to properly show a view of (Width x Height) tiles from within the
      ;; tilemap, every time a row has been drawn, we need to move tilemap pointer
      ;; to the start of the next row. As the complete tilemap is (tilemapWidth) bytes
      ;; wide and we are showing a view only (Width) tiles wide, to complete (tilemapWidth)
      ;; bytes at each loop, we need to add (tilemapWidth - Width) bytes.
      sub_de_a                      ;; [7] tilemapWidth - Width
      ld (pp_updateWidth), de   ;; [6] set the difference in updateWidth placeholder

      ;; Calculate HL update that has to be performed for each new row loop.
      ;; HL advances through video memory as tiles are being drawn. When a row
      ;; is completely drawn, HL is at the right-most place of the screen.
      ;; As each screen row has a width of 0x50 bytes (in standard modes), 
      ;; if the Row that has been drawn has less than 0x50 bytes, this difference
      ;; has to be added to HL to make it point to the start of next screen row.
      ;; As each tile is 4-bytes wide, this amount is (0x50 - 4*Width). Also,
      ;; taking into account that 4*Width cannot exceed 255 (1-byte), a maximum
      ;; of 63 tiles can be considered as Width.
      ld     a, c                ;; [1] A = Width
      add    a                   ;; [1] A = 2*Width
      add    a                   ;; [1] A = 4*Width
      cpl                        ;; [1] A = -4*Width - 1
      add #0x28 + 1              ;; [2] A = -4*Width-1 + 0x50+1 = 0x50 - 4*Width
      ld (pp_incrementHL), a ;; [4] Set HL increment in its placeholder

      ;; Set the restoring of Interrupt Status. drawTileMap4x8_ag disables interrupts before
      ;; drawing each tile row, and then it restores previous interrupt status after the row
      ;; has been drawn. To do this, present interrupt status is considered. This code detects
      ;; present interrupt status and sets a EI/DI instruction at the end of tile row drawing
      ;; to either reactivate interrupts or preserve interrupts disabled.
      ld     a, i             ;; [3] P/V flag set to current interrupt status (IFF2 flip-flop)
      ld     a, #opc_EI       ;; [2] A = Opcode for Enable Interrupts instruction (EI = 0xFB)
      jp    pe, int_enabled   ;; [3] If interrupts are enabled, EI is the appropriate instruction
        ld   a, #opc_DI       ;; [2] Otherwise, it is DI, so A = Opcode for Disable Interrupts instruction (DI = 0xF3)
   
   int_enabled:
      ld (pp_restoreI), a ;; [4] Set the Restore Interrupt status at the end with corresponding DI or EI

ret                     ;; [3] Return to caller



mydrawtilemap::

   ;;;;
   .macro drawSpriteRow MOV
      pop   bc             ;; [3] Get next 2 sprite bytes
      ld  (hl), c          ;; [2] Copy byte 1
      MOV    l             ;; [1] HL++ / HL-- (4-byte aligned) -> next video mem location
      ld  (hl), b          ;; [2] Copy byte 2
      MOV    l             ;; [1] HL++ / HL-- (4-byte aligned) -> next video mem location
      pop   bc             ;; [3] Get next 2 sprite bytes
      ld  (hl), c          ;; [2] Copy byte 3
      MOV    l             ;; [1] HL++ / HL-- (4-byte aligned) -> next video mem location
      ld  (hl), b          ;; [2] Copy byte 4
   .endm
   ;;
   ;;;; LOCAL MACRO: drawTilemap4x8_ag_gen
   ;;;;    All code function is defined as a macro to prevent code duplication on reuse
   ;;;; between ASM/C bindings. As setDrawtilemap4x8_ag ASM/C bindings have to couple
   ;;;; each one with its correct version, different global labels can be generated
   ;;;; from the same source using different pp_parameters. 
   ;;;;    Therefore, ASM/C bindings include this file and use this macro to generate
   ;;;; specific source code that will be compiled, with the appropriate labels.
   ;;;;
   ;;.macro drawTilemap4x8_ag_gen pp_   ;; Set Height and Width of the View Window of the current 
   ;;   ;; tilemap to be drawn (This is set by setDrawTilemap4x8_agf)
   widthHeightSet = .+2
      ld iy, #0000         ;; [4] IYL=View Window Width, IYH=View Window Height

   nextRow:
      ;; Disable interrupts and save SP before starting
      di                   ;; [1] Disable interrupts before starting (we are using SP to read values)
      ld (restoreSP), sp   ;; [6] Save actual SP to restore it in the end
      ;; Start of the code that draws the next tile of the present row being drawn
      ;;
   nexttile:
      ;; Get next tile to be drawn from the tilemap, which is pointed by DE
      ld     a, (de)    ;; [2] A = present tile-ID of the tile to be drawn
      ld     b, a       ;; [1] B = A

      ;; From the tile-ID we hold in B, we need to calculate the Offset of the 
      ;; tile definition (its 32-bytes of screen pixel data). As each tile takes 32-bytes,
      ;; offsets are tile_0: 0-bytes, tile_1: 32-bytes, tile_2: 64-bytes... tile_N: N*32-bytes.
      ;; Therefore, we need to multiply 32*B (32*tile-ID). As this multiplication may result 
      ;; in a 16-bits value, we will perform BC = 32*B. Considering B=[abcdefgh], result 
      ;; has to be BC = [000abcde][fgh00000] (B shifted 5 times left = BC = 32*tile-ID).  
      xor    a       ;; [1] A = [00000000]
      srl    b       ;; [2] B = [0abcdefg] (Right shift, Carry = h)
      rra            ;; [1] A = [h0000000] (Rotate Right + Bit7 = h (Carry insertion))
      srl    b       ;; [2] B = [00abcdef] (Right shift, Carry = g)
      rra            ;; [1] A = [gh000000] (Rotate Right + Bit7 = g (Carry insertion))
      srl    b       ;; [2] B = [000abcde] (Right shift, Carry = f). 
      rra            ;; [1] A = [fgh00000] (Rotate Right + Bit7 = f (Carry insertion)). 
      ld     c, a    ;; [1] C = A. BC = 32*tile-ID complete.

      ;; Make IX point to the 32-byte screen pixel definition of the selected tile.
      ;; For that, we need to add previous calculated tile Offset (BC) and the start location
      ;; of the tileset (IX). So operation is IX = tilesetPtr + Offset = IX + BC. 
   tilesetPtr = .+2
      ld    ix, #0000   ;; [4] IX = Pointer to start of tileset (0000 is placeholder set with tileset address)
      add   ix, bc      ;; [4] IX += Tile Offset  
      ld    sp, ix      ;; [3] Make SP Point to the start of the 32-byte screen pixel data
                        ;; ... definition of the current tile (IX is used to save and restore this pointer)
      ;;
      ;; This section of the code draws 1 8x8 pixels (4x8 bytes) tile
      ;; Uses:
      ;;    SP = Pointer to the start of the 32-bytes screen pixel definition of the tile
      ;;    HL = Video Memory Pointer (top-left-corner)
      ;; Modifies BC 
      ;;

      ;; Draw Sprite Lines using Gray-Code order and Zig-Zag movement
      ;; Gray Code scanline order: 0,1,3,2,6,7,5,4
      drawSpriteRow inc ;; [17] Copy tile line Left-to-Right [>>]
      set    3, h       ;; [ 2] --000---=>--001--- (Next sprite line: 1)
      drawSpriteRow dec ;; [17] Copy tile line Right-to-Left [<<]
      set    4, h       ;; [ 2] --001---=>--011--- (Next sprite line: 3)
      drawSpriteRow inc ;; [17] Copy tile line Left-to-Right [>>]
      res    3, h       ;; [ 2] --011---=>--010--- (Next sprite line: 2)
      drawSpriteRow dec ;; [17] Copy tile line Right-to-Left [<<]
      set    5, h       ;; [ 2] --010---=>--110--- (Next sprite line: 6)
      drawSpriteRow inc ;; [17] Copy tile line Left-to-Right [>>]
      set    3, h       ;; [ 2] --110---=>--111--- (Next sprite line: 7)
      drawSpriteRow dec ;; [17] Copy tile line Right-to-Left [<<] 
      res    4, h       ;; [ 2] --111---=>--101--- (Next sprite line: 5)
      drawSpriteRow inc ;; [17] Copy tile line Left-to-Right [>>]
      res    3, h       ;; [ 2] --101---=>--100--- (Next sprite line: 4)
      drawSpriteRow dec ;; [17] Copy tile line Right-to-Left [<<]
      res    5, h       ;; [ 2] --100---=>--000--- (Next sprite line: 0)

      ;; After drawing the tile, HL points to the same place in video memory
      ;; as it started. We need to move it to the right 4 bytes (the width of 1 tile)
      ;; to point to the place in video memory for the next tile. As this function
      ;; requires tilemap to be 4-bytes aligned in video memory, maximum value 
      ;; for L will be L=0xFC, so we can always safely add 3 to L with INC L, without 
      ;; modifying H. Then for safety reasons, last increment will be INC HL to 
      ;; ensure that H gets incremented when L=0xFF. This saves 1 microsecond
      ;; from LD BC, #4: ADD HL, BC.
      inc    l  ;; [1] /
      inc    l  ;; [1] | HL+=3 (Incrementing L only)  
      inc    l  ;; [1] \ 
      inc   hl  ;; [2] HL++ (HL += 4 in total)

      ;; We now test if we have finished drawing present row of tiles. If that is
      ;; the case, the Width counter will be 0 (IYL=0). 
      inc   de           ;; [2] ++DE (Make tilemapPtr point to next tile to be drawn)
      dec__iyl           ;; [2] --IYL (--Width, One less tile to be drawn in this row)
      jp    nz, nexttile ;; [3] if (IYL!=0), then more tiles are left to be drawn in this row,
                         ;; ... so continue with next tile.
   rowEnd:
      ;; We have finished drawing present row of tiles. We restore SP original value
      ;; and previous interrupt status. This will enable interrupts to occur in a
      ;; safe way, permitting the use of this function along with split rasters
      ;; and/or music played on interrupts
   restoreSP = .+1
      ld    sp, #0000      ;; [3] Restore SP (#0000 is a placeholder)
   restoreI = .
      ei                   ;; [1] Restore previous interrupt status (Enabled or disabled)
                           ;; ... EI gets modified by setDrawTilemap_agf and could by DI instead

      ;; Decrement the Height counter (IYH) as we have finished a complete row.
      ;; If the counter is 0, then we have finished drawing the whole tilemap.
      dec__iyh             ;; [3]   --IYH (--Height)
      jr     z, return     ;; [2/3] if (Height==0) then return

      ;;
      ;; As Height counter is not 0 (IYH > 0), there are more rows to draw.
      ;; Set up pointers before drawing next tile row.
      ;;

      ;; Video Memory Pointer (Currently HL) has to point to next row in the screen.
      ;; As each row takes 0x50 bytes (in standard modes) we need to add to HL
      ;; the difference between the bytes drawn in this row and 0x50 to ensure that
      ;; each loop makes HL increment exactly 0x50 bytes, so that it points to next line.
      ;; Also, as width is measured in tiles, and each tile is 4 bytes-wide, the 
      ;; final calculation will be HL += screenWidth - drawnWidth = 0x50 - 4*width
   incrementHL = .+1
      ld    bc, #0000      ;; [3] BC = (0x50 - 4*width) (#0000 is a placeholder that gets the value)
      add   hl, bc         ;; [3] HL += 0x50 - 4*width

      ;; As IYL has been used as width counter, it has been decremented to 0.
      ;; Restore it to the width value before using it again.
   restoreWidth = .+2
      ld__iyl  #00         ;; [2] IYL = Width (#00 is a placeholder)

      ;; Tilemap pointer (Currently at DE) has to point to the start of the next row 
      ;; of the tilemap to be drawn. Similarly to the Video Memory Pointer, if our tilemap
      ;; is wider than our view width, we need to increment the pointer with the 
      ;; difference between tilemapWidth and our view width to ensure that the pointer
      ;; gets incremented by exactly tilemapWidth at each loop (ensuring that we always
      ;; end up pointing to the first tile of the next row). As we have incremented
      ;; the tilemap pointer by (width), the operation will be 
      ;; TilemapPtr += tilemapWidth - width
      ex    de, hl         ;; [1] Temporarily exchange HL<=>DE to do 16-bit maths for updating DE
   updateWidth = .+1
      ld    bc, #0000      ;; [3] BC = tilemapWidth - width
      add   hl, bc         ;; [3] HL += tilemapWidth - width (TilemapPtr points to first tile of next row)
      ex    de, hl         ;; [1] Restore DE,HL into its proper registers, now with DE incremented

      jp    nextRow        ;; [3] Next Row

      ;; When everything is finished, we safely return
      ;; 
   return:

   ;; Set up association of global symbols with locals
   pp_tilesetPtr     == tilesetPtr
   pp_widthHeightSet == widthHeightSet
   pp_restoreWidth   == restoreWidth
   pp_updateWidth    == updateWidth
   pp_incrementHL    == incrementHL
   pp_restoreI       == restoreI

ret