diff --git a/testsBP/crt0/Makefile b/testsBP/crt0/Makefile new file mode 100644 index 00000000..97b83faf --- /dev/null +++ b/testsBP/crt0/Makefile @@ -0,0 +1,23 @@ +TARGETDIR := bin +TARGET := $(TARGETDIR)/start +ROOT := .. +LIBRARY_DIRS := +LIBRARY_FILES := +LINK_FLAGS := -nostartfiles + +AFLAGS =-march=rv64ifd -W +CFLAGS =-march=rv64ifd -mcmodel=medany +AS=riscv64-unknown-elf-as +CC=riscv64-unknown-elf-gcc +AR=riscv64-unknown-elf-ar + +all: libcrt0.a + +%.o: %.s + ${AS} ${AFLAGS} -c $< -o $@ + +libcrt0.a: start.o + ${AR} -r $@ $^ + +clean: + rm -rf *.a *.o diff --git a/testsBP/crt0/isr.s b/testsBP/crt0/isr.s new file mode 100644 index 00000000..789d2d62 --- /dev/null +++ b/testsBP/crt0/isr.s @@ -0,0 +1,213 @@ +.section .text +.global __trap_handler +.type __trap_handler, @function + +__trap_handler: + # save the context of the cpu to the top of the current stack + addi sp, sp, -124 + sw x1, 0x0(sp) + sw x2, 0x4(sp) + sw x3, 0x8(sp) + sw x4, 0xC(sp) + sw x5, 0x10(sp) + sw x6, 0x14(sp) + sw x7, 0x18(sp) + sw x8, 0x1C(sp) + sw x9, 0x20(sp) + sw x10, 0x24(sp) + sw x11, 0x28(sp) + sw x12, 0x2C(sp) + sw x13, 0x30(sp) + sw x14, 0x34(sp) + sw x15, 0x38(sp) + sw x16, 0x3C(sp) + sw x17, 0x40(sp) + sw x18, 0x44(sp) + sw x19, 0x48(sp) + sw x20, 0x4C(sp) + sw x21, 0x50(sp) + sw x22, 0x54(sp) + sw x23, 0x58(sp) + sw x24, 0x5C(sp) + sw x25, 0x60(sp) + sw x26, 0x64(sp) + sw x27, 0x68(sp) + sw x28, 0x6C(sp) + sw x29, 0x70(sp) + sw x30, 0x74(sp) + sw x31, 0x78(sp) + + # figure out what caused the trap. + csrrw t0, mcause, x0 + # mcause is {int, 31 bit exception code} + # for this implementation only the lowest 4 bits are used + srli t1, t0, 31 # interrupt flag + andi t2, t0, 0xF # 4 bit cause + + slli t1, t1, 5 # shift int flag + or t1, t1, t2 # combine + slli t1, t1, 2 # multiply by 4 + la t3, exception_table + add t4, t3, t1 + lw t5, 0(t4) + jr t5, 0 # jump to specific ISR + # specific ISR is expected to set epc + +restore_st: + # restore register from stack on exit. + + lw x1, 0x0(sp) + lw x2, 0x4(sp) + lw x3, 0x8(sp) + lw x4, 0xC(sp) + lw x5, 0x10(sp) + lw x6, 0x14(sp) + lw x7, 0x18(sp) + lw x8, 0x1C(sp) + lw x9, 0x20(sp) + lw x10, 0x24(sp) + lw x11, 0x28(sp) + lw x12, 0x2C(sp) + lw x13, 0x30(sp) + lw x14, 0x34(sp) + lw x15, 0x38(sp) + lw x16, 0x3C(sp) + lw x17, 0x40(sp) + lw x18, 0x44(sp) + lw x19, 0x48(sp) + lw x20, 0x4C(sp) + lw x21, 0x50(sp) + lw x22, 0x54(sp) + lw x23, 0x58(sp) + lw x24, 0x5C(sp) + lw x25, 0x60(sp) + lw x26, 0x64(sp) + lw x27, 0x68(sp) + lw x28, 0x6C(sp) + lw x29, 0x70(sp) + lw x30, 0x74(sp) + lw x31, 0x78(sp) + + addi sp, sp, 124 + + mret + +.section .text +.type trap_instr_addr_misalign, @function +trap_instr_addr_misalign: + # fatal error, report error and halt + addi sp, sp, 4 + sw ra, 0(sp) + jal fail + lw ra, 0(sp) + la t0, restore_st + jr t0, 0 + +.section .text +.type trap_m_ecall, @function +trap_m_ecall: + addi sp, sp, -4 + sw ra, 0(sp) + # select which system call based on a7. + # for this example we will just define the following. + # not standard with linux or anything. + # 0: execute a call back function + # 1: decrease privilege by 1 (m=>s, s=>u, u=>u) + # 2: increase privilege by 1 (m=>m, s=>m, u=>s) + + # check a7 + li t0, 1 + beq a7, t0, trap_m_decrease_privilege + li t0, 2 + beq a7, t0, trap_m_increase_privilege + + # call call back function if not zero + la t1, isr_m_ecall_cb_fp + lw t0, 0(t1) + beq t0, x0, trap_m_ecall_skip_cb + jalr ra, t0, 0 +trap_m_ecall_skip_cb: + # modify the mepc + csrrw t0, mepc, x0 + addi t0, t0, 4 + csrrw x0, mepc, t0 + lw ra, 0(sp) + addi sp, sp, 4 + la t0, restore_st + jr t0, 0 + +trap_m_decrease_privilege: + # read the mstatus register + csrrw t0, mstatus, x0 + # 11 => 01, and 01 => 00. + # this is accomplished by clearing bit 12 and taking the old + # bit 12 as the new bit 11. + li t3, 0x00001800 + and t1, t0, t3 # isolates the bits 12 and 11. + # shift right by 1. + srli t2, t1, 1 + and t2, t2, t3 # this will clear bit 10. + li t3, ~0x00001800 + and t4, t0, t3 + or t0, t2, t4 + csrrw x0, mstatus, t0 + j trap_m_ecall_skip_cb + +trap_m_increase_privilege: + # read the mstatus register + csrrw t0, mstatus, x0 + # 11 => 01, and 01 => 00. + # this is accomplished by setting bit 11 and taking the old + # bit 11 as the new bit 12. + li t3, 0x00000800 + li t4, ~0x00000800 + and t1, t0, t3 + slli t2, t1, 1 # shift left by 1. + or t2, t2, t3 # bit 11 is always set. + and t1, t0, t5 + or t0, t1, t2 + csrrw x0, mstatus, t0 + j trap_m_ecall_skip_cb + +.data +exception_table: + .int trap_instr_addr_misalign + .int trap_instr_addr_misalign #trap_instr_access_fault + .int trap_instr_addr_misalign #trap_illegal_instr + .int trap_instr_addr_misalign #trap_breakpoint + .int trap_instr_addr_misalign #trap_load_addr_misalign + .int trap_instr_addr_misalign #trap_load_access_fault + .int trap_instr_addr_misalign #trap_store_addr_misalign + .int trap_instr_addr_misalign #trap_store_access_fault + .int trap_m_ecall + .int trap_m_ecall + .int restore_st + .int trap_m_ecall + .int trap_instr_addr_misalign #trap_instr_page_fault + .int trap_instr_addr_misalign #trap_load_page_fault + .int restore_st + .int trap_instr_addr_misalign #trap_store_page_fault +#.data +#interrupt_table: + .int trap_instr_addr_misalign #trap_u_software + .int trap_instr_addr_misalign #trap_s_software + .int restore_st + .int trap_instr_addr_misalign #trap_m_software + .int trap_instr_addr_misalign #trap_u_timer + .int trap_instr_addr_misalign #trap_s_timer + .int restore_st + .int trap_instr_addr_misalign #trap_m_timer + .int trap_instr_addr_misalign #trap_u_external + .int trap_instr_addr_misalign #trap_s_external + .int restore_st + .int trap_instr_addr_misalign #trap_m_external + .int restore_st + .int restore_st + .int restore_st + .int restore_st + + +.section .data +.global isr_m_ecall_cb_fp +isr_m_ecall_cb_fp: + .int 0 diff --git a/testsBP/crt0/start.s b/testsBP/crt0/start.s new file mode 100644 index 00000000..17543581 --- /dev/null +++ b/testsBP/crt0/start.s @@ -0,0 +1,60 @@ +.section .init +.global _start +.type _start, @function + +_start: + # Initialize global pointer + .option push + .option norelax + 1:auipc gp, %pcrel_hi(__global_pointer$) + addi gp, gp, %pcrel_lo(1b) + .option pop + + li x1, 0 + li x2, 0 + li x4, 0 + li x5, 0 + li x6, 0 + li x7, 0 + li x8, 0 + li x9, 0 + li x10, 0 + li x11, 0 + li x12, 0 + li x13, 0 + li x14, 0 + li x15, 0 + li x16, 0 + li x17, 0 + li x18, 0 + li x19, 0 + li x20, 0 + li x21, 0 + li x22, 0 + li x23, 0 + li x24, 0 + li x25, 0 + li x26, 0 + li x27, 0 + li x28, 0 + li x29, 0 + li x30, 0 + li x31, 0 + + + + # set the stack pointer to the top of memory + # 0x8000_0000 + 64K - 8 bytes + li sp, 0x0000FFF8 + + jal ra, main + jal ra, _halt + +.section .text +.global _halt +.type _halt, @function +_halt: + li gp, 1 + li a0, 0 + ecall + j _halt diff --git a/testsBP/linker.x b/testsBP/linker.x new file mode 100644 index 00000000..f448109c --- /dev/null +++ b/testsBP/linker.x @@ -0,0 +1,244 @@ +OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", + "elf64-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(_start) +SEARCH_DIR("/opt/riscv/riscv64-unknown-elf/lib"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + /* init segment to ensure we get a consistent start routine*/ + . = 0x0000000000000000; + . = ALIGN(0x0); + .init : { + *(.init) + } + _start_end = .; + + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x0)); . = SEGMENT_START("text-segment", _start_end); + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .rela.plt : + { + *(.rela.plt) + } + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) } + .iplt : { *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf64.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .sdata2 : + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + } + .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + . = DATA_SEGMENT_RELRO_END (0, .); + .data : + { + __DATA_BEGIN__ = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + __SDATA_BEGIN__ = .; + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .sbss : + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(64 / 8); + __BSS_END__ = .; + __global_pointer$ = MIN(__SDATA_BEGIN__ + 0x800, + MAX(__DATA_BEGIN__ + 0x800, __BSS_END__ - 0x800)); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} diff --git a/testsBP/makefile.inc b/testsBP/makefile.inc new file mode 100644 index 00000000..af0b03bc --- /dev/null +++ b/testsBP/makefile.inc @@ -0,0 +1,92 @@ +CEXT := c +CPPEXT := cpp +AEXT := s +SEXT := S +SRCEXT := \([$(CEXT)$(AEXT)$(SEXT)]\|$(CPPEXT)\) +OBJEXT := o +DEPEXT := d +SRCDIR := . +BUILDDIR := OBJ +LINKER := ${ROOT}/linker.x + +SOURCES ?= $(shell find $(SRCDIR) -type f -regex ".*\.$(SRCEXT)" | sort) +OBJECTS := $(SOURCES:.$(CEXT)=.$(OBJEXT)) +OBJECTS := $(OBJECTS:.$(AEXT)=.$(OBJEXT)) +OBJECTS := $(OBJECTS:.$(SEXT)=.$(OBJEXT)) +OBJECTS := $(OBJECTS:.$(CPPEXT)=.$(OBJEXT)) +OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(OBJECTS)) + +#Default Make +all: directories $(TARGET).memfile + +#Remake +remake: clean all + +#Make the Directories +directories: + @mkdir -p $(TARGETDIR) + @mkdir -p $(BUILDDIR) + +clean: + rm -rf $(BUILDDIR) $(TARGETDIR) *.memfile *.objdump + + +#Needed for building additional library projects +ifdef LIBRARY_DIRS +LIBS+=${LIBRARY_DIRS:%=-L%} ${LIBRARY_FILES:%=-l%} +INC+=${LIBRARY_DIRS:%=-I%} + +${LIBRARY_DIRS}: + make -C $@ -j 1 + +.PHONY: $(LIBRARY_DIRS) $(TARGET) +endif + + +#Pull in dependency info for *existing* .o files +-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) + +#Link +$(TARGET): $(OBJECTS) $(LIBRARY_DIRS) + $(CC) $(LINK_FLAGS) -g -o $(TARGET) $(OBJECTS) ${LIBS} -T ${LINKER} + + +#Compile +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(CEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< > $(BUILDDIR)/$*.list + @$(CC) $(CFLAGS) $(INC) -MM $(SRCDIR)/$*.$(CEXT) > $(BUILDDIR)/$*.$(DEPEXT) + @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp + @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) + @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) + @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp + +# gcc won't output dependencies for assembly files for some reason +# most asm files don't have dependencies so the echo will work for now. +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(AEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c -o $@ $< > $(BUILDDIR)/$*.list + @echo $@: $< > $(BUILDDIR)/$*.$(DEPEXT) + +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< > $(BUILDDIR)/$*.list + @echo $@: $< > $(BUILDDIR)/$*.$(DEPEXT) + +# C++ +$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(CPPEXT) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INC) -c -o $@ $< > $(BUILDDIR)/$*.list + @$(CC) $(CFLAGS) $(INC) -MM $(SRCDIR)/$*.$(CPPEXT) > $(BUILDDIR)/$*.$(DEPEXT) + @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp + @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) + @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) + @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp + +# convert to hex +$(TARGET).memfile: $(TARGET) + @echo 'Making object dump file.' + @riscv64-unknown-elf-objdump -D $< > $<.objdump + @echo 'Making memory file' + exe2memfile0.pl $< + extractFunctionRadix.sh $<.objdump diff --git a/testsBP/sieve/Makefile b/testsBP/sieve/Makefile new file mode 100644 index 00000000..9dcaab8d --- /dev/null +++ b/testsBP/sieve/Makefile @@ -0,0 +1,15 @@ +TARGETDIR := sieve +TARGET := $(TARGETDIR)/$(TARGETDIR).elf +ROOT := .. +LIBRARY_DIRS := ${ROOT}/crt0 +LIBRARY_FILES := crt0 +LINK_FLAGS := -nostartfiles -Wl,-Map=$(TARGET).map + +CFLAGS =-march=rv64ifd -Wa,-alhs -Wa,-L -mcmodel=medany -mstrict-align +CC=riscv64-unknown-elf-gcc +DA=riscv64-unknown-elf-objdump -d + + +include $(ROOT)/makefile.inc + + diff --git a/testsBP/sieve/sieve.c b/testsBP/sieve/sieve.c new file mode 100644 index 00000000..949d9fde --- /dev/null +++ b/testsBP/sieve/sieve.c @@ -0,0 +1,101 @@ +/* + * Filename: + * + * sieve.c + * + * Description: + * + * The Sieve of Eratosthenes benchmark, from Byte Magazine + * early 1980s, when a PC would do well to run this in 10 + * seconds. This version really does count prime numbers + * but omits the numbers 1, 3 and all even numbers. The + * expected count is 1899. + * + */ + +#include +#include + +#define SIZE 8190 + +//#define SIZE 8388608 +double time_diff(struct timeval x , struct timeval y); + +int sieve () { + + unsigned char flags [SIZE + 1]; + int iter; + int count; + + for (iter = 1; iter <= 10; iter++) + { + int i, prime, k; + + count = 0; + + for (i = 0; i <= SIZE; i++) + flags [i] = 1; + + for (i = 0; i <= SIZE; i++) + { + if (flags [i]) + { + prime = i + i + 3; + k = i + prime; + + while (k <= SIZE) + { + flags [k] = 0; + k += prime; + } + + count++; + } + } + } + + return count; +} + +int main () { + + int ans; + + struct timeval before , after; + gettimeofday(&before , NULL); + + ans = sieve (); + gettimeofday(&after , NULL); + if (ans != 1899) + printf ("Sieve result wrong, ans = %d, expected 1899", ans); + + printf("Total time elapsed : %.0lf us\n" , time_diff(before , after) ); + + + printf("Round 2\n"); + gettimeofday(&before , NULL); + + ans = sieve (); + gettimeofday(&after , NULL); + if (ans != 1899) + printf ("Sieve result wrong, ans = %d, expected 1899", ans); + + printf("Total time elapsed : %.0lf us\n" , time_diff(before , after) ); + + return 0; + +} + + +double time_diff(struct timeval x , struct timeval y) +{ + double x_ms , y_ms , diff; + + x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; + y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; + + diff = (double)y_ms - (double)x_ms; + + return diff; +} + diff --git a/testsBP/simple/Makefile b/testsBP/simple/Makefile new file mode 100644 index 00000000..aa350755 --- /dev/null +++ b/testsBP/simple/Makefile @@ -0,0 +1,15 @@ +TARGETDIR := simple +TARGET := $(TARGETDIR)/$(TARGETDIR).elf +ROOT := .. +LIBRARY_DIRS := ${ROOT}/crt0 +LIBRARY_FILES := crt0 +LINK_FLAGS := -nostartfiles -Wl,-Map=$(TARGET).map + +CFLAGS =-march=rv64ifd -Wa,-alhs -Wa,-L -mcmodel=medany -mstrict-align +CC=riscv64-unknown-elf-gcc +DA=riscv64-unknown-elf-objdump -d + + +include $(ROOT)/makefile.inc + + diff --git a/testsBP/simple/fail.s b/testsBP/simple/fail.s new file mode 100644 index 00000000..552604fe --- /dev/null +++ b/testsBP/simple/fail.s @@ -0,0 +1,11 @@ +# Ross Thompson +# March 17, 2021 +# Oklahoma State University + +.section .text +.global fail +.type fail, @function +fail: + li gp, 1 + li a0, -1 + ecall diff --git a/testsBP/simple/header.h b/testsBP/simple/header.h new file mode 100644 index 00000000..b5268fbf --- /dev/null +++ b/testsBP/simple/header.h @@ -0,0 +1,6 @@ +#ifndef __header +#define __header + +int fail(); +int simple_csrbr_test(); +#endif diff --git a/testsBP/simple/main.c b/testsBP/simple/main.c new file mode 100644 index 00000000..047a52f8 --- /dev/null +++ b/testsBP/simple/main.c @@ -0,0 +1,10 @@ +#include "header.h" + +int main(){ + int res = simple_csrbr_test(); + if (res < 0) { + fail(); + return 0; + }else + return 0; +} diff --git a/testsBP/simple/sample.s b/testsBP/simple/sample.s new file mode 100644 index 00000000..399d3bd7 --- /dev/null +++ b/testsBP/simple/sample.s @@ -0,0 +1,52 @@ +.section .text +.global simple_csrbr_test +.type simple_csrbr_test, @function + +simple_csrbr_test: + + # step 1 enable the performance counters + # by default the hardware enables all performance counters + # however we will eventually want to manually enable incase + # some other code disables thems + + # step 2 read performance counters into general purpose registers + + csrrw t2, 0xB05, x0 # t2 = BR COUNT (perf count 5) + csrrw t3, 0xB04, x0 # t3 = BRMP COUNT (perf count 4) + + # step 3 simple loop to show the counters are updated. + li t0, 0 # this is the loop counter + li t1, 100 # this is the loop end condition + + # for(t1 = 0; t1 < t0; t1++); + +loop: + addi t0, t0, 1 + blt t0, t1, loop + +loop_done: + + # step 2 read performance counters into general purpose registers + + csrrw t4, 0xB05, x0 # t4 = BR COUNT (perf count 5) + csrrw t5, 0xB04, x0 # t5 = BRMP COUNT (perf count 4) + + sub t2, t4, t2 # this is the number of branch instructions committed. + sub t3, t5, t3 # this is the number of branch mispredictions committed. + + # now check if the branch count equals 100 and if the branch + bne t4, t2, fail + # *** come back to t3 + + +pass: + li a0, 0 + ret + +fail: + li a0, -1 + ret + +.data +sample_data: +.int 0 diff --git a/wally-pipelined/bin/exe2memfile0.pl b/wally-pipelined/bin/exe2memfile0.pl index 975d38d2..8fbea6f8 100755 --- a/wally-pipelined/bin/exe2memfile0.pl +++ b/wally-pipelined/bin/exe2memfile0.pl @@ -49,6 +49,7 @@ for(my $i=0; $i<=$#ARGV; $i++) { } while() { + # *** this mode stuff does not work if a section is missing or reordered. if ($mode == 0) { # Parse code # print("Examining $_\n"); if (/^\s*(\S{1,16}):\s+(\S+)\s+/) { diff --git a/wally-pipelined/testbench/testbench-imperas.sv b/wally-pipelined/testbench/testbench-imperas.sv index 8a244428..4627cff3 100644 --- a/wally-pipelined/testbench/testbench-imperas.sv +++ b/wally-pipelined/testbench/testbench-imperas.sv @@ -316,7 +316,7 @@ string tests32i[] = { }; string testsBP64[] = '{ - "rv64BP/reg-test", "10000", + "rv64BP/simple", "10000", "rv64BP/sieve", "1000000" }; string tests[];