; Tile test program by Simon Owen ; ; Written to match original ZXodus engine by Andrew Owen ; ; Run on a 48K Spectrum, or changing timing below for 128K ; Requires tiles.bin sample data from ZXodus demo ; ; 2011/09/29/zxodus-engine/ ; Last updated: 2011/9/28 21:50 org &8000 grid_offset:equ 1 ; display offset for left edge num_rows: equ 9 num_cols: equ 9 tile_height:equ 16 line_size: equ 41 ; 41 bytes per rainbow line num_tiles: equ num_rows*num_cols row_offset: equ line_size*tile_height start: ld a,&ff ; &FF file byte for vector table ld hl,&fe00 ; IM2 vector table fill_lp: ld (hl),a inc l jr nz,fill_lp inc h ld (hl),a ; 257th byte ld a,&18 ; JR using &F3 of ROM to jump back to &FFF4 ld (&ffff),a ld a,&c3 ; JP ld (&fff4),a ld hl,im2_handler ld (&fff5),hl ld a,&fe ld i,a im 2 ; ret ; optional return to BASIC halt jr $-1 ; Draw tile in A (*timing sensitive*!) draw_tile: ld c,a ; save tile add a,tile_map%256 ld l,a ld h,tile_map/256 ; tile map entry for tile number ld a,(hl) ; tile value ld l,0 srl a rr l ; /2 rra rr l ; /4 ld h,a ; *64 ld de,tile_gfx add hl,de ld a,c ; restore tile exx add a,a ; *2 add a,rowcol_tab%256 ld l,a ld h,rowcol_tab/256; tile to row/col table ld a,(hl) ; row*2 add a,a ; *4 add a,(hl) ; *6 add a,addr_tab%256 ld e,a ld d,addr_tab/256 ; row in address look-up table inc l ld a,(hl) ; col ld c,a ; save col add a,offset_tab%256 ld l,a ld h,offset_tab/256; column in offset table ld a,c ; restore col ld c,(hl) ; column offset in rainbow code ld b,0 ex de,hl ld e,(hl) inc l ld d,(hl) ; attr base for row inc l ex de,hl add hl,bc ; tile attr addr push hl ; keep for drawing below ex de,hl add a,a ; col*2 ld c,a ; bc=data offset in row REPT 2 ld e,(hl) inc l ld d,(hl) ; display base for row inc l ex de,hl add hl,bc ; tile display addr(s) push hl ex de,hl ENDM exx ld bc,32 data_lp:pop de ; next tile display address REPT 7 ldi ; copy 2 bytes ldi dec e dec e inc d ; next line ENDM ldi ; final bytes ldi jp pe,data_lp pop de ; tile attr address inc b ; ensure B zero after first LDI REPT 15 ldi ; copy 2 bytes ldi ex de,hl ld c,line_size-2 ; offset to next rainbow code line add hl,bc ex de,hl ENDM ldi ; final attrs ldi ret ; Set and return next tile (*timing sensitive*!) next_tile: ld a,(tile_num) and a;inc a ld c,a cp num_tiles sbc a,a and c ld (tile_num),a ret im2_handler: push af push bc push de push hl ex af,af' exx push af push bc push de push hl ld (sp_save+1),sp ; We've got time to draw the next 7 tiles in sequence ld a,(tile_num) ld b,7 draw_lp: push bc call draw_tile call next_tile pop bc djnz draw_lp ; Waste the remaining time until it's time to draw ld bc,22 delay: dec bc ld a,b or c jr nz,delay timing_128: jr timing_48 ; poke &3E (LD A,n) here for 128K timings ex (sp),hl ; 128K timing padding with short expensive instructions ex (sp),hl add hl,hl add hl,hl nop timing_48: ; We should close to cycle 15900 at this point on a 48K machine ; This repeated block expands to 144*41=5094 bytes! rainbow: REPT 144/2, line, 0, 2 ld sp,&5820+((line*4) & ~&1f)+grid_offset+(num_cols*2) ld hl,&0800 ld de,&1810 ld bc,&2820 exx ld hl,&3028 ld de,&0800 ld bc,&1810 push bc push de push hl ld hl,&0030 ld de,&1008 ld bc,&2018 push bc push de push hl exx push bc push de push hl ld sp,&5820+(((line+1)*4) & ~&1f)+grid_offset+(num_cols*2) ld hl,&3838;&0800 ld de,&3838;&1810 ld bc,&3838;&2820 exx ld hl,&3838;&3028 ld de,&3838;&0800 ld bc,&3838;&1810 push bc push de push hl ld hl,&3838;&0030 ld de,&3838;&1008 ld bc,&3838;&2018 push bc push de push hl exx push bc push de push hl ENDM sp_save: ld sp,0 ld a,(tile_num) ld b,9 draw_lp2: push bc call draw_tile call next_tile pop bc djnz draw_lp2 pop hl pop de pop bc pop af ex af,af' exx pop hl pop de pop bc pop af jp &0038 ; optional jump to ROM IM 1 handler to read keyboard ei reti ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; align to next 256-byte boundary defs (-$)%256 ; 16K of graphics data for 256 tiles tile_gfx: incbin "tiles.bin" ; 81 bytes for tile map of tile values tile_map: REPT num_tiles, tile defb tile ; fill with corresponding number to match ZXodus demo ENDM ; 162 bytes for tile to row(*2) and column look-up table rowcol_tab: REPT num_tiles, tile defb (tile/num_cols)*2, tile%num_cols ; row*2, col ENDM ; 9 bytes for column to rainbow code offset look-up table offset_tab: defb 4, 7, 10, 26, 29, 32, 14, 17, 20 ; align to next 256-byte boundary defs (-$)%256 ; 54 bytes for row to base addresses (attr, data2, data1) look-up table addr_tab: defw rainbow+row_offset*0, &4041, &4021 defw rainbow+row_offset*1, &4081, &4061 defw rainbow+row_offset*2, &40c1, &40a1 defw rainbow+row_offset*3, &4801, &40e1 defw rainbow+row_offset*4, &4841, &4821 defw rainbow+row_offset*5, &4881, &4861 defw rainbow+row_offset*6, &48c1, &48a1 defw rainbow+row_offset*7, &5001, &48e1 defw rainbow+row_offset*8, &5041, &5021 ; Next tile to draw tile_num: defb 11 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Assemble-time asserts to check alignments if (tile_map/256) != ((tile_map+num_tiles)/256) .error 'tile_map must not span 256-byte boundary' endif if (rowcol_tab/256) != ((rowcol_tab+162)/256) .error 'rowcol_tab must not span 256-byte boundary' endif if (offset_tab/256) != ((offset_tab+9)/256) .error 'offset_tab must not span 256-byte boundary' endif if (addr_tab/256) != ((addr_tab+54)/256) .error 'addr_tab must not span 256-byte boundary' endif end start ; auto-run address