$(z80bin): $(z80obj)
$(Z80LD) -o $@ $(Z80LDFLAGS) $(z80obj)
-src/data.o: src/data.s data/font8x8.img
+src/data.o: src/data.s data/font8x8.img data/cellspr.img
src/z80prog-asm.o: src/z80prog.s $(z80bin)
-include $(dep)
$(AS) -o $@ $(ASFLAGS) $<
%-asm.o: %.S
- $(CC) -o $@ $(ASFLAGS) -c $<
+ $(CC) -o $@ $(ASFLAGS) -DASM -c $<
%.z80: %.asm
$(Z80AS) -o $@ $(Z80ASFLAGS) $< >/dev/null
0000
-8000
+8000 sprite tiles
b400 font 96 glyphs * 8x8 / 2 = 3072 bytes
c000 nametable A (64x32 * 2 = 4096)
d000 nametable B
.globl font8x8_data
.globl font8x8_data_end
+ .globl cellspr_data
+ .globl cellspr_data_end
font8x8_data:
.incbin "data/font8x8.img"
font8x8_data_end:
+ .align 2
+cellspr_data:
+ .incbin "data/cellspr.img"
+cellspr_data_end:
+
| vi:ft=gas68k:
--- /dev/null
+ .text
+
+#include "hwregs.h"
+#include "vdp.inc"
+
+ | dma_systovram(vmem_addr, src, count)
+ .globl dma_systovram
+dma_systovram:
+ vdp_setreg VDP_REG_MODE2, VDP_M2_INIT + VDP_M2_DISP + VDP_M2_DMA
+
+ | set source address
+ move.l 8(%sp), %d0
+ move.l %d0, %d1
+ vdp_setreg_reg VDP_REG_DMASRCL, %d0
+ lsr.w #8, %d1
+ vdp_setreg_reg VDP_REG_DMASRCM, %d1
+ swap %d0
+ vdp_setreg_reg VDP_REG_DMASRCH, %d0
+ | set count (in words)
+ move.w 14(%sp), %d0
+ move.w %d0, %d1
+ vdp_setreg_reg VDP_REG_DMACNTL, %d0
+ lsr.w #8, %d1
+ vdp_setreg_reg VDP_REG_DMACNTH, %d1
+ | set the destination address.
+ move.w 6(%sp), %d0
+ move.w %d0, %d1
+ and.w #0x3fff, %d0
+ or.w #(VDP_VRAM_DMA >> 16), %d0
+ move.w %d0, VDP_CTL_PORT
+ | 2 upper bits and rest of the type flags
+ rol.w #2, %d1
+ and.w #3, %d1
+ or.w #(VDP_VRAM_DMA & 0xf0), %d1
+ | last word needs to come from RAM, so we push it on the stack
+ move.w %d1, -(%sp)
+ move.w (%sp), VDP_CTL_PORT
+ add.l #2, %sp
+
+ | after DMA ends the cpu can continue, turn DMA off
+ vdp_setreg VDP_REG_MODE2, VDP_M2_INIT + VDP_M2_DISP
+ rts
+
+| vi:ft=gas68k:
--- /dev/null
+#ifndef DMA_H_
+#define DMA_H_
+
+#include "vdp.h"
+
+#define dma_enable() \
+ vdp_setreg(VDP_REG_MODE2, VDP_M2_INIT | VDP_M2_DISP | VDP_M2_DMA)
+
+#define dma_disable() \
+ vdp_setreg(VDP_REG_MODE2, VDP_M2_INIT | VDP_M2_DISP)
+
+void dma_systovram(uint32_t vaddr, void *src, int count);
+
+#endif /* DMA_H_ */
#define VDP_CRAM 0xc0000000
#define VDP_VSRAM 0x40000010
+#define VDP_VRAM_DMA 0x40000080
+#define VDP_CRAM_DMA 0xc0000080
+#define VDP_VSRAM_DMA 0x40000090
+
#ifndef ASM
#include <stdint.h>
int snprintf(char *buf, size_t sz, const char *fmt, ...);
int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap);
-void perror(const char *s);
-
#endif /* STDIO_H_ */
#include <stdint.h>
#include <stddef.h>
+void *memset(void *s, int c, size_t n)
+{
+ char *ptr = s;
+ while(n--) *ptr++ = c;
+ return s;
+}
+
void *memcpy(void *dest, const void *src, size_t n)
{
- size_t i;
char *dptr = dest;
const char *sptr = src;
- for(i=0; i<n; i++) {
- dptr[i] = sptr[i];
- }
-
+ while(n--) *dptr++ = *sptr++;
return dest;
}
+#include <stdio.h>
#include "z80.h"
#include "vdp.h"
+#include "sprite.h"
#include "debug.h"
+#define SPRITE_BASE 0x8000
+extern uint16_t cellspr_data[], cellspr_data_end[];
+
int main(void)
{
+ uint16_t *src;
+ int tile;
+
z80_init();
vdp_init();
dbg_init();
vdp_setcolor(0, 0, 2, 2, 2);
vdp_setcolor(0, 15, 15, 15, 15);
- dbg_printstr(0, 0, "Mindlapse");
+ /* upload sprite tiles */
+ src = cellspr_data;
+ vdp_setup_addr(VDP_VRAM, SPRITE_BASE);
+ while(src < cellspr_data_end) {
+ VDP_DATA = *src++;
+ }
+
+ for(;;) {
+ spr_begin();
+ tile = SPRITE_BASE / 32 + 2;
+ spr_add(160, 100, VDP_TILENAME(tile, 0, VDP_TILE_FG), SPR_SIZE(1,1));
+
+ vdp_wait_vblank();
+ spr_submit();
+ }
return 0;
}
--- /dev/null
+ .text
+
+#include "hwregs.h"
+
+ .extern spr_shadow
+ .extern spr_count
+ .extern dma_systovram
+
+ .globl spr_submit
+spr_submit:
+ move.l spr_count, -(%sp)
+ move.l #spr_shadow, -(%sp)
+ move.l #0x8000, -(%sp)
+ jsr dma_systovram
+ add.l #12, %sp
+ rts
+
+| vi:ft=gas68k:
--- /dev/null
+#include <string.h>
+#include "sprite.h"
+#include "vdp.h"
+
+struct hwsprite spr_shadow[MAX_HWSPRITES];
+int spr_count;
+
+void spr_begin(void)
+{
+ memset(spr_shadow, 0, sizeof spr_shadow[0]);
+ spr_count = 0;
+}
+
+void spr_add(int x, int y, unsigned int tile, int sprsz)
+{
+ int id;
+ struct hwsprite *spr;
+
+ if(spr_count >= MAX_HWSPRITES) {
+ return;
+ }
+ id = spr_count++;
+ spr = spr_shadow + id;
+ if(id > 0) {
+ spr[-1].next = id;
+ }
+
+ spr->x = x + 128;
+ spr->y = y + 128;
+ spr->sz = sprsz;
+ spr->tile = tile;
+ spr->next = 0;
+}
--- /dev/null
+#ifndef SPRITE_H_
+#define SPRITE_H_
+
+#include <stdint.h>
+
+struct hwsprite {
+ uint16_t y;
+ uint8_t sz;
+ uint8_t next;
+ uint16_t tile;
+ uint16_t x;
+} __attribute__((packed));
+
+#define SPR_SIZE(x, y) ((((x) - 1) << 2) | ((y) - 1))
+
+#define MAX_HWSPRITES 64
+extern struct hwsprite spr_shadow[MAX_HWSPRITES];
+extern int spr_count;
+
+void spr_begin(void);
+void spr_add(int x, int y, unsigned int tile, int sprsz);
+void spr_submit(void);
+
+#endif /* SPRITE_H_ */
.text
-#define ASM
#include "hwregs.h"
.globl vdp_init
#define vdp_setreg(reg, val) \
(VDP_CTL = 0x8000 | ((reg) << 8) | (val))
+#define vdp_wait_vblank() \
+ while(!(VDP_STAT & VDP_ST_VBLANK))
+
+#define vdp_wait_vblank_end() \
+ while((VDP_STAT & VDP_ST_VBLANK))
+
+#define vdp_vsync() \
+ (vdp_wait_vblank_end(), vdp_wait_vblank())
+
+
#define VDP_TILE_BG 0
#define VDP_TILE_FG 0x8000
#define VDP_TILE_PAL(x) ((x) << 13)
--- /dev/null
+ .macro vdp_setreg reg val
+ move.w #(\val), %d0
+ or.w #(0x8000 + (\reg << 8)), %d0
+ move.w %d0, VDP_CTL_PORT
+ .endm
+
+ .macro vdp_setreg_reg reg val
+ or.w #(0x8000 + (\reg << 8)), \val
+ move.w \val, VDP_CTL_PORT
+ .endm
+
+| vi:ft=gas68k: