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:
parent
016e1abcff
commit
51eb310b0e
|
@ -0,0 +1 @@
|
|||
from litex.soc.cores.cpu.cortex_m1.core import CortexM1
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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
|
||||
)"
|
||||
);
|
|
@ -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 */
|
|
@ -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 */
|
Loading…
Reference in New Issue