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>
This commit is contained in:
Ilia Sergachev 2022-04-22 16:40:45 +02:00 committed by Florent Kermarrec
parent 99a034268d
commit 1211cb6ab5
6 changed files with 315 additions and 0 deletions

View File

@ -0,0 +1 @@
from litex.soc.cores.cpu.cortex_m3.core import CortexM3

View File

@ -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;
}

View File

@ -0,0 +1,108 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2022 Ilia Sergachev <ilia@sergachev.ch>
# 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)

View File

@ -0,0 +1,107 @@
#include <stdint.h>
#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"
);

View File

@ -0,0 +1,52 @@
#ifndef __IRQ_H
#define __IRQ_H
#include <stdint.h>
#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 */

View File

@ -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 */