From 1211cb6ab5dce0c720e3a41e450e3285ded9cf43 Mon Sep 17 00:00:00 2001 From: Ilia Sergachev Date: Fri, 22 Apr 2022 16:40:45 +0200 Subject: [PATCH] cpu: Add initial Cortex-M3 support. can be test with targets from LiteX-Boards and Cortex-M3 sources in execution path: python3 -m litex_boards.targets.digilent_arty --cpu-type=cortex_m3 --sy-clk-freq=50e6 --build --load __ _ __ _ __ / / (_) /____ | |/_/ / /__/ / __/ -_)> < /____/_/\__/\__/_/|_| Build your hardware, easily! (c) Copyright 2012-2022 Enjoy-Digital (c) Copyright 2007-2015 M-Labs BIOS built on Apr 22 2022 16:23:30 BIOS CRC passed (b390faf0) LiteX git sha1: 99a03426 --=============== SoC ==================-- CPU: ARM Cortex-M3 @ 50MHz BUS: WISHBONE 32-bit @ 4GiB CSR: 32-bit data ROM: 128KiB SRAM: 8KiB L2: 8KiB SDRAM: 262144KiB 16-bit @ 400MT/s (CL-7 CWL-5) --========== Initialization ============-- Initializing SDRAM @0x10000000... Switching SDRAM to software control. Read leveling: m0, b00: |00000000000000000000000000000000| delays: - m0, b01: |11111111111111111111111111100000| delays: 13+-13 m0, b02: |00000000000000000000000000001111| delays: 30+-02 m0, b03: |00000000000000000000000000000000| delays: - m0, b04: |00000000000000000000000000000000| delays: - m0, b05: |00000000000000000000000000000000| delays: - m0, b06: |00000000000000000000000000000000| delays: - m0, b07: |00000000000000000000000000000000| delays: - best: m0, b01 delays: 13+-13 m1, b00: |00000000000000000000000000000000| delays: - m1, b01: |11111111111111111111111111000000| delays: 13+-13 m1, b02: |00000000000000000000000000000111| delays: 31+-02 m1, b03: |00000000000000000000000000000000| delays: - m1, b04: |00000000000000000000000000000000| delays: - m1, b05: |00000000000000000000000000000000| delays: - m1, b06: |00000000000000000000000000000000| delays: - m1, b07: |00000000000000000000000000000000| delays: - best: m1, b01 delays: 13+-13 Switching SDRAM to hardware control. Memtest at 0x10000000 (2.0MiB)... Write: 0x10000000-0x10200000 2.0MiB Read: 0x10000000-0x10200000 2.0MiB Memtest OK Memspeed at 0x10000000 (Sequential, 2.0MiB)... Write speed: 9.7MiB/s Read speed: 12.6MiB/s --============== Boot ==================-- Booting from serial... Press Q or ESC to abort boot completely. sL5DdSMmkekro Timeout No boot medium found --============= Console ================-- litex> --- litex/soc/cores/cpu/cortex_m3/__init__.py | 1 + litex/soc/cores/cpu/cortex_m3/boot-helper.c | 5 + litex/soc/cores/cpu/cortex_m3/core.py | 108 ++++++++++++++++++++ litex/soc/cores/cpu/cortex_m3/crt0.c | 107 +++++++++++++++++++ litex/soc/cores/cpu/cortex_m3/irq.h | 52 ++++++++++ litex/soc/cores/cpu/cortex_m3/system.h | 42 ++++++++ 6 files changed, 315 insertions(+) create mode 100644 litex/soc/cores/cpu/cortex_m3/__init__.py create mode 100644 litex/soc/cores/cpu/cortex_m3/boot-helper.c create mode 100644 litex/soc/cores/cpu/cortex_m3/core.py create mode 100644 litex/soc/cores/cpu/cortex_m3/crt0.c create mode 100644 litex/soc/cores/cpu/cortex_m3/irq.h create mode 100644 litex/soc/cores/cpu/cortex_m3/system.h diff --git a/litex/soc/cores/cpu/cortex_m3/__init__.py b/litex/soc/cores/cpu/cortex_m3/__init__.py new file mode 100644 index 000000000..11c1d6826 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m3/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.cortex_m3.core import CortexM3 diff --git a/litex/soc/cores/cpu/cortex_m3/boot-helper.c b/litex/soc/cores/cpu/cortex_m3/boot-helper.c new file mode 100644 index 000000000..4dd8ae2d3 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m3/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_m3/core.py b/litex/soc/cores/cpu/cortex_m3/core.py new file mode 100644 index 000000000..f515efb52 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m3/core.py @@ -0,0 +1,108 @@ +# +# 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 CortexM3(CPU): + variants = ["standard"] + family = "arm" + name = "cortex_m3" + human_name = "ARM Cortex-M3" + data_width = 32 + endianness = "little" + reset_address = 0x0000_0000 + gcc_triple = "arm-none-eabi" + gcc_flags = "-march=armv7-m -mthumb" + 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, + "main_ram": 0x1000_0000, + "sram": 0x2000_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) + ibus = wishbone.Interface(data_width=32, adr_width=30) + self.periph_buses = [pbus, ibus] + 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_MPU_PRESENT = 0, + p_ITCM_SIZE = _mem_size(0 * 1024), # embedded ROM + p_DTCM_SIZE = _mem_size(0 * 1024), # embedded RAM + p_TRACE_LVL = 0, + p_DEBUG_LVL = 2, + i_CFGITCMEN = 0, # 1 = alias ITCM at 0x0 + ) + + 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) + + ibus_axi = axi.AXIInterface(data_width=self.data_width, address_width=32) + ibus_a2w = axi.AXI2Wishbone(ibus_axi, ibus, base_address=0) + self.submodules += ibus_a2w + connect_axi(ibus_axi, 'C') + + 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, 'S') + + platform.add_source_dir("AT426-BU-98000-r0p1-00rel0/vivado/Arm_ipi_repository/CM3DbgAXI/rtl") + + def connect_jtag(self, pads): + self.cpu_params.update( + p_JTAG_PRESENT = 1, + 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("CortexM3DbgAXI", **self.cpu_params) diff --git a/litex/soc/cores/cpu/cortex_m3/crt0.c b/litex/soc/cores/cpu/cortex_m3/crt0.c new file mode 100644 index 000000000..7a07ea0b5 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m3/crt0.c @@ -0,0 +1,107 @@ +#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 + default_handler, // mem manage + default_handler, // bus fault + default_handler, // usage fault + (void *) 0x55, // reserved + 0, // reserved + 0, // reserved + 0, // reserved + default_handler, // svc + default_handler, // debug mon + 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__ ( +"__gnu_thumb1_case_uhi:\n" +"push {r0, r1}\n" +"mov r1, lr\n" +"lsrs r1, r1, #1\n" +"lsls r0, r0, #1\n" +"lsls r1, r1, #1\n" +"ldrh r1, [r1, r0]\n" +"lsls r1, r1, #1\n" +"add lr, lr, r1\n" +"pop {r0, r1}\n" +"bx lr\n" +); diff --git a/litex/soc/cores/cpu/cortex_m3/irq.h b/litex/soc/cores/cpu/cortex_m3/irq.h new file mode 100644 index 000000000..043652e31 --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m3/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_m3/system.h b/litex/soc/cores/cpu/cortex_m3/system.h new file mode 100644 index 000000000..5a137903a --- /dev/null +++ b/litex/soc/cores/cpu/cortex_m3/system.h @@ -0,0 +1,42 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define UART_POLLING + +typedef struct +{ + volatile uint32_t ISER[8]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24]; + volatile uint32_t ICER[8]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[24]; + volatile uint32_t ISPR[8]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24]; + volatile uint32_t ICPR[8]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24]; + volatile uint32_t IABR[8]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56]; + volatile uint8_t IP[240]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644]; + volatile uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt 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 */