diff --git a/litex/soc/cores/cpu/cortex_m1/__init__.py b/litex/soc/cores/cpu/cortex_m1/__init__.py new file mode 100644 index 000000000..4a9a98990 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m1/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.cortex_m1.core import CortexM1 diff --git a/litex/soc/cores/cpu/cortex_m1/boot-helper.c b/litex/soc/cores/cpu/cortex_m1/boot-helper.c new file mode 100644 index 000000000..4dd8ae2d3 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m1/boot-helper.c @@ -0,0 +1,5 @@ +void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); + +void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { + goto *addr; +} diff --git a/litex/soc/cores/cpu/cortex_m1/core.py b/litex/soc/cores/cpu/cortex_m1/core.py new file mode 100644 index 000000000..c3b2b627b --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m1/core.py @@ -0,0 +1,107 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2022 Ilia Sergachev +# SPDX-License-Identifier: BSD-2-Clause + +import os +from migen import * +from litex.soc.interconnect import wishbone +from litex.soc.cores.cpu import CPU +from litex.soc.interconnect import axi + + +class CortexM1(CPU): + variants = ["standard"] + family = "arm" + name = "cortex_m1" + human_name = "ARM Cortex-M1" + data_width = 32 + endianness = "little" + reset_address = 0x0000_0000 + gcc_triple = "arm-none-eabi" + gcc_flags = "-march=armv6-m -mthumb -mfloat-abi=soft" + linker_output_format = "elf32-littlearm" + nop = "nop" + io_regions = {0x4000_0000: 0x2000_0000, + 0xA000_0000: 0x6000_0000 + } # Origin, Length. + + @property + def mem_map(self): + return { + "rom" : 0x0000_0000, + "sram" : 0x2000_0000, + "main_ram" : 0x1000_0000, + "csr" : 0xA000_0000 + } + + def __init__(self, platform, variant, *args, **kwargs): + super().__init__(*args, **kwargs) + self.platform = platform + self.reset = Signal() + self.interrupt = Signal(2) + pbus = wishbone.Interface(data_width=32, adr_width=30) + self.periph_buses = [pbus] + self.memory_buses = [] + + def _mem_size(x): + return log2_int(x // 512) + + self.cpu_params = dict( + i_HCLK = ClockSignal("sys"), + i_SYSRESETn = ~(ResetSignal() | self.reset), + p_NUM_IRQ = len(self.interrupt), + i_IRQ = self.interrupt, + i_DBGRESETn = ~(ResetSignal() | self.reset), + p_ITCM_SIZE = _mem_size(0 * 1024), # embedded ROM + p_DTCM_SIZE = _mem_size(0 * 1024), # embedded RAM + p_DEBUG_SEL = 1, # JTAG + p_SMALL_DEBUG = True, + i_CFGITCMEN = 0, # 1 = alias ITCM at 0x0 + o_DBGRESTARTED = Signal(), + o_LOCKUP = Signal(), + o_HALTED = Signal(), + o_SYSRESETREQ = Signal(), + i_NMI = 0, + i_EDBGRQ = 0, + i_DBGRESTART = 0, + ) + + def connect_axi(axi_bus, suffix=''): + layout = axi_bus.layout_flat() + dir_map = {DIR_M_TO_S: 'o', DIR_S_TO_M: 'i'} + for group, signal, direction in layout: + if signal in ['id', 'qos', 'first']: + continue + if signal == 'last': + if group in ['b', 'a', 'ar', 'aw']: + continue + prefix = 'H' if signal == 'data' else '' + direction = dir_map[direction] + self.cpu_params[f'{direction}_{prefix}{group.upper()}{signal.upper()}{suffix}'] = \ + getattr(getattr(axi_bus, group), signal) + + pbus_axi = axi.AXIInterface(data_width=self.data_width, address_width=32) + pbus_a2w = axi.AXI2Wishbone(pbus_axi, pbus, base_address=0) + self.submodules += pbus_a2w + connect_axi(pbus_axi) + + platform.add_source_dir("AT472-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM1DbgAXI/logical/rtl") + + def connect_jtag(self, pads): + self.cpu_params.update( + i_SWDITMS = pads.tms, + i_TDI = pads.tdi, + o_TDO = pads.tdo, + o_nTDOEN = Signal(), + i_nTRST = pads.ntrst, + i_SWCLKTCK = pads.tck, + o_JTAGNSW = Signal(), # Indicates debug mode, JTAG or SWD + o_JTAGTOP = Signal(), # ? + o_SWDO = Signal(), # TODO + o_SWDOEN = Signal(), # TODO + ) + + def do_finalize(self): + self.specials += Instance("CortexM1DbgAXI", **self.cpu_params) diff --git a/litex/soc/cores/cpu/cortex_m1/crt0.c b/litex/soc/cores/cpu/cortex_m1/crt0.c new file mode 100644 index 000000000..71c350728 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m1/crt0.c @@ -0,0 +1,137 @@ +#include +#include "system.h" +#include "generated/soc.h" + +extern uint32_t _fdata_rom, _fdata, _edata, _fbss, _ebss, _fstack; +extern void isr(void); + +void _start(void); +void default_handler(void); +void uart_handler_proxy(void); + +volatile unsigned int irqs_enabled; + +void _start(void) { + __asm__( + "mov r0, %0\n" + "mov sp, r0\n" : : "r" (&_fstack) + ); + uint32_t *y = &_fdata_rom; + for (uint32_t *x = &_fdata; x < &_edata; x ++) + *x = *y ++; + + for (uint32_t *x = &_fbss; x < &_ebss; x ++) + *x = 0; + + __asm__("bl main"); + while(1); +} + + +void default_handler(void) { + while(1); +} + + +void uart_handler_proxy(void) { + NVIC->ISPR[0] = (1 << UART_INTERRUPT); + isr(); + NVIC->ICPR[0] = (1 << UART_INTERRUPT); +} + + +const void* isr_vector[] __attribute__((__used__)) __attribute__((section(".isr_vector"))) = { + &_fstack, + _start, // reset + default_handler, // nmi + default_handler, // hard fault + 0, // reserved + 0, // reserved + 0, // reserved + 0, // reserved + 0, // reserved + 0, // reserved + 0, // reserved + default_handler, // svc + 0, // reserved + 0, // reserved + default_handler, // pend sv + default_handler, // systick + // external + uart_handler_proxy, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, +}; + +__asm__ ( +R"( +.syntax unified + +.global __gnu_thumb1_case_uhi +__gnu_thumb1_case_uhi: + push {r0, r1} + mov r1, lr + lsrs r1, r1, #1 + lsls r0, r0, #1 + lsls r1, r1, #1 + ldrh r1, [r1, r0] + lsls r1, r1, #1 + add lr, lr, r1 + pop {r0, r1} + bx lr + +.global __gnu_thumb1_case_uqi +__gnu_thumb1_case_uqi: + mov r12, r1 + mov r1, lr + lsrs r1, r1, #1 + lsls r1, r1, #1 + ldrb r1, [r1, r0] + lsls r1, r1, #1 + add lr, lr, r1 + mov r1, r12 + bx lr + +.global __aeabi_uldivmod +__aeabi_uldivmod: + push {r0, r1} + mov r0, sp + push {r0, lr} + ldr r0, [sp, #8] + bl __udivmoddi4 + ldr r3, [sp, #4] + mov lr, r3 + add sp, sp, #8 + pop {r2, r3} + bx lr +)" +); diff --git a/litex/soc/cores/cpu/cortex_m1/irq.h b/litex/soc/cores/cpu/cortex_m1/irq.h new file mode 100644 index 000000000..043652e31 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m1/irq.h @@ -0,0 +1,52 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#include +#include "system.h" +#include "generated/soc.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +extern volatile unsigned int irqs_enabled; + +static inline unsigned int irq_getie(void) +{ + return irqs_enabled; /* FIXME */ +} + +static inline void irq_setie(unsigned int ie) +{ + if (ie) + __asm__ volatile ("cpsie i" : : : "memory"); + else + __asm__ volatile ("cpsid i" : : : "memory"); + irqs_enabled = ie; +} + +static inline unsigned int irq_getmask(void) +{ + return (1 << UART_INTERRUPT); // FIXME +} + +static inline void irq_setmask(unsigned int mask) +{ + // fixme: there are more interrupts + NVIC->ISER[0] = mask; + NVIC->ICER[0] = ~mask; +} + +static inline unsigned int irq_pending(void) +{ + // fixme: there are more interrupts + return NVIC->ISPR[0]; +} + + +#ifdef __cplusplus +} +#endif + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/cortex_m1/system.h b/litex/soc/cores/cpu/cortex_m1/system.h new file mode 100644 index 000000000..88d6f57d0 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m1/system.h @@ -0,0 +1,39 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define UART_POLLING + +typedef struct +{ + volatile uint32_t ISER[1]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31]; + volatile uint32_t ICER[1]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[31]; + volatile uint32_t ISPR[1]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31]; + volatile uint32_t ICPR[1]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31]; + uint32_t RESERVED4[64]; + volatile uint32_t IP[8]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +#define SCS_BASE (0xE000E000UL) +#define NVIC_BASE (SCS_BASE + 0x0100UL) +#define NVIC ((NVIC_Type *) NVIC_BASE) + +__attribute__((unused)) static void flush_cpu_icache(void){}; /* No instruction cache */ +__attribute__((unused)) static void flush_cpu_dcache(void){}; /* No instruction cache */ +void flush_l2_cache(void); + +void busy_wait(unsigned int ms); +void busy_wait_us(unsigned int us); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_H */