-
Notifications
You must be signed in to change notification settings - Fork 561
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
soc/cores/cpu: Add Loongson GS232 MIPS CPU
Loongson GS232 Dual issue pipeline MIPS32 CPU capable for running Linux. Opensourced by Loongson under 2-Clause BSD License (as shown in verilog source). Signed-off-by: Jiaxun Yang <[email protected]>
- Loading branch information
Showing
6 changed files
with
359 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from litex.soc.cores.cpu.gs232.core import GS232 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.section .text, "ax", @progbits | ||
.global boot_helper | ||
boot_helper: | ||
jr $a3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
# | ||
# This file is part of LiteX. | ||
# | ||
# Copyright (c) 2024 Jiaxun Yang <[email protected]> | ||
# SPDX-License-Identifier: BSD-2-Clause | ||
|
||
import os | ||
|
||
from migen import * | ||
from litex.gen import * | ||
|
||
from litex.soc.interconnect import axi | ||
from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_MIPS | ||
|
||
class GS232(CPU): | ||
category = "softcore" | ||
family = "mips" | ||
name = "gs232" | ||
human_name = "Loongson GS232" | ||
variants = ["standard"] | ||
data_width = 32 | ||
endianness = "little" | ||
gcc_triple = CPU_GCC_TRIPLE_MIPS | ||
linker_output_format = "elf32-tradlittlemips" | ||
nop = "nop" | ||
io_regions = {0x1000_0000: 0x0c00_0000} # Origin, Length. | ||
|
||
# GCC Flags. | ||
@property | ||
def gcc_flags(self): | ||
flags = "-march=mips32 -mabi=32 -msoft-float" | ||
flags += " -D__gs232__ " | ||
flags += " -DUART_POLLING" | ||
return flags | ||
|
||
# Memory Mapping. | ||
@property | ||
def mem_map(self): | ||
# Based on vanilla sysmap.h | ||
return { | ||
"main_ram" : 0x0000_0000, | ||
"csr" : 0x1800_0000, | ||
"sram" : 0x1c00_0000, | ||
"rom" : 0x1fc0_0000, | ||
} | ||
|
||
def __init__(self, platform, variant="standard"): | ||
self.platform = platform | ||
self.variant = variant | ||
self.reset = Signal() | ||
self.interrupt = Signal(5) | ||
# Peripheral bus (Connected to main SoC's bus). | ||
axi_if = axi.AXIInterface(data_width=32, address_width=32, id_width=4) | ||
self.periph_buses = [axi_if] | ||
# Memory buses (Connected directly to LiteDRAM). | ||
self.memory_buses = [] | ||
|
||
tlb_to_ram = Signal(66) | ||
ram_to_tlb = Signal(52) | ||
icache_to_ram = Signal(1444) | ||
ram_to_icache = Signal(1152) | ||
dcache_to_ram = Signal(1404) | ||
ram_to_dcache = Signal(1112) | ||
|
||
# CPU Instance. | ||
self.cpu_params = dict( | ||
# Clk / Rst | ||
i_coreclock = ClockSignal("sys"), | ||
i_areset_n = ~ResetSignal("sys") & ~self.reset, | ||
o_core_rst_ = Open(), | ||
|
||
# Interrupts (Low active) | ||
i_interrupt_i = ~self.interrupt, | ||
i_nmi = 1, | ||
|
||
# AXI interface | ||
i_aclk = ClockSignal("sys"), | ||
o_arid = axi_if.ar.id, | ||
o_araddr = axi_if.ar.addr, | ||
o_arlen = axi_if.ar.len, | ||
o_arsize = axi_if.ar.size, | ||
o_arburst = axi_if.ar.burst, | ||
o_arlock = axi_if.ar.lock, | ||
o_arcache = axi_if.ar.cache, | ||
o_arprot = axi_if.ar.prot, | ||
o_arvalid = axi_if.ar.valid, | ||
i_arready = axi_if.ar.ready, | ||
|
||
i_rid = axi_if.r.id, | ||
i_rdata = axi_if.r.data, | ||
i_rresp = axi_if.r.resp, | ||
i_rlast = axi_if.r.last, | ||
i_rvalid = axi_if.r.valid, | ||
o_rready = axi_if.r.ready, | ||
|
||
o_awid = axi_if.aw.id, | ||
o_awaddr = axi_if.aw.addr, | ||
o_awlen = axi_if.aw.len, | ||
o_awsize = axi_if.aw.size, | ||
o_awburst = axi_if.aw.burst, | ||
o_awlock = axi_if.aw.lock, | ||
o_awcache = axi_if.aw.cache, | ||
o_awprot = axi_if.aw.prot, | ||
o_awvalid = axi_if.aw.valid, | ||
i_awready = axi_if.aw.ready, | ||
|
||
o_wid = axi_if.w.id, | ||
o_wdata = axi_if.w.data, | ||
o_wstrb = axi_if.w.strb, | ||
o_wlast = axi_if.w.last, | ||
o_wvalid = axi_if.w.valid, | ||
i_wready = axi_if.w.ready, | ||
|
||
i_bid = axi_if.b.id, | ||
i_bresp = axi_if.b.resp, | ||
i_bvalid = axi_if.b.valid, | ||
o_bready = axi_if.b.ready, | ||
|
||
# SRAM interface | ||
o_tlb_to_ram = tlb_to_ram, | ||
i_ram_to_tlb = ram_to_tlb, | ||
|
||
o_icache_to_ram = icache_to_ram, | ||
i_ram_to_icache = ram_to_icache, | ||
|
||
o_dcache_to_ram = dcache_to_ram, | ||
i_ram_to_dcache = ram_to_dcache, | ||
|
||
# DFT | ||
o_prrst_to_core = Open(), | ||
i_testmode = 0, | ||
) | ||
|
||
# TLB & Cache SRAMs | ||
# Magic numbers all from godson_ram_bist.v, don't touch! | ||
tlb_cen = tlb_to_ram[0] # Active low | ||
tlb_wen = tlb_to_ram[7] # Active low | ||
tlb_din = tlb_to_ram[8:(59 + 1)] | ||
tlb_mem = Memory(52, 32) | ||
tlb_p = tlb_mem.get_port(write_capable=True, has_re=True) | ||
self.specials += tlb_mem, tlb_p | ||
self.comb += [ | ||
tlb_p.re.eq(~tlb_cen & tlb_wen), | ||
If(tlb_wen, tlb_p.adr.eq(tlb_to_ram[1:(5 + 1)])).Else(tlb_p.adr.eq(tlb_to_ram[60:(64 + 1)])), | ||
tlb_p.we.eq(~tlb_cen & ~tlb_wen), | ||
tlb_p.dat_w.eq(tlb_din), | ||
ram_to_tlb.eq(tlb_p.dat_r), | ||
] | ||
|
||
for iway in range(4): | ||
tag_ena = ~icache_to_ram[ 361 * iway + 0] | ||
tag_addra = icache_to_ram[(361 * iway + 1):(361 * iway + 7 + 1)] | ||
tag_wea = ~icache_to_ram[ 361 * iway + 8] | ||
tag_dina = icache_to_ram[(361 * iway + 9):(361 * iway + 40 + 1)] | ||
tag_douta = ram_to_icache[(288 * iway + 0):(288 * iway + 31 + 1)] | ||
tag_mem = Memory(32, 128) | ||
tag_p = tag_mem.get_port(write_capable=True, has_re=True) | ||
self.specials += tag_mem, tag_p | ||
self.comb += [ | ||
tag_p.re.eq(tag_ena & ~tag_wea), | ||
tag_p.adr.eq(tag_addra), | ||
tag_p.we.eq(tag_ena & tag_wea), | ||
tag_p.dat_w.eq(tag_dina), | ||
tag_douta.eq(tag_p.dat_r), | ||
] | ||
|
||
for ibank in range(4): | ||
data_ena = ~icache_to_ram[ 361 * iway + 41 + 80 * ibank + 0] | ||
data_addra = icache_to_ram[(361 * iway + 41 + 80 * ibank + 1):(361 * iway + 41 + 80 * ibank + 7 + 1)] | ||
data_wea = ~icache_to_ram[(361 * iway + 41 + 80 * ibank + 8):(361 * iway + 41 + 80 * ibank + 15 + 1)] # Byte wise | ||
data_dina = icache_to_ram[(361 * iway + 41 + 80 * ibank + 16):(361 * iway + 41 + 80 * ibank + 79 + 1)] | ||
data_douta = ram_to_icache[(288 * iway + 32 + 64 * ibank + 0):(288 * iway + 32 + 64 * ibank + 63 + 1)] | ||
data_mem = Memory(64, 128) | ||
data_p = data_mem.get_port(write_capable=True, has_re=True, we_granularity=8) | ||
self.specials += data_mem, data_p | ||
self.comb += [ | ||
data_p.re.eq(data_ena & ~data_wea), | ||
data_p.adr.eq(data_addra), | ||
data_p.we.eq(Replicate(data_ena, 8) & data_wea), | ||
data_p.dat_w.eq(data_dina), | ||
data_douta.eq(data_p.dat_r), | ||
] | ||
|
||
for dway in range(4): | ||
tag_ena = ~dcache_to_ram[ 351 * dway + 0] | ||
tag_addra = dcache_to_ram[(351 * dway + 1):(351 * dway + 7 + 1)] | ||
tag_wea = ~dcache_to_ram[ 351 * dway + 8] | ||
tag_dina = dcache_to_ram[(351 * dway + 9):(351 * dway + 30 + 1)] | ||
tag_douta = ram_to_dcache[(278 * dway + 0):(278 * dway + 21 + 1)] | ||
tag_mem = Memory(22, 128) | ||
tag_p = tag_mem.get_port(write_capable=True, has_re=True) | ||
self.specials += tag_mem, tag_p | ||
self.comb += [ | ||
tag_p.re.eq(tag_ena & ~tag_wea), | ||
tag_p.adr.eq(tag_addra), | ||
tag_p.we.eq(tag_ena & tag_wea), | ||
tag_p.dat_w.eq(tag_dina), | ||
tag_douta.eq(tag_p.dat_r), | ||
] | ||
|
||
for dbank in range(4): | ||
data_ena = ~dcache_to_ram[ 351 * dway + 31 + 80 * dbank + 0] | ||
data_addra = dcache_to_ram[(351 * dway + 31 + 80 * dbank + 1):(351 * dway + 31 + 80 * dbank + 7 + 1)] | ||
data_wea = ~dcache_to_ram[(351 * dway + 31 + 80 * dbank + 8):(351 * dway + 31 + 80 * dbank + 15 + 1)] # Byte wise | ||
data_dina = dcache_to_ram[(351 * dway + 31 + 80 * dbank + 16):(351 * dway + 31 + 80 * dbank + 79 + 1)] | ||
data_douta = ram_to_dcache[(278 * dway + 22 + 64 * dbank + 0):(278 * dway + 22 + 64 * dbank + 63 + 1)] | ||
data_mem = Memory(64, 128) | ||
data_p = data_mem.get_port(write_capable=True, has_re=True, we_granularity=8) | ||
self.specials += data_mem, data_p | ||
self.comb += [ | ||
data_p.re.eq(data_ena & ~data_wea), | ||
data_p.adr.eq(data_addra), | ||
data_p.we.eq(Replicate(data_ena, 8) & data_wea), | ||
data_p.dat_w.eq(data_dina), | ||
data_douta.eq(data_p.dat_r), | ||
] | ||
|
||
# Add sources. | ||
basedir = "cpu_gs232" | ||
self.platform.add_source_dir(basedir) | ||
platform.add_verilog_include_path(basedir) | ||
|
||
def add_jtag(self, pads): | ||
self.cpu_params.update( | ||
i_EJTAG_TMS = pads.tms, | ||
i_EJTAG_TDI = pads.tdi, | ||
o_EJTAG_TDO = pads.tdo, | ||
i_EJTAG_TRST = pads.ntrst, | ||
i_EJTAG_TCK = pads.tck, | ||
) | ||
|
||
def set_reset_address(self, reset_address): | ||
# Hardcoded reset address. | ||
assert reset_address == 0x1fc0_0000 | ||
self.reset_address = reset_address | ||
|
||
def bios_map(self, addr, cached): | ||
# We can't access beyond KSEG0/1 in BIOS | ||
assert addr < 0x2000_0000 | ||
if cached: | ||
return addr + 0x8000_0000 | ||
else: | ||
return addr + 0xa000_0000 | ||
|
||
def do_finalize(self): | ||
self.specials += Instance("godson_cpu_core", **self.cpu_params) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
.global main | ||
.global isr | ||
.global _start | ||
|
||
_start: | ||
j crt_init | ||
|
||
.org 0x200 | ||
|
||
crt_init: | ||
/* Enable Cache for KSEG0 */ | ||
mfc0 $t0, $16 | ||
and $t0, $t0, ~((1 << 12) | 7) | ||
or $t0, $t0, 2 | ||
mtc0 $t0, $16 | ||
|
||
la $sp, _fstack | ||
data_init: | ||
la $t0, _fdata | ||
la $t1, _edata | ||
la $t2, _fdata_rom | ||
data_loop: | ||
beq $t0, $t1, data_done | ||
lw $t3, 0($t2) | ||
sw $t3, 0($t0) | ||
addiu $t0, $t0,4 | ||
addiu $t2, $t2,4 | ||
b data_loop | ||
data_done: | ||
|
||
bss_init: | ||
la $t0, _fbss | ||
la $t1, _ebss | ||
bss_loop: | ||
beq $t0, $t1, bss_done | ||
sw $zero, 0($t0) | ||
addiu $t0, $t0, 4 | ||
b bss_loop | ||
bss_done: | ||
|
||
la $t9, main | ||
jalr $t9 | ||
inf_loop: | ||
b inf_loop |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#ifndef __IRQ_H | ||
#define __IRQ_H | ||
|
||
#include <stdint.h> | ||
#include "system.h" | ||
#include "generated/soc.h" | ||
|
||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
|
||
static inline unsigned int irq_getie(void) | ||
{ | ||
return 0; /* FIXME */ | ||
} | ||
|
||
static inline void irq_setie(unsigned int ie) | ||
{ | ||
/* TODO */ | ||
} | ||
|
||
static inline unsigned int irq_getmask(void) | ||
{ | ||
return (1 << UART_INTERRUPT); // FIXME | ||
} | ||
|
||
static inline void irq_setmask(unsigned int mask) | ||
{ | ||
/* TODO */ | ||
} | ||
|
||
static inline unsigned int irq_pending(void) | ||
{ | ||
/* TODO */ | ||
return 0; | ||
} | ||
|
||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* __IRQ_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#ifndef __SYSTEM_H | ||
#define __SYSTEM_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
__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 */ |