brought the code over from the amiga test
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 23 Jan 2021 17:38:52 +0000 (19:38 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 23 Jan 2021 17:38:52 +0000 (19:38 +0200)
28 files changed:
.gitignore [new file with mode: 0644]
Makefile.amiga [new file with mode: 0644]
amiga.ld [new file with mode: 0644]
fs-uae.conf [new file with mode: 0644]
src/amiga/boot/boot.s [new file with mode: 0644]
src/amiga/copper.c [new file with mode: 0644]
src/amiga/copper.h [new file with mode: 0644]
src/amiga/gfx.c [new file with mode: 0644]
src/amiga/gfx.h [new file with mode: 0644]
src/amiga/hwregs.h [new file with mode: 0644]
src/amiga/libc/ctype.c [new file with mode: 0644]
src/amiga/libc/ctype.h [new file with mode: 0644]
src/amiga/libc/inttypes.h [new file with mode: 0644]
src/amiga/libc/stdarg.h [new file with mode: 0644]
src/amiga/libc/stdint.h [new file with mode: 0644]
src/amiga/libc/stdio.c [new file with mode: 0644]
src/amiga/libc/stdio.h [new file with mode: 0644]
src/amiga/libc/stdlib.c [new file with mode: 0644]
src/amiga/libc/stdlib.h [new file with mode: 0644]
src/amiga/libc/string.c [new file with mode: 0644]
src/amiga/libc/string.h [new file with mode: 0644]
src/amiga/main.c [new file with mode: 0644]
src/amiga/serial.c [new file with mode: 0644]
src/amiga/serial.h [new file with mode: 0644]
src/amiga/startup.s [new file with mode: 0644]
src/game.c [new file with mode: 0644]
src/game.h [new file with mode: 0644]
tools/mk_adf.py [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..5a73195
--- /dev/null
@@ -0,0 +1,7 @@
+*.o
+*.d
+*.swp
+*.elf
+*.bin
+*.adf
+link.map
diff --git a/Makefile.amiga b/Makefile.amiga
new file mode 100644 (file)
index 0000000..cff0ffb
--- /dev/null
@@ -0,0 +1,57 @@
+src = $(wildcard src/*.c) \
+         $(wildcard src/amiga/*.c) \
+         $(wildcard src/amiga/libc/*.c)
+asrc = $(wildcard src/*.s) \
+          $(wildcard src/amiga/*.s) \
+          $(wildcard src/amiga/libc/*.s)
+obj = $(src:.c=.o) $(asrc:.s=.o) 
+dep = $(src:.c=.d)
+
+name = lugburz
+elf = $(name).elf
+bin = $(name).bin
+adf = $(name).adf
+bootblock = boot.bin
+
+tool_prefix = m68k-elf-
+
+CC = $(tool_prefix)gcc
+AS = $(tool_prefix)as
+LD = $(tool_prefix)gcc
+OBJCOPY = $(tool_prefix)objcopy
+
+inc = -Isrc -Isrc/amiga -Isrc/amiga/libc
+
+ASFLAGS = -m68000
+CFLAGS = -m68000 -ffreestanding -nostdinc -fno-builtin -pedantic -Wall -Os $(inc)
+LDFLAGS = -T amiga.ld -Wl,-print-gc-sections -Wl,-Map,link.map -ffreestanding \
+                 -nostdlib -lgcc
+
+$(adf): $(bin) $(bootblock)
+       tools/mk_adf.py $(bootblock) $(bin) $@
+
+$(bin): $(elf)
+       $(OBJCOPY) -O binary $< $@
+
+$(elf): $(obj)
+       $(LD) -o $@ $(obj) $(LDFLAGS)
+
+$(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
diff --git a/amiga.ld b/amiga.ld
new file mode 100644 (file)
index 0000000..2183783
--- /dev/null
+++ b/amiga.ld
@@ -0,0 +1,25 @@
+OUTPUT_ARCH(m68k)
+
+PROVIDE (_stacktop = 0x80000);
+
+SECTIONS {
+       /* bootblock will load us at 10000h */
+       . = 0x10000;
+
+       .startup : { * (.startup); }
+       .text : { * (.text); }
+       .rodata : { * (.rodata); }
+       .data : { * (.data); }
+
+       .dummy ALIGN(4): { LONG(42); }
+
+       .bss ALIGN(4): {
+               _bss_start = .;
+               * (.bss);
+               . = ALIGN(4);
+               _bss_end = .;
+       }
+       _bss_size = SIZEOF(.bss);
+
+       _mem_start = .;
+}
diff --git a/fs-uae.conf b/fs-uae.conf
new file mode 100644 (file)
index 0000000..b57374e
--- /dev/null
@@ -0,0 +1,19 @@
+[config]
+keep_aspect = 1
+floppies_dir = $HOME/amiga/disks
+floppy_overlays_dir = $HOME/amiga/disks
+kickstarts_dir = $HOME/amiga/rom
+logs_dir = $HOME/amiga/logs
+screenshots_output_dir = .
+floppy_drive_speed = 0
+floppy_drive_volume = 0
+kickstart_file = $HOME/amiga/rom/kickstart-1.3.rom
+console_debugger = 1
+warp_mode = 1
+chip_memory = 512
+fast_memory = 0
+slow_memory = 0
+initial_grab_input = 0
+serial_port = /tmp/uaetty
+
+floppy_drive_0 = lugburz.adf
diff --git a/src/amiga/boot/boot.s b/src/amiga/boot/boot.s
new file mode 100644 (file)
index 0000000..4f1ccb7
--- /dev/null
@@ -0,0 +1,20 @@
+| vi:filetype=gas68k:
+       .equ CMD_READ, 2
+       .equ EXEC_DO_IO, -0x1c8
+       .equ LOADADDR,  0x10000
+
+start:
+| starting with trackdisk device I/O request pointer in a1
+| load the program at 0x100 and jump there
+| program length is patched by mk_adf just before start
+       move.l -6(%pc), %d0             | get program size
+       move.w #0x080, 0xdff180
+       move.l %d0, 0x24(%a1)           | I/O length
+       move.l #LOADADDR, 0x28(%a1)     | I/O data pointer
+       move.l #512, 0x2c(%a1)          | I/O offset (skip first sector)
+       move.w #CMD_READ, 0x1c(%a1)     | I/O command
+       jsr EXEC_DO_IO(%a6)
+       move.w #0xf0f, 0xdff180
+
+       jmp LOADADDR
+       .align 4
diff --git a/src/amiga/copper.c b/src/amiga/copper.c
new file mode 100644 (file)
index 0000000..bee6a8a
--- /dev/null
@@ -0,0 +1,77 @@
+#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(uint32_t *cmem, 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 = cmem ? cmem : *_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;
+}
diff --git a/src/amiga/copper.h b/src/amiga/copper.h
new file mode 100644 (file)
index 0000000..29be226
--- /dev/null
@@ -0,0 +1,39 @@
+#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(uint32_t *cmem, 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_ */
diff --git a/src/amiga/gfx.c b/src/amiga/gfx.c
new file mode 100644 (file)
index 0000000..b18e027
--- /dev/null
@@ -0,0 +1,26 @@
+#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;
+}
diff --git a/src/amiga/gfx.h b/src/amiga/gfx.h
new file mode 100644 (file)
index 0000000..f2287c1
--- /dev/null
@@ -0,0 +1,31 @@
+#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)
+
+#define wait_blit() \
+       asm volatile ( \
+               "tst 0xdff002\n\t" \
+               "0: btst #6, 0xdff002\n\t" \
+               "bne 0b\n\t")
+
+unsigned char framebuf[BPLSZ * NBPL];
+unsigned char *bplptr[NBPL];
+
+int init_gfx(void);
+
+#endif /* GFX_H_ */
diff --git a/src/amiga/hwregs.h b/src/amiga/hwregs.h
new file mode 100644 (file)
index 0000000..ccedb57
--- /dev/null
@@ -0,0 +1,515 @@
+#ifndef HWREGS_H_
+#define HWREGS_H_
+
+#include "inttypes.h"
+
+#define REG_BASE_ADDR  0xdff000
+
+#define REGN_BLTDDAT   0x000
+#define REGN_DMACONR   0x002
+#define REGN_VPOSR             0x004
+#define REGN_VHPOSR            0x006
+#define REGN_DSKDATR   0x008
+#define REGN_JOY0DAT   0x00a
+#define REGN_JOY1DAT   0x00c
+#define REGN_CLXDAT            0x00e
+#define REGN_ADKCONR   0x010
+#define REGN_POT0DAT   0x012
+#define REGN_POT1DAT   0x014
+#define REGN_POTGOR            0x016
+#define REGN_SERDATR   0x018
+#define REGN_DSKBYTR   0x01a
+#define REGN_INTENAR   0x01c
+#define REGN_INTREQR   0x01e
+#define REGN_DSKPTH            0x020
+#define REGN_DSKPTL            0x022
+#define REGN_DSKLEN            0x024
+#define REGN_DSKDAT            0x026
+#define REGN_REFPTR            0x028
+#define REGN_VPOSW             0x02a
+#define REGN_VHPOSW            0x02c
+#define REGN_COPCON            0x02e
+#define REGN_SERDAT            0x030
+#define REGN_SERPER            0x032
+#define REGN_POTGO             0x034
+#define REGN_JOYTEST   0x036
+#define REGN_STREQU            0x038
+#define REGN_STRVBL            0x03a
+#define REGN_STRHOR            0x03c
+#define REGN_STRLONG   0x03e
+#define REGN_BLTCON0   0x040
+#define REGN_BLTCON1   0x042
+#define REGN_BLTAFWM   0x044
+#define REGN_BLTALWM   0x046
+#define REGN_BLTCPTH   0x048
+#define REGN_BLTCPTL   0x04a
+#define REGN_BLTBPTH   0x04c
+#define REGN_BLTBPTL   0x04e
+#define REGN_BLTAPTH   0x050
+#define REGN_BLTAPTL   0x052
+#define REGN_BLTDPTH   0x054
+#define REGN_BLTDPTL   0x056
+#define REGN_BLTSIZE   0x058
+#define REGN_BLTCON0L  0x05a
+#define REGN_BLTSIZV   0x05c
+#define REGN_BLTSIZH   0x05e
+#define REGN_BLTCMOD   0x060
+#define REGN_BLTBMOD   0x062
+#define REGN_BLTAMOD   0x064
+#define REGN_BLTDMOD   0x066
+#define REGN_BLTCDAT   0x070
+#define REGN_BLTBDAT   0x072
+#define REGN_BLTADAT   0x074
+#define REGN_SPRHDAT   0x078
+#define REGN_DENISEID  0x07c
+#define REGN_DSKSYNC   0x07e
+#define REGN_COP1LCH   0x080
+#define REGN_COP1LCL   0x082
+#define REGN_COP2LCH   0x084
+#define REGN_COP2LCL   0x086
+#define REGN_CMPJMP1   0x088
+#define REGN_CMPJMP2   0x08a
+#define REGN_COPINS            0x08c
+#define REGN_DIWSTART  0x08e
+#define REGN_DIWSTOP   0x090
+#define REGN_DDFSTART  0x092
+#define REGN_DDFSTOP   0x094
+#define REGN_DMACON            0x096
+#define REGN_CLXCON            0x098
+#define REGN_INTENA            0x09a
+#define REGN_INTREQ            0x09c
+#define REGN_ADKCON            0x09e
+
+#define REGN_AUDIO_LCH(c)      (REGN_AUDIO0_BASE + (c) * 16 + 0)
+#define REGN_AUDIO_LCL(c)      (REGN_AUDIO0_BASE + (c) * 16 + 2)
+#define REGN_AUDIO_LEN(c)      (REGN_AUDIO0_BASE + (c) * 16 + 4)
+#define REGN_AUDIO_PER(c)      (REGN_AUDIO0_BASE + (c) * 16 + 6)
+#define REGN_AUDIO_VOL(c)      (REGN_AUDIO0_BASE + (c) * 16 + 8)
+#define REGN_AUDIO_DAT(c)      (REGN_AUDIO0_BASE + (c) * 16 + 10)
+
+#define REGN_AUDIO0_BASE       0x0a0
+#define REGN_AUD0LCH           (REGN_AUDIO0_BASE + 0)
+#define REGN_AUD0LCL           (REGN_AUDIO0_BASE + 2)
+#define REGN_AUD0LEN           (REGN_AUDIO0_BASE + 4)
+#define REGN_AUD0PER           (REGN_AUDIO0_BASE + 6)
+#define REGN_AUD0VOL           (REGN_AUDIO0_BASE + 8)
+#define REGN_AUD0DAT           (REGN_AUDIO0_BASE + 10)
+#define REGN_AUDIO1_BASE       0x0b0
+#define REGN_AUD1LCH           (REGN_AUDIO1_BASE + 0)
+#define REGN_AUD1LCL           (REGN_AUDIO1_BASE + 2)
+#define REGN_AUD1LEN           (REGN_AUDIO1_BASE + 4)
+#define REGN_AUD1PER           (REGN_AUDIO1_BASE + 6)
+#define REGN_AUD1VOL           (REGN_AUDIO1_BASE + 8)
+#define REGN_AUD1DAT           (REGN_AUDIO1_BASE + 10)
+#define REGN_AUDIO2_BASE       0x0c0
+#define REGN_AUD2LCH           (REGN_AUDIO2_BASE + 0)
+#define REGN_AUD2LCL           (REGN_AUDIO2_BASE + 2)
+#define REGN_AUD2LEN           (REGN_AUDIO2_BASE + 4)
+#define REGN_AUD2PER           (REGN_AUDIO2_BASE + 6)
+#define REGN_AUD2VOL           (REGN_AUDIO2_BASE + 8)
+#define REGN_AUD2DAT           (REGN_AUDIO2_BASE + 10)
+#define REGN_AUDIO3_BASE       0x0d0
+#define REGN_AUD3LCH           (REGN_AUDIO3_BASE + 0)
+#define REGN_AUD3LCL           (REGN_AUDIO3_BASE + 2)
+#define REGN_AUD3LEN           (REGN_AUDIO3_BASE + 4)
+#define REGN_AUD3PER           (REGN_AUDIO3_BASE + 6)
+#define REGN_AUD3VOL           (REGN_AUDIO3_BASE + 8)
+#define REGN_AUD3DAT           (REGN_AUDIO3_BASE + 10)
+
+#define REGN_BPL1PTH   0x0e0
+#define REGN_BPL1PTL   0x0e2
+#define REGN_BPL2PTH   0x0e4
+#define REGN_BPL2PTL   0x0e6
+#define REGN_BPL3PTH   0x0e8
+#define REGN_BPL3PTL   0x0ea
+#define REGN_BPL4PTH   0x0ec
+#define REGN_BPL4PTL   0x0ee
+#define REGN_BPL5PTH   0x0f0
+#define REGN_BPL5PTL   0x0f2
+#define REGN_BPL6PTH   0x0f4
+#define REGN_BPL6PTL   0x0f6
+#define REGN_BPLCON0   0x100
+#define REGN_BPLCON1   0x102
+#define REGN_BPLCON2   0x104
+#define REGN_BPLCON3   0x106
+#define REGN_BPL1MOD   0x108
+#define REGN_BPL2MOD   0x10a
+#define REGN_BPL1DAT   0x110
+#define REGN_BPL2DAT   0x112
+#define REGN_BPL3DAT   0x114
+#define REGN_BPL4DAT   0x116
+#define REGN_BPL5DAT   0x118
+#define REGN_BPL6DAT   0x11a
+
+#define REGN_SPR0PTH   0x120
+#define REGN_SPR0PTL   0x122
+#define REGN_SPR1PTH   0x124
+#define REGN_SPR1PTL   0x126
+#define REGN_SPR2PTH   0x128
+#define REGN_SPR2PTL   0x12a
+#define REGN_SPR3PTH   0x12c
+#define REGN_SPR3PTL   0x12e
+#define REGN_SPR4PTH   0x130
+#define REGN_SPR4PTL   0x132
+#define REGN_SPR5PTH   0x134
+#define REGN_SPR5PTL   0x136
+#define REGN_SPR6PTH   0x138
+#define REGN_SPR6PTL   0x13a
+#define REGN_SPR7PTH   0x13c
+#define REGN_SPR7PTL   0x13e
+
+#define REGN_SPRITE_POS(s)     (REGN_SPRITE0_BASE + (s) * 8 + 0)
+#define REGN_SPRITE_CTL(s)     (REGN_SPRITE0_BASE + (s) * 8 + 2)
+#define REGN_SPRITE_DATA(s)    (REGN_SPRITE0_BASE + (s) * 8 + 4)
+#define REGN_SPRITE_DATB(s)    (REGN_SPRITE0_BASE + (s) * 8 + 6)
+
+#define REGN_SPRITE0_BASE      0x140
+#define REGN_SPR0POS           REGN_SPRITE_POS(0)
+#define REGN_SPR0CTL           REGN_SPRITE_CTL(0)
+#define REGN_SPR0DATA          REGN_SPRITE_DATA(0)
+#define REGN_SPR0DATB          REGN_SPRITE_DATB(0)
+#define REGN_SPRITE1_BASE      0x148
+#define REGN_SPR1POS           REGN_SPRITE_POS(1)
+#define REGN_SPR1CTL           REGN_SPRITE_CTL(1)
+#define REGN_SPR1DATA          REGN_SPRITE_DATA(1)
+#define REGN_SPR1DATB          REGN_SPRITE_DATB(1)
+#define REGN_SPRITE2_BASE      0x150
+#define REGN_SPR2POS           REGN_SPRITE_POS(2)
+#define REGN_SPR2CTL           REGN_SPRITE_CTL(2)
+#define REGN_SPR2DATA          REGN_SPRITE_DATA(2)
+#define REGN_SPR2DATB          REGN_SPRITE_DATB(2)
+#define REGN_SPRITE3_BASE      0x158
+#define REGN_SPR3POS           REGN_SPRITE_POS(3)
+#define REGN_SPR3CTL           REGN_SPRITE_CTL(3)
+#define REGN_SPR3DATA          REGN_SPRITE_DATA(3)
+#define REGN_SPR3DATB          REGN_SPRITE_DATB(3)
+#define REGN_SPRITE4_BASE      0x160
+#define REGN_SPR4POS           REGN_SPRITE_POS(4)
+#define REGN_SPR4CTL           REGN_SPRITE_CTL(4)
+#define REGN_SPR4DATA          REGN_SPRITE_DATA(4)
+#define REGN_SPR4DATB          REGN_SPRITE_DATB(4)
+#define REGN_SPRITE5_BASE      0x168
+#define REGN_SPR5POS           REGN_SPRITE_POS(5)
+#define REGN_SPR5CTL           REGN_SPRITE_CTL(5)
+#define REGN_SPR5DATA          REGN_SPRITE_DATA(5)
+#define REGN_SPR5DATB          REGN_SPRITE_DATB(5)
+#define REGN_SPRITE6_BASE      0x170
+#define REGN_SPR6POS           REGN_SPRITE_POS(6)
+#define REGN_SPR6CTL           REGN_SPRITE_CTL(6)
+#define REGN_SPR6DATA          REGN_SPRITE_DATA(6)
+#define REGN_SPR6DATB          REGN_SPRITE_DATB(6)
+#define REGN_SPRITE7_BASE      0x178
+#define REGN_SPR7POS           REGN_SPRITE_POS(7)
+#define REGN_SPR7CTL           REGN_SPRITE_CTL(7)
+#define REGN_SPR7DATA          REGN_SPRITE_DATA(7)
+#define REGN_SPR7DATB          REGN_SPRITE_DATB(7)
+
+#define REGN_COLOR_BASE                0x180
+#define REGN_COLOR(idx)                (REGN_COLOR_BASE + (idx) * 2)
+
+#define REGN_COLOR0                    REGN_COLOR(0)
+#define REGN_COLOR1                    REGN_COLOR(1)
+#define REGN_COLOR2                    REGN_COLOR(2)
+#define REGN_COLOR3                    REGN_COLOR(3)
+#define REGN_COLOR4                    REGN_COLOR(4)
+#define REGN_COLOR5                    REGN_COLOR(5)
+#define REGN_COLOR6                    REGN_COLOR(6)
+#define REGN_COLOR7                    REGN_COLOR(7)
+#define REGN_COLOR8                    REGN_COLOR(8)
+#define REGN_COLOR9                    REGN_COLOR(9)
+#define REGN_COLOR10           REGN_COLOR(10)
+#define REGN_COLOR11           REGN_COLOR(11)
+#define REGN_COLOR12           REGN_COLOR(12)
+#define REGN_COLOR13           REGN_COLOR(13)
+#define REGN_COLOR14           REGN_COLOR(14)
+#define REGN_COLOR15           REGN_COLOR(15)
+#define REGN_COLOR16           REGN_COLOR(16)
+#define REGN_COLOR17           REGN_COLOR(17)
+#define REGN_COLOR18           REGN_COLOR(18)
+#define REGN_COLOR19           REGN_COLOR(19)
+#define REGN_COLOR20           REGN_COLOR(20)
+#define REGN_COLOR21           REGN_COLOR(21)
+#define REGN_COLOR22           REGN_COLOR(22)
+#define REGN_COLOR23           REGN_COLOR(23)
+#define REGN_COLOR24           REGN_COLOR(24)
+#define REGN_COLOR25           REGN_COLOR(25)
+#define REGN_COLOR26           REGN_COLOR(26)
+#define REGN_COLOR27           REGN_COLOR(27)
+#define REGN_COLOR28           REGN_COLOR(28)
+#define REGN_COLOR29           REGN_COLOR(29)
+#define REGN_COLOR30           REGN_COLOR(30)
+#define REGN_COLOR31           REGN_COLOR(31)
+
+#define REGN_HTOTAL            0x1c0
+#define REGN_HSSTOP            0x1c2
+#define REGN_HBSTART   0x1c4
+#define REGN_HBSTOP            0x1c6
+#define REGN_VTOTAL            0x1c8
+#define REGN_VSSTOP            0x1ca
+#define REGN_VBSTART   0x1cc
+#define REGN_VBSTOP            0x1ce
+#define REGN_BEAMCON0  0x1dc
+#define REGN_HSSTART   0x1de
+#define REGN_VSSTART   0x1e0
+#define REGN_HCENTER   0x1e2
+#define REGN_DIWHIGH   0x1e4
+
+#define REGN_COP1LCH   0x080
+#define REGN_COP1LCL   0x082
+#define REGN_COP2LCH   0x084
+#define REGN_COP2LCL   0x086
+#define REGN_COPJMP1   0x088
+#define REGN_COPJMP2   0x08a
+
+#define REG(r) (*(volatile uint16_t*)(REG_BASE_ADDR | (r)))
+
+#define REG_CIAA_PORTA *(volatile uint8_t*)0xbfe001
+
+#define REG_INTENA             REG(REGN_INTENA)
+#define REG_INTENAR            REG(REGN_INTENAR)
+#define REG_INTREQ             REG(REGN_INTREQ)
+#define REG_INTREQR            REG(REGN_INTREQR)
+#define REG_ADKCON             REG(REGN_ADKCON)
+#define REG_ADKCONR            REG(REGN_ADKCONR)
+#define REG_DMACON             REG(REGN_DMACON)
+#define REG_DMACONR            REG(REGN_DMACONR)
+#define REG_BPLCON0            REG(REGN_BPLCON0)
+#define REG_BPLCON1            REG(REGN_BPLCON1)
+#define REG_BPLCON2            REG(REGN_BPLCON2)
+#define REG_BPL1PTH            REG(REGN_BPL1PTH)
+#define REG_BPL2PTH            REG(REGN_BPL2PTH)
+#define REG_BPL3PTH            REG(REGN_BPL3PTH)
+#define REG_BPL4PTH            REG(REGN_BPL4PTH)
+#define REG_BPL5PTH            REG(REGN_BPL5PTH)
+#define REG_BPL6PTH            REG(REGN_BPL6PTH)
+#define REG_BPL1PTL            REG(REGN_BPL1PTL)
+#define REG_BPL2PTL            REG(REGN_BPL2PTL)
+#define REG_BPL3PTL            REG(REGN_BPL3PTL)
+#define REG_BPL4PTL            REG(REGN_BPL4PTL)
+#define REG_BPL5PTL            REG(REGN_BPL5PTL)
+#define REG_BPL6PTL            REG(REGN_BPL6PTL)
+#define REG32_BPL1PT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BPL1PTH)
+#define REG32_BPL2PT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BPL2PTH)
+#define REG32_BPL3PT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BPL3PTH)
+#define REG32_BPL4PT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BPL4PTH)
+#define REG32_BPL5PT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BPL5PTH)
+#define REG32_BPL6PT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BPL6PTH)
+#define REG_BPL1MOD            REG(REGN_BPL1MOD)
+#define REG_BPL2MOD            REG(REGN_BPL2MOD)
+#define REG_DIWSTART   REG(REGN_DIWSTART)
+#define REG_DIWSTOP            REG(REGN_DIWSTOP)
+#define REG_DDFSTART   REG(REGN_DDFSTART)
+#define REG_DDFSTOP            REG(REGN_DDFSTOP)
+#define REG_VPOS               REG(REGN_VPOS)
+#define REG_VPOSR              REG(REGN_VPOSR)
+#define REG_VHPOS              REG(REGN_VHPOS)
+#define REG_VHPOSR             REG(REGN_VHPOSR)
+#define REG32_VPOSR            *(volatile uint32_t*)(REG_BASE_ADDR | REGN_VPOSR)
+
+#define REG_COLOR_PTR  ((volatile uint16_t*)(REG_BASE_ADDR | REGN_COLOR0))
+#define REG_COLOR0             REG(REGN_COLOR0)
+#define REG_COLOR1             REG(REGN_COLOR1)
+#define REG_COLOR2             REG(REGN_COLOR2)
+#define REG_COLOR3             REG(REGN_COLOR3)
+#define REG_COLOR4             REG(REGN_COLOR4)
+#define REG_COLOR5             REG(REGN_COLOR5)
+#define REG_COLOR6             REG(REGN_COLOR6)
+#define REG_COLOR7             REG(REGN_COLOR7)
+#define REG_COLOR8             REG(REGN_COLOR8)
+#define REG_COLOR9             REG(REGN_COLOR9)
+#define REG_COLOR10            REG(REGN_COLOR10)
+#define REG_COLOR11            REG(REGN_COLOR11)
+#define REG_COLOR12            REG(REGN_COLOR12)
+#define REG_COLOR13            REG(REGN_COLOR13)
+#define REG_COLOR14            REG(REGN_COLOR14)
+#define REG_COLOR15            REG(REGN_COLOR15)
+#define REG_COLOR16            REG(REGN_COLOR16)
+#define REG_COLOR17            REG(REGN_COLOR17)
+#define REG_COLOR18            REG(REGN_COLOR18)
+#define REG_COLOR19            REG(REGN_COLOR19)
+#define REG_COLOR20            REG(REGN_COLOR20)
+#define REG_COLOR21            REG(REGN_COLOR21)
+#define REG_COLOR22            REG(REGN_COLOR22)
+#define REG_COLOR23            REG(REGN_COLOR23)
+#define REG_COLOR24            REG(REGN_COLOR24)
+#define REG_COLOR25            REG(REGN_COLOR25)
+#define REG_COLOR26            REG(REGN_COLOR26)
+#define REG_COLOR27            REG(REGN_COLOR27)
+#define REG_COLOR28            REG(REGN_COLOR28)
+#define REG_COLOR29            REG(REGN_COLOR29)
+#define REG_COLOR30            REG(REGN_COLOR30)
+#define REG_COLOR31            REG(REGN_COLOR31)
+
+#define REG32_COP1LC   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_COP1LCH)
+#define REG32_COP2LC   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_COP2LCH)
+#define REG_COPJMP1            REG(REGN_COPJMP1)
+#define REG_COPJMP2            REG(REGN_COPJMP2)
+
+#define REG_BLTCON0            REG(REGN_BLTCON0)
+#define REG_BLTCON1            REG(REGN_BLTCON1)
+#define REG32_BLTCON   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BLTCON0)
+#define REG_BLTAFWM            REG(REGN_BLTAFWM)
+#define REG_BLTALWM            REG(REGN_BLTALWM)
+#define REG32_BLTAFLWM *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BLTAFWM)
+#define REG_BLTCPTH            REG(REGN_BLTCPTH)
+#define REG_BLTCPTL            REG(REGN_BLTCPTL)
+#define REG32_BLTCPT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BLTCPTH)
+#define REG_BLTBPTH            REG(REGN_BLTBPTH)
+#define REG_BLTBPTL            REG(REGN_BLTBPTL)
+#define REG32_BLTBPT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BLTBPTH)
+#define REG_BLTAPTH            REG(REGN_BLTAPTH)
+#define REG_BLTAPTL            REG(REGN_BLTAPTL)
+#define REG32_BLTAPT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BLTAPTH)
+#define REG_BLTDPTH            REG(REGN_BLTDPTH)
+#define REG_BLTDPTL            REG(REGN_BLTDPTL)
+#define REG32_BLTDPT   *(volatile uint32_t*)(REG_BASE_ADDR | REGN_BLTDPTH)
+#define REG_BLTSIZE            REG(REGN_BLTSIZE)
+#define REG_BLTCMOD            REG(REGN_BLTCMOD)
+#define REG_BLTBMOD            REG(REGN_BLTBMOD)
+#define REG_BLTAMOD            REG(REGN_BLTAMOD)
+#define REG_BLTDMOD            REG(REGN_BLTDMOD)
+#define REG_BLTCDAT            REG(REGN_BLTCDAT)
+#define REG_BLTBDAT            REG(REGN_BLTBDAT)
+#define REG_BLTADAT            REG(REGN_BLTADAT)
+
+#define REG_SERPER             REG(REGN_SERPER)
+#define REG_SERDATR            REG(REGN_SERDATR)
+#define REG_SERDAT             REG(REGN_SERDAT)
+
+/* ------ bits ------- */
+#define SETBITS(x)     ((x) | 0x8000)
+#define CLRBITS(x)     (x)
+
+/* interrupt numbers */
+enum {
+       INTR_TBE,
+       INTR_DSKBLK,
+       INTR_SOFT,
+       INTR_PORTS,
+       INTR_COPPER,
+       INTR_VERTB,
+       INTR_BLITTER,
+       INTR_AUDIO0,
+       INTR_AUDIO1,
+       INTR_AUDIO2,
+       INTR_AUDIO3,
+       INTR_RBF,
+       INTR_DSKSYN,
+       INTR_EXTER
+};
+
+/* interrupt enable flags */
+enum {
+       INTEN_TBE               = 0x0001,
+       INTEN_DSKBLK    = 0x0002,
+       INTEN_SOFT              = 0x0004,
+       INTEN_PORTS             = 0x0008,
+       INTEN_COPPER    = 0x0010,
+       INTEN_VERTB             = 0x0020,
+       INTEN_BLITTER   = 0x0040,
+       INTEN_AUDIO0    = 0x0080,
+       INTEN_AUDIO1    = 0x0100,
+       INTEN_AUDIO2    = 0x0200,
+       INTEN_AUDIO3    = 0x0400,
+       INTEN_RBF               = 0x0800,
+       INTEN_DSKSYN    = 0x1000,
+       INTEN_EXTER             = 0x2000,
+       INTEN_MASTER    = 0x4000,
+
+       INTEN_ALL               = 0x7fff
+};
+
+/* DMA control flags */
+enum {
+       DMA_AUD0                = 0x0001,
+       DMA_AUD1                = 0x0002,
+       DMA_AUD2                = 0x0004,
+       DMA_AUD3                = 0x0008,
+       DMA_AUDIO               = 0x000f,       /* all the above */
+       DMA_DISK                = 0x0010,
+       DMA_SPRITE              = 0x0020,
+       DMA_BLITTER             = 0x0040,
+       DMA_COPPER              = 0x0080,
+       DMA_BPL                 = 0x0100,
+       DMA_MASTER              = 0x0200,
+
+       DMA_ALL                 = 0x01ff
+};
+
+/* Bitplane control */
+enum {
+       BPLCON0_ERSY    = 0x0002,
+       BPLCON0_LACE    = 0x0004,
+       BPLCON0_LPEN    = 0x0008,
+       BPLCON0_GAUD    = 0x0100,
+       BPLCON0_COLOR   = 0x0200,
+       BPLCON0_DBLPF   = 0x0400,
+       BPLCON0_HOMOD   = 0x0800,
+       BPLCON0_BPU0    = 0x1000,
+       BPLCON0_BPU1    = 0x2000,
+       BPLCON0_BPU2    = 0x4000,
+       BPLCON0_HIRES   = 0x8000
+};
+
+#define BPLCON0_COUNT(x)       ((x) << 12)
+
+/* blitter control */
+enum {
+       BLTCON0_USED    = 0x0100,
+       BLTCON0_USEC    = 0x0200,
+       BLTCON0_USEB    = 0x0400,
+       BLTCON0_USEA    = 0x0800
+};
+
+enum {
+       BLTCON1_LINE    = 0x0001,
+       BLTCON1_DECR    = 0x0002,
+       BLTCON1_FCI             = 0x0004,
+       BLTCON1_IFE             = 0x0008,
+       BLTCON1_EFE             = 0x0010,
+       BLTCON1_DOFF    = 0x0080
+};
+
+#define BLTCON0_LF(x)  (x)
+#define BLTCON0_ASH(x) ((x) << 12)
+#define BLTCON1_BSH(x) ((x) << 12)
+
+enum {
+       BLTCON_LINE             = 0x00000001,
+       BLTCON_DECR             = 0x00000002,
+       BLTCON_FCI              = 0x00000004,
+       BLTCON_IFE              = 0x00000008,
+       BLTCON_EFE              = 0x00000010,
+       BLTCON_DOFF             = 0x00000080,
+       BLTCON_USED             = 0x01000000,
+       BLTCON_USEC             = 0x02000000,
+       BLTCON_USEB             = 0x04000000,
+       BLTCON_USEA             = 0x08000000
+};
+
+#define BLTCON_LF(x)   ((uint32_t)(x) << 16)
+#define BLTCON_ASH(x)  ((uint32_t)(x) << 28)
+#define BLTCON_BSH(x)  ((uint32_t)(x) << 12)
+
+#define BLTSIZE_XWORDS(x)      ((uint16_t)(x) & 0x7f)
+#define BLTSIZE_X(x)           BLTSIZE_XWORDS((x) / 16)
+#define BLTSIZE_Y(x)           ((uint16_t)(x) << 6)
+#define BLTSIZE(x, y)          (BLTSIZE_X(x) | BLTSIZE_Y(y))
+
+
+#define CIAA_PA_FIR0   0x40
+#define CIAA_PA_FIR1   0x80
+
+enum {
+       SERDATR_STOP8   = 0x0100,
+       SERDATR_STOP9   = 0x0200,
+       SERDATR_RXD             = 0x0800,
+       SERDATR_TSRE    = 0x1000,
+       SERDATR_TBE             = 0x2000,
+       SERDATR_RBF             = 0x4000,
+       SERDATR_OVRUN   = 0x8000
+};
+
+#define ADKCON_UARTBRK 0x0800
+
+#endif /* HWREGS_H_ */
diff --git a/src/amiga/libc/ctype.c b/src/amiga/libc/ctype.c
new file mode 100644 (file)
index 0000000..9676441
--- /dev/null
@@ -0,0 +1,56 @@
+#include "ctype.h"
+
+int isalnum(int c)
+{
+       return isalpha(c) || isdigit(c);
+}
+
+int isalpha(int c)
+{
+       return isupper(c) || islower(c);
+}
+
+int isblank(int c)
+{
+       return c == ' ' || c == '\t';
+}
+
+int isdigit(int c)
+{
+       return c >= '0' && c <= '9';
+}
+
+int isupper(int c)
+{
+       return c >= 'A' && c <= 'Z';
+}
+
+int islower(int c)
+{
+       return c >= 'a' && c <= 'z';
+}
+
+int isgraph(int c)
+{
+       return c > ' ' && c <= '~';
+}
+
+int isprint(int c)
+{
+       return isgraph(c) || c == ' ';
+}
+
+int isspace(int c)
+{
+       return isblank(c) || c == '\f' || c == '\n' || c == '\r' || c == '\v';
+}
+
+int toupper(int c)
+{
+       return islower(c) ? (c + ('A' - 'a')) : c;
+}
+
+int tolower(int c)
+{
+       return isupper(c) ? (c + ('A' - 'a')) : c;
+}
diff --git a/src/amiga/libc/ctype.h b/src/amiga/libc/ctype.h
new file mode 100644 (file)
index 0000000..5b010d4
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef CTYPE_H_
+#define CTYPE_H_
+
+int isalnum(int c);
+int isalpha(int c);
+#define isascii(c)     ((c) < 128)
+int isblank(int c);
+int isdigit(int c);
+int isupper(int c);
+int islower(int c);
+int isprint(int c);
+int isspace(int c);
+
+int toupper(int c);
+int tolower(int c);
+
+#endif /* CTYPE_H_ */
diff --git a/src/amiga/libc/inttypes.h b/src/amiga/libc/inttypes.h
new file mode 100644 (file)
index 0000000..1edfed1
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef AMIGA_LIBC_INTTYPES_H_
+#define AMIGA_LIBC_INTTYPES_H_
+
+typedef char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef int32_t intptr_t;
+typedef uint32_t uintptr_t;
+
+#endif /* AMIGA_LIBC_INTTYPES_H_ */
diff --git a/src/amiga/libc/stdarg.h b/src/amiga/libc/stdarg.h
new file mode 100644 (file)
index 0000000..696aab2
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef STDARG_H_
+#define STDARG_H_
+
+typedef __builtin_va_list va_list;
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+
+#endif /* STDARG_H_ */
diff --git a/src/amiga/libc/stdint.h b/src/amiga/libc/stdint.h
new file mode 100644 (file)
index 0000000..775c434
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef AMIGA_LIBC_STDINT_H_
+#define AMIGA_LIBC_STDINT_H_
+
+#include <inttypes.h>
+
+#endif /* AMIGA_LIBC_STDINT_H_ */
diff --git a/src/amiga/libc/stdio.c b/src/amiga/libc/stdio.c
new file mode 100644 (file)
index 0000000..c404a52
--- /dev/null
@@ -0,0 +1,265 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "serial.h"
+
+static void bwrite(char *buf, size_t buf_sz, char *str, int sz);
+static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap);
+
+int putchar(int c)
+{
+       if(c == '\n') {
+               ser_putchar('\r');
+       }
+       ser_putchar(c);
+       return c;
+}
+
+int puts(const char *s)
+{
+       while(*s) {
+               putchar(*s++);
+       }
+       putchar('\n');
+       return 0;
+}
+
+/* -- printf and friends -- */
+
+static char *convc = "dioxXucsfeEgGpn%";
+
+#define IS_CONV(c)     strchr(convc, c)
+
+int printf(const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(0, 0, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vprintf(const char *fmt, va_list ap)
+{
+       return intern_printf(0, 0, fmt, ap);
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(buf, 0, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list ap)
+{
+       return intern_printf(buf, 0, fmt, ap);
+}
+
+int snprintf(char *buf, size_t sz, const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(buf, sz, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
+{
+       return intern_printf(buf, sz, fmt, ap);
+}
+
+
+/* intern_printf provides all the functionality needed by all the printf
+ * variants.
+ * - buf: optional buffer onto which the formatted results are written. If null
+ *   then the output goes to the terminal through putchar calls. This is used
+ *   by the (v)sprintf variants which write to an array of char.
+ * - sz: optional maximum size of the output, 0 means unlimited. This is used
+ *   by the (v)snprintf variants to avoid buffer overflows.
+ * The rest are obvious, format string and variable argument list.
+ */
+
+#define BUF(x) ((x) ? (x) + cnum : (x))
+#define SZ(x)  ((x) ? (x) - cnum : (x))
+
+static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap)
+{
+       char conv_buf[32];
+       char *str;
+       int i, slen;
+       const char *fstart = 0;
+
+       /* state */
+       int cnum = 0;
+       int base = 10;
+       int alt = 0;
+       int fwidth = 0;
+       int padc = ' ';
+       int sign = 0;
+       int left_align = 0;     /* not implemented yet */
+       int hex_caps = 0;
+       int unsig = 0;
+
+       while(*fmt) {
+               if(*fmt == '%') {
+                       fstart = fmt++;
+                       continue;
+               }
+
+               if(fstart) {
+                       if(IS_CONV(*fmt)) {
+                               switch(*fmt) {
+                               case 'X':
+                                       hex_caps = 1;
+
+                               case 'x':
+                               case 'p':
+                                       base = 16;
+
+                                       if(alt) {
+                                               bwrite(BUF(buf), SZ(sz), "0x", 2);
+                                       }
+
+                               case 'u':
+                                       unsig = 1;
+
+                                       if(0) {
+                               case 'o':
+                                               base = 8;
+
+                                               if(alt) {
+                                                       bwrite(BUF(buf), SZ(sz), "0", 1);
+                                               }
+                                       }
+
+                               case 'd':
+                               case 'i':
+                                       if(unsig) {
+                                               utoa(va_arg(ap, unsigned int), conv_buf, base);
+                                       } else {
+                                               itoa(va_arg(ap, int), conv_buf, base);
+                                       }
+                                       if(hex_caps) {
+                                               for(i=0; conv_buf[i]; i++) {
+                                                       conv_buf[i] = toupper(conv_buf[i]);
+                                               }
+                                       }
+
+                                       slen = strlen(conv_buf);
+                                       for(i=slen; i<fwidth; i++) {
+                                               bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+
+                                       bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
+                                       cnum += slen;
+                                       break;
+
+                               case 'c':
+                                       {
+                                               char c = va_arg(ap, int);
+                                               bwrite(BUF(buf), SZ(sz), &c, 1);
+                                               cnum++;
+                                       }
+                                       break;
+
+                               case 's':
+                                       str = va_arg(ap, char*);
+                                       slen = strlen(str);
+
+                                       for(i=slen; i<fwidth; i++) {
+                                               bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+                                       bwrite(BUF(buf), SZ(sz), str, slen);
+                                       cnum += slen;
+                                       break;
+
+                               case 'n':
+                                       *va_arg(ap, int*) = cnum;
+                                       break;
+
+                               default:
+                                       break;
+                               }
+
+                               /* restore default conversion state */
+                               base = 10;
+                               alt = 0;
+                               fwidth = 0;
+                               padc = ' ';
+                               hex_caps = 0;
+
+                               fstart = 0;
+                               fmt++;
+                       } else {
+                               switch(*fmt) {
+                               case '#':
+                                       alt = 1;
+                                       break;
+
+                               case '+':
+                                       sign = 1;
+                                       break;
+
+                               case '-':
+                                       left_align = 1;
+                                       break;
+
+                               case 'l':
+                               case 'L':
+                                       break;
+
+                               case '0':
+                                       padc = '0';
+                                       break;
+
+                               default:
+                                       if(isdigit(*fmt)) {
+                                               const char *fw = fmt;
+                                               while(*fmt && isdigit(*fmt)) fmt++;
+
+                                               fwidth = atoi(fw);
+                                               continue;
+                                       }
+                               }
+                               fmt++;
+                       }
+               } else {
+                       bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1);
+                       cnum++;
+               }
+       }
+
+       return 0;
+}
+
+
+/* bwrite is called by intern_printf to transparently handle writing into a
+ * buffer (if buf is non-null) or to the terminal (if buf is null).
+ */
+static void bwrite(char *buf, size_t buf_sz, char *str, int sz)
+{
+       if(buf) {
+               if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
+               memcpy(buf, str, sz);
+
+               buf[sz] = 0;
+       } else {
+               int i;
+               for(i=0; i<sz; i++) {
+                       putchar(*str++);
+               }
+       }
+}
+
diff --git a/src/amiga/libc/stdio.h b/src/amiga/libc/stdio.h
new file mode 100644 (file)
index 0000000..50daaaa
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef STDIO_H_
+#define STDIO_H_
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+int putchar(int c);
+int getchar(void);
+
+int puts(const char *s);
+
+int printf(const char *fmt, ...);
+int vprintf(const char *fmt, va_list ap);
+
+int sprintf(char *buf, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list ap);
+
+int snprintf(char *buf, size_t sz, const char *fmt, ...);
+int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap);
+
+#endif /* STDIO_H_ */
diff --git a/src/amiga/libc/stdlib.c b/src/amiga/libc/stdlib.c
new file mode 100644 (file)
index 0000000..9b8dcc4
--- /dev/null
@@ -0,0 +1,119 @@
+#include <stdlib.h>
+#include <ctype.h>
+
+int atoi(const char *str)
+{
+       return strtol(str, 0, 10);
+}
+
+long atol(const char *str)
+{
+       return strtol(str, 0, 10);
+}
+
+long strtol(const char *str, char **endp, int base)
+{
+       long acc = 0;
+       int sign = 1;
+
+       while(isspace(*str)) str++;
+
+       if(base == 0) {
+               if(str[0] == '0') {
+                       if(str[1] == 'x' || str[1] == 'X') {
+                               base = 16;
+                       } else {
+                               base = 8;
+                       }
+               } else {
+                       base = 10;
+               }
+       }
+
+       if(*str == '+') {
+               str++;
+       } else if(*str == '-') {
+               sign = -1;
+               str++;
+       }
+
+       while(*str) {
+               long val;
+               char c = tolower(*str);
+
+               if(isdigit(c)) {
+                       val = *str - '0';
+               } else if(c >= 'a' || c <= 'f') {
+                       val = 10 + c - 'a';
+               }
+               if(val >= base) {
+                       break;
+               }
+
+               acc = acc * base + val;
+               str++;
+       }
+
+       if(endp) {
+               *endp = (char*)str;
+       }
+
+       return sign > 0 ? acc : -acc;
+}
+
+void itoa(int val, char *buf, int base)
+{
+       static char rbuf[16];
+       char *ptr = rbuf;
+       int neg = 0;
+
+       if(val < 0) {
+               neg = 1;
+               val = -val;
+       }
+
+       if(val == 0) {
+               *ptr++ = '0';
+       }
+
+       while(val) {
+               int digit = val % base;
+               *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a');
+               val /= base;
+       }
+
+       if(neg) {
+               *ptr++ = '-';
+       }
+
+       ptr--;
+
+       while(ptr >= rbuf) {
+               *buf++ = *ptr--;
+       }
+       *buf = 0;
+}
+
+void utoa(unsigned int val, char *buf, int base)
+{
+       static char rbuf[16];
+       char *ptr = rbuf;
+
+       if(val == 0) {
+               *ptr++ = '0';
+       }
+
+       while(val) {
+               unsigned int digit = val % base;
+               *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a');
+               val /= base;
+       }
+
+       ptr--;
+
+       while(ptr >= rbuf) {
+               *buf++ = *ptr--;
+       }
+       *buf = 0;
+}
+
diff --git a/src/amiga/libc/stdlib.h b/src/amiga/libc/stdlib.h
new file mode 100644 (file)
index 0000000..ea0a6dc
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef AMIGA_LIBC_STDLIB_H_
+#define AMIGA_LIBC_STDLIB_H_
+
+#include <stdint.h>
+
+typedef int32_t ssize_t;
+typedef uint32_t size_t;
+
+int atoi(const char *str);
+long atol(const char *str);
+long strtol(const char *str, char **endp, int base);
+
+void itoa(int val, char *buf, int base);
+void utoa(unsigned int val, char *buf, int base);
+
+#endif /* AMIGA_LIBC_STDLIB_H_ */
diff --git a/src/amiga/libc/string.c b/src/amiga/libc/string.c
new file mode 100644 (file)
index 0000000..9260cca
--- /dev/null
@@ -0,0 +1,116 @@
+#include <string.h>
+#include <ctype.h>
+
+void memset(void *s, int c, size_t n)
+{
+       char *ptr = s;
+       while(n--) {
+               *ptr++ = c;
+       }
+}
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+       char *dptr = dest;
+       const char *sptr = src;
+
+       while(n--) {
+               *dptr++ = *sptr++;
+       }
+       return dest;
+}
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       int i;
+       char *dptr;
+       const char *sptr;
+
+       if(dest <= src) {
+               /* forward copy */
+               dptr = dest;
+               sptr = src;
+               for(i=0; i<n; i++) {
+                       *dptr++ = *sptr++;
+               }
+       } else {
+               /* backwards copy */
+               dptr = (char*)dest + n - 1;
+               sptr = (char*)src + n - 1;
+               for(i=0; i<n; i++) {
+                       *dptr-- = *sptr--;
+               }
+       }
+
+       return dest;
+}
+
+size_t strlen(const char *s)
+{
+       size_t len = 0;
+       while(*s++) len++;
+       return len;
+}
+
+char *strchr(const char *s, int c)
+{
+       while(*s) {
+               if(*s == c) {
+                       return (char*)s;
+               }
+               s++;
+       }
+       return 0;
+}
+
+char *strrchr(const char *s, int c)
+{
+       const char *ptr = s;
+
+       /* find the end */
+       while(*ptr) ptr++;
+
+       /* go back checking for c */
+       while(--ptr >= s) {
+               if(*ptr == c) {
+                       return (char*)ptr;
+               }
+       }
+       return 0;
+}
+
+char *strstr(const char *str, const char *substr)
+{
+       while(*str) {
+               const char *s1 = str;
+               const char *s2 = substr;
+
+               while(*s1 && *s1 == *s2) {
+                       s1++;
+                       s2++;
+               }
+               if(!*s2) {
+                       return (char*)str;
+               }
+               str++;
+       }
+       return 0;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+       while(*s1 && *s1 == *s2) {
+               s1++;
+               s2++;
+       }
+       return *s1 - *s2;
+}
+
+int strcasecmp(const char *s1, const char *s2)
+{
+       while(*s1 && tolower(*s1) == tolower(*s2)) {
+               s1++;
+               s2++;
+       }
+       return tolower(*s1) - tolower(*s2);
+}
diff --git a/src/amiga/libc/string.h b/src/amiga/libc/string.h
new file mode 100644 (file)
index 0000000..e1a1182
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef AMIGA_LIBC_STRING_H_
+#define AMIGA_LIBC_STRING_H_
+
+#include <stdlib.h>
+
+void memset(void *dest, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+
+size_t strlen(const char *s);
+
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+
+char *strstr(const char *str, const char *substr);
+
+int strcmp(const char *s1, const char *s2);
+int strcasecmp(const char *s1, const char *s2);
+
+#endif /* AMIGA_LIBC_STRING_H_ */
diff --git a/src/amiga/main.c b/src/amiga/main.c
new file mode 100644 (file)
index 0000000..7585bf0
--- /dev/null
@@ -0,0 +1,53 @@
+#include <string.h>
+#include "hwregs.h"
+#include "copper.h"
+#include "gfx.h"
+#include "game.h"
+#include "serial.h"
+
+static uint32_t coplist[128];
+
+int main(void)
+{
+       int i;
+
+       REG_INTENA = SETBITS(INTEN_VERTB | INTEN_MASTER);
+       REG_DMACON = CLRBITS(DMA_ALL);
+
+       ser_init(38400);
+       ser_print("lugburz amiga starting up...\n");
+
+       init_gfx();
+
+       REG_COLOR0 = 0x111;
+       REG_COLOR1 = 0x23c;
+       REG_COLOR2 = 0xc32;
+       REG_COLOR3 = 0x22c;
+       REG_COLOR4 = 0xcc2;
+
+       wait_vblank();
+
+       init_copper(coplist, 32, COPPER_SINGLE);
+       for(i=0; i<NBPL; i++) {
+               uint32_t addr = (intptr_t)bplptr[i];
+               int reg = REGN_BPL1PTH + i * 4;
+               add_copper(COPPER_MOVE(reg, addr >> 16));
+               add_copper(COPPER_MOVE(reg + 2, addr));
+       }
+       add_copper(COPPER_VWAIT(50));
+       add_copper(COPPER_MOVE(REGN_COLOR0, 0xf00));
+       add_copper(COPPER_VWAIT(60));
+       add_copper(COPPER_MOVE(REGN_COLOR0, 0x111));
+       *copperlist_end = COPPER_END;
+
+       game_init();
+
+       wait_vblank();
+       REG_DMACON = SETBITS(DMA_BPL | DMA_COPPER | DMA_MASTER);
+
+       for(;;) {
+               wait_vblank();
+               game_draw();
+       }
+       return 0;
+}
diff --git a/src/amiga/serial.c b/src/amiga/serial.c
new file mode 100644 (file)
index 0000000..dae3a12
--- /dev/null
@@ -0,0 +1,48 @@
+#include "hwregs.h"
+#include "serial.h"
+
+#define CLK            3546895
+#define BVAL(b)        (CLK / (b) - 1)
+
+static inline uint16_t baudval(int baud)
+{
+       switch(baud) {
+       case 110: return BVAL(110);
+       case 300: return BVAL(300);
+       case 600: return BVAL(600);
+       case 1200: return BVAL(1200);
+       case 2400: return BVAL(2400);
+       case 4800: return BVAL(4800);
+       case 9600: return BVAL(9600);
+       case 14400: return BVAL(14400);
+       case 19200: return BVAL(19200);
+       case 38400: return BVAL(38400);
+       case 57600: return BVAL(57600);
+       case 115200: return BVAL(115200);
+       default:
+               break;
+       }
+       return BVAL(baud);
+}
+
+void ser_init(int baud)
+{
+       REG_SERPER = baudval(baud) & 0x7fff;
+}
+
+/*
+void ser_putchar(int c)
+{
+       REG_SERDAT = ((uint16_t)c & 0xff) | 0x100;
+}
+*/
+
+void ser_print(const char *s)
+{
+       while(*s) {
+               if(*s == '\n') {
+                       ser_putchar('\r');
+               }
+               ser_putchar(*s++);
+       }
+}
diff --git a/src/amiga/serial.h b/src/amiga/serial.h
new file mode 100644 (file)
index 0000000..e460c98
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SERIAL_H_
+#define SERIAL_H_
+
+#include "hwregs.h"
+
+/* dff030 is REG_SERDAT
+ * dff018 is REG_SERDATR
+ * bit 13 of SERDATR is TBE (transmit buffer empty)
+ */
+#define ser_putchar(c) \
+       asm volatile( \
+               "or.w #0x100, %0\n\t" \
+               "0: btst #13, 0xdff018\n\t" \
+               "beq 0b\n\t" \
+               "move.w %0, 0xdff030\n\t" \
+               :: "d"((int16_t)c))
+
+void ser_init(int baud);
+void ser_print(const char *s);
+
+#endif /* SERIAL_H_ */
diff --git a/src/amiga/startup.s b/src/amiga/startup.s
new file mode 100644 (file)
index 0000000..745cf67
--- /dev/null
@@ -0,0 +1,30 @@
+| vi:filetype=gas68k:
+       .global halt_cpu
+       .extern main
+
+       .section .startup,"a"
+
+       | enter supervisor mode (assumes VBR=0)
+       move.l #super, 0x80
+       trap #0
+super:
+       ori.w #0x0300, %sr      | disable interrupts
+
+       | zero the .bss section
+       move.l #_bss_start, %a0
+       move.l #_bss_end, %a1
+       cmp.l %a0, %a1
+       beq.s 1f        | skip zeroing if the section is empty
+0:     clr.b (%a0)+
+       cmp.l %a0, %a1
+       bne.s 0b
+1:
+       | setup the stack
+       move.l #_stacktop, %sp
+       andi.w #0xf8ff, %sr     | enable interrupts
+
+       jsr main
+0:     bra.b 0b
+
+halt_cpu:
+       stop #0x2700
diff --git a/src/game.c b/src/game.c
new file mode 100644 (file)
index 0000000..e5b6912
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <string.h>
+#include "game.h"
+#include "gfx.h"
+
+int game_init(void)
+{
+       printf("hello world\n");
+
+       return 0;
+}
+
+void game_draw(void)
+{
+}
diff --git a/src/game.h b/src/game.h
new file mode 100644 (file)
index 0000000..69c14e8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef GAME_H_
+#define GAME_H_
+
+int game_init(void);
+void game_draw(void);
+
+#endif /* GAME_H_ */
diff --git a/tools/mk_adf.py b/tools/mk_adf.py
new file mode 100755 (executable)
index 0000000..64b0d94
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+# mk_adf.py <bootblock> <payload> <output_adf>
+#
+# Stuff a given bootblock and payload into an output ADF image.
+# 
+# Written & released by Keir Fraser <keir.xen@gmail.com>
+# 
+# This is free and unencumbered software released into the public domain.
+# See the file COPYING for more details, or visit <http://unlicense.org>.
+
+import struct, sys
+
+# Amiga bootblock checksum
+def checksum(bb, sum=0):
+    while len(bb):
+        x, bb = struct.unpack(">L",bb[:4]), bb[4:]
+        sum += x[0]
+        if sum >= (1<<32):
+            sum -= (1<<32)-1
+    return sum
+
+def main(argv):
+    bb_f = open(argv[1], "rb")
+    pl_f = open(argv[2], "rb")
+    out_f = open(argv[3], "wb")
+    bb_dat = bb_f.read()
+    pl_dat = pl_f.read()
+
+    # Construct bootblock header. We will splice in the checksum later.
+    header = struct.pack(">ccccLLLL",
+                         'D', 'O', 'S', '\0',         # Bootblock signature
+                         0,                           # Checksum (placeholder)
+                         880,                         # Root block
+                         0x60060000,                  # BRA.B +6
+                         (len(pl_dat) + 511) & ~511)  # Payload length, padded
+                         
+    
+    # Compute checksum over header, bootblock, and first 512 bytes of payload.
+    sum = checksum(pl_dat[:512], checksum(bb_dat, checksum(header)))
+    sum ^= 0xFFFFFFFF
+    # Splice the computed checksum into the header
+    header = header[:4] + struct.pack(">L", sum) + header[8:]
+    # Write out the header and bootblock code
+    out_f.write(header)
+    out_f.write(bb_dat)
+    # Pad bootblock to 512 bytes
+    for x in xrange((512-len(bb_dat)-len(header))/4):
+        out_f.write(struct.pack(">L", 0))
+    # Write the payload from sector 1 onwards
+    out_f.write(pl_dat)
+    # Pad the ADF image to 880kB
+    for x in xrange((901120-len(pl_dat)-512)/4):
+        out_f.write(struct.pack(">L", 0))
+        
+if __name__ == "__main__":
+    main(sys.argv)