diff --git a/.github/workflows/github-ci.yml b/.github/workflows/github-ci.yml index 28eb29e8..3cdd0c5a 100644 --- a/.github/workflows/github-ci.yml +++ b/.github/workflows/github-ci.yml @@ -42,6 +42,7 @@ jobs: - pico-test - sifive-e-test - sifive-unleashed-test + - rosco-m68k-test exclude: # no toolchain for 7.5.0 for or1k - project: or1ksim diff --git a/arch/m68k/arch.c b/arch/m68k/arch.c index 468c5d5d..19948a23 100644 --- a/arch/m68k/arch.c +++ b/arch/m68k/arch.c @@ -8,16 +8,22 @@ #include #include #include +#include #include +#include #define LOCAL_TRACE 0 void arch_early_init(void) { LTRACE; + arch_disable_ints(); + +#if M68K_CPU >= 68010 // set the exception vector base extern uint32_t exc_vectors[256]; asm volatile("movec %0, %%vbr" :: "r"(exc_vectors)); +#endif } void arch_init(void) { @@ -42,3 +48,13 @@ void arch_clean_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLE void arch_invalidate_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; } void arch_sync_cache_range(addr_t start, size_t len) { PANIC_UNIMPLEMENTED; } +/* atomics that may need to be implemented */ +// from https://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary +unsigned int __atomic_fetch_add_4 (volatile void *mem, unsigned int val, int model) { + spin_lock_saved_state_t state; + arch_interrupt_save(&state, 0); + unsigned int old = *(volatile unsigned int *)mem; + *(volatile unsigned int *)mem = old + val; + arch_interrupt_restore(state, 0); + return old; +} diff --git a/arch/m68k/exceptions.c b/arch/m68k/exceptions.c index 7e853387..8c34e21b 100644 --- a/arch/m68k/exceptions.c +++ b/arch/m68k/exceptions.c @@ -10,27 +10,71 @@ #include #include #include +#include #define LOCAL_TRACE 0 +typedef struct m68k_iframe { + uint32_t d[8]; + uint32_t a[7]; + uint16_t sr; + uint16_t pc_high; + uint16_t pc_low; + uint16_t format : 4; + uint16_t vector_offset : 12; +} m68k_iframe_t; + +void dump_iframe(const m68k_iframe_t *iframe) { + printf("pc 0x%08x sr 0x%04x format %#x vector %#x\n", iframe->pc_low | iframe->pc_high << 16, iframe->sr, + iframe->format, iframe->vector_offset / 4); + printf("d0 0x%08x d1 0x%08x d2 0x%08x d3 0x%08x\n", iframe->d[0], iframe->d[1], iframe->d[2], iframe->d[3]); + printf("d4 0x%08x d5 0x%08x d6 0x%08x d7 0x%08x\n", iframe->d[4], iframe->d[5], iframe->d[6], iframe->d[7]); + printf("a0 0x%08x a1 0x%08x a2 0x%08x a3 0x%08x\n", iframe->a[0], iframe->a[1], iframe->a[2], iframe->a[3]); + printf("a4 0x%08x a5 0x%08x a6 0x%08x\n", iframe->a[4], iframe->a[5], iframe->a[6]); +} + +void m68k_exception(m68k_iframe_t *frame) { + uint8_t code = frame->vector_offset / 4; + + LTRACEF("frame %p, code %#hhx\n", frame, code); + + dump_iframe(frame); + + printf("more stack:\n"); + hexdump8(frame, 256); + + panic("unimplemented exception %#hhx\n", code); +} + +void m68k_trap_exception(m68k_iframe_t *frame) { + panic("unhandled trap exception!\n"); +} + +void m68k_null_trap(m68k_iframe_t *frame) { + panic("unhandled null trap exception!"); +} + // defined in platform interrupt controller extern enum handler_return m68k_platform_irq(uint8_t irq); -void m68k_exception(void *frame, uint8_t code) { - LTRACEF("frame %p, code %hhu\n", frame, code); +void m68k_irq(m68k_iframe_t *frame) { + uint8_t code = frame->vector_offset / 4; - panic("unimplemented exception %hhu\n", code); -} + LTRACEF("frame %p, code %#hhx\n", frame, code); -void m68k_irq(void *frame, uint8_t code) { - LTRACEF("frame %p, code %hhu\n", frame, code); + THREAD_STATS_INC(interrupts); if (unlikely(code == 0)) { // spurious interrupt return; } + target_set_debug_led(1, true); + enum handler_return ret = m68k_platform_irq(code); + + target_set_debug_led(1, false); + if (ret == INT_RESCHEDULE) { thread_preempt(); } diff --git a/arch/m68k/exceptions_asm.S b/arch/m68k/exceptions_asm.S index 46776a60..ceb844fa 100644 --- a/arch/m68k/exceptions_asm.S +++ b/arch/m68k/exceptions_asm.S @@ -9,75 +9,80 @@ .text -.macro irq_vector n -m68k_irq_vector_\n: +#if M68K_CPU >= 68010 +// For 68010s and above the exception frame already has a code pushed on the stack, +// so it's easy to just vector most of the handlers into one of a few classes of handlers +// and decode the vector in C. + +.align 4 +_m68k_irq_vector: + // TODO: save less state for IRQs moveml %d0-%d7/%a0-%a6, %sp@- - pea \n movel %sp,%sp@- jsr m68k_irq - addaw #8, %sp + add #4, %sp moveml %sp@+, %d0-%d7/%a0-%a6 rte -.endm -irq_vector 0 -irq_vector 1 -irq_vector 2 -irq_vector 3 -irq_vector 4 -irq_vector 5 -irq_vector 6 -irq_vector 7 - -.macro exception_vector name n +.macro exception_vector name func +.align 4 \name: moveml %d0-%d7/%a0-%a6, %sp@- - pea \n movel %sp,%sp@- - jsr m68k_exception - addaw #8, %sp + jsr \func + add #4, %sp moveml %sp@+, %d0-%d7/%a0-%a6 rte .endm -exception_vector m68k_access_fault 2 -exception_vector m68k_address_error 3 -exception_vector m68k_illegal_vector 4 -exception_vector m68k_div_by_zero 5 -exception_vector m68k_chk 6 -exception_vector m68k_trap 7 -exception_vector m68k_priv_violation 8 -exception_vector m68k_trace 9 -exception_vector m68k_unimp_aline 10 -exception_vector m68k_unimp_fline 11 +exception_vector _m68k_general_exception m68k_exception +exception_vector _m68k_trap_exception m68k_trap_exception .section .text.vectab -.align 4 +.align 16 DATA(exc_vectors) -.org 0x8 - .long m68k_access_fault - .long m68k_address_error - .long m68k_illegal_vector - .long m68k_div_by_zero - .long m68k_chk - .long m68k_trap - .long m68k_priv_violation - .long m68k_trace - .long m68k_unimp_aline - .long m68k_unimp_fline -.org 0x60 - .long m68k_irq_vector_0 - .long m68k_irq_vector_1 - .long m68k_irq_vector_2 - .long m68k_irq_vector_3 - .long m68k_irq_vector_4 - .long m68k_irq_vector_5 - .long m68k_irq_vector_6 - .long m68k_irq_vector_7 + // first two entries are the reset vector + .long 0 + .long 0 + // general exceptions + .rept (15 - 2) + .long _m68k_general_exception + .endr +.org (15*4) + // uninitialized irq vector + .long _m68k_irq_vector +.org (16*4) + .rept (24 - 16) + .long _m68k_general_exception + .endr +.org (24 * 4) // offset 0x60 + // start of autovectored interrupts + .rept (32 - 24) + .long _m68k_irq_vector + .endr +.org (32 * 4) // offset 0x60 + // index 32, offset 0x80 + .rept (48 - 32) + .long _m68k_trap_exception + .endr +.org (48 * 4) + // start of FPU, MMU vectors + .rept (64 - 48) + .long _m68k_general_exception + .endr +.org (64 * 4) // offset 0x100 + // index 64, offset 0x100, end of reserved vectors + // start of user vectors + .rept (256 - 64) + .long _m68k_irq_vector + .endr .org 4*256 END_DATA(exc_vectors) +#else +#error add support for pre 68010 exceptions +#endif diff --git a/arch/m68k/rules.mk b/arch/m68k/rules.mk index 49911dbf..1183027a 100644 --- a/arch/m68k/rules.mk +++ b/arch/m68k/rules.mk @@ -2,24 +2,14 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) -MODULE_SRCS += \ - $(LOCAL_DIR)/arch.c \ - $(LOCAL_DIR)/asm.S \ - $(LOCAL_DIR)/exceptions.c \ - $(LOCAL_DIR)/exceptions_asm.S \ - $(LOCAL_DIR)/start.S \ - $(LOCAL_DIR)/thread.c \ +MODULE_SRCS += $(LOCAL_DIR)/arch.c +MODULE_SRCS += $(LOCAL_DIR)/asm.S +MODULE_SRCS += $(LOCAL_DIR)/exceptions.c +MODULE_SRCS += $(LOCAL_DIR)/exceptions_asm.S +MODULE_SRCS += $(LOCAL_DIR)/start.S +MODULE_SRCS += $(LOCAL_DIR)/thread.c -# $(LOCAL_DIR)/asm.S \ - $(LOCAL_DIR)/cache.c \ - $(LOCAL_DIR)/cache-ops.S \ - $(LOCAL_DIR)/ops.S \ - $(LOCAL_DIR)/mmu.c \ - $(LOCAL_DIR)/faults.c \ - $(LOCAL_DIR)/descriptor.c - -GLOBAL_DEFINES += \ - SMP_MAX_CPUS=1 +GLOBAL_DEFINES += SMP_MAX_CPUS=1 # set the default toolchain to microblaze elf and set a #define ifndef TOOLCHAIN_PREFIX @@ -28,7 +18,16 @@ endif WITH_LINKER_GC ?= 0 +# select the cpu based on flags the platform/target passes in +M68K_CPU ?= 68040 + +ifeq ($(M68K_CPU),68010) +ARCH_COMPILEFLAGS := -mcpu=68010 +else ifeq ($(M68K_CPU),68040) ARCH_COMPILEFLAGS := -mcpu=68040 +else +$(error add support for selected cpu $(M68K_CPU)) +endif LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(GLOBAL_COMPILEFLAGS) $(ARCH_COMPILEFLAGS) $(GLOBAL_COMPILEFLAGS) -print-libgcc-file-name) $(info LIBGCC = $(LIBGCC)) @@ -41,9 +40,10 @@ ARCH_OPTFLAGS := -O2 KERNEL_BASE ?= $(MEMBASE) KERNEL_LOAD_OFFSET ?= 0 -GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) +GLOBAL_DEFINES += MEMBASE=$(MEMBASE) +GLOBAL_DEFINES += MEMSIZE=$(MEMSIZE) +GLOBAL_DEFINES += M68K_CPU=$(M68K_CPU) +GLOBAL_DEFINES += M68K_CPU_$(M68K_CPU)=1 # potentially generated files that should be cleaned out with clean make rule GENERATED += \ diff --git a/arch/m68k/start.S b/arch/m68k/start.S index a9bc7a5b..15410eed 100644 --- a/arch/m68k/start.S +++ b/arch/m68k/start.S @@ -9,25 +9,56 @@ .section .text.boot FUNCTION(_start) - // clear bss - lea __bss_start,%a0 - cmpal #__bss_end,%a0 - beqs 1f +#if ARCH_DO_RELOCATION + lea %pc@(_start),%a0 // load the current address using PC relative addressing mode + movl #_start,%a1 // load the same symbol absolutely + cmpal %a0,%a1 + beqs bss_clear + + // load the end address for loop termination + movl #_end,%a2 + + // copy forwards + // NOTE: assumes the source and target do not overlap 0: - clrb %a0@+ - cmpal #__bss_end,%a0 - bnes 0b + movel %a0@+,%a1@+ + cmpal %a1,%a2 + bne 0b + + // branch to the new location + movl #bss_clear,%a0 + jmp %a0@ +#endif + + // clear bss +bss_clear: + lea __bss_start,%a0 + lea __bss_end,%a1 + cmpl %a0,%a1 + beqs 1f + // zero 4 bytes at a time +0: + clrl %a0@+ + cmpal %a1,%a0 + bne 0b 1: - movel #_default_stack_top,%sp + // load the initial stack pointer + lea _default_stack_top,%sp + // branch into C land with 4 zeroed args + clrl %sp@- + clrl %sp@- + clrl %sp@- + clrl %sp@- jsr lk_main - jmp . + // if we return from main just loop forever + bra . END_FUNCTION(_start) .bss -.align 8 +.align 4 _default_stack_base: .skip 4096 _default_stack_top: diff --git a/kernel/thread.c b/kernel/thread.c index 5427d1f8..cfb713af 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/platform/qemu-virt-m68k/pic.c b/platform/qemu-virt-m68k/pic.c index 4a35990b..8612cf15 100644 --- a/platform/qemu-virt-m68k/pic.c +++ b/platform/qemu-virt-m68k/pic.c @@ -96,9 +96,10 @@ enum handler_return m68k_platform_irq(uint8_t m68k_irq) { LTRACEF("m68k irq vector %d\n", m68k_irq); // translate m68k irqs to pic numbers + // incoming IRQs are from 0x19-0x1f (autovectored 1 - 7 on the cpu) int pic_num; - if (likely(m68k_irq >= 1 && m68k_irq <= 6)) { - pic_num = m68k_irq - 1; + if (likely(m68k_irq >= 0x19 && m68k_irq <= 0x1f)) { + pic_num = m68k_irq - 0x19; } else { panic("unhandled irq %d from cpu\n", m68k_irq); } diff --git a/platform/qemu-virt-m68k/rules.mk b/platform/qemu-virt-m68k/rules.mk index 21dbeeb2..b7a1f8e4 100644 --- a/platform/qemu-virt-m68k/rules.mk +++ b/platform/qemu-virt-m68k/rules.mk @@ -3,6 +3,7 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) ARCH := m68k +M68K_CPU := 68040 LK_HEAP_IMPLEMENTATION ?= dlmalloc MODULE_DEPS += lib/cbuf diff --git a/platform/rosco-m68k/duart.c b/platform/rosco-m68k/duart.c new file mode 100644 index 00000000..5df92a56 --- /dev/null +++ b/platform/rosco-m68k/duart.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2021 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include "platform_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +// driver for a 68c681 acting as a dual uart and a system timer and a few gpios + +// ticks in units of ms +static volatile uint32_t ticks; + +// periodic timer callback stuff +static platform_timer_callback t_callback; +static void *t_arg; +static lk_time_t t_next_periodic_tick; +static lk_time_t t_periodic_interval; + +// uart stuff +#define RXBUF_SIZE 128 +static char uart_rx_buf_data[RXBUF_SIZE]; +static cbuf_t uart_rx_buf; + +static volatile uint8_t * const DUART_BASE = (void *)0xf00001; + +// registers, swizzled according to +// https://github.com/rosco-m68k/rosco_m68k/blob/develop/code/shared/rosco_m68k_public.asm +enum { + DUART_REG_MR1A_RW = 0x00, // mode register, channel A + DUART_REG_SRA_R = 0x01, // status register, channel A + DUART_REG_CSRA_W = 0x01, // clock select register, channel A + DUART_REG_MISR_R = 0x02, // masked interrupt status register + DUART_REG_CRA_W = 0x02, // command register, channel A + DUART_REG_RHRA_R = 0x03, // rx holding register, channel A + DUART_REG_THRA_W = 0x03, // tx holding register, channel A + DUART_REG_IPCR_R = 0x04, // input port config register + DUART_REG_ACR_W = 0x04, // auxillary control register + DUART_REG_ISR_R = 0x05, // interrupt status register + DUART_REG_IMR_W = 0x05, // interrupt mask register + DUART_REG_CTU_RW = 0x06, // counter timer, upper byte + DUART_REG_CTL_RW = 0x07, // counter timer, lower byte + + DUART_REG_MR1B_RW = 0x08, // mode register, channel B + DUART_REG_SRB_R = 0x09, // status register, channel B + DUART_REG_CSRB_W = 0x09, // clock select register, channel B + DUART_REG_CRB_W = 0x0a, // command register, channel B + DUART_REG_RHRB_R = 0x0b, // rx holding register, channel B + DUART_REG_THRB_W = 0x0b, // tx holding register, channel B + + DUART_REG_IVR_RW = 0x0c, // interrupt vector register + DUART_REG_IP_R = 0x0d, // input port + DUART_REG_OPCR_W = 0x0d, // output port configuration register + + DUART_REG_SCC_R = 0x0e, // start counter/timer command + DUART_REG_STC_R = 0x0f, // stop counter/timer command + + DUART_REG_SOPBC_W = 0x0e, // set output port bits command + DUART_REG_COPBC_W = 0x0f, // clear output port bits command +}; + +// save a copy of whatever IMR was set to before +static uint8_t cached_imr; + +static void write_reg(uint reg, uint8_t val) { + DUART_BASE[reg * 2] = val; +} + +static uint8_t read_reg(uint reg) { + return DUART_BASE[reg * 2]; +} + +void duart_early_init(void) { + // clear all IRQs + cached_imr = 0; + write_reg(DUART_REG_IMR_W, cached_imr); + + // Set the IRQ vector to 0x45 + write_reg(DUART_REG_IVR_RW, 0x45); + + // TODO: set up UARTA again + // for now assume it's already configured + + // set up a periodic counter at 1khz + read_reg(DUART_REG_STC_R); // stop the counter + + // compute the counter + uint16_t count = 3686400 / 2 / 1000; + write_reg(DUART_REG_CTL_RW, count & 0xff); + write_reg(DUART_REG_CTU_RW, (count >> 8) & 0xff); + + // set timer mode + write_reg(DUART_REG_ACR_W, (0b110 << 4)); // timer mode, X1/CLK + + // start timer + read_reg(DUART_REG_SCC_R); // start counter + + // unmask irq + cached_imr = (1<<3); // counter #1 ready + write_reg(DUART_REG_IMR_W, cached_imr); +} + +void duart_init(void) { + // finish uart init to get rx going + cbuf_initialize_etc(&uart_rx_buf, RXBUF_SIZE, uart_rx_buf_data); + + // enable uart RX irq + cached_imr |= (1<<1); // RXRDY/FFULLA + write_reg(DUART_REG_IMR_W, cached_imr); + +} + +status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, lk_time_t interval) { + LTRACEF("cb %p, arg %p, interval %u\n", callback, arg, interval); + t_callback = callback; + t_arg = arg; + t_periodic_interval = interval; + t_next_periodic_tick = current_time() + interval; + + return NO_ERROR; +} + +enum handler_return duart_irq(void) { + enum handler_return ret = INT_NO_RESCHEDULE; + + uint8_t isr = read_reg(DUART_REG_ISR_R); + + if (likely(isr & (1<<3))) { // counter #1 ready + ticks++; + + // ack the timer hardware + read_reg(DUART_REG_STC_R); + + // call back the registered timer + if (likely(t_callback)) { + lk_time_t now = current_time(); + if (unlikely(now >= t_next_periodic_tick)) { + ret = t_callback(t_arg, now); + t_next_periodic_tick += t_periodic_interval; + } + } + } + if (isr & (1<<1)) { // RXRDY/FFULLA + uint8_t status = read_reg(DUART_REG_SRA_R); + if (status & (1<<0)) { // RXRDY + if (status & (0b111 << 5)) { // any of break, framing, or parity error + // consume this byte + __UNUSED volatile uint8_t hole = read_reg(DUART_REG_RHRA_R); + } else { + char c = read_reg(DUART_REG_RHRA_R); + cbuf_write_char(&uart_rx_buf, c, false); + ret = INT_RESCHEDULE; + } + } + } + + return ret; +} + +void platform_dputc(char c) { + if (c == '\n') { + platform_dputc('\r'); + } + + // spin while TXRDY is clear + while ((read_reg(DUART_REG_SRA_R) & (1 << 2)) == 0) // TXRDY + ; + write_reg(DUART_REG_THRA_W, c); +} + +int platform_dgetc(char *c, bool wait) { + return cbuf_read_char(&uart_rx_buf, c, wait); +} + +int platform_pgetc(char *c, bool wait) { + for (;;) { + uint8_t status = read_reg(DUART_REG_SRA_R); + if (status & (1<<0)) { // RXRDY + if (status & (0b111 << 5)) { // any of break, framing, or parity error + // consume this byte + __UNUSED volatile uint8_t hole = read_reg(DUART_REG_RHRA_R); + continue; + } + + *c = read_reg(DUART_REG_RHRA_R); + return 1; + } + if (wait) { + continue; + } + break; + } while (0); + return 0; +} + +lk_bigtime_t current_time_hires(void) { + // TODO: look at the current countdown registers + return ticks * 1000ULL; +} + +lk_time_t current_time(void) { + return ticks; +} + +void target_set_debug_led(unsigned int led, bool on) { + uint8_t bit = 0; + switch (led) { + case 0: + bit = 5; // green LED + break; + case 1: + bit = 3; // red LED + break; + } + + if (on) { + write_reg(DUART_REG_SOPBC_W, (1< PIC #1 + * IRQ #1 to IRQ #31 -> unused + * IRQ #32 -> goldfish-tty + * CPU IRQ #2 -> PIC #2 + * IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32 + * CPU IRQ #3 -> PIC #3 + * IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64 + * CPU IRQ #4 -> PIC #4 + * IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96 + * CPU IRQ #5 -> PIC #5 + * IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128 + * CPU IRQ #6 -> PIC #6 + * IRQ #1 -> goldfish-rtc + * IRQ #2 to IRQ #32 -> unused + * CPU IRQ #7 -> NMI + */ +#define NUM_PICS 6 +#define NUM_IRQS (NUM_PICS * 32) // PIC 1 - 6 + +#define PIC_IRQ_TO_LINEAR(pic, irq) (((pic) - 1) * 32 + ((irq) - 1)) +#define GOLDFISH_TTY_IRQ PIC_IRQ_TO_LINEAR(1, 32) // PIC 1, irq 32 +#define GOLDFISH_RTC_IRQ PIC_IRQ_TO_LINEAR(6, 1) // PIC 6, irq 1 + +#define PIC_IRQ_BASE(num) (8 + (num - 1) * 32) +#define PIC_IRQ(num, irq) (PIC_IRQ_BASE(num) + irq - 1) +//#define PIC_GPIO(pic_irq) (qdev_get_gpio_in(pic_dev[(pic_irq - 8) / 32], (pic_irq - 8) % 32)) + +#define VIRT_GF_PIC_MMIO_BASE 0xff000000 /* MMIO: 0xff000000 - 0xff005fff */ +#define VIRT_GF_PIC_IRQ_BASE 1 /* IRQ: #1 -> #6 */ +#define VIRT_GF_PIC_NB 6 + +/* 2 goldfish-rtc (and timer) */ +#define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff007fff */ +#define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */ +#define VIRT_GF_RTC_NB 2 + +/* 1 goldfish-tty */ +#define VIRT_GF_TTY_MMIO_BASE 0xff008000 /* MMIO: 0xff008000 - 0xff008fff */ +#define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */ + +/* 1 virt-ctrl */ +#define VIRT_CTRL_MMIO_BASE 0xff009000 /* MMIO: 0xff009000 - 0xff009fff */ +#define VIRT_CTRL_IRQ_BASE PIC_IRQ(1, 1) /* PIC: #1, IRQ: #1 */ + +/* + * virtio-mmio size is 0x200 bytes + * we use 4 goldfish-pic to attach them, + * we can attach 32 virtio devices / goldfish-pic + * -> we can manage 32 * 4 = 128 virtio devices + */ +#define VIRT_VIRTIO_MMIO_BASE 0xff010000 /* MMIO: 0xff010000 - 0xff01ffff */ +#define VIRT_VIRTIO_IRQ_BASE PIC_IRQ(2, 1) /* PIC: 2, 3, 4, 5, IRQ: ALL */ + +#define NUM_VIRT_VIRTIO 128 diff --git a/platform/rosco-m68k/platform.c b/platform/rosco-m68k/platform.c new file mode 100644 index 00000000..b932e72f --- /dev/null +++ b/platform/rosco-m68k/platform.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if WITH_LIB_MINIP +#include +#endif +#include +#if WITH_LIB_CONSOLE +#include +#endif + +#include "platform_p.h" + +#define LOCAL_TRACE 0 + +extern uint8_t __bss_end; + +void platform_early_init(void) { + duart_early_init(); + + dprintf(INFO, "ROSCO-M68K: firmware structure at 0x400 - 0x41f:\n"); + hexdump((void *)0x400, 0x20); + + uint32_t cpu_info = *(uint32_t *)0x41c; + printf("cpu family %u speed %u\n", cpu_info >> 29, cpu_info & 0x1fffffff); + + // TODO: probe memory + // TODO: consider using firmware struct left around 0x400 + uint32_t membase = 0x0; + uint32_t memsize = 0x100000; // 1MB + + dprintf(INFO, "ROSCO-M68K: memory base %#x size %#x\n", membase, memsize); + novm_add_arena("mem", membase, memsize); + + // build a table of illegal instructions around 0 to try to catch bad branches + volatile uint16_t *ptr = 0; + for (int i = 0; i < 256; i++) { + ptr[i] = 0x4afa; // undefined opcode + } +} + +void platform_init(void) { + duart_init(); +} + +enum handler_return m68k_platform_irq(uint8_t irq) { + LTRACEF("irq %u\n", irq); + + switch (irq) { + case 0x45: // DUART irq + return duart_irq(); + default: + panic("unhandled platform irq %u\n", irq); + } + return INT_NO_RESCHEDULE; +} diff --git a/platform/rosco-m68k/platform_p.h b/platform/rosco-m68k/platform_p.h new file mode 100644 index 00000000..5a80b83e --- /dev/null +++ b/platform/rosco-m68k/platform_p.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2018 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#pragma once + +#include + +void duart_early_init(void); +void duart_init(void); +enum handler_return duart_irq(void); diff --git a/platform/rosco-m68k/rules.mk b/platform/rosco-m68k/rules.mk new file mode 100644 index 00000000..e29a0b4b --- /dev/null +++ b/platform/rosco-m68k/rules.mk @@ -0,0 +1,32 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +ARCH := m68k +M68K_CPU := 68010 +LK_HEAP_IMPLEMENTATION ?= dlmalloc + +MODULE_DEPS += lib/cbuf + +#MODULE_SRCS += $(LOCAL_DIR)/goldfish_rtc.c +#MODULE_SRCS += $(LOCAL_DIR)/goldfish_tty.c +#MODULE_SRCS += $(LOCAL_DIR)/pic.c +MODULE_SRCS += $(LOCAL_DIR)/duart.c +MODULE_SRCS += $(LOCAL_DIR)/platform.c + +MEMBASE ?= 0x00002000 # 8k. Just off the end of firmware reserved areas +MEMSIZE ?= 0x00100000 # 1MB + +# relocate ourself from the load address (0x40000) +GLOBAL_DEFINES += ARCH_DO_RELOCATION=1 + +# we can revert to a poll based uart spin routine +GLOBAL_DEFINES += PLATFORM_SUPPORTS_PANIC_SHELL=1 + +# we will find the memory size by probing it +GLOBAL_DEFINES += NOVM_DEFAULT_ARENA=0 + +# we will find the memory size by probing it +GLOBAL_DEFINES += TARGET_HAS_DEBUG_LED=1 + +include make/module.mk diff --git a/project/rosco-m68k-test.mk b/project/rosco-m68k-test.mk new file mode 100644 index 00000000..8d79de09 --- /dev/null +++ b/project/rosco-m68k-test.mk @@ -0,0 +1,7 @@ +# main project for rosco-m68k +MODULES += \ + app/shell + +include project/virtual/test.mk +include project/target/rosco-m68k.mk + diff --git a/project/target/rosco-m68k.mk b/project/target/rosco-m68k.mk new file mode 100644 index 00000000..7208051a --- /dev/null +++ b/project/target/rosco-m68k.mk @@ -0,0 +1,2 @@ +TARGET := rosco-m68k + diff --git a/target/rosco-m68k/rules.mk b/target/rosco-m68k/rules.mk new file mode 100644 index 00000000..f5566947 --- /dev/null +++ b/target/rosco-m68k/rules.mk @@ -0,0 +1,5 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +PLATFORM := rosco-m68k