cpu: Add initial Cortex-M1 support.

Can be tested with targets from LiteX-Boards and Cortex-M1 sources in execution path:

python3 -m litex_boards.targets.digilent_arty --cpu-type=cortex_m1 --build --load

        __   _ __      _  __
       / /  (_) /____ | |/_/
      / /__/ / __/ -_)>  <
     /____/_/\__/\__/_/|_|
   Build your hardware, easily!

 (c) Copyright 2012-2022 Enjoy-Digital
 (c) Copyright 2007-2015 M-Labs

 BIOS built on Apr 22 2022 15:04:52
 BIOS CRC passed (5773c241)

 LiteX git sha1: 6b3a5412

--=============== SoC ==================--
CPU:		ARM Cortex-M1 @ 100MHz
BUS:		WISHBONE 32-bit @ 4GiB
CSR:		32-bit data
ROM:		128KiB
SRAM:		8KiB
L2:		8KiB
SDRAM:		262144KiB 16-bit @ 800MT/s (CL-7 CWL-5)

--========== Initialization ============--
Initializing SDRAM @0x10000000...
Switching SDRAM to software control.
Read leveling:
  m0, b00: |00000000000000000000000000000000| delays: -
  m0, b01: |00000000000000000000000000000000| delays: -
  m0, b02: |11111111110000000000000000000000| delays: 05+-05
  m0, b03: |00000000000011111111111111000000| delays: 19+-07
  m0, b04: |00000000000000000000000000011111| delays: 30+-02
  m0, b05: |00000000000000000000000000000000| delays: -
  m0, b06: |00000000000000000000000000000000| delays: -
  m0, b07: |00000000000000000000000000000000| delays: -
  best: m0, b03 delays: 19+-07
  m1, b00: |00000000000000000000000000000000| delays: -
  m1, b01: |00000000000000000000000000000000| delays: -
  m1, b02: |11111111110000000000000000000000| delays: 05+-05
  m1, b03: |00000000000011111111111111000000| delays: 19+-07
  m1, b04: |00000000000000000000000000001111| delays: 30+-02
  m1, b05: |00000000000000000000000000000000| delays: -
  m1, b06: |00000000000000000000000000000000| delays: -
  m1, b07: |00000000000000000000000000000000| delays: -
  best: m1, b03 delays: 19+-07
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: 16.5MiB/s
   Read speed: 19.3MiB/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 15:20:04 +02:00 committed by Florent Kermarrec
parent 016e1abcff
commit 51eb310b0e
6 changed files with 341 additions and 0 deletions

View File

@ -0,0 +1 @@
from litex.soc.cores.cpu.cortex_m1.core import CortexM1

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,107 @@
#
# 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 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)

View File

@ -0,0 +1,137 @@
#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
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
)"
);

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