diff --git a/.circleci/config.yml b/.circleci/config.yml index 6b258f649..885132fd9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,6 +18,7 @@ jobs: name: Build command: | make -j 2 + make -C src/mips/hello -j 2 make -C src/mips/shell -j 2 make -C src/mips/openbios -j 2 diff --git a/src/mips/common.mk b/src/mips/common.mk index 9c10b824f..f66f13b0d 100644 --- a/src/mips/common.mk +++ b/src/mips/common.mk @@ -2,13 +2,15 @@ PREFIX = mipsel-linux-gnu CC = $(PREFIX)-gcc +TARGETBASE = $(basename $(TARGET)) + ARCHFLAGS = -march=mips1 -mabi=32 -EL -msoft-float -Wa,-msoft-float -fno-pic -mno-shared -mno-abicalls CPPFLAGS = -mno-gpopt -fomit-frame-pointer CPPFLAGS += -fno-builtin CPPFLAGS += $(ARCHFLAGS) CPPFLAGS += -I.. -LDFLAGS = -Wl,-Map=$(TARGET).map -nostdlib -T$(LDSCRIPT) -static -Wl,--gc-sections +LDFLAGS += -Wl,-Map=$(TARGETBASE).map -nostdlib -T$(LDSCRIPT) -static -Wl,--gc-sections -Wl,-v LDFLAGS += $(ARCHFLAGS) LDFLAGS += -g -O3 -flto @@ -16,16 +18,22 @@ CPPFLAGS += -g -O3 -flto OBJS += $(addsuffix .o, $(basename $(SRCS))) -all: $(TARGET).bin +all: $(TARGET) clean: - rm -f $(OBJS) $(TARGET).elf $(TARGET).map $(TARGET).bin + rm -f $(OBJS) $(TARGETBASE).psx $(TARGETBASE).elf $(TARGET).map $(TARGETBASE).bin $(TARGET) + +$(TARGETBASE).bin: $(TARGETBASE).elf + $(PREFIX)-objcopy -O binary $< $@ -$(TARGET).bin: $(TARGET).elf +$(TARGETBASE).psx: $(TARGETBASE).elf $(PREFIX)-objcopy -O binary $< $@ -$(TARGET).elf: $(OBJS) - $(CC) $(LDFLAGS) -g -o $(TARGET).elf $(OBJS) +$(TARGETBASE).elf: $(OBJS) + $(CC) $(LDFLAGS) -g -o $(TARGETBASE).elf $(OBJS) + +%.o: %.S + $(CC) $(CPPFLAGS) -I.. -g -c -o $@ $< %.o: %.s $(CC) $(ARCHFLAGS) -I.. -g -c -o $@ $< diff --git a/src/mips/common/include/mipsregs.h b/src/mips/common/include/mipsregs.h new file mode 100644 index 000000000..100164508 --- /dev/null +++ b/src/mips/common/include/mipsregs.h @@ -0,0 +1,163 @@ +#ifndef _MIPSREGS_H +#define _MIPSREGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* general registers */ + +#define r0 $0 +#define r1 $1 +#define r2 $2 +#define r3 $3 +#define r4 $4 +#define r5 $5 +#define r6 $6 +#define r7 $7 +#define r8 $8 +#define r9 $9 +#define r10 $10 +#define r11 $11 +#define r12 $12 +#define r13 $13 +#define r14 $14 +#define r15 $15 +#define r16 $16 +#define r17 $17 +#define r18 $18 +#define r19 $19 +#define r20 $20 +#define r21 $21 +#define r22 $22 +#define r23 $23 +#define r24 $24 +#define r25 $25 +#define r26 $26 +#define r27 $27 +#define r28 $28 +#define r29 $29 +#define r30 $30 +#define r31 $31 + +#define zero $0 +//#define at $1 +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 +#define t9 $25 +#define k0 $26 +#define k1 $27 +#define gp $28 +#define sp $29 +#define s8 $30 +#define fp $30 +#define ra $31 + +/* COP0 Registers */ + +/* BreakPoint Control */ +#define C0_BPC $3 +/* BreakPoint on Data Access */ +#define C0_BDA $5 +/* BreakPoint on Data Access */ +#define C0_DCIC $7 +#define C0_BADVADDR $8 +#define C0_BDAM $9 +#define C0_BPCM $11 + +/* Status Register */ +#define C0_STATUS $12 + +/* Cause Register */ +#define C0_CAUSE $13 + +/* Error PC Register */ +#define C0_EPC $14 + +/* Processor ID */ +#define C0_PRID $15 + +// Interrupt Enable(current) +#define SR_IEC (1 << 0) +// Kernel/User mode(current) +#define SR_KUC (1 << 1) +// Interrupt Enable(previous) +#define SR_IEP (1 << 2) +// Kernel/User mode(previous) +#define SR_KUP (1 << 3) +// Interrupt Enable(old) +#define SR_IEO (1 << 4) +// Kernel/User mode(old) +#define SR_KUO (1 << 5) + +/* Interrupt Mask 0 */ +#define SR_IMO (1 << 8) +/* Interrupt Mask 1 */ +#define SR_IM1 (1 << 9) +/* Interrupt Mask 2 */ +#define SR_IM2 (1 << 10) +/* Interrupt Mask 3 */ +#define SR_IM3 (1 << 11) +/* Interrupt Mask 4 */ +#define SR_IM4 (1 << 12) +/* Interrupt Mask 5 */ +#define SR_IM5 (1 << 13) +/* Interrupt Mask 6 */ +#define SR_IM6 (1 << 14) +/* Interrupt Mask 7 */ +#define SR_IM7 (1 << 15) + +/* Isolate Cache */ +#define SR_ISC (1 << 16) +/* Swap Caches */ +#define SR_SWC (1 << 17) +/* Parity Zero */ +#define SR_PZ (1 << 18) +/* Cache Miss */ +#define SR_CM (1 << 19) +/* Parity Error */ +#define SR_PE (1 << 20) +/* TLB Shutdown */ +#define SR_TS (1 << 21) +/* Boot-time Exception Vector */ +#define SR_BEV (1 << 22) + +/* Reverse Endian enable */ +#define SR_RE (1 << 25) + +/* Coprocessor 0 Usable */ +#define SR_CU0 (1 << 28) +/* Coprocessor 1 Usable */ +#define SR_CU1 (1 << 29) +/* Coprocessor 2 Usable */ +#define SR_CU2 (1 << 30) +/* Coprocessor 3 Usable */ +#define SR_CU3 (1 << 31) + +#ifdef __cplusplus +} +#endif + +#endif /* _MIPSREGS_H */ + diff --git a/src/mips/hello/Makefile b/src/mips/hello/Makefile new file mode 100644 index 000000000..9e87f34e3 --- /dev/null +++ b/src/mips/hello/Makefile @@ -0,0 +1,17 @@ +TARGET = hello.psx +TLOAD_ADDR = 0x80010000 +SRCS = \ +../common/hardware/cop0.s \ +crt0/crt0.s \ +main/main.c \ + +LDSCRIPT = psx-exe.ld + +## If "TLOAD_ADDR" was specified in the Makefile, pass it to the linker. +ifneq ($(strip $(TLOAD_ADDR)),) +LDFLAGS := -Wl,--defsym,TLOAD_ADDR=$(TLOAD_ADDR) +else +LDFLAGS = +endif + +include ../common.mk diff --git a/src/mips/hello/crt0/crt0.S b/src/mips/hello/crt0/crt0.S new file mode 100644 index 000000000..e1d246126 --- /dev/null +++ b/src/mips/hello/crt0/crt0.S @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2019 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include + +.set push +.set noreorder +.set noat + + .section .start, "ax", @progbits + .align 2 + .global main + .global _start + .type _start, @function +_start: + la t0, __bss_start + la t1, __bss_end + addiu t1, t1, 3 + srl t1, t1, 2 + sll t1, t1, 2 + beq t0, t1, _zero_bss_done + nop + +_zero_bss: + sw zero, 0(t0) + addiu t0, t0, 4 + bne t0, t1, _zero_bss + nop + +_zero_bss_done: +/* la gp, _gp*/ + li a0, 0 + j main + li a1, 0 + +/* +.end _start +.data + +.bss +*/ + .extern __bss_start + .extern __bss_end + .extern _gp +/* int _main(int argc, const char **argv, const char **envp) */ + .extern main + +.set pop diff --git a/src/mips/hello/main/main.c b/src/mips/hello/main/main.c new file mode 100644 index 000000000..a7e3c2b61 --- /dev/null +++ b/src/mips/hello/main/main.c @@ -0,0 +1,24 @@ +/*************************************************************************** + * Copyright (C) 2019 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "common/hardware/cop0.h" + +int main() { + return 0; +} diff --git a/src/mips/hello/psx-exe.ld b/src/mips/hello/psx-exe.ld new file mode 100644 index 000000000..78923d777 --- /dev/null +++ b/src/mips/hello/psx-exe.ld @@ -0,0 +1,167 @@ +/*************************************************************************** + * Copyright (C) 2019 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +OUTPUT_FORMAT("elf32-tradlittlemips") +/*OUTPUT_ARCH("mips:3000")*/ +OUTPUT_FORMAT("binary") + +EXTERN(_start) +ENTRY(_start) + +TLOAD_ADDR = DEFINED(_TLOAD_ADDR) ? TLOAD_ADDR : 0x80010000; + +MEMORY { + loader : ORIGIN = 0x8000f800, LENGTH = 2048 + ram (rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 + dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 +} + +__ram_top = ORIGIN(ram) + LENGTH(ram); +__sp = __ram_top - 0x100; + +__dcache = ORIGIN(dcache); +__dcache_top = ORIGIN(dcache) + LENGTH(dcache); + +__bss_len = (__bss_end - __bss_start); +__ftext_len = (__ftext_end - __ftext_start); +__fdata_len = (__fdata_end - __fdata_start); + +SECTIONS { + .PSX_EXE_Header : { + /* + 0x0000 - 0x0007 : "PS-X EXE" + */ + BYTE(80); BYTE(83); BYTE(45); BYTE(88); BYTE(32); BYTE(69); BYTE(88); BYTE(69); + + /* 0x0008 - 0x000F : skip text_off and data_off since they're not supported by the PS1 BIOS */ + LONG(0); LONG(0); + + /* 0x0010 - 0x0013 : entry point */ + LONG(ABSOLUTE(_start)); + + /* 0x0014 - 0x0017 : initial value of $gp */ + LONG(0); + + /* 0x0018 - 0x001B : Memory address to load "text" section to. */ + /* + NOTE: The "text" section is actually all of the "load" + sections of the file including .text, .rodata, .data. + etc. + */ + LONG(TLOAD_ADDR); + + /* 0x001C - 0x001F : size, in bytes, of the "text" section. */ + LONG(__ftext_len + __fdata_len); + + /* 0x0020 - 0x002F : + Skip "data_addr", "data_size", "bss_addr" and "bss_size". + None of these are supported by retail PS1 BIOS. + */ + LONG(0); LONG(0); + LONG(0); LONG(0); + + /* 0x0030 - 0x0033 : Initial stack address. */ + LONG(DEFINED(_sp) ? ABSOLUTE(_sp) : 0x801FFF00); + + /* 0x0034 - 0x0037 : Initial stack size, set it to 0. */ + LONG(0); + + /* Skip the remaining fields as they're not supported by the BIOS */ + . = . + 1992; + /* + . = ADDR(.text); + */ + } > loader + + __ftext_start = ABSOLUTE(.); + .text TLOAD_ADDR : { + *(.start) + *(.init) + KEEP (*(SORT_NONE(.fini))) + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + . = ALIGN(16); + } > ram + + .fini : { + . = ALIGN(16); + } > ram + + . = ALIGN(16); + __text_end = .; + __ftext_end = ABSOLUTE(.); + + __fdata_start = ABSOLUTE(.); + + .rodata : { + *(.rodata .rodata.* .rdata .rdata.* .gnu.linkonce.r.*) + } > ram + + .rodata1 : { + *(.rodata1) + } > ram + + __data_start = .; + .data : { + *(.a0table) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.got.plt) + *(.got) + } > ram + + . = ALIGN(4); + __data_end = .; + __fdata_end = .; + __bss_start = .; + .sbss : { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + } > ram + + . = ALIGN(4); + __bss_end = .; + + __end = .; + + /* pad file to be a multiple of 2048 bytes. Needed for loading from CD-ROM. */ + /* .__pad : { BYTE(0); . = ALIGN(2048); }*/ + . = ADDR(.text) - 0x800; + + + /DISCARD/ : { *(.MIPS.abiflags) } + + /* Everything is statically linked, so discard PLTs. */ + /DISCARD/ : { *(.rel.iplt) *(.rela.iplt) *(.rel.plt) *(.rela.plt) *(.plt) *(.iplt) } + + /* We don't make use of debugging information, so drop that, too. */ + /DISCARD/ : { *(.debug) *(.debug_srcinfo) *(.debug_sfnames) *(.debug_aranges) *(.debug_pubnames) *(.debug_info .gnu.linkonce.wi.*) *(.debug_abbrev) *(.debug_line .debug_line.* .debug_line_end ) *(.debug_frame) *(.debug_str) *(.debug_loc) *(.debug_macinfo) *(.debug_weaknames) *(.debug_funcnames) *(.debug_typenames) *(.debug_varnames) *(.debug_pubtypes) *(.debug_ranges) *(.debug_macro) *(.mdebug.abi32) *(.mdebug.abiN32) *(.mdebug.abi64) *(.mdebug.abiO64) *(.mdebug.eabi32) *(.mdebug.eabi64) } + + /* Discard things that the standard link script drops, too. */ + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } + + /DISCARD/ : { *(.note.gnu.build-id) } +} diff --git a/src/mips/openbios/Makefile b/src/mips/openbios/Makefile index a204a959d..0a576f95a 100644 --- a/src/mips/openbios/Makefile +++ b/src/mips/openbios/Makefile @@ -1,4 +1,4 @@ -TARGET = openbios +TARGET = openbios.bin SRCS = \ ../common/hardware/cop0.s \ diff --git a/src/mips/shell/Makefile b/src/mips/shell/Makefile index e5de4fbcc..f408d6914 100644 --- a/src/mips/shell/Makefile +++ b/src/mips/shell/Makefile @@ -1,4 +1,5 @@ -TARGET = shell +TARGET = shell.bin +LOAD_ADDR = 0x80030000 SRCS = \ ../common/hardware/cop0.s \