cores/cpu: add initial Gowin EMCU support
This commit is contained in:
parent
18a1d74cf6
commit
db83b38a2a
|
@ -92,6 +92,8 @@ from litex.soc.cores.cpu.zynq7000 import Zynq7000
|
||||||
# EOS-S3
|
# EOS-S3
|
||||||
from litex.soc.cores.cpu.eos_s3 import EOS_S3
|
from litex.soc.cores.cpu.eos_s3 import EOS_S3
|
||||||
|
|
||||||
|
from litex.soc.cores.cpu.gowin_emcu import GowinEMCU
|
||||||
|
|
||||||
CPUS = {
|
CPUS = {
|
||||||
# None
|
# None
|
||||||
"None" : CPUNone,
|
"None" : CPUNone,
|
||||||
|
@ -127,4 +129,6 @@ CPUS = {
|
||||||
|
|
||||||
# EOS-S3
|
# EOS-S3
|
||||||
"eos-s3" : EOS_S3,
|
"eos-s3" : EOS_S3,
|
||||||
|
|
||||||
|
'gowin_emcu' : GowinEMCU
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
from litex.soc.cores.cpu.gowin_emcu.core import GowinEMCU
|
|
@ -0,0 +1,187 @@
|
||||||
|
from migen import *
|
||||||
|
from litex.soc.interconnect import wishbone, ahb
|
||||||
|
from litex.soc.cores.cpu import CPU
|
||||||
|
|
||||||
|
|
||||||
|
class AHBFlash(Module):
|
||||||
|
def __init__(self, bus):
|
||||||
|
addr = Signal(13)
|
||||||
|
read_enable = Signal()
|
||||||
|
self.comb += bus.resp.eq(0)
|
||||||
|
self.submodules.fsm = fsm = FSM()
|
||||||
|
fsm.act("IDLE",
|
||||||
|
bus.readyout.eq(1),
|
||||||
|
If(bus.sel & bus.trans[1],
|
||||||
|
NextValue(addr, bus.addr[2:]),
|
||||||
|
NextState('READ'),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("READ",
|
||||||
|
read_enable.eq(1),
|
||||||
|
NextState('WAIT'),
|
||||||
|
)
|
||||||
|
fsm.act('WAIT',
|
||||||
|
NextState('IDLE')
|
||||||
|
)
|
||||||
|
self.specials += Instance(
|
||||||
|
'FLASH256K',
|
||||||
|
o_DOUT=bus.rdata,
|
||||||
|
i_DIN=Signal(32),
|
||||||
|
i_XADR=addr[6:],
|
||||||
|
i_YADR=addr[:6],
|
||||||
|
i_XE=~ResetSignal(),
|
||||||
|
i_YE=~ResetSignal(),
|
||||||
|
i_SE=read_enable,
|
||||||
|
i_PROG=0,
|
||||||
|
i_ERASE=0,
|
||||||
|
i_NVSTR=0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class GowinEMCU(CPU):
|
||||||
|
variants = ["standard"]
|
||||||
|
family = "arm"
|
||||||
|
name = "gowin_emcu"
|
||||||
|
human_name = "Gowin EMCU"
|
||||||
|
data_width = 32
|
||||||
|
endianness = "little"
|
||||||
|
gcc_triple = "arm-none-eabi"
|
||||||
|
gcc_flags = '-mcpu=cortex-m3 -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,
|
||||||
|
"sram": 0x2000_0000,
|
||||||
|
"csr": 0xA000_0000,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, platform, variant, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.reset = Signal()
|
||||||
|
self.bus_reset = Signal()
|
||||||
|
bus_reset_n = Signal()
|
||||||
|
self.comb += self.bus_reset.eq(~bus_reset_n)
|
||||||
|
self.interrupt = Signal(5)
|
||||||
|
self.reset_address = self.mem_map['rom'] + 0
|
||||||
|
|
||||||
|
self.gpio_in = Signal(16)
|
||||||
|
self.gpio_out = Signal(16)
|
||||||
|
self.gpio_out_en = Signal(16)
|
||||||
|
|
||||||
|
self.cpu_params = dict()
|
||||||
|
self.cpu_params.update(
|
||||||
|
i_MTXREMAP=Signal(4, reset=0b1111),
|
||||||
|
o_MTXHRESETN=bus_reset_n,
|
||||||
|
|
||||||
|
i_FLASHERR=Signal(),
|
||||||
|
i_FLASHINT=Signal(),
|
||||||
|
|
||||||
|
i_FCLK=ClockSignal(),
|
||||||
|
i_PORESETN=~self.reset,
|
||||||
|
i_SYSRESETN=~self.reset,
|
||||||
|
i_RTCSRCCLK=Signal(), # TODO - RTC clk in
|
||||||
|
|
||||||
|
i_IOEXPINPUTI=self.gpio_in,
|
||||||
|
o_IOEXPOUTPUTO=self.gpio_out,
|
||||||
|
o_IOEXPOUTPUTENO=self.gpio_out_en,
|
||||||
|
|
||||||
|
i_GPINT=self.interrupt,
|
||||||
|
o_INTMONITOR=Signal(),
|
||||||
|
)
|
||||||
|
|
||||||
|
# 32b CPU SRAM split between 8 SRAMs x 4 bit each
|
||||||
|
|
||||||
|
sram_dw = 32
|
||||||
|
single_sram_dw = 4
|
||||||
|
n_srams = sram_dw // single_sram_dw
|
||||||
|
|
||||||
|
sram0_addr = Signal(13)
|
||||||
|
sram0_rdata = Signal(sram_dw)
|
||||||
|
sram0_wdata = Signal(sram_dw)
|
||||||
|
sram0_cs = Signal()
|
||||||
|
sram0_wren = Signal(4)
|
||||||
|
self.cpu_params.update(
|
||||||
|
i_SRAM0RDATA=sram0_rdata,
|
||||||
|
o_SRAM0ADDR=sram0_addr,
|
||||||
|
o_SRAM0WREN=sram0_wren,
|
||||||
|
o_SRAM0WDATA=sram0_wdata,
|
||||||
|
o_SRAM0CS=sram0_cs,
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in range(n_srams):
|
||||||
|
self.specials += Instance(
|
||||||
|
'SDPB',
|
||||||
|
p_READ_MODE=0,
|
||||||
|
p_BIT_WIDTH_0=single_sram_dw,
|
||||||
|
p_BIT_WIDTH_1=single_sram_dw,
|
||||||
|
p_RESET_MODE='SYNC',
|
||||||
|
p_BLK_SEL_0=0b111,
|
||||||
|
p_BLK_SEL_1=0b111,
|
||||||
|
o_DO=Cat(sram0_rdata[i * single_sram_dw: (i + 1) * single_sram_dw], Signal(sram_dw - single_sram_dw)),
|
||||||
|
i_DI=Cat(sram0_wdata[i * single_sram_dw: (i + 1) * single_sram_dw], Signal(sram_dw - single_sram_dw)),
|
||||||
|
i_ADA=Cat(Signal(2), sram0_addr[:-1]),
|
||||||
|
i_ADB=Cat(Signal(2), sram0_addr[:-1]),
|
||||||
|
i_CEA=sram0_wren[i // 2],
|
||||||
|
i_CEB=~sram0_wren[i // 2],
|
||||||
|
i_CLKA=ClockSignal(),
|
||||||
|
i_CLKB=ClockSignal(),
|
||||||
|
i_RESETA=0,
|
||||||
|
i_RESETB=self.bus_reset,
|
||||||
|
i_OCE=1,
|
||||||
|
i_BLKSELA=Cat(sram0_cs, sram0_cs, sram0_cs),
|
||||||
|
i_BLKSELB=Cat(sram0_cs, sram0_cs, sram0_cs),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Boot Flash memory connected via AHB
|
||||||
|
|
||||||
|
ahb_flash = ahb.Interface()
|
||||||
|
for s, _ in ahb_flash.master_signals:
|
||||||
|
if s in ['wdata', 'write', 'mastlock', 'prot']:
|
||||||
|
continue
|
||||||
|
self.cpu_params[f'o_TARGFLASH0H{s.upper()}'] = getattr(ahb_flash, s)
|
||||||
|
for s, _ in ahb_flash.slave_signals:
|
||||||
|
self.cpu_params[f'i_TARGFLASH0H{s.upper()}'] = getattr(ahb_flash, s)
|
||||||
|
flash = ResetInserter()(AHBFlash(ahb_flash))
|
||||||
|
self.comb += flash.reset.eq(self.bus_reset)
|
||||||
|
self.submodules += flash
|
||||||
|
|
||||||
|
# Extension AHB -> Wishbone CSR via bridge
|
||||||
|
|
||||||
|
self.pbus = wishbone.Interface(data_width=32, adr_width=30)
|
||||||
|
self.periph_buses = [self.pbus]
|
||||||
|
ahb_targexp0 = ahb.Interface()
|
||||||
|
for s, _ in ahb_targexp0.master_signals:
|
||||||
|
# TODO: due to unexpected writes by the CPU bus is currently forced read-only
|
||||||
|
if s == 'write':
|
||||||
|
continue
|
||||||
|
self.cpu_params[f'o_TARGEXP0H{s.upper()}'] = getattr(ahb_targexp0, s)
|
||||||
|
for s, _ in ahb_targexp0.slave_signals:
|
||||||
|
self.cpu_params[f'i_TARGEXP0H{s.upper()}'] = getattr(ahb_targexp0, s)
|
||||||
|
self.submodules += ahb.AHB2Wishbone(ahb_targexp0, self.pbus)
|
||||||
|
|
||||||
|
def connect_uart(self, pads, n=0):
|
||||||
|
assert n in (0, 1), "this CPU has 2 built-in UARTs, 0 and 1"
|
||||||
|
self.cpu_params.update({
|
||||||
|
f'i_UART{n}RXDI': pads.rx,
|
||||||
|
f'o_UART{n}TXDO': pads.tx,
|
||||||
|
f'o_UART{n}BAUDTICK': Signal()
|
||||||
|
})
|
||||||
|
|
||||||
|
def connect_jtag(self, pads):
|
||||||
|
self.cpu_params.update(
|
||||||
|
i_DAPSWDITMS=pads.tms,
|
||||||
|
i_DAPTDI=pads.tdi,
|
||||||
|
o_DAPTDO=pads.tdo,
|
||||||
|
o_DAPNTDOEN=Signal(),
|
||||||
|
i_DAPNTRST=~self.reset,
|
||||||
|
i_DAPSWCLKTCK=pads.tck,
|
||||||
|
o_DAPJTAGNSW=Signal(), # indicates debug mode, JTAG or SWD
|
||||||
|
)
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
self.specials += Instance("EMCU", **self.cpu_params)
|
|
@ -275,7 +275,7 @@ class Builder:
|
||||||
self.soc.platform.output_dir = self.output_dir
|
self.soc.platform.output_dir = self.output_dir
|
||||||
|
|
||||||
# Check if BIOS is used and add software package if so.
|
# Check if BIOS is used and add software package if so.
|
||||||
with_bios = self.soc.cpu_type not in [None, "zynq7000", "eos-s3"]
|
with_bios = self.soc.cpu_type not in [None, "zynq7000", "eos-s3", 'gowin_emcu']
|
||||||
if with_bios:
|
if with_bios:
|
||||||
self.add_software_package("bios")
|
self.add_software_package("bios")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue