[platform][rosco-m68k] Add port to the Rosco M68k board
Port to the really neat 68010 based board at https://rosco-m68k.com/ Port Features: -10Mhz 68010 -1MB ram -Dual UART + timer implemented as a 68c681 chip -timer running at 1Khz, UART A for console -interrupt driven RX support Some amount of extending of the 68k exceptinon code was needed to support the autovectored irqs that the 68681 uart uses. Added build system support for 68010.
This commit is contained in:
1
.github/workflows/github-ci.yml
vendored
1
.github/workflows/github-ci.yml
vendored
@@ -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
|
||||
|
||||
@@ -8,16 +8,22 @@
|
||||
#include <lk/trace.h>
|
||||
#include <lk/debug.h>
|
||||
#include <stdint.h>
|
||||
#include <arch/ops.h>
|
||||
#include <arch/m68k.h>
|
||||
#include <kernel/spinlock.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -10,27 +10,71 @@
|
||||
#include <lk/debug.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <target.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 += \
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <lk/debug.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/list.h>
|
||||
#include <lk/trace.h>
|
||||
#include <malloc.h>
|
||||
#include <platform.h>
|
||||
#include <printf.h>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
238
platform/rosco-m68k/duart.c
Normal file
238
platform/rosco-m68k/duart.c
Normal file
@@ -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 <assert.h>
|
||||
#include <lk/err.h>
|
||||
#include <lk/debug.h>
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <lib/cbuf.h>
|
||||
#include <kernel/debug.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/rosco-m68k.h>
|
||||
#include <platform/timer.h>
|
||||
#include <platform.h>
|
||||
|
||||
#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<<bit));
|
||||
} else {
|
||||
write_reg(DUART_REG_COPBC_W, (1<<bit));
|
||||
}
|
||||
}
|
||||
|
||||
71
platform/rosco-m68k/include/platform/rosco-m68k.h
Normal file
71
platform/rosco-m68k/include/platform/rosco-m68k.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// TODO: add for rosco-m68k
|
||||
|
||||
// Top level #defines for the 68k-virt machine in qemu 6.0
|
||||
//
|
||||
// From qemu/hw/m68k/virt.c
|
||||
|
||||
/*
|
||||
* 6 goldfish-pic for CPU IRQ #1 to IRQ #6
|
||||
* CPU IRQ #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
|
||||
70
platform/rosco-m68k/platform.c
Normal file
70
platform/rosco-m68k/platform.c
Normal file
@@ -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 <lk/err.h>
|
||||
#include <lk/reg.h>
|
||||
#include <lk/trace.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <platform.h>
|
||||
#include <platform/interrupts.h>
|
||||
#include <platform/debug.h>
|
||||
#include <platform/timer.h>
|
||||
#include <platform/rosco-m68k.h>
|
||||
#include <sys/types.h>
|
||||
#if WITH_LIB_MINIP
|
||||
#include <lib/minip.h>
|
||||
#endif
|
||||
#include <kernel/novm.h>
|
||||
#if WITH_LIB_CONSOLE
|
||||
#include <lib/console.h>
|
||||
#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;
|
||||
}
|
||||
14
platform/rosco-m68k/platform_p.h
Normal file
14
platform/rosco-m68k/platform_p.h
Normal file
@@ -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 <stdbool.h>
|
||||
|
||||
void duart_early_init(void);
|
||||
void duart_init(void);
|
||||
enum handler_return duart_irq(void);
|
||||
32
platform/rosco-m68k/rules.mk
Normal file
32
platform/rosco-m68k/rules.mk
Normal file
@@ -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
|
||||
7
project/rosco-m68k-test.mk
Normal file
7
project/rosco-m68k-test.mk
Normal file
@@ -0,0 +1,7 @@
|
||||
# main project for rosco-m68k
|
||||
MODULES += \
|
||||
app/shell
|
||||
|
||||
include project/virtual/test.mk
|
||||
include project/target/rosco-m68k.mk
|
||||
|
||||
2
project/target/rosco-m68k.mk
Normal file
2
project/target/rosco-m68k.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
TARGET := rosco-m68k
|
||||
|
||||
5
target/rosco-m68k/rules.mk
Normal file
5
target/rosco-m68k/rules.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
MODULE := $(LOCAL_DIR)
|
||||
|
||||
PLATFORM := rosco-m68k
|
||||
Reference in New Issue
Block a user