src = $(wildcard src/*.c) \
$(wildcard src/amiga/*.c)
-asrc = $(wildcard src/amiga/*.s)
+asrc = $(wildcard src/amiga/*.s) \
+ $(wildcard src/amiga/libc/*.s)
obj = $(src:.c=.o) $(asrc:.s=.o)
+dep = $(src:.c=.d)
name = retrocrawl
elf = $(name).elf
LD = $(tool_prefix)ld
OBJCOPY = $(tool_prefix)objcopy
+inc = -Isrc -Isrc/amiga -Isrc/amiga/libc
+
ASFLAGS = -m68000
-CFLAGS = -m68000 -ffreestanding -pedantic -Wall -Os
+CFLAGS = -m68000 -ffreestanding -pedantic -Wall -Os $(inc)
LDFLAGS = -T amiga.ld -print-gc-sections \
-L/usr/lib/gcc-cross/m68k-linux-gnu/6 -lgcc
$(bootblock): src/amiga/boot/boot.o
$(OBJCOPY) -O binary $< $@
+-include $(dep)
+
+%.d: %.c
+ @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
+
.PHONY: clean
clean:
rm -f $(obj) src/amiga/boot/boot.o $(bin) $(elf)
+.PHONY: cleandep
+cleandep:
+ rm -f $(dep)
+
.PHONY: run
run:
fs-uae
--- /dev/null
+#include "copper.h"
+#include "hwregs.h"
+
+uint32_t *copperlist, *copperlist_end;
+static uint32_t *copmem, *curlist;
+static int mode, copmem_size;
+
+extern uint32_t **_mem_start;
+
+int init_copper(int maxlist, int nlists)
+{
+ /* allocate and set new copper lists */
+ if(maxlist <= 0) maxlist = 256;
+ mode = nlists >= COPPER_DOUBLE ? COPPER_DOUBLE : COPPER_SINGLE;
+
+ copmem_size = maxlist * 4 * mode;
+ copmem = *_mem_start;
+
+ curlist = copperlist = copmem;
+ *curlist = COPPER_END;
+
+ if(mode == COPPER_DOUBLE) {
+ copperlist = curlist + maxlist;
+ *copperlist = COPPER_END;
+ }
+ copperlist_end = copperlist;
+
+ REG32_COP1LC = (uint32_t)curlist;
+ REG_COPJMP1 = 0; /* causes copper to read COP1LC */
+ return 0;
+}
+
+void cleanup_copper(void)
+{
+}
+
+void enable_copper(void)
+{
+ REG_DMACON = SETBITS(DMA_COPPER);
+}
+
+void disable_copper(void)
+{
+ REG_DMACON = CLRBITS(DMA_COPPER);
+}
+
+void clear_copper(void)
+{
+ copperlist_end = copperlist;
+ *copperlist_end = COPPER_END;
+}
+
+void add_copper(uint32_t cmd)
+{
+ *copperlist_end++ = cmd;
+}
+
+void sort_copper(void)
+{
+ /* TODO */
+}
+
+void swap_copper(void)
+{
+ if(mode == COPPER_DOUBLE) {
+ uint32_t *tmpptr;
+ tmpptr = curlist;
+ curlist = copperlist;
+ copperlist = copperlist_end = tmpptr;
+
+ REG32_COP1LC = (uint32_t)curlist;
+ REG_COPJMP1 = 0;
+ } else {
+ copperlist_end = curlist;
+ }
+ *copperlist_end = COPPER_END;
+}
--- /dev/null
+#ifndef COPPER_H_
+#define COPPER_H_
+
+#include "inttypes.h"
+
+#define COPPER_MOVE(reg, data) (((uint32_t)(reg) << 16) | ((uint32_t)(data) & 0xffff))
+#define COPPER_WAIT(x, y) \
+ (0x0001fffe | ((uint32_t)((x) + 0x81) << 16) | ((uint32_t)((y) + 0x2c) << 24))
+#define COPPER_WAIT_OVERSCAN(x, y) \
+ (0x0001fffe | ((uint32_t)(x) << 16) | ((uint32_t)(y) << 24))
+#define COPPER_VWAIT(s) (0x0001ff00 | ((uint32_t)((s) + 0x2c) << 24))
+#define COPPER_VWAIT_OVERSCAN(s) \
+ (0x0001ff00 | ((uint32_t)(s) << 24))
+#define COPPER_OVERFLOW 0xffdffffe
+#define COPPER_END 0xfffffffe
+
+extern uint32_t *copperlist, *copperlist_end;
+
+enum {
+ COPPER_SINGLE = 1,
+ COPPER_DOUBLE = 2
+};
+
+int init_copper(int maxlist, int nlists);
+void cleanup_copper(void);
+
+/* enables copper DMA */
+void enable_copper(void);
+/* disables copper DMA */
+void disable_copper(void);
+
+void clear_copper(void);
+void add_copper(uint32_t cmd);
+void sort_copper(void); /* TODO */
+
+void swap_copper(void);
+
+
+#endif /* COPPER_H_ */
--- /dev/null
+#include "gfx.h"
+#include "hwregs.h"
+
+int init_gfx(void)
+{
+ int i;
+
+ REG_BPLCON0 = BPLCON0_COUNT(NBPL) | BPLCON0_COLOR;
+ REG_BPLCON1 = 0;
+ REG_DIWSTART = 0x2c81;
+ REG_DIWSTOP = 0x2cc1;
+ REG_DDFSTART = 0x38;
+ REG_DDFSTOP = 0xd0;
+
+ for(i=0; i<NBPL; i++) {
+ bplptr[i] = framebuf + SCANSZ * i;
+ }
+ REG_BPL1MOD = SCANSZ * (NBPL - 1);
+ REG_BPL2MOD = SCANSZ * (NBPL - 1);
+
+ for(i=0; i<32; i++) {
+ REG_COLOR_PTR[i] = 0xf0f;
+ }
+
+ return 0;
+}
--- /dev/null
+#ifndef GFX_H_
+#define GFX_H_
+
+#define SCR_W 320
+#define SCR_H 256
+#define SCANSZ (SCR_W / 8)
+#define BPLSZ (SCANSZ * SCR_H)
+#define NBPL 5
+
+#define wait_vpos(x) \
+ asm volatile ( \
+ "0: move.l 0xdff004, %%d0\n\t" \
+ "and.l #0x1ff00, %%d0\n\t" \
+ "cmp.l %0, %%d0\n\t" \
+ "bne 0b\n\t" \
+ :: "i"((x) << 8) : "%d0")
+
+#define wait_vblank() wait_vpos(300)
+
+unsigned char framebuf[BPLSZ * NBPL];
+unsigned char *bplptr[NBPL];
+
+int init_gfx(void);
+
+#endif /* GFX_H_ */
--- /dev/null
+| vi:filetype=gas68k:
+ .text
+
+ | optimize: transfer words at a time
+ .global memcpy
+memcpy:
+ move.l 4(%sp), %a0
+ move.l 8(%sp), %a1
+ move.l 12(%sp), %d0
+ sub.l #1, %d0
+0: move.b (%a1)+, (%a0)+
+ dbra %d0, 0b
+ rts
+
+ | optimize: same as above
+ .global memset
+memset:
+ move.l 4(%sp), %a0
+ move.l 8(%sp), %d1
+ move.l 12(%sp), %d0
+ sub.l #1, %d0
+0: move.b %d1, (%a0)+
+ dbra %d0, 0b
+ rts
--- /dev/null
+#ifndef AMIGA_LIBC_STDLIB_H_
+#define AMIGA_LIBC_STDLIB_H_
+
+typedef long size_t;
+
+#endif /* AMIGA_LIBC_STDLIB_H_ */
--- /dev/null
+#ifndef AMIGA_LIBC_STRING_H_
+#define AMIGA_LIBC_STRING_H_
+
+#include <stdlib.h>
+
+void memcpy(void *dest, const void *src, size_t n);
+void memset(void *dest, int c, size_t n);
+
+#endif /* AMIGA_LIBC_STRING_H_ */
+#include <string.h>
#include "hwregs.h"
+#include "copper.h"
+#include "gfx.h"
+#include "game.h"
+
+static uint32_t coplist[32];
int main(void)
{
- REG_INTENA = SETBITS(INTEN_VERTB | INTEN_MASTER);
+ int i;
+ REG_INTENA = SETBITS(INTEN_VERTB | INTEN_MASTER);
REG_DMACON = CLRBITS(DMA_ALL);
- REG_BPLCON0 = BPLCON0_COLOR;
- REG_BPLCON1 = 0;
- REG_DIWSTART = 0x2c81;
- REG_DIWSTOP = 0x2cc1;
- REG_DDFSTART = 0x38;
- REG_DDFSTOP = 0xd0;
- REG_COLOR0 = 0x237;
+ init_gfx();
+
+ REG_COLOR0 = 0x111;
+ REG_COLOR1 = 0x23c;
+ REG_COLOR2 = 0xc32;
+ REG_COLOR3 = 0x22c;
+ REG_COLOR4 = 0xcc2;
+
+ wait_vblank();
+
+ uint32_t *copptr = coplist;
+ for(i=0; i<NBPL; i++) {
+ uint32_t addr = (intptr_t)bplptr[i];
+ int reg = REGN_BPL1PTH + i * 4;
+ *copptr++ = COPPER_MOVE(reg, addr >> 16);
+ *copptr++ = COPPER_MOVE(reg + 2, addr);
+ }
+ *copptr = COPPER_END;
+ REG32_COP1LC = (uint32_t)coplist;
+ REG_COPJMP1 = 0;
+
+ REG_DMACON = SETBITS(DMA_BPL | DMA_COPPER | DMA_MASTER);
+
+ game_init();
- for(;;);
+ for(;;) {
+ wait_vblank();
+ game_draw();
+ }
return 0;
}
--- /dev/null
+const char test_tiles_cpix[][16][32] = {
+ {
+ "...............#x...............",
+ ".............###xxx.............",
+ "...........x####xxxx#...........",
+ ".........xxx####xxxx###.........",
+ ".......x####xxxx####xxxx#.......",
+ ".....xxx####xxxx####xxxx###.....",
+ "...#xxxx####xxxx####xxxx####x...",
+ ".###xxxx####xxxx####xxxx####xxx.",
+ ".xxx####xxxx####xxxx####xxxx###.",
+ "...x####xxxx####xxxx####xxxx#...",
+ ".....###xxxx####xxxx####xxx.....",
+ ".......#xxxx####xxxx####x.......",
+ ".........###xxxx####xxx.........",
+ "...........#xxxx####x...........",
+ ".............xxx###.............",
+ "...............x#..............."
+ },
+ {
+ "...............@o...............",
+ ".............@@@ooo.............",
+ "...........o@@@@oooo@...........",
+ ".........ooo@@@@oooo@@@.........",
+ ".......o@@@@oooo@@@@oooo@.......",
+ ".....ooo@@@@oooo@@@@oooo@@@.....",
+ "...@oooo@@@@oooo@@@@oooo@@@@o...",
+ ".@@@oooo@@@@oooo@@@@oooo@@@@ooo.",
+ ".ooo@@@@oooo@@@@oooo@@@@oooo@@@.",
+ "...o@@@@oooo@@@@oooo@@@@oooo@...",
+ ".....@@@oooo@@@@oooo@@@@ooo.....",
+ ".......@oooo@@@@oooo@@@@o.......",
+ ".........@@@oooo@@@@ooo.........",
+ "...........@oooo@@@@o...........",
+ ".............ooo@@@.............",
+ "...............o@..............."
+ }
+};
--- /dev/null
+#include <string.h>
+#include "game.h"
+#include "data_test.h"
+#include "gfx.h"
+
+#define TILE_W 32
+#define TILE_H 16
+
+void draw_tile(int tid, int x, int y, int light);
+void convert_tile_data(unsigned char *dest, const char *src);
+
+static unsigned char test_tiles[2][TILE_W * TILE_H / 8 * NBPL];
+
+int game_init(void)
+{
+ int i;
+
+ for(i=0; i<2; i++) {
+ convert_tile_data(test_tiles[i], test_tiles_cpix[i][0]);
+ }
+ return 0;
+}
+
+void game_draw(void)
+{
+ draw_tile(0, 32, 16, 0);
+}
+
+
+void draw_tile(int tid, int x, int y, int light)
+{
+ int i;
+
+ unsigned char *dest = bplptr[0] + (y * SCANSZ * NBPL) + x / 8;
+ unsigned char *src = test_tiles[tid];
+
+ for(i=0; i<TILE_H * NBPL; i++) {
+ memcpy(dest, src, TILE_W / 8);
+ dest += SCANSZ;
+ src += TILE_W / 8;
+ }
+}
+
+static inline int charpix_color(char c)
+{
+ switch(c) {
+ case '#':
+ return 1;
+ case 'x':
+ return 2;
+ case '@':
+ return 3;
+ case 'o':
+ return 4;
+ default:
+ case '.':
+ break;
+ }
+ return 0;
+}
+
+#define TILE_SCANSZ (TILE_W / 8)
+void convert_tile_data(unsigned char *dest, const char *src)
+{
+ int i, j, k;
+ unsigned char *bptr[NBPL];
+
+ for(i=0; i<NBPL; i++) {
+ bptr[i] = dest + TILE_SCANSZ * i;
+ }
+
+ for(i=0; i<TILE_H; i++) {
+ for(j=0; j<TILE_W; j++) {
+ int col = charpix_color(*src++);
+
+ for(k=0; k<NBPL; k++) {
+ *bptr[k] = (*bptr[k] << 1) | (col & 1);
+ col >>= 1;
+
+ if((j & 7) == 7) {
+ bptr[k]++;
+ }
+ }
+ }
+
+ for(j=0; j<NBPL; j++) {
+ bptr[j] += TILE_SCANSZ * (NBPL - 1);
+ }
+ }
+}
--- /dev/null
+#ifndef GAME_H_
+#define GAME_H_
+
+int game_init(void);
+void game_draw(void);
+
+#endif /* GAME_H_ */