├── .gitattributes ├── .gitignore ├── README.md ├── bitmap_8bit.asm ├── bitmap_hicolor.asm ├── bitmap_hicolor_vertcompress.asm ├── blend.asm ├── blendgraphics.bin ├── font.bin ├── hw.asm ├── image_8bit.bin ├── image_hicolor.bin ├── palette_8bit.bin ├── spg2xx.inc └── vertstretch.asm /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bin binary 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out.hex 2 | out.bin 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # V.Smile demos 2 | 3 | Various assorted [V.Smile](https://en.wikipedia.org/wiki/V.Smile) demos written in µ'nSP assembly. 4 | 5 | ## Compilation 6 | 7 | The demos can be compiled using [naken_asm](https://github.com/mikeakohn/naken_asm), for example as follows:`naken_asm -type bin hw.asm` 8 | -------------------------------------------------------------------------------- /bitmap_8bit.asm: -------------------------------------------------------------------------------- 1 | .include "spg2xx.inc" 2 | .define hi(addr) ((addr >> 16) & 0x3f) 3 | .define lo(addr) (addr & 0xffff) 4 | 5 | .unsp 6 | .low_address 0 7 | .high_address 0x1ffff 8 | 9 | .org 0x10 10 | 11 | ; allocate space for tile and attribute maps, which are stored in standard RAM 12 | ; the low part of the bitmap address of each line is stored in the tilemap 13 | ; the high part of the bitmap address of each line is stored in the attribute map 14 | ; each word in the attribute map store data for two lines, one in each half 15 | tilemap: 16 | .resw 240 17 | tilemap_end: 18 | attrmap: 19 | .resw 240/2 20 | attrmap_end: 21 | 22 | ; put the program code in suitable ROM area 23 | .org 0x8000 24 | start: 25 | int off ; turn off interrupts as soon as possible 26 | 27 | ld r1, #0 28 | 29 | ; initialize system ctrl 30 | st r1, [SYSTEM_CTRL] 31 | 32 | ; clear watchdog just to be safe 33 | ld r2, #0x55aa 34 | st r2, [WATCHDOG_CLEAR] 35 | 36 | ; set background scroll values 37 | st r1, [PPU_BG1_SCROLL_X] ; scroll X offset of bg 1 = 0 38 | st r1, [PPU_BG1_SCROLL_Y] ; scroll Y offset of bg 1 = 0 39 | 40 | ; set attribute config for bg 1 41 | ; bit 0-1: color depth (3 = 8-bit) 42 | ; bit 2: horizontal flip (0 = no flip) 43 | ; bit 3: vertical flip (0 = no flip) 44 | ; bit 4-5: X size (0 = 8 pixels) 45 | ; bit 6-7: Y size (0 = 8 pixels) 46 | ; bit 8-11: palette (0 = palette 0, colors 0-3 for 2-bit) 47 | ; bit 12-13: depth (0 = bottom layer) 48 | ld r2, #0x03 49 | st r2, [PPU_BG1_ATTR] 50 | 51 | ; set control config for bg 1 52 | ; bit 0: bitmap mode (1 = enable) 53 | ; bit 1: attribute map mode or register mode (0 = map mode) 54 | ; bit 2: wallpaper mode (0 = disable) 55 | ; bit 3: enable bg (1 = enable) 56 | ; bit 4: horizontal line-specific movement (0 = disable) 57 | ; bit 5: horizontal compression (0 = disable) 58 | ; bit 6: vertical compression (0 = disable) 59 | ; bit 7: 16-bit color mode (0 = disable) 60 | ; bit 8: blend (0 = disable) 61 | ld r2, #0x09 62 | st r2, [PPU_BG1_CTRL] 63 | 64 | st r1, [PPU_BG2_CTRL] ; disable bg 2 since bit 3 = 0 65 | 66 | st r1, [PPU_FADE_CTRL] ; clear fade control 67 | 68 | st r1, [PPU_SPRITE_CTRL] ; disable sprites 69 | 70 | ld r1, #lo(image) ; low part of line address 71 | ld r2, #hi(image) ; high part of line address 72 | 73 | ld r3, #tilemap 74 | ld r4, #attrmap 75 | 76 | ; configure the tile and attribute maps 77 | configure_bitmap_loop: 78 | st r1, [r3++] ; set low part of address for odd line 79 | ld r5, r2 ; save high part of address for later 80 | 81 | ; update line address for next line 82 | add r1, #(320/2) 83 | adc r2, #0 ; add 1 to high part if low part overflows 84 | 85 | st r1, [r3++] ; set low part of address for even line 86 | 87 | ld r2, r2 lsl 4 88 | or r5, r2 lsl 4 89 | ld r2, r2 lsr 4 90 | st r5, [r4++] ; set high part of address for a pair of lines 91 | 92 | ; update line address for next line 93 | add r1, #(320/2) 94 | adc r2, #0 95 | 96 | cmp r3, #tilemap_end 97 | jb configure_bitmap_loop 98 | 99 | ; copy palette into palette memory 100 | ld r2, #PPU_COLOR_MEM 101 | ld r3, #palette 102 | ld r4, #(palette_end - palette) 103 | copy_palette_loop: 104 | ld r1, [r3++] 105 | st r1, [r2++] 106 | sub r4, #1 107 | jne copy_palette_loop 108 | 109 | ; set address of bg 1 tilemap 110 | ld r2, #tilemap 111 | st r2, [PPU_BG1_TILE_ADDR] 112 | 113 | ; set address of bg 1 attribute map 114 | ld r2, #attrmap 115 | st r2, [PPU_BG1_ATTR_ADDR] 116 | 117 | ; now done, run infinite loop 118 | loop: jmp loop 119 | 120 | palette: 121 | .binfile "palette_8bit.bin" 122 | palette_end: 123 | 124 | ; configure interrupt vector 125 | ; we disabled interrupts, but still need to set the start address 126 | .org 0xfff5 127 | .dw 0 ;break 128 | .dw 0 ;fiq 129 | .dw start ;reset 130 | .dw 0 ;irq 0 131 | .dw 0 ;irq 1 132 | .dw 0 ;irq 2 133 | .dw 0 ;irq 3 134 | .dw 0 ;irq 4 135 | .dw 0 ;irq 5 136 | .dw 0 ;irq 6 137 | .dw 0 ;irq 7 138 | 139 | image: 140 | .binfile "image_8bit.bin" 141 | 142 | 143 | -------------------------------------------------------------------------------- /bitmap_hicolor.asm: -------------------------------------------------------------------------------- 1 | .include "spg2xx.inc" 2 | .define hi(addr) ((addr >> 16) & 0x3f) 3 | .define lo(addr) (addr & 0xffff) 4 | 5 | .unsp 6 | .low_address 0 7 | .high_address 0x3ffff 8 | 9 | .org 0x10 10 | 11 | ; allocate space for tile and attribute maps, which are stored in standard RAM 12 | ; the low part of the bitmap address of each line is stored in the tilemap 13 | ; the high part of the bitmap address of each line is stored in the attribute map 14 | ; each word in the attribute map store data for two lines, one in each half 15 | tilemap: 16 | .resw 240 17 | tilemap_end: 18 | attrmap: 19 | .resw 240/2 20 | attrmap_end: 21 | 22 | ; put the program code in suitable ROM area 23 | .org 0x8000 24 | start: 25 | int off ; turn off interrupts as soon as possible 26 | 27 | ld r1, #0 28 | 29 | ; initialize system ctrl 30 | st r1, [SYSTEM_CTRL] 31 | 32 | ; clear watchdog just to be safe 33 | ld r2, #0x55aa 34 | st r2, [WATCHDOG_CLEAR] 35 | 36 | ; set background scroll values 37 | st r1, [PPU_BG1_SCROLL_X] ; scroll X offset of bg 1 = 0 38 | st r1, [PPU_BG1_SCROLL_Y] ; scroll Y offset of bg 1 = 0 39 | 40 | ; set attribute config 41 | ; bit 0-1: color depth (0 = 2-bit) 42 | ; bit 2: horizontal flip (0 = no flip) 43 | ; bit 3: vertical flip (0 = no flip) 44 | ; bit 4-5: X size (0 = 8 pixels) 45 | ; bit 6-7: Y size (0 = 8 pixels) 46 | ; bit 8-11: palette (0 = palette 0, colors 0-3 for 2-bit) 47 | ; bit 12-13: depth (0 = bottom layer) 48 | st r1, [PPU_BG1_ATTR] ; set attribute of bg 1 49 | 50 | ; initialize control config for bg 1 51 | ; bit 0: bitmap mode (1 = enable) 52 | ; bit 1: attribute map mode or register mode (0 = map mode) 53 | ; bit 2: wallpaper mode (0 = disable) 54 | ; bit 3: enable bg (1 = enable) 55 | ; bit 4: horizontal line-specific movement (0 = disable) 56 | ; bit 5: horizontal compression (0 = disable) 57 | ; bit 6: vertical compression (0 = disable) 58 | ; bit 7: 16-bit color mode (1 = enable) 59 | ; bit 8: blend (0 = disable) 60 | ld r2, #0x89 61 | st r2, [PPU_BG1_CTRL] ; enable bg 1 in register mode 62 | 63 | st r1, [PPU_BG2_CTRL] ; disable bg 2 since bit 3 = 0 64 | 65 | st r1, [PPU_FADE_CTRL] ; clear fade control 66 | 67 | st r1, [PPU_SPRITE_CTRL] ; disable sprites 68 | 69 | ld r1, #lo(image) ; low part of line address 70 | ld r2, #hi(image) ; high part of line address 71 | 72 | ld r3, #tilemap 73 | ld r4, #attrmap 74 | 75 | ; configure the tile and attribute maps 76 | configure_bitmap_loop: 77 | st r1, [r3++] ; set low part of address for odd line 78 | ld r5, r2 ; save high part of address for later 79 | 80 | ; update line address for next line 81 | add r1, #320 82 | adc r2, #0 ; add 1 to high part if low part overflows 83 | 84 | st r1, [r3++] ; set low part of address for even line 85 | 86 | ld r2, r2 lsl 4 87 | or r5, r2 lsl 4 88 | ld r2, r2 lsr 4 89 | st r5, [r4++] ; set high part of address for a pair of lines 90 | 91 | ; update line address for next line 92 | add r1, #320 93 | adc r2, #0 94 | 95 | cmp r3, #tilemap_end 96 | jb configure_bitmap_loop 97 | 98 | ; set address of bg 1 tilemap 99 | ld r2, #tilemap 100 | st r2, [PPU_BG1_TILE_ADDR] 101 | 102 | ; set address of bg 1 attribute map 103 | ld r2, #attrmap 104 | st r2, [PPU_BG1_ATTR_ADDR] 105 | 106 | ; now done, run infinite loop 107 | loop: jmp loop 108 | 109 | ; configure interrupt vector 110 | ; we disabled interrupts, but still need to set the start address 111 | .org 0xfff5 112 | .dw 0 ;break 113 | .dw 0 ;fiq 114 | .dw start ;reset 115 | .dw 0 ;irq 0 116 | .dw 0 ;irq 1 117 | .dw 0 ;irq 2 118 | .dw 0 ;irq 3 119 | .dw 0 ;irq 4 120 | .dw 0 ;irq 5 121 | .dw 0 ;irq 6 122 | .dw 0 ;irq 7 123 | 124 | image: 125 | .binfile "image_hicolor.bin" 126 | -------------------------------------------------------------------------------- /bitmap_hicolor_vertcompress.asm: -------------------------------------------------------------------------------- 1 | .include "spg2xx.inc" 2 | .define hi(addr) ((addr >> 16) & 0x3f) 3 | .define lo(addr) (addr & 0xffff) 4 | 5 | .unsp 6 | .low_address 0 7 | .high_address 0x3ffff 8 | 9 | .org 0x10 10 | 11 | ; allocate space for tile and attribute maps, which are stored in standard RAM 12 | ; the low part of the bitmap address of each line is stored in the tilemap 13 | ; the high part of the bitmap address of each line is stored in the attribute map 14 | ; each word in the attribute map store data for two lines, one in each half 15 | tilemap: 16 | .resw 240 17 | tilemap_end: 18 | attrmap: 19 | .resw 240/2 20 | attrmap_end: 21 | 22 | ; put the program code in suitable ROM area 23 | .org 0x8000 24 | start: 25 | int off ; turn off interrupts as soon as possible 26 | 27 | ld r1, #0 28 | 29 | ; initialize system ctrl 30 | st r1, [SYSTEM_CTRL] 31 | 32 | ; clear watchdog just to be safe 33 | ld r2, #0x55aa 34 | st r2, [WATCHDOG_CLEAR] 35 | 36 | ; set background scroll values 37 | st r1, [PPU_BG1_SCROLL_X] ; scroll X offset of bg 1 = 0 38 | st r1, [PPU_BG1_SCROLL_Y] ; scroll Y offset of bg 1 = 0 39 | 40 | ; set attribute config 41 | ; bit 0-1: color depth (0 = 2-bit) 42 | ; bit 2: horizontal flip (0 = no flip) 43 | ; bit 3: vertical flip (0 = no flip) 44 | ; bit 4-5: X size (0 = 8 pixels) 45 | ; bit 6-7: Y size (0 = 8 pixels) 46 | ; bit 8-11: palette (0 = palette 0, colors 0-3 for 2-bit) 47 | ; bit 12-13: depth (0 = bottom layer) 48 | st r1, [PPU_BG1_ATTR] ; set attribute of bg 1 49 | 50 | ; initialize control config for bg 1 51 | ; bit 0: bitmap mode (1 = enable) 52 | ; bit 1: attribute map mode or register mode (0 = map mode) 53 | ; bit 2: wallpaper mode (0 = disable) 54 | ; bit 3: enable bg (1 = enable) 55 | ; bit 4: horizontal line-specific movement (0 = disable) 56 | ; bit 5: horizontal compression (0 = disable) 57 | ; bit 6: vertical compression (1 = enable) 58 | ; bit 7: 16-bit color mode (1 = enable) 59 | ; bit 8: blend (0 = disable) 60 | ld r2, #0xc9 61 | st r2, [PPU_BG1_CTRL] ; enable bg 1 in register mode 62 | 63 | st r1, [PPU_BG2_CTRL] ; disable bg 2 since bit 3 = 0 64 | 65 | st r1, [PPU_FADE_CTRL] ; clear fade control 66 | 67 | st r1, [PPU_SPRITE_CTRL] ; disable sprites 68 | 69 | ; set vertical compression amount (0x40 = 2x compressed) 70 | ld r2, #0x40 71 | st r2, [PPU_VERT_COMPRESS_AMOUNT] 72 | 73 | ; set vertical compression offset (0 = center of screen) 74 | st r1, [PPU_VERT_COMPRESS_OFFSET] 75 | 76 | ld r1, #lo(image) ; low part of line address 77 | ld r2, #hi(image) ; high part of line address 78 | 79 | ld r3, #tilemap 80 | ld r4, #attrmap 81 | 82 | ; configure the tile and attribute maps 83 | configure_bitmap_loop: 84 | st r1, [r3++] ; set low part of address for odd line 85 | ld r5, r2 ; save high part of address for later 86 | 87 | ; update line address for next line 88 | add r1, #320 89 | adc r2, #0 ; add 1 to high part if low part overflows 90 | 91 | st r1, [r3++] ; set low part of address for even line 92 | 93 | ld r2, r2 lsl 4 94 | or r5, r2 lsl 4 95 | ld r2, r2 lsr 4 96 | st r5, [r4++] ; set high part of address for a pair of lines 97 | 98 | ; update line address for next line 99 | add r1, #320 100 | adc r2, #0 101 | 102 | cmp r3, #tilemap_end 103 | jb configure_bitmap_loop 104 | 105 | ; set address of bg 1 tilemap 106 | ld r2, #tilemap 107 | st r2, [PPU_BG1_TILE_ADDR] 108 | 109 | ; set address of bg 1 attribute map 110 | ld r2, #attrmap 111 | st r2, [PPU_BG1_ATTR_ADDR] 112 | 113 | ; now done, run infinite loop 114 | loop: jmp loop 115 | 116 | ; configure interrupt vector 117 | ; we disabled interrupts, but still need to set the start address 118 | .org 0xfff5 119 | .dw 0 ;break 120 | .dw 0 ;fiq 121 | .dw start ;reset 122 | .dw 0 ;irq 0 123 | .dw 0 ;irq 1 124 | .dw 0 ;irq 2 125 | .dw 0 ;irq 3 126 | .dw 0 ;irq 4 127 | .dw 0 ;irq 5 128 | .dw 0 ;irq 6 129 | .dw 0 ;irq 7 130 | 131 | image: 132 | .binfile "image_hicolor.bin" 133 | -------------------------------------------------------------------------------- /blend.asm: -------------------------------------------------------------------------------- 1 | .include "spg2xx.inc" 2 | .define color(r,g,b) ((r << 10) | (g << 5) | (b << 0)) 3 | 4 | .unsp 5 | .low_address 0 6 | .high_address 0x1ffff 7 | 8 | .org 0x10 9 | 10 | ; allocate space for the tilemaps, which is stored in standard RAM 11 | ; put the tilemap somewhere other than 0 for test purposes 12 | tilemap1: 13 | .resw (512/64)*(256/64) ;64x64 sized tiles = 8*4 sized tilemap 14 | tilemap1_end: 15 | tilemap2: 16 | .resw (512/64)*(256/64) ;64x64 sized tiles = 8*4 sized tilemap 17 | tilemap2_end: 18 | 19 | ; put the program code in suitable ROM area 20 | .org 0x8000 21 | start: 22 | int off ; turn off interrupts as soon as possible 23 | 24 | ld r1, #0 25 | 26 | ; initialize system ctrl 27 | st r1, [SYSTEM_CTRL] 28 | 29 | ; clear watchdog just to be safe 30 | ld r2, #0x55aa 31 | st r2, [WATCHDOG_CLEAR] 32 | 33 | ; set background scroll values 34 | st r1, [PPU_BG1_SCROLL_X] ; scroll X offset of bg 1 = 0 35 | st r1, [PPU_BG1_SCROLL_Y] ; scroll Y offset of bg 1 = 0 36 | st r1, [PPU_BG2_SCROLL_X] ; scroll X offset of bg 2 = 0 37 | st r1, [PPU_BG2_SCROLL_Y] ; scroll Y offset of bg 2 = 0 38 | 39 | ; set attribute config for bg 1 40 | ; bit 0-1: color depth (0 = 2-bit) 41 | ; bit 2: horizontal flip (0 = no flip) 42 | ; bit 3: vertical flip (0 = no flip) 43 | ; bit 4-5: X size (3 = 64 pixels) 44 | ; bit 6-7: Y size (3 = 64 pixels) 45 | ; bit 8-11: palette (0 = palette 0, colors 0-3 for 2-bit) 46 | ; bit 12-13: depth (0 = bottom layer) 47 | ld r2, #0xf0 48 | st r2, [PPU_BG1_ATTR] ; set attribute of bg 1 49 | 50 | ; set attribute config for bg 2 51 | ; bit 0-1: color depth (0 = 2-bit) 52 | ; bit 2: horizontal flip (0 = no flip) 53 | ; bit 3: vertical flip (0 = no flip) 54 | ; bit 4-5: X size (3 = 64 pixels) 55 | ; bit 6-7: Y size (3 = 64 pixels) 56 | ; bit 8-11: palette (1 = palette 1, colors 16-19 for 2-bit) 57 | ; bit 12-13: depth (3 = top layer) 58 | or r2, #0x31f0 59 | st r2, [PPU_BG2_ATTR] 60 | 61 | ; set control config for bg 1 62 | ; bit 0: bitmap mode (0 = disable) 63 | ; bit 1: attribute map mode or register mode (1 = register mode) 64 | ; bit 2: wallpaper mode (0 = disable) 65 | ; bit 3: enable bg (1 = enable) 66 | ; bit 4: horizontal line-specific movement (0 = disable) 67 | ; bit 5: horizontal compression (0 = disable) 68 | ; bit 6: vertical compression (0 = disable) 69 | ; bit 7: 16-bit color mode (0 = disable) 70 | ; bit 8: blend (0 = disable) 71 | ld r2, #0x0a 72 | st r2, [PPU_BG1_CTRL] 73 | 74 | ; set control config for bg 1 75 | ; bit 0: bitmap mode (0 = disable) 76 | ; bit 1: attribute map mode or register mode (1 = register mode) 77 | ; bit 2: wallpaper mode (0 = disable) 78 | ; bit 3: enable bg (1 = enable) 79 | ; bit 4: horizontal line-specific movement (0 = disable) 80 | ; bit 5: horizontal compression (0 = disable) 81 | ; bit 6: vertical compression (0 = disable) 82 | ; bit 7: 16-bit color mode (0 = disable) 83 | ; bit 8: blend (1 = enable) 84 | ld r2, #0x10a 85 | st r2, [PPU_BG2_CTRL] 86 | 87 | st r1, [PPU_FADE_CTRL] ; clear fade control 88 | 89 | ld r2, #1 90 | st r2, [PPU_BLEND_LEVEL] ; set blend level to 50% 91 | 92 | ld r2, #1 93 | st r2, [PPU_SPRITE_CTRL] ; enable sprites 94 | 95 | ; clear bg 1 tile map 96 | ld r2, #1 97 | ld r3, #tilemap1 98 | ld r4, #tilemap1_end 99 | clear_tilemap1_loop: 100 | st r2, [r3++] 101 | cmp r3, r4 102 | jb clear_tilemap1_loop 103 | 104 | ; clear bg 2 tile map 105 | ld r2, #0 106 | ld r3, #tilemap2 107 | ld r4, #tilemap2_end 108 | clear_tilemap2_loop: 109 | st r2, [r3++] 110 | cmp r3, r4 111 | jb clear_tilemap2_loop 112 | 113 | ; clear sprite memory 114 | ld r2, #0 115 | ld r3, #PPU_SPRITE_MEM 116 | ld r4, #PPU_SPRITE_MEM + 0x400 117 | clear_sprite_loop: 118 | st r2, [r3++] 119 | cmp r3, r4 120 | jb clear_sprite_loop 121 | 122 | ; set address of bg 1 tilemap 123 | ld r2, #tilemap1 124 | st r2, [PPU_BG1_TILE_ADDR] 125 | 126 | ; set address of bg 2 tilemap 127 | ld r2, #tilemap2 128 | st r2, [PPU_BG2_TILE_ADDR] 129 | 130 | ; set address of tile graphics data 131 | ; the register only stores the 16 most significant bits of a 22-bit address 132 | ; lowest 6 bits are expected to be zero, graphics therefore need to be 64-word aligned. 133 | ld r2, #(graphics >> 6) 134 | st r2, [PPU_BG1_SEGMENT_ADDR] 135 | st r2, [PPU_BG2_SEGMENT_ADDR] 136 | st r2, [PPU_SPRITE_SEGMENT_ADDR] 137 | 138 | ; set color 0 of palette 0 139 | ld r2, #color(29,26,15) 140 | st r2, [PPU_COLOR(0)] 141 | 142 | ;set color 0 of other palettes 143 | ld r2, #0x8000 144 | st r2, [PPU_COLOR(16)] 145 | st r2, [PPU_COLOR(32)] 146 | st r2, [PPU_COLOR(48)] 147 | st r2, [PPU_COLOR(64)] 148 | 149 | ; set color 1 of palette 0 and 1 150 | ld r2, #color(31,0,0) 151 | st r2, [PPU_COLOR(1)] 152 | st r2, [PPU_COLOR(17)] 153 | 154 | ; set color 2 of palette 0 and 1 155 | ld r2, #color(0,0,31) 156 | st r2, [PPU_COLOR(2)] 157 | st r2, [PPU_COLOR(18)] 158 | 159 | ; set color 3 of palette 0+1 160 | ld r2, #color(0,0,0) 161 | st r2, [PPU_COLOR(3)] 162 | st r2, [PPU_COLOR(19)] 163 | 164 | ; set color 1 of palette 2 165 | ld r2, #color(0,31,0) 166 | st r2, [PPU_COLOR(33)] 167 | 168 | ; set color 1 of palette 3 169 | ld r2, #color(0,0,31) 170 | st r2, [PPU_COLOR(49)] 171 | 172 | ; set color 1 of palette 4 173 | ld r2, #color(31,31,31) 174 | st r2, [PPU_COLOR(65)] 175 | 176 | ; write tile map contents 177 | 178 | ; the position of a specific tile can be calculated by: 179 | ; tilemap start address + (row * number of columns) + column 180 | ; where row and column values are 0-indexed 181 | ; number of columns is 512 / horizontal size 182 | ; number of rows is 256 / vertical size 183 | 184 | ; the start address of the tile to draw is determined by 185 | ; graphics start address + tile size in words * tile ID 186 | ; where tile size in words is calculated by: 187 | ; (vertical size * horizontal size * color depth in bits) / 16 188 | 189 | ld r2, #2 190 | st r2, [tilemap1+1] ; left red triangle 191 | st r2, [tilemap1+3] ; right red triangle 192 | 193 | ld r2, #3 194 | st r2, [tilemap2+1] ; left blue triangle 195 | 196 | ld r2, #4 197 | st r2, [tilemap2+(8*1)+1] ; left black square 198 | st r2, [tilemap1+(8*1)+2] ; middle black square 199 | 200 | ; set tile to use for sprites 201 | ld r2, #3 202 | st r2, [PPU_SPRITE_TILE(0)] ; right blue triangle 203 | ld r2, #4 204 | st r2, [PPU_SPRITE_TILE(1)] ; right black square 205 | ld r2, #2 206 | st r2, [PPU_SPRITE_TILE(2)] 207 | st r2, [PPU_SPRITE_TILE(3)] 208 | st r2, [PPU_SPRITE_TILE(4)] 209 | st r2, [PPU_SPRITE_TILE(5)] 210 | 211 | ; set tile X positions 212 | ; note that the coordinates of a sprite refers to its center point 213 | ; with its coordinate system having screen position x=160, y=128 as its origin 214 | ; and higher Y values going upwards 215 | ld r2, #64 216 | st r2, [PPU_SPRITE_X(0)] 217 | st r2, [PPU_SPRITE_X(1)] 218 | ld r2, #-64 219 | st r2, [PPU_SPRITE_X(2)] 220 | ld r2, #-48 221 | st r2, [PPU_SPRITE_X(3)] 222 | ld r2, #-32 223 | st r2, [PPU_SPRITE_X(4)] 224 | ld r2, #-16 225 | st r2, [PPU_SPRITE_X(5)] 226 | 227 | ; set tile Y positions 228 | ld r2, #96 229 | st r2, [PPU_SPRITE_Y(0)] 230 | ld r2, #32 231 | st r2, [PPU_SPRITE_Y(1)] 232 | ld r2, #-32 233 | st r2, [PPU_SPRITE_Y(2)] 234 | st r2, [PPU_SPRITE_Y(3)] 235 | st r2, [PPU_SPRITE_Y(4)] 236 | st r2, [PPU_SPRITE_Y(5)] 237 | 238 | ; set attribute config for sprites 239 | ; bit 0-1: color depth (0 = 2-bit) 240 | ; bit 2: horizontal flip (0 = no flip) 241 | ; bit 3: vertical flip (0 = no flip) 242 | ; bit 4-5: X size (3 = 64 pixels) 243 | ; bit 6-7: Y size (3 = 64 pixels) 244 | ; bit 8-11: palette (1 = palette 1, colors 16-19 for 2-bit) 245 | ; bit 12-13: depth (3 = top layer) 246 | ; bit 14: blend (1 = enable) 247 | ld r2, #0x71f0 248 | st r2, [PPU_SPRITE_ATTR(0)] 249 | st r2, [PPU_SPRITE_ATTR(1)] 250 | 251 | ; bottom triangle sprite attributes 252 | ; same as above but with different depths and palettes 253 | 254 | ; bit 8-11: palette (palette 1, colors 16-19 for 2-bit) 255 | ; bit 12-13: depth (0 = bottom layer) 256 | ld r2, #0x41f0 257 | st r2, [PPU_SPRITE_ATTR(2)] 258 | 259 | ; bit 8-11: palette (palette 2, colors 32-35 for 2-bit) 260 | ; bit 12-13: depth (1) 261 | ld r2, #0x52f0 262 | st r2, [PPU_SPRITE_ATTR(3)] 263 | 264 | ; bit 8-11: palette (palette 3, colors 48-51 for 2-bit) 265 | ; bit 12-13: depth (2) 266 | ld r2, #0x63f0 267 | st r2, [PPU_SPRITE_ATTR(4)] 268 | 269 | ; bit 8-11: palette (palette 4, colors 64-67 for 2-bit) 270 | ; bit 12-13: depth (3 = top layer) 271 | ld r2, #0x74f0 272 | st r2, [PPU_SPRITE_ATTR(5)] 273 | 274 | ; now done, run infinite loop 275 | loop: jmp loop 276 | 277 | ; configure interrupt vector 278 | ; we disabled interrupts, but still need to set the start address 279 | .org 0xfff5 280 | .dw 0 ;break 281 | .dw 0 ;fiq 282 | .dw start ;reset 283 | .dw 0 ;irq 0 284 | .dw 0 ;irq 1 285 | .dw 0 ;irq 2 286 | .dw 0 ;irq 3 287 | .dw 0 ;irq 4 288 | .dw 0 ;irq 5 289 | .dw 0 ;irq 6 290 | .dw 0 ;irq 7 291 | 292 | ; the graphics data needs to be 64-word aligned as mentioned earlier 293 | .align_bits 64*16 294 | graphics: 295 | .binfile "blendgraphics.bin" 296 | -------------------------------------------------------------------------------- /blendgraphics.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sp1187/vsmile-demos/43d49cac7a91a1774668097d8f8eaca4ea9ae1c5/blendgraphics.bin -------------------------------------------------------------------------------- /font.bin: -------------------------------------------------------------------------------- 1 | T@TDDTTDDT@TDDTDDT@PD@DTDDT@PT@TT@PT@DTDTTDTDDDDPDDPDP@D@P@@TPDPTD@PTTDDTTDD@@@T@@TP@@DDDTDT@PT@@@P@@T@@T@DTTPDT@TTDTDDTT@TTTTPDD@D@P@@TPDDDPPTPDDTDPT@TPDDTDPTPDDDDDPTTDDDDDDPDDT@TDDTTT@PP@DTPDPT@@T@DTDDDT@PD@TTDDDP@@T@PT@@T@@TT@PT@@@TTT@DTD@TTTTDTTP@DTTDDDTD@TTT@@@@@@PPUTPUTPP@TPP@PPP@P@P@QPPP@@P@@P@PPP@PUUP@@T@@@@T@@P@PPTP@@@@@@TPP@TPPPPPPPPUTPPTPPPPPTP@@@PPPPTP@@@@@@@@@P@@PTT@P@PP@@PPQTQTQTPP@PTPPPPP@PP@TPTTPPTTTT@@@@@TPPPPQ@UQ@PPPTPTTUTQPPPPTUQTPTPPPPPPPPPPPPPPT@@@@@@PP@PPPQUTTTPPP@PPPP@@@@TP@TPPP@PPPPPPPP@PPUU@PPTTPPPPTTPTPPPTTPP@@@@@TPPPPPP@P@P@@@@@@TPPUTQQPPPPPPTTPTPPTTTP@PPQPPPP@PPTPTP@TT@@@@T@@@@@@@@@T@@QPPDDTDPTDTTDDTDDTTDTDPTTTDTTDTT@TTDTTDTTTTTDTDDDTDD@D@D@@TT@TT@TTTT@PT@@TTTDDTTD@DTTDDTDDDTDDDTD@TTTDTP@D@DDPTDTD@D@DDTPDPTDDTT@TTTT@TT@TTTTPDDTD@P@@TTDT@P@TTDTT@@T@TT@TT@TP@TT@@T@@T@@TDTTDDDDTTDT@TTDTT@@T@PT@DTT@@TDTTDTTDTTDTTDTTTTDTTDTTDDT@@T@@TTTT@TTTTDDTD@TTTTDTD@T@TDDTDTTDDDT@@@@@@@@@TQ@Q@T@@PUUPPPPP@P@@@@@@@@PPPPT@AQEEAQ@TPPPTTPPTPT@EADEAD@TTPP@@T@@T@@@P@P@P@PPTDDDDDD@@@@PP@PPPPPPPDDPUPPTPPUPPDUDPU@@PPTTPT@PTQPPTPT@@PTUPPPUTPPPPPUPP@UTPU@PUTTUTPU@PUT@UTUPUTUTPU@PUTT@@@TTT@@@T@T@@TT@@@T@PUP@QPPUQTPPPPPPTPPPPP@PPPPQPPPPPPPPPPPP@PPTTTPPPPPPTPPPPP@PPPPPPPPPTP@@PPUPPUPPPPPPPTTTPTT@TPTQPTPTPTT@@TPTTEUQ@PP@PTPTPTP@PTPPTP@@@@PT@@@@P@@@@P@@@@PPTPPPPPP@QPPPPTPP@PPQPPPPP@@T@@PPTQTP@TTT@TTTTPPPTP -------------------------------------------------------------------------------- /hw.asm: -------------------------------------------------------------------------------- 1 | .include "spg2xx.inc" 2 | .define color(r,g,b) ((r << 10) | (g << 5) | (b << 0)) 3 | 4 | .unsp 5 | .low_address 0 6 | .high_address 0x1ffff 7 | 8 | .org 0x10 9 | 10 | ; allocate space for the tilemap, which is stored in standard RAM 11 | ; put the tilemap somewhere other than 0 for test purposes 12 | tilemap: 13 | .resw (512/8)*(256/8) ; 8x8 sized tiles = 64*32 sized tilemap 14 | tilemap_end: 15 | 16 | ; put the program code in suitable ROM area 17 | .org 0x8000 18 | start: 19 | int off ; turn off interrupts as soon as possible 20 | 21 | ld r1, #0 22 | 23 | ; initialize system ctrl 24 | st r1, [SYSTEM_CTRL] 25 | 26 | ; clear watchdog just to be safe 27 | ld r2, #0x55aa 28 | st r2, [WATCHDOG_CLEAR] 29 | 30 | ; set background scroll values for bg 1 31 | st r1, [PPU_BG1_SCROLL_X] ; scroll X offset of bg 1 = 0 32 | st r1, [PPU_BG1_SCROLL_Y] ; scroll Y offset of bg 1 = 0 33 | 34 | ; set attribute config for bg 1 35 | ; bit 0-1: color depth (0 = 2-bit) 36 | ; bit 2: horizontal flip (0 = no flip) 37 | ; bit 3: vertical flip (0 = no flip) 38 | ; bit 4-5: X size (0 = 8 pixels) 39 | ; bit 6-7: Y size (0 = 8 pixels) 40 | ; bit 8-11: palette (0 = palette 0, colors 0-3 for 2-bit) 41 | ; bit 12-13: depth (0 = bottom layer) 42 | st r1, [PPU_BG1_ATTR] ; set attribute of bg 1 43 | 44 | ; set control config for bg 1 45 | ; bit 0: bitmap mode (0 = disable) 46 | ; bit 1: attribute map mode or register mode (1 = register mode) 47 | ; bit 2: wallpaper mode (0 = disable) 48 | ; bit 3: enable bg (1 = enable) 49 | ; bit 4: horizontal line-specific movement (0 = disable) 50 | ; bit 5: horizontal compression (0 = disable) 51 | ; bit 6: vertical compression (0 = disable) 52 | ; bit 7: 16-bit color mode (0 = disable) 53 | ; bit 8: blend (0 = disable) 54 | ld r2, #0x0a 55 | st r2, [PPU_BG1_CTRL] 56 | 57 | st r1, [PPU_BG2_CTRL] ; disable bg 2 since bit 3 = 0 58 | 59 | st r1, [PPU_FADE_CTRL] ; clear fade control 60 | 61 | st r1, [PPU_SPRITE_CTRL] ; disable sprites 62 | 63 | ; clear tilemap 64 | ld r2, #' ' ; ASCII space 65 | ld r3, #tilemap 66 | ld r4, #tilemap_end 67 | clear_tilemap_loop: 68 | st r2, [r3++] 69 | cmp r3, r4 70 | jb clear_tilemap_loop 71 | 72 | ;set address of bg 1 tilemap 73 | ld r2, #tilemap 74 | st r2, [PPU_BG1_TILE_ADDR] 75 | 76 | ; set address of tile graphics data 77 | ; the register only stores the 16 most significant bits of a 22-bit address 78 | ; lowest 6 bits are expected to be zero, graphics therefore need to be 64-word aligned. 79 | ld r2, #(font >> 6) 80 | st r2, [PPU_BG1_SEGMENT_ADDR] 81 | 82 | ; set color 0 of palette 83 | ld r2, #color(29,26,15) 84 | st r2, [PPU_COLOR(0)] 85 | 86 | ; set color 1 of palette 87 | ld r2, #color(0,8,16) 88 | st r2, [PPU_COLOR(1)] 89 | 90 | ; current palette also uses color 2 and 3 91 | ; though our graphics only use color 0-1 92 | 93 | ; write string into tilemap 94 | 95 | ; the position of a specific tile can be calculated by: 96 | ; tilemap start address + (row * number of columns) + column 97 | ; where row and column values are 0-indexed 98 | ; number of columns is 512 / horizontal size 99 | ; number of rows is 256 / vertical size 100 | 101 | ; start string in row 2, column 3 102 | ld r3, #(tilemap + 64*2 + 3) 103 | 104 | ; the start address of the sprite to draw is determined by 105 | ; graphics start address + sprite size in words * tile ID 106 | ; where sprite size in words is calculated by: 107 | ; (vertical size * horizontal size * color depth in bits) / 16 108 | 109 | ld r2, #'H' ; write some characters 110 | st r2, [r3++] 111 | 112 | ld r2, #'e' 113 | st r2, [r3++] 114 | 115 | ld r2, #'y' 116 | st r2, [r3++] 117 | 118 | ld r2, #'!' 119 | st r2, [r3++] 120 | 121 | ld r2, #' ' 122 | st r2, [r3++] 123 | 124 | ld r2, #'V' 125 | st r2, [r3++] 126 | 127 | ld r2, #'.' 128 | st r2, [r3++] 129 | 130 | ld r2, #'S' 131 | st r2, [r3++] 132 | 133 | ld r2, #'m' 134 | st r2, [r3++] 135 | 136 | ld r2, #'i' 137 | st r2, [r3++] 138 | 139 | ld r2, #'l' 140 | st r2, [r3++] 141 | 142 | ld r2, #'e' 143 | st r2, [r3++] 144 | 145 | ld r2, #'!' 146 | st r2, [r3++] 147 | 148 | ; now done, run infinite loop 149 | loop: jmp loop 150 | 151 | ; configure interrupt vector 152 | ; we disabled interrupts, but still need to set the start address 153 | .org 0xfff5 154 | .dw 0 ;break 155 | .dw 0 ;fiq 156 | .dw start ;reset 157 | .dw 0 ;irq 0 158 | .dw 0 ;irq 1 159 | .dw 0 ;irq 2 160 | .dw 0 ;irq 3 161 | .dw 0 ;irq 4 162 | .dw 0 ;irq 5 163 | .dw 0 ;irq 6 164 | .dw 0 ;irq 7 165 | 166 | ; the graphics data needs to be 64-word aligned as mentioned earlier 167 | .align_bits 64*16 168 | font: 169 | .binfile "font.bin" 170 | -------------------------------------------------------------------------------- /image_8bit.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sp1187/vsmile-demos/43d49cac7a91a1774668097d8f8eaca4ea9ae1c5/image_8bit.bin -------------------------------------------------------------------------------- /image_hicolor.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sp1187/vsmile-demos/43d49cac7a91a1774668097d8f8eaca4ea9ae1c5/image_hicolor.bin -------------------------------------------------------------------------------- /palette_8bit.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sp1187/vsmile-demos/43d49cac7a91a1774668097d8f8eaca4ea9ae1c5/palette_8bit.bin -------------------------------------------------------------------------------- /spg2xx.inc: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; This is an include file for the SunPlus SPG2xx game SoC series. 3 | ;; This is a part of the naken_asm assembler 4 | ;; 5 | ;; For more info: 6 | ;; http://www.mikekohn.net/micro/naken_asm.php 7 | ;; 8 | 9 | PPU_BG1_SCROLL_X equ 0x2810 10 | PPU_BG1_SCROLL_Y equ 0x2811 11 | PPU_BG1_ATTR equ 0x2812 12 | PPU_BG1_CTRL equ 0x2813 13 | PPU_BG1_TILE_ADDR equ 0x2814 14 | PPU_BG1_ATTR_ADDR equ 0x2815 15 | PPU_BG2_SCROLL_X equ 0x2816 16 | PPU_BG2_SCROLL_Y equ 0x2817 17 | PPU_BG2_ATTR equ 0x2818 18 | PPU_BG2_CTRL equ 0x2819 19 | PPU_BG2_TILE_ADDR equ 0x281a 20 | PPU_BG2_ATTR_ADDR equ 0x281b 21 | PPU_VERT_COMPRESS_AMOUNT equ 0x281c 22 | PPU_VERT_COMPRESS_OFFSET equ 0x281d 23 | PPU_BG1_SEGMENT_ADDR equ 0x2820 24 | PPU_BG2_SEGMENT_ADDR equ 0x2821 25 | PPU_SPRITE_SEGMENT_ADDR equ 0x2822 26 | PPU_BLEND_LEVEL equ 0x282a 27 | PPU_FADE_CTRL equ 0x2830 28 | PPU_IRQ_POS_Y equ 0x2836 29 | PPU_IRQ_POS_X equ 0x2837 30 | PPU_CURRENT_LINE equ 0x2838 31 | PPU_LIGHTPEN_LATCH_1ST_LINE equ 0x2839 32 | PPU_TV_CTRL1 equ 0x283c 33 | PPU_TV_CTRL2 equ 0x283d 34 | PPU_LIGHTPEN_Y equ 0x283e 35 | PPU_LIGHTPEN_X equ 0x283f 36 | PPU_SPRITE_CTRL equ 0x2842 37 | PPU_STN_LCD_CTRL equ 0x2854 38 | PPU_IRQ_ENABLE equ 0x2862 39 | PPU_IRQ_STATUS equ 0x2863 40 | PPU_SPRITE_DMA_SRC equ 0x2870 41 | PPU_SPRITE_DMA_DEST equ 0x2871 42 | PPU_SPRITE_DMA_LEN equ 0x2872 43 | 44 | PPU_LINE_SCROLL_MEM equ 0x2900 45 | PPU_LINE_COMPRESS_MEM equ 0x2a00 46 | PPU_COLOR_MEM equ 0x2b00 47 | PPU_SPRITE_MEM equ 0x2c00 48 | 49 | .define PPU_LINE_SCROLL(n) (0x2900 + (n)) 50 | .define PPU_LINE_COMPRESS(n) (0x2a00 + (n)) 51 | .define PPU_COLOR(n) (0x2b00 + (n)) 52 | .define PPU_SPRITE_TILE(n) (0x2c00 + (n)*4) 53 | .define PPU_SPRITE_X(n) (0x2c01 + (n)*4) 54 | .define PPU_SPRITE_Y(n) (0x2c02 + (n)*4) 55 | .define PPU_SPRITE_ATTR(n) (0x2c03 + (n)*4) 56 | 57 | .define SPU_CH_WAVE_ADDR(n) (0x3000 + (n)*16) 58 | .define SPU_CH_MODE(n) (0x3001 + (n)*16) 59 | .define SPU_CH_LOOP_ADDR(n) (0x3002 + (n)*16) 60 | .define SPU_CH_PAN_VOL(n) (0x3003 + (n)*16) 61 | .define SPU_CH_ENVELOPE0(n) (0x3004 + (n)*16) 62 | .define SPU_CH_ENVELOPE_DATA(n) (0x3005 + (n)*16) 63 | .define SPU_CH_ENVELOPE1(n) (0x3006 + (n)*16) 64 | .define SPU_CH_ENVELOPE_ADDR_HI(n) (0x3007 + (n)*16) 65 | .define SPU_CH_ENVELOPE_ADDR_LO(n) (0x3008 + (n)*16) 66 | .define SPU_CH_WAVE_DATA_PREV(n) (0x3009 + (n)*16) 67 | .define SPU_CH_ENVELOPE_LOOP_CTRL(n) (0x300a + (n)*16) 68 | .define SPU_CH_WAVE_DATA(n) (0x300b + (n)*16) 69 | .define SPU_CH_ADPCM_SEL(n) (0x300d + (n)*16) 70 | 71 | .define SPU_CH_PHASE_HI(n) (0x3200 + (n)*16) 72 | .define SPU_CH_PHASE_ACCUM_HI(n) (0x3201 + (n)*16) 73 | .define SPU_CH_TARGET_PHASE_HI(n) (0x3202 + (n)*16) 74 | .define SPU_CH_RAMP_DOWN_CLOCK(n) (0x3203 + (n)*16) 75 | .define SPU_CH_PHASE_LO(n) (0x3204 + (n)*16) 76 | .define SPU_CH_PHASE_ACCUM_LO(n) (0x3205 + (n)*16) 77 | .define SPU_CH_TARGET_PHASE_LO(n) (0x3206 + (n)*16) 78 | .define SPU_CH_PHASE_CTRL(n) (0x3207 + (n)*16) 79 | 80 | SPU_CHANNEL_ENABLE equ 0x3400 81 | SPU_MAIN_VOLUME equ 0x3401 82 | SPU_CHANNEL_FIQ_ENABLE equ 0x3402 83 | SPU_CHANNEL_FIQ_STATUS equ 0x3403 84 | SPU_BEAT_BASE_COUNT equ 0x3404 85 | SPU_BEAT_COUNT equ 0x3405 86 | SPU_ENVCLK0_LO equ 0x3406 87 | SPU_ENVCLK0_HI equ 0x3407 88 | SPU_ENVCLK1_LO equ 0x3408 89 | SPU_ENVCLK1_HI equ 0x3409 90 | SPU_ENV_RAMP_DOWN equ 0x340a 91 | SPU_CHANNEL_STOP equ 0x340b 92 | SPU_CHANNEL_ZERO_CROSS equ 0x340c 93 | SPU_CTRL equ 0x340d 94 | SPU_COMPRESS_CTRL equ 0x340e 95 | SPU_CHANNEL_STATUS equ 0x340f 96 | SPU_WAVE_IN_L equ 0x3410 97 | SPU_FIFO_WRITE_DATA equ 0x3410 98 | SPU_WAVE_IN_R equ 0x3411 99 | SPU_FIFO_IRQ_CTRL equ 0x3411 100 | SPU_WAVE_OUT_L equ 0x3412 101 | SPU_WAVE_OUT_R equ 0x3413 102 | SPU_CHANNEL_REPEAT equ 0x3414 103 | SPU_CHANNEL_ENV_MODE equ 0x3415 104 | SPU_CHANNEL_TONE_RELEASE equ 0x3416 105 | SPU_ENV_IRQ equ 0x3417 106 | SPU_CHANNEL_PITCH_BEND equ 0x3418 107 | SPU_SOFT_PHASE equ 0x3419 108 | SPU_ATTACK_RELEASE equ 0x341a 109 | SPU_EQ_CUTOFF10 equ 0x341b 110 | SPU_EQ_CUTOFF32 equ 0x341c 111 | SPU_EQ_GAIN10 equ 0x341d 112 | SPU_EQ_GAIN32 equ 0x341e 113 | 114 | GPIO_MODE equ 0x3d00 115 | GPIO_A_DATA equ 0x3d01 116 | GPIO_A_BUFFER equ 0x3d02 117 | GPIO_A_DIR equ 0x3d03 118 | GPIO_A_ATTRIB equ 0x3d04 119 | GPIO_A_MASK equ 0x3d05 120 | GPIO_B_DATA equ 0x3d06 121 | GPIO_B_BUFFER equ 0x3d07 122 | GPIO_B_DIR equ 0x3d08 123 | GPIO_B_ATTRIB equ 0x3d09 124 | GPIO_B_MASK equ 0x3d0a 125 | GPIO_C_DATA equ 0x3d0b 126 | GPIO_C_BUFFER equ 0x3d0c 127 | GPIO_C_DIR equ 0x3d0d 128 | GPIO_C_ATTRIB equ 0x3d0e 129 | GPIO_C_MASK equ 0x3d0f 130 | 131 | TIMEBASE_SETUP equ 0x3d10 132 | TIMEBASE_CLEAR equ 0x3d11 133 | TIMER_A_DATA equ 0x3d12 134 | TIMER_A_CTRL equ 0x3d13 135 | TIMER_A_ON equ 0x3d14 136 | TIMER_A_IRQCLR equ 0x3d15 137 | TIMER_B_DATA equ 0x3d16 138 | TIMER_B_CTRL equ 0x3d17 139 | TIMER_B_ON equ 0x3d18 140 | TIMER_B_IRQCLR equ 0x3d19 141 | 142 | CURRENT_LINE equ 0x3d1c 143 | 144 | SYSTEM_CTRL equ 0x3d20 145 | IO_IRQ_ENABLE equ 0x3d21 146 | IO_IRQ_STATUS equ 0x3d22 147 | EXT_MEMORY_CTRL equ 0x3d23 148 | WATCHDOG_CLEAR equ 0x3d24 149 | 150 | ADC_CTRL equ 0x3d25 151 | ADC_PAD equ 0x3d26 152 | ADC_DATA equ 0x3d27 153 | 154 | SLEEP_MODE equ 0x3d28 155 | WAKEUP_SOURCE equ 0x3d29 156 | WAKEUP_TIME equ 0x3d2a 157 | 158 | TV_SYSTEM equ 0x3d2b 159 | 160 | PRNG_GEN1 equ 0x3d2c 161 | PRNG_GEN2 equ 0x3d2d 162 | 163 | FIQ_SELECT equ 0x3d2e 164 | 165 | DS_ACCESS equ 0x3d2f 166 | 167 | UART_CTRL equ 0x3d30 168 | UART_STATUS equ 0x3d31 169 | UART_RESET equ 0x3d32 170 | UART_BAUD equ 0x3d33 171 | UART_BAUD_LO equ 0x3d33 172 | UART_BAUD_HI equ 0x3d34 173 | UART_TXBUF equ 0x3d35 174 | UART_RXBUF equ 0x3d36 175 | UART_RXFIFO equ 0x3d37 176 | 177 | SPI_CTRL equ 0x3d40 178 | SPI_TXSTATUS equ 0x3d41 179 | SPI_TXDATA equ 0x3d42 180 | SPI_RXSTATUS equ 0x3d43 181 | SPI_RXDATA equ 0x3d44 182 | SPI_MISC equ 0x3d45 183 | 184 | SIO_SETUP equ 0x3d50 185 | SIO_STATUS equ 0x3d51 186 | SIO_ADDR_LO equ 0x3d52 187 | SIO_ADDR_HI equ 0x3d53 188 | SIO_DATA equ 0x3d54 189 | SIO_AUTO_TX_NUM equ 0x3d55 190 | 191 | I2C_CMD equ 0x3d58 192 | I2C_STATUS equ 0x3d59 193 | I2C_ACCESS equ 0x3d5a 194 | I2C_ADDR equ 0x3d5b 195 | I2C_SUBADDR equ 0x3d5c 196 | I2C_DATA_OUT equ 0x3d5d 197 | I2C_DATA_IN equ 0x3d5e 198 | I2C_MODE equ 0x3d5f 199 | 200 | REGULATOR_CTRL equ 0x3d60 201 | CLOCK_CTRL equ 0x3d61 202 | IODRIVE_CTRL equ 0x3d62 203 | 204 | SYSDMA_SRC_LO equ 0x3e00 205 | SYSDMA_SRC_HI equ 0x3e01 206 | SYSDMA_LEN equ 0x3e02 207 | SYSDMA_DEST equ 0x3e03 208 | -------------------------------------------------------------------------------- /vertstretch.asm: -------------------------------------------------------------------------------- 1 | .include "spg2xx.inc" 2 | .define color(r,g,b) ((r << 10) | (g << 5) | (b << 0)) 3 | 4 | .unsp 5 | .low_address 0 6 | .high_address 0x1ffff 7 | 8 | .org 0x10 9 | 10 | ; allocate space for the tilemap, which is stored in standard RAM 11 | ; put the tilemap somewhere other than 0 for test purposes 12 | tilemap: 13 | .resw (512/8)*(256/8) ; 8x8 sized tiles = 64*32 sized tilemap 14 | tilemap_end: 15 | 16 | ; put the program code in suitable ROM area 17 | .org 0x8000 18 | start: 19 | int off ; turn off interrupts as soon as possible 20 | 21 | ld r1, #0 22 | 23 | ; initialize system ctrl 24 | st r1, [SYSTEM_CTRL] 25 | 26 | ; clear watchdog just to be safe 27 | ld r2, #0x55aa 28 | st r2, [WATCHDOG_CLEAR] 29 | 30 | ; set background scroll values for bg 1 31 | st r1, [PPU_BG1_SCROLL_X] ; scroll X offset of bg 1 = 0 32 | st r1, [PPU_BG1_SCROLL_Y] ; scroll Y offset of bg 1 = 0 33 | 34 | ; set attribute config for bg 1 35 | ; bit 0-1: color depth (0 = 2-bit) 36 | ; bit 2: horizontal flip (0 = no flip) 37 | ; bit 3: vertical flip (0 = no flip) 38 | ; bit 4-5: X size (0 = 8 pixels) 39 | ; bit 6-7: Y size (0 = 8 pixels) 40 | ; bit 8-11: palette (0 = palette 0, colors 0-3 for 2-bit) 41 | ; bit 12-13: depth (0 = bottom layer) 42 | st r1, [PPU_BG1_ATTR] ; set attribute of bg 1 43 | 44 | ; set control config for bg 1 45 | ; bit 0: bitmap mode (0 = disable) 46 | ; bit 1: attribute map mode or register mode (1 = register mode) 47 | ; bit 2: wallpaper mode (0 = disable) 48 | ; bit 3: enable bg (1 = enable) 49 | ; bit 4: horizontal line-specific movement (0 = disable) 50 | ; bit 5: horizontal compression (0 = disable) 51 | ; bit 6: vertical compression (1 = enable) 52 | ; bit 7: 16-bit color mode (0 = disable) 53 | ; bit 8: blend (0 = disable) 54 | ld r2, #0x4a 55 | st r2, [PPU_BG1_CTRL] 56 | 57 | st r1, [PPU_BG2_CTRL] ; disable bg 2 since bit 3 = 0 58 | 59 | st r1, [PPU_FADE_CTRL] ; clear fade control 60 | 61 | st r1, [PPU_SPRITE_CTRL] ; disable sprites 62 | 63 | ; set vertical compression amount (0x08 = 4x stretched) 64 | ld r2, #0x08 65 | st r2, [PPU_VERT_COMPRESS_AMOUNT] 66 | 67 | ; set vertical compression offset (0 = center of screen) 68 | ld r2, #-96 69 | st r2, [PPU_VERT_COMPRESS_OFFSET] 70 | 71 | ; clear tilemap 72 | ld r2, #' ' ; ASCII space 73 | ld r3, #tilemap 74 | ld r4, #tilemap_end 75 | clear_tilemap_loop: 76 | st r2, [r3++] 77 | cmp r3, r4 78 | jb clear_tilemap_loop 79 | 80 | ;set address of bg 1 tilemap 81 | ld r2, #tilemap 82 | st r2, [PPU_BG1_TILE_ADDR] 83 | 84 | ; set address of tile graphics data 85 | ; the register only stores the 16 most significant bits of a 22-bit address 86 | ; lowest 6 bits are expected to be zero, graphics therefore need to be 64-word aligned. 87 | ld r2, #(font >> 6) 88 | st r2, [PPU_BG1_SEGMENT_ADDR] 89 | 90 | ; set color 0 of palette 91 | ld r2, #color(29,26,15) 92 | st r2, [PPU_COLOR(0)] 93 | 94 | ; set color 1 of palette 95 | ld r2, #color(0,8,16) 96 | st r2, [PPU_COLOR(1)] 97 | 98 | ; current palette also uses color 2 and 3 99 | ; though our graphics only use color 0-1 100 | 101 | ; the position of a specific tile can be calculated by: 102 | ; tilemap start address + (row * number of columns) + column 103 | ; where row and column values are 0-indexed 104 | ; number of columns is 512 / horizontal size 105 | ; number of rows is 256 / vertical size 106 | 107 | ; the start address of the sprite to draw is determined by 108 | ; graphics start address + sprite size in words * tile ID 109 | ; where sprite size in words is calculated by: 110 | ; (vertical size * horizontal size * color depth in bits) / 16 111 | 112 | ; print out numbers in each line of tilemap for easier verification 113 | 114 | ld r2, #'0' 115 | ld r3, #(tilemap + 64*0 + 3) 116 | print_numbers: 117 | st r2, [r3] 118 | add r3, r3, #64 119 | add r2, #1 120 | cmp r2, #'7' 121 | jbe print_numbers 122 | 123 | ; write string into tilemap 124 | 125 | ; start string in row 2, column 3 126 | ld r3, #(tilemap + 64*2 + 3) 127 | 128 | ld r2, #'H' ; write some characters 129 | st r2, [r3++] 130 | 131 | ld r2, #'e' 132 | st r2, [r3++] 133 | 134 | ld r2, #'y' 135 | st r2, [r3++] 136 | 137 | ld r2, #'!' 138 | st r2, [r3++] 139 | 140 | ld r2, #' ' 141 | st r2, [r3++] 142 | 143 | ld r2, #'V' 144 | st r2, [r3++] 145 | 146 | ld r2, #'.' 147 | st r2, [r3++] 148 | 149 | ld r2, #'S' 150 | st r2, [r3++] 151 | 152 | ld r2, #'m' 153 | st r2, [r3++] 154 | 155 | ld r2, #'i' 156 | st r2, [r3++] 157 | 158 | ld r2, #'l' 159 | st r2, [r3++] 160 | 161 | ld r2, #'e' 162 | st r2, [r3++] 163 | 164 | ld r2, #'!' 165 | st r2, [r3++] 166 | 167 | ; now done, run infinite loop 168 | loop: jmp loop 169 | 170 | ; configure interrupt vector 171 | ; we disabled interrupts, but still need to set the start address 172 | .org 0xfff5 173 | .dw 0 ;break 174 | .dw 0 ;fiq 175 | .dw start ;reset 176 | .dw 0 ;irq 0 177 | .dw 0 ;irq 1 178 | .dw 0 ;irq 2 179 | .dw 0 ;irq 3 180 | .dw 0 ;irq 4 181 | .dw 0 ;irq 5 182 | .dw 0 ;irq 6 183 | .dw 0 ;irq 7 184 | 185 | ; the graphics data needs to be 64-word aligned as mentioned earlier 186 | .align_bits 64*16 187 | font: 188 | .binfile "font.bin" 189 | --------------------------------------------------------------------------------