re-adding jax stuff
parent
5c3995b053
commit
7f209442ef
@ -0,0 +1,38 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
REM Script assumes tools directory is in your path.
|
||||||
|
REM For now, this is done by running shell.bat inside of tools directory
|
||||||
|
|
||||||
|
set CommonCompilerFlags=-I../libcommon/src -I../tests/src -DBUILD_WIN32=1 -D_CRT_SECURE_NO_WARNINGS -fp:fast -fp:except- -nologo -Gm- -GR- -EHsc- -EHa- -Od -Oi -WX -W3 -FC -Zi -GS- -Gs9999999
|
||||||
|
set CommonLinkerFlags= -nologo -STACK:0x100000,0x100000 -incremental:no -opt:ref -nodefaultlib libcmt.lib libvcruntime.lib libucrt.lib user32.lib gdi32.lib winmm.lib kernel32.lib shlwapi.lib
|
||||||
|
|
||||||
|
set BuildDir=%~dp0build
|
||||||
|
|
||||||
|
REM set CompileCommand=clang-cl
|
||||||
|
set CompileCommand=cl
|
||||||
|
|
||||||
|
IF NOT EXIST tools\btime.exe (
|
||||||
|
pushd tools\build-timer
|
||||||
|
call build.bat
|
||||||
|
popd
|
||||||
|
)
|
||||||
|
|
||||||
|
IF NOT EXIST %BuildDir% mkdir %BuildDir%
|
||||||
|
pushd %BuildDir%
|
||||||
|
del *.pdb > NUL 2> NUL
|
||||||
|
del *.map > NUL 2> NUL
|
||||||
|
|
||||||
|
..\tools\btime.exe --begin ePenguin-Software-Framework.aet
|
||||||
|
|
||||||
|
%CompileCommand% %CommonCompilerFlags% -LD ../libcommon/src/libcommon.cpp -Folibcommon.obj -Fmlibcommon.map /link %CommonLinkerFlags% -noentry
|
||||||
|
lib -nologo libcommon.obj
|
||||||
|
|
||||||
|
%CompileCommand% %CommonCompilerFlags% ../tests/src/tests.cpp -Fotests.obj -Fmtests.map /link %CommonLinkerFlags% libcommon.lib
|
||||||
|
|
||||||
|
robocopy . ..\ libcommon.lib > NUL 2> NUL
|
||||||
|
del ..\test > NUL 2> NUL
|
||||||
|
copy tests.exe ..\test > NUL 2> NUL
|
||||||
|
|
||||||
|
..\tools\btime.exe --end ePenguin-Software-Framework.aet
|
||||||
|
popd
|
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Script assumes tools directory is in your path.
|
||||||
|
# For now, this is done by running shell.sh inside of tools directory
|
||||||
|
|
||||||
|
if [ ! -f tools/btime ]; then
|
||||||
|
pushd tools/build-timer
|
||||||
|
./build.sh
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
tools/btime --begin ePenguin-Software-Framework.aet
|
||||||
|
|
||||||
|
tools/btime --end ePenguin-Software-Framework.aet
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,3 @@
|
|||||||
|
load
|
||||||
|
monitor reset
|
||||||
|
q
|
@ -0,0 +1,96 @@
|
|||||||
|
LDSCRIPT = ./ld/ex.ld
|
||||||
|
MCUTYPE=__SAMD21J18A__
|
||||||
|
print-% : ; @echo $* = $($*)
|
||||||
|
BUILD_DIR:=build
|
||||||
|
SRC_DIR:=src
|
||||||
|
INC_DIR:=inc
|
||||||
|
BIN_DIR:=bin
|
||||||
|
|
||||||
|
VERBOSE:=0
|
||||||
|
_ATSYM_:=@
|
||||||
|
|
||||||
|
ifeq ($(VERBOSE),1)
|
||||||
|
_ATSYM_=
|
||||||
|
clean-build:
|
||||||
|
else
|
||||||
|
_ATSYM_=@
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Tools
|
||||||
|
CC=arm-none-eabi-g++
|
||||||
|
LD=arm-none-eabi-gcc
|
||||||
|
AR=arm-none-eabi-ar
|
||||||
|
AS=arm-none-eabi-as
|
||||||
|
|
||||||
|
ELF=$(BIN_DIR)/main.elf
|
||||||
|
|
||||||
|
INC:=$(sort $(shell find -L . -type f,l \( -name '*.h' -o -name '*.hpp' \) -printf '-I%h ' | sort -u))
|
||||||
|
|
||||||
|
vpath %.c $(sort $(shell find -L ./src -type f,l -name "*.c" -printf '%h\n' | sort -u))
|
||||||
|
vpath %.s $(sort $(shell find -L ./src -type f,l -name "*.s" -printf '%h\n' | sort -u))
|
||||||
|
vpath %.cpp $(sort $(shell find -L ./src -type f,l -name "*.cpp" -printf '%h\n' | sort -u))
|
||||||
|
vpath %.o $(BUILD_DIR)
|
||||||
|
|
||||||
|
OBJ_C=$(shell find -L ./src -type f,l -name '*.c')
|
||||||
|
OBJ_CPP=$(shell find -L ./src -type f,l -name '*.cpp')
|
||||||
|
OBJ_S=$(shell find -L ./src -type f,l -name '*.s')
|
||||||
|
|
||||||
|
|
||||||
|
OBJ:=$(addprefix $(BUILD_DIR)/, $(notdir $(OBJ_C:%.c=%.o)))
|
||||||
|
OBJ+=$(addprefix $(BUILD_DIR)/, $(notdir $(OBJ_CPP:%.cpp=%.o)))
|
||||||
|
OBJ+=$(addprefix $(BUILD_DIR)/, $(notdir $(OBJ_S:%.s=%.o)))
|
||||||
|
|
||||||
|
|
||||||
|
DEPS:=$(OBJ:.o=.d)
|
||||||
|
|
||||||
|
LDFLAGS+= -T$(LDSCRIPT) -Wall -mthumb -mcpu=cortex-m0 -Wl,--gc-sections
|
||||||
|
CFLAGS+= $(INC) -mcpu=cortex-m0 -mthumb -ggdb -D$(MCUTYPE)
|
||||||
|
|
||||||
|
.PHONY: all clean-build clean
|
||||||
|
|
||||||
|
all: $(ELF)
|
||||||
|
$(ELF): $(OBJ)
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@echo "***************"
|
||||||
|
@echo "Linking Target: " $@
|
||||||
|
@echo "prereq: $(OBJ)"
|
||||||
|
$(_ATSYM_)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LDLIBS)
|
||||||
|
|
||||||
|
# compile and generate dependency info
|
||||||
|
$(BUILD_DIR)/%.o: %.c
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@echo "***************"
|
||||||
|
@echo "Compiling $< ---> $@"
|
||||||
|
$(_ATSYM_)arm-none-eabi-gcc -c $(CFLAGS) $< -o $@
|
||||||
|
@echo "Outputting Dependency from $< ---> "$(BUILD_DIR)/$*.d
|
||||||
|
$(_ATSYM_)arm-none-eabi-gcc -MM $(CFLAGS) $< > $(BUILD_DIR)/$*.d
|
||||||
|
|
||||||
|
# compile and generate dependency info
|
||||||
|
$(BUILD_DIR)/%.o: %.cpp
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@echo "***************"
|
||||||
|
@echo "Compiling $< ---> $@"
|
||||||
|
$(_ATSYM_)$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
@echo "Outputting Dependency from $< ---> "$(BUILD_DIR)/$*.d
|
||||||
|
$(_ATSYM_)$(CC) -MM $(CFLAGS) $< > $(BUILD_DIR)/$*.d
|
||||||
|
$(BUILD_DIR)/%.o: %.s
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
@echo "***************"
|
||||||
|
@echo "Assembling $< ---> $@"
|
||||||
|
$(_ATSYM_)$(AS) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning project..."
|
||||||
|
$(_ATSYM_)rm -f $(OBJ) $(DEPS)
|
||||||
|
$(_ATSYM_)rm -f $(BUILD_DIR)/*.d $(BUILD_DIR)/*.o
|
||||||
|
$(_ATSYM_)rm -f $(ELF) .gdb_history
|
||||||
|
|
||||||
|
clean-build: clean all
|
||||||
|
|
||||||
|
debug: $(ELF)
|
||||||
|
arm-none-eabi-gdb -iex "target extended-remote localhost:3333" $(ELF)
|
||||||
|
|
||||||
|
# pull in dependencies
|
||||||
|
-include $(DEPS)
|
||||||
|
|
||||||
|
|
Binary file not shown.
@ -0,0 +1,11 @@
|
|||||||
|
hal_sam_d2x.o: src/hal/hal_sam_d2x.cpp inc/hal/hal_sam_d2x.hpp \
|
||||||
|
inc/common/hal_arm.hpp conf/epenguin_conf.h inc/hdi/hdi_sam_d2x.h \
|
||||||
|
inc/common/epenguin_dev_arm_util.h inc/common/cmsis/core_cm0plus.h \
|
||||||
|
inc/common/cmsis/cmsis_version.h inc/common/cmsis/cmsis_compiler.h \
|
||||||
|
inc/common/cmsis/cmsis_gcc.h inc/hdi/hdi_ac.h inc/hdi/hdi_adc.h \
|
||||||
|
inc/hdi/hdi_dmac.h inc/hdi/hdi_dsu.h inc/hdi/hdi_eic.h \
|
||||||
|
inc/hdi/hdi_evsys.h inc/hdi/hdi_gclk.h inc/hdi/hdi_hmatrixb.h \
|
||||||
|
inc/hdi/hdi_i2s.h inc/hdi/hdi_mtb.h inc/hdi/hdi_nvmctrl.h \
|
||||||
|
inc/hdi/hdi_pac.h inc/hdi/hdi_pm.h inc/hdi/hdi_port.h inc/hdi/hdi_rtc.h \
|
||||||
|
inc/hdi/hdi_sercom.h inc/hdi/hdi_sysctrl.h inc/hdi/hdi_tc.h \
|
||||||
|
inc/hdi/hdi_tcc.h inc/hdi/hdi_usb.h inc/hdi/hdi_wdt.h
|
Binary file not shown.
@ -0,0 +1,10 @@
|
|||||||
|
hdi_sam_d2x.o: src/hdi/hdi_sam_d2x.c inc/hdi/hdi_sam_d2x.h \
|
||||||
|
inc/common/epenguin_dev_arm_util.h inc/common/cmsis/core_cm0plus.h \
|
||||||
|
inc/common/cmsis/cmsis_version.h inc/common/cmsis/cmsis_compiler.h \
|
||||||
|
inc/common/cmsis/cmsis_gcc.h inc/hdi/hdi_ac.h inc/hdi/hdi_adc.h \
|
||||||
|
inc/hdi/hdi_dmac.h inc/hdi/hdi_dsu.h inc/hdi/hdi_eic.h \
|
||||||
|
inc/hdi/hdi_evsys.h inc/hdi/hdi_gclk.h inc/hdi/hdi_hmatrixb.h \
|
||||||
|
inc/hdi/hdi_i2s.h inc/hdi/hdi_mtb.h inc/hdi/hdi_nvmctrl.h \
|
||||||
|
inc/hdi/hdi_pac.h inc/hdi/hdi_pm.h inc/hdi/hdi_port.h inc/hdi/hdi_rtc.h \
|
||||||
|
inc/hdi/hdi_sercom.h inc/hdi/hdi_sysctrl.h inc/hdi/hdi_tc.h \
|
||||||
|
inc/hdi/hdi_tcc.h inc/hdi/hdi_usb.h inc/hdi/hdi_wdt.h
|
Binary file not shown.
@ -0,0 +1,11 @@
|
|||||||
|
main.o: src/main.cpp inc/epenguin.hpp conf/epenguin_conf.h \
|
||||||
|
inc/hal/hal_sam_d2x.hpp inc/common/hal_arm.hpp inc/hdi/hdi_sam_d2x.h \
|
||||||
|
inc/common/epenguin_dev_arm_util.h inc/common/cmsis/core_cm0plus.h \
|
||||||
|
inc/common/cmsis/cmsis_version.h inc/common/cmsis/cmsis_compiler.h \
|
||||||
|
inc/common/cmsis/cmsis_gcc.h inc/hdi/hdi_ac.h inc/hdi/hdi_adc.h \
|
||||||
|
inc/hdi/hdi_dmac.h inc/hdi/hdi_dsu.h inc/hdi/hdi_eic.h \
|
||||||
|
inc/hdi/hdi_evsys.h inc/hdi/hdi_gclk.h inc/hdi/hdi_hmatrixb.h \
|
||||||
|
inc/hdi/hdi_i2s.h inc/hdi/hdi_mtb.h inc/hdi/hdi_nvmctrl.h \
|
||||||
|
inc/hdi/hdi_pac.h inc/hdi/hdi_pm.h inc/hdi/hdi_port.h inc/hdi/hdi_rtc.h \
|
||||||
|
inc/hdi/hdi_sercom.h inc/hdi/hdi_sysctrl.h inc/hdi/hdi_tc.h \
|
||||||
|
inc/hdi/hdi_tcc.h inc/hdi/hdi_usb.h inc/hdi/hdi_wdt.h
|
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
mcu.o: src/common/mcu.cpp
|
Binary file not shown.
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _EPENGUIN_CONF_H_
|
||||||
|
#define _EPENGUIN_CONF_H_
|
||||||
|
|
||||||
|
#define EP_UARCH __UARCH_ARM__
|
||||||
|
#define EP_MCU_FAMILY __SAM_D2X__
|
||||||
|
#define EP_MCU __ATSAMD21J18A__
|
||||||
|
|
||||||
|
#define EP_DRIVERS (0)
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/common/inc/cmsis/
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/arm/common/inc
|
@ -0,0 +1,89 @@
|
|||||||
|
#ifndef _EPENGUIN_HPP_
|
||||||
|
#define _EPENGUIN_HPP_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* -- ePenguin --
|
||||||
|
|
||||||
|
This master file dictates all supported hardware. It lists supported
|
||||||
|
architectures, mcu families, and specific mcus. This software framework
|
||||||
|
targets hardware at the mcu level--not at the board level. Board layers can
|
||||||
|
be applied, but this framework targets the mcu and the mcu alone.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef __UARCHITECTURES__
|
||||||
|
#define __UARCHITECTURES__
|
||||||
|
#define __UARCH_ARM__ (0)
|
||||||
|
#define __UARCH_ARM64__ (1)
|
||||||
|
#define __UARCH_AVR__ (2)
|
||||||
|
#define __UARCH_AVR32__ (3)
|
||||||
|
#define __UARCH_X86__ (4)
|
||||||
|
#define __UARCH_RISCV__ (5)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __UFAMILIES__
|
||||||
|
#define __UFAMILIES__
|
||||||
|
/* Support ARM MCU Families */
|
||||||
|
|
||||||
|
/* Microchip */
|
||||||
|
#define __SAM_D1X__ (0)
|
||||||
|
#define __SAM_C1X__ (1)
|
||||||
|
#define __SAM_D2X__ (2)
|
||||||
|
#define __SAM_E_D5X__ (3)
|
||||||
|
#define __SAM_C2X__ (4)
|
||||||
|
#define __SAM_L2X__ (5)
|
||||||
|
|
||||||
|
/* STMicroelectronics */
|
||||||
|
|
||||||
|
/* NXP */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __UCONTROLLERS__
|
||||||
|
#define __UCONTROLLERS__
|
||||||
|
|
||||||
|
/* ARM */
|
||||||
|
/* Microchip */
|
||||||
|
/* SAM_D2X */
|
||||||
|
/* D2X Series E */
|
||||||
|
#define __ATSAMD21E15A__ (0)
|
||||||
|
#define __ATSAMD21E15B__ (1)
|
||||||
|
#define __ATSAMD21E15BU__ (2)
|
||||||
|
#define __ATSAMD21E15L__ (3)
|
||||||
|
#define __ATSAMD21E16A__ (4)
|
||||||
|
#define __ATSAMD21E16B__ (5)
|
||||||
|
#define __ATSAMD21E16BU__ (6)
|
||||||
|
#define __ATSAMD21E16L__ (7)
|
||||||
|
#define __ATSAMD21E17A__ (8)
|
||||||
|
#define __ATSAMD21E17D__ (9)
|
||||||
|
#define __ATSAMD21E17DU__ (10)
|
||||||
|
#define __ATSAMD21E17L__ (11)
|
||||||
|
#define __ATSAMD21E18A__ (12)
|
||||||
|
/* D2X Series G */
|
||||||
|
#define __ATSAMD21G15A__ (13)
|
||||||
|
#define __ATSAMD21G15B__ (14)
|
||||||
|
#define __ATSAMD21G15L__ (15)
|
||||||
|
#define __ATSAMD21G16A__ (16)
|
||||||
|
#define __ATSAMD21G16B__ (17)
|
||||||
|
#define __ATSAMD21G16L__ (18)
|
||||||
|
#define __ATSAMD21G17A__ (19)
|
||||||
|
#define __ATSAMD21G17AU__ (20)
|
||||||
|
#define __ATSAMD21G17D__ (21)
|
||||||
|
#define __ATSAMD21G17L__ (22)
|
||||||
|
#define __ATSAMD21G18A__ (23)
|
||||||
|
#define __ATSAMD21G18AU__ (24)
|
||||||
|
/* D2X Series J */
|
||||||
|
#define __ATSAMD21J15A__ (25)
|
||||||
|
#define __ATSAMD21J15B__ (26)
|
||||||
|
#define __ATSAMD21J16A__ (27)
|
||||||
|
#define __ATSAMD21J16B__ (28)
|
||||||
|
#define __ATSAMD21J17A__ (29)
|
||||||
|
#define __ATSAMD21J17D__ (30)
|
||||||
|
#define __ATSAMD21J18A__ (31)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#include "epenguin_conf.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/arm/SAM_D2X/hal/inc
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/arm/SAM_D2X/hdi/inc
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/arm/SAM_D2X/ld/ex.ld
|
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# links cmsis folder into our inc folder
|
||||||
|
# ln -s /storage/Shared/Documents/ASF_LIBS/xdk-asf-3.48.0/thirdparty/CMSIS/Include ./inc/cmsis
|
||||||
|
ln -s ${EPSF_HAL}/arch/common/inc/cmsis/ ./inc/cmsis
|
||||||
|
# links asf3 samd21 include folder into our inc folder
|
||||||
|
# ln -s /storage/Shared/Documents/ASF_LIBS/xdk-asf-3.48.0/sam0/utils/cmsis/samd21/include ./inc/asf3-inc
|
||||||
|
ln -s ${EPSF_HAL}/arch/arm/SAM_D2X/hal/inc ./inc/hal
|
||||||
|
ln -s ${EPSF_HAL}/arch/arm/SAM_D2X/hdi/inc ./inc/hdi
|
||||||
|
ln -s ${EPSF_HAL}/arch/arm/SAM_D2X/hal/src ./src/hal
|
||||||
|
ln -s ${EPSF_HAL}/arch/arm/SAM_D2X/hdi/src ./src/hdi
|
||||||
|
ln -s ${EPSF_HAL}/arch/arm/common/inc ./inc/common
|
||||||
|
ln -s ${EPSF_HAL}/arch/arm/common/src ./src/common
|
||||||
|
# links linker script into our linker folder
|
||||||
|
# ln -s /storage/Shared/Documents/ASF_LIBS/xdk-asf-3.48.0/sam0/utils/linker_scripts/samd21/gcc/samd21j18a_flash.ld ./linker/.
|
||||||
|
ln -s ${EPSF_HAL}/arch/arm/SAM_D2X/ld/ex.ld ./ld/ex.ld
|
||||||
|
# links asf3 startup code for d21 into our src folder
|
||||||
|
# ln -s /storage/Shared/Documents/ASF_LIBS/xdk-asf-3.48.0/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c ./src/.
|
||||||
|
# ln -s /storage/Shared/Documents/ASF_LIBS/xdk-asf-3.48.0/sam0/utils/cmsis/samd21/source/system_samd21.c ./src/.
|
||||||
|
# ln -s /storage/Shared/Documents/ASF_LIBS/xdk-asf-3.48.0/sam0/utils/cmsis/samd21/source/system_samd21.h ./inc/.
|
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
rm -rf ./inc/cmsis ./inc/hal ./inc/hdi ./src/hal ./src/hdi ./ld/ex.ld ./inc/common ./src/common
|
@ -0,0 +1,8 @@
|
|||||||
|
# Atmel-ICE JTAG/SWD in-circuit debugger.
|
||||||
|
interface cmsis-dap
|
||||||
|
cmsis_dap_vid_pid 0x03eb 0x2111
|
||||||
|
cmsis_dap_serial 3 ATML2748051800004709
|
||||||
|
|
||||||
|
# Chip info
|
||||||
|
set CHIPNAME at91samd21j18
|
||||||
|
source [find target/at91samdXX.cfg]
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/arm/common/src
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/arm/SAM_D2X/hal/src
|
@ -0,0 +1 @@
|
|||||||
|
/storage/Shared/Documents/Projects/epenguin_software_framework/arch/arm/SAM_D2X/hdi/src
|
@ -0,0 +1,86 @@
|
|||||||
|
#include "epenguin.hpp"
|
||||||
|
#include "hal_sam_d2x.hpp"
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define PORT_ADDR (0x41004400)
|
||||||
|
|
||||||
|
#define PORT_GROUP_SIZE (0x80)
|
||||||
|
|
||||||
|
#define PORT_A_OFF (0x00)
|
||||||
|
#define PORT_B_OFF (0x80)
|
||||||
|
|
||||||
|
#define PORT_DIR_OFF (0x00)
|
||||||
|
#define PORT_OUT_OFF (0x10)
|
||||||
|
|
||||||
|
// LED 0: PA09
|
||||||
|
// LED 1: PB01
|
||||||
|
|
||||||
|
#define LED0_PORT (0)
|
||||||
|
#define LED0_PIN (9)
|
||||||
|
|
||||||
|
#define LED1_PORT (1)
|
||||||
|
#define LED1_PIN (1)
|
||||||
|
|
||||||
|
static void init_pin(int port, int pin);
|
||||||
|
static void set_pin(int port, int pin);
|
||||||
|
static void clr_pin(int port, int pin);
|
||||||
|
|
||||||
|
static void delay(int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(;n>0;n--)
|
||||||
|
{
|
||||||
|
for(i=0;i<100;i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
asm volatile("nop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
init_pin(LED0_PORT, LED0_PIN);
|
||||||
|
init_pin(LED1_PORT, LED1_PIN);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
set_pin(LED0_PORT, LED0_PIN);
|
||||||
|
clr_pin(LED1_PORT, LED1_PIN);
|
||||||
|
delay(500);
|
||||||
|
clr_pin(LED0_PORT, LED0_PIN);
|
||||||
|
set_pin(LED1_PORT, LED1_PIN);
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// port 0: A
|
||||||
|
// port 1: B
|
||||||
|
|
||||||
|
|
||||||
|
void init_pin(int port, int pin)
|
||||||
|
{
|
||||||
|
uint32_t* dir_reg = (uint32_t*)((PORT_ADDR | (port * PORT_GROUP_SIZE) | PORT_DIR_OFF));
|
||||||
|
*dir_reg |= (1 << pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_pin(int port, int pin)
|
||||||
|
{
|
||||||
|
uint32_t* out_reg = (uint32_t*)((PORT_ADDR | (port * PORT_GROUP_SIZE) | PORT_OUT_OFF));
|
||||||
|
*out_reg |= (1 << pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clr_pin(int port, int pin)
|
||||||
|
{
|
||||||
|
uint32_t* out_reg = (uint32_t*)((PORT_ADDR | (port * PORT_GROUP_SIZE) | PORT_OUT_OFF));
|
||||||
|
*out_reg &= ~(1 << pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
|||||||
|
#include "types.h"
|
||||||
|
#include "shared.h"
|
||||||
|
#include "shared.cpp"
|
||||||
|
#include "tokenizer.h"
|
||||||
|
#include "tokenizer.cpp"
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,358 @@
|
|||||||
|
struct format_dest {
|
||||||
|
umm Size;
|
||||||
|
char* At;
|
||||||
|
};
|
||||||
|
|
||||||
|
void OutChar(format_dest* Dest, char Value) {
|
||||||
|
if (Dest->Size){
|
||||||
|
--Dest->Size;
|
||||||
|
*Dest->At++ = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutChars(format_dest* Dest, char* Value) {
|
||||||
|
// note(jax): Not particularily speedy@
|
||||||
|
while (*Value) {
|
||||||
|
OutChar(Dest, *Value++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ReadVarArgUnsignedInteger(Length, ArgList) ((Length) == 8) ? _crt_va_arg(*ArgList, u64) : (u64)_crt_va_arg(*ArgList, u32)
|
||||||
|
#define ReadVarArgSignedInteger(Length, ArgList) ((Length) == 8) ? _crt_va_arg(*ArgList, s64) : (s64)_crt_va_arg(*ArgList, s32)
|
||||||
|
#define ReadVarArgFloat(Length, ArgList) _crt_va_arg(*ArgList, f64)
|
||||||
|
|
||||||
|
static char DecChars[] = "0123456789";
|
||||||
|
static char LowerHexChars[] = "0123456789abcdef";
|
||||||
|
static char UpperHexChars[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
void U64ToASCII(format_dest* Dest, u64 Value, u32 Base, char* Digits) {
|
||||||
|
Assert(Base != 0);
|
||||||
|
|
||||||
|
char* Start = Dest->At;
|
||||||
|
do {
|
||||||
|
u64 DigitIndex = (Value % Base);
|
||||||
|
char Digit = Digits[DigitIndex];
|
||||||
|
OutChar(Dest, Digit);
|
||||||
|
|
||||||
|
Value /= Base;
|
||||||
|
} while (Value != 0);
|
||||||
|
char* End = Dest->At;
|
||||||
|
|
||||||
|
while (Start < End) {
|
||||||
|
--End;
|
||||||
|
char Temp = *End;
|
||||||
|
*End = *Start;
|
||||||
|
*Start = Temp;
|
||||||
|
++Start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void F64ToASCII(format_dest* Dest, f64 Value, u32 Precision) {
|
||||||
|
if (Value < 0) {
|
||||||
|
OutChar(Dest, '-');
|
||||||
|
Value = -Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 IntegerPart = (u64)Value;
|
||||||
|
Value -= (f64)IntegerPart;
|
||||||
|
U64ToASCII(Dest, IntegerPart, 10, DecChars);
|
||||||
|
|
||||||
|
OutChar(Dest, '.');
|
||||||
|
|
||||||
|
// tood(jax): Note that this is NOT an accurate way to do this!
|
||||||
|
for (u32 PrecisionIndex = 0; PrecisionIndex < Precision; ++PrecisionIndex) {
|
||||||
|
Value *= 10.0f;
|
||||||
|
u32 Integer = (u32)Value;
|
||||||
|
Value -= (f32)Integer;
|
||||||
|
OutChar(Dest, DecChars[Integer]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// note(jax): This function serves as a replacement to `stdio.h` sprintf()
|
||||||
|
umm FormatArgList(umm DestSize, char* DestInit, char* Format, va_list ArgList) {
|
||||||
|
format_dest Dest = {DestSize, DestInit};
|
||||||
|
if (Dest.Size) {
|
||||||
|
char* At = Format;
|
||||||
|
while (At[0]) {
|
||||||
|
if (*At == '%') {
|
||||||
|
++At;
|
||||||
|
|
||||||
|
b32 ForceSign = false;
|
||||||
|
b32 PadWithZeros = false;
|
||||||
|
b32 LeftJustify = false;
|
||||||
|
b32 PositiveSignIsBlank = false;
|
||||||
|
b32 AnnotateIfNotZero = false;
|
||||||
|
|
||||||
|
// note(jax): Handle the flags
|
||||||
|
b32 Parsing = true;
|
||||||
|
|
||||||
|
Parsing = true;
|
||||||
|
while (Parsing) {
|
||||||
|
switch (*At) {
|
||||||
|
case '+': { ForceSign = true; } break;
|
||||||
|
case '0': { PadWithZeros = true; } break;
|
||||||
|
case '-': { LeftJustify = true; } break;
|
||||||
|
case ' ': { PositiveSignIsBlank = true; } break;
|
||||||
|
case '#': { AnnotateIfNotZero = true; } break;
|
||||||
|
default: { Parsing = false; } break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Parsing) {
|
||||||
|
++At;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// note(jax): Handle the width
|
||||||
|
b32 WidthSpecified = false;
|
||||||
|
int32 Width = 0;
|
||||||
|
if (*At == '*') {
|
||||||
|
Width = _crt_va_arg(ArgList, int);
|
||||||
|
WidthSpecified = true;
|
||||||
|
++At;
|
||||||
|
} else if ((*At >= '0') && (*At <= '9')) {
|
||||||
|
Width = StringToI32(At);
|
||||||
|
WidthSpecified = true;
|
||||||
|
//? ++At;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note(jax): Handle the precision
|
||||||
|
b32 PrecisionSpecified = false;
|
||||||
|
int32 Precision = 0;
|
||||||
|
if (*At == '.') {
|
||||||
|
++At;
|
||||||
|
|
||||||
|
if (*At == '*') {
|
||||||
|
Precision = _crt_va_arg(ArgList, int);
|
||||||
|
PrecisionSpecified = true;
|
||||||
|
++At;
|
||||||
|
} else if ((*At >= '0') && (*At <= '9')) {
|
||||||
|
Precision = StringToI32(At);
|
||||||
|
PrecisionSpecified = true;
|
||||||
|
//++At;
|
||||||
|
} else {
|
||||||
|
Assert(!"Malformed precision specifier!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo(jax): Right now our routine doesn't allow non-specified
|
||||||
|
// precisions, so we just set non-specified precisions to a specific value.
|
||||||
|
if (!PrecisionSpecified) {
|
||||||
|
Precision = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note(jax): Handle the length
|
||||||
|
u32 IntegerLength = 4;
|
||||||
|
u32 FloatLength = 8;
|
||||||
|
// todo(jax): Actually set different values here.
|
||||||
|
if ((At[0] == 'h') && (At[1] == 'h')) {
|
||||||
|
At += 2;
|
||||||
|
} else if ((At[0] == 'l') && (At[1] == 'l')) {
|
||||||
|
At += 2;
|
||||||
|
} else if (*At == 'h') {
|
||||||
|
++At;
|
||||||
|
} else if (*At == 'l') {
|
||||||
|
IntegerLength = 8;
|
||||||
|
++At;
|
||||||
|
} else if (*At == 'j') {
|
||||||
|
++At;
|
||||||
|
} else if (*At == 'z') {
|
||||||
|
++At;
|
||||||
|
} else if (*At == 't') {
|
||||||
|
++At;
|
||||||
|
} else if (*At == 'L') {
|
||||||
|
++At;
|
||||||
|
}
|
||||||
|
|
||||||
|
char TempBuffer[64];
|
||||||
|
char* Temp = TempBuffer;
|
||||||
|
format_dest TempDest = {ArrayCount(TempBuffer), Temp};
|
||||||
|
char* Prefix = "";
|
||||||
|
b32 IsFloat = false;
|
||||||
|
|
||||||
|
switch (*At) {
|
||||||
|
case 'd':
|
||||||
|
case 'i': {
|
||||||
|
s64 Value = ReadVarArgSignedInteger(IntegerLength, &ArgList);
|
||||||
|
b32 WasNegative = (Value < 0);
|
||||||
|
if (WasNegative) {
|
||||||
|
Value = -Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
U64ToASCII(&TempDest, (u64)Value, 10, DecChars);
|
||||||
|
// todo(jax): Make this a common routine once floating poiunt is available.
|
||||||
|
if (WasNegative) {
|
||||||
|
Prefix = "-";
|
||||||
|
} else if (ForceSign) {
|
||||||
|
Assert(!PositiveSignIsBlank); // note(jax): Not a problem, but probably shouldn't be specified.
|
||||||
|
Prefix = "+";
|
||||||
|
} else if (PositiveSignIsBlank) {
|
||||||
|
Prefix = " ";
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'u': {
|
||||||
|
u64 Value = ReadVarArgUnsignedInteger(IntegerLength, &ArgList);
|
||||||
|
U64ToASCII(&TempDest, Value, 10, DecChars);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'o': {
|
||||||
|
u64 Value = ReadVarArgUnsignedInteger(IntegerLength, &ArgList);
|
||||||
|
U64ToASCII(&TempDest, Value, 8, DecChars);
|
||||||
|
if (AnnotateIfNotZero && (Value != 0)) {
|
||||||
|
Prefix = "0";
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'x': {
|
||||||
|
u64 Value = ReadVarArgUnsignedInteger(IntegerLength, &ArgList);
|
||||||
|
U64ToASCII(&TempDest, Value, 16, LowerHexChars);
|
||||||
|
if (AnnotateIfNotZero && (Value != 0)) {
|
||||||
|
Prefix = "0x";
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'X': {
|
||||||
|
u64 Value = ReadVarArgUnsignedInteger(IntegerLength, &ArgList);
|
||||||
|
U64ToASCII(&TempDest, Value, 16, UpperHexChars);
|
||||||
|
if (AnnotateIfNotZero && (Value != 0)) {
|
||||||
|
Prefix = "0X";
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// todo(jax): Support other kinds of floating point prints
|
||||||
|
// Currently we only do basic decimal output.
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
case 'a':
|
||||||
|
case 'A': {
|
||||||
|
f64 Value = ReadVarArgFloat(FloatLength, &ArgList);
|
||||||
|
F64ToASCII(&TempDest, Value, Precision);
|
||||||
|
IsFloat = true;
|
||||||
|
|
||||||
|
// @Speed @Cleanup todo(jax): If we still have more floats in temp, increase
|
||||||
|
// the size again. This is a very, very bad hack and is NOT shippable! (shame!)
|
||||||
|
if (Temp) {
|
||||||
|
Dest.Size += FloatLength;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'c': {
|
||||||
|
// todo(jax): How much are we supposed to read here?
|
||||||
|
int Value = _crt_va_arg(ArgList, int);
|
||||||
|
OutChar(&TempDest, (char)Value);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 's': {
|
||||||
|
char* String = _crt_va_arg(ArgList, char*);
|
||||||
|
|
||||||
|
// todo(jax): Obey precision, width, etc.
|
||||||
|
|
||||||
|
Temp = String;
|
||||||
|
if (PrecisionSpecified) {
|
||||||
|
TempDest.Size = 0;
|
||||||
|
for (char* Scan = String; *Scan && (TempDest.Size < Precision); ++Scan) {
|
||||||
|
++TempDest.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TempDest.Size = StringLength(String);
|
||||||
|
}
|
||||||
|
|
||||||
|
TempDest.At = String + TempDest.Size;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'p': {
|
||||||
|
void* Value = _crt_va_arg(ArgList, void*);
|
||||||
|
U64ToASCII(&TempDest, *(umm*)&Value, 16, LowerHexChars);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'n': {
|
||||||
|
int* TabDest = _crt_va_arg(ArgList, int*);
|
||||||
|
*TabDest = (int)(Dest.At - DestInit);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case '%': {
|
||||||
|
OutChar(&Dest, '%');
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
Assert(!"Unrecognized format specifier!");
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TempDest.At - Temp) {
|
||||||
|
smm UsePrecision = Precision;
|
||||||
|
if (IsFloat || !PrecisionSpecified) {
|
||||||
|
UsePrecision = (TempDest.At - Temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
smm PrefixLength = StringLength(Prefix);
|
||||||
|
smm UseWidth = Width;
|
||||||
|
smm ComputedWidth = UsePrecision + PrefixLength;
|
||||||
|
if (UseWidth < ComputedWidth) {
|
||||||
|
UseWidth = ComputedWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PadWithZeros) {
|
||||||
|
Assert(!LeftJustify); // note(jax): Not a problem, but no way to do it?
|
||||||
|
LeftJustify = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!LeftJustify) {
|
||||||
|
while (UseWidth > (UsePrecision + PrefixLength)) {
|
||||||
|
OutChar(&Dest, PadWithZeros ? '0' : ' ');
|
||||||
|
--UseWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (char* Pre = Prefix; *Pre && UseWidth; ++Pre) {
|
||||||
|
OutChar(&Dest, *Pre);
|
||||||
|
--UseWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UsePrecision > UseWidth) {
|
||||||
|
UsePrecision = UseWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (UsePrecision > (TempDest.At - Temp)) {
|
||||||
|
OutChar(&Dest, '0');
|
||||||
|
--UsePrecision;
|
||||||
|
--UseWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (UsePrecision && (TempDest.At != Temp)) {
|
||||||
|
OutChar(&Dest, *Temp++);
|
||||||
|
--UsePrecision;
|
||||||
|
--UseWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LeftJustify) {
|
||||||
|
while (UseWidth) {
|
||||||
|
OutChar(&Dest, ' ');
|
||||||
|
--UseWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*At) {
|
||||||
|
++At;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OutChar(&Dest, *At++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Dest.Size) {
|
||||||
|
Dest.At[0] = 0;
|
||||||
|
} else {
|
||||||
|
Dest.At[-1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
umm Result = Dest.At - DestInit;
|
||||||
|
return Result;
|
||||||
|
}
|
@ -0,0 +1,296 @@
|
|||||||
|
#ifndef SHARED_H
|
||||||
|
#define SHARED_H
|
||||||
|
|
||||||
|
#define ZeroStruct(Struct) ZeroSize(&Struct, sizeof(Struct))
|
||||||
|
inline void ZeroSize(void* Ptr, size_t Size) {
|
||||||
|
u8* Byte = (u8*)Ptr;
|
||||||
|
// todo(jax): @Speed: Check performance of the two code blocks
|
||||||
|
#if 0
|
||||||
|
for (size_t i = 0; i < Size; ++i) {
|
||||||
|
*Byte++ = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
while (Size--) {
|
||||||
|
*Byte++ = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CopyArray(Dest, Source, Count) MemoryCopy((Dest), (Source), (Count)*sizeof(*(Source)))
|
||||||
|
inline void* MemoryCopy(void* _Dest, void* _Source, size_t Size) {
|
||||||
|
#if 0
|
||||||
|
return memcpy(_Dest, _Source, Size);
|
||||||
|
#else //NO CRT VERSION HERE!
|
||||||
|
if (_Source == 0) {
|
||||||
|
ZeroSize(_Dest, Size);
|
||||||
|
return _Dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* Source = (u8*)_Source;
|
||||||
|
u8* Dest = (u8*)_Dest;
|
||||||
|
|
||||||
|
while (Size--) {
|
||||||
|
*Dest++ = *Source++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _Dest;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u8* Advance(string* String, umm Count) {
|
||||||
|
u8 *Result = 0;
|
||||||
|
|
||||||
|
if(String->Count >= Count) {
|
||||||
|
Result = String->Data;
|
||||||
|
String->Data += Count;
|
||||||
|
String->Count -= Count;
|
||||||
|
} else {
|
||||||
|
String->Data += String->Count;
|
||||||
|
String->Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b32 IsSpacing(char C) {
|
||||||
|
b32 Result = ((C == ' ') || (C == '\t') || (C == '\v') ||(C == '\f'));
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b32 IsEndOfLine(char Value) {
|
||||||
|
b32 Result = ((Value == '\n') || (Value == '\r'));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b32 IsWhitespace(char Value, bool IncludeEOL = false) {
|
||||||
|
b32 Result = ((Value == ' ') || (Value == '\t') || (Value == '\v') || (Value == '\f') || ( IncludeEOL ? IsEndOfLine(Value) : 1));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b32 IsAlphabetical(char Value) {
|
||||||
|
b32 Result = (((Value >= 'a') && (Value <= 'z')) || ((Value >= 'A') && (Value <= 'Z')));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b32 IsNumeric(char Value) {
|
||||||
|
b32 Result = ((Value >= '0') && (Value <= '9'));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* GetNextLine(char** Contents) {
|
||||||
|
char* Text = *Contents;
|
||||||
|
if (!*Text) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Line = Text;
|
||||||
|
while (*Text && (*Text != '\n') && (*Text != '\r')) {
|
||||||
|
++Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* End = Text;
|
||||||
|
++End;
|
||||||
|
if (*Text == '\r') {
|
||||||
|
if (*End == '\n') {
|
||||||
|
++End;
|
||||||
|
}
|
||||||
|
|
||||||
|
*Text = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
*Contents = End;
|
||||||
|
|
||||||
|
return Line;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int StringLength(char* String) {
|
||||||
|
int Count = 0;
|
||||||
|
while (*String++) {
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline string make_string(char* String) {
|
||||||
|
string Result = {};
|
||||||
|
Result.Data = (u8*)String;
|
||||||
|
Result.Count = StringLength(String);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* Substring(char* Source, char* String) {
|
||||||
|
while (*Source) {
|
||||||
|
char *Begin = Source;
|
||||||
|
char *Pattern = String;
|
||||||
|
|
||||||
|
// If first character of sub string match, check for whole string
|
||||||
|
while (*Source && *Pattern && *Source == *Pattern) {
|
||||||
|
Source++;
|
||||||
|
Pattern++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If complete sub string match, return starting address
|
||||||
|
if (!*Pattern)
|
||||||
|
return Begin;
|
||||||
|
|
||||||
|
Source = Begin + 1;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: _Char is expected to be an ASCII character
|
||||||
|
inline char* FindFirstChar(char* String, int _Char) {
|
||||||
|
char Char = (char)_Char;
|
||||||
|
while (*String != Char) {
|
||||||
|
if (!*String++) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (char*)String;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo(jax): Consider using while loops for Append and StringCopy?? Query performance benefit.
|
||||||
|
|
||||||
|
inline char* Append(char* Dest, size_t DestSize, char* Source) {
|
||||||
|
// todo(jax): Do we need to terminate annd or allocate needed memory?
|
||||||
|
Dest = (char*)malloc(DestSize + (1 + StringLength(Source) * sizeof(char)));
|
||||||
|
MemoryCopy(Dest + StringLength(Dest), Source, DestSize + 1);
|
||||||
|
return Dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* StringCopy(char* String) {
|
||||||
|
char* Result = (char*)malloc(sizeof(char) * (StringLength(String) + 1));
|
||||||
|
MemoryCopy(Result, String, sizeof(char) * (StringLength(String) + 1));
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool StringsMatch(char* A, char* B) {
|
||||||
|
while (*A && *B) {
|
||||||
|
if (*A != *B){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
++A;
|
||||||
|
++B;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*A != *B){
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CatStrings(size_t SourceACount, char* SourceA, size_t SourceBCount, char* SourceB, size_t DestCount, char* Dest) {
|
||||||
|
// todo(jax): Bounds check the Destination. This code is risky!
|
||||||
|
for (int Index = 0; Index < SourceACount; ++Index) {
|
||||||
|
*Dest++ = *SourceA++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int Index = 0; Index < SourceBCount; ++Index) {
|
||||||
|
*Dest++ = *SourceB++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*Dest++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// NOT REALLY SURE IF WE WANT TO USE THE FOLLOWING CODE!
|
||||||
|
//
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
void __cdecl __va_start(va_list*, ...);
|
||||||
|
#define _crt_va_start(ap, x) ((void)(__va_start(&ap, x)))
|
||||||
|
#define _crt_va_arg(ap, t) \
|
||||||
|
((sizeof(t) > sizeof(__int64) || (sizeof(t) & (sizeof(t) - 1)) != 0) \
|
||||||
|
? **(t**)((ap += sizeof(__int64)) - sizeof(__int64)) \
|
||||||
|
: *(t* )((ap += sizeof(__int64)) - sizeof(__int64)))
|
||||||
|
#define _crt_va_end(ap) ((void)(ap = (va_list)0))
|
||||||
|
#else
|
||||||
|
#define _crt_va_start(ap, v) va_start(ap, v)
|
||||||
|
#define _crt_va_arg(ap, t) va_arg(ap, t)
|
||||||
|
#define _crt_va_end(ap) va_end(ap)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline int32 StringToI32_(char** AtInit) {
|
||||||
|
int32 Result = {};
|
||||||
|
|
||||||
|
char* At = *AtInit;
|
||||||
|
while ((*At >= '0') && (*At <= '9')) {
|
||||||
|
Result *= 10;
|
||||||
|
Result += (*At - '0');
|
||||||
|
++At;
|
||||||
|
}
|
||||||
|
|
||||||
|
*AtInit = At;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int32 StringToI32(char* At) {
|
||||||
|
char* Ignored = At;
|
||||||
|
int32 Result = StringToI32_(&Ignored);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct format_dest;
|
||||||
|
|
||||||
|
void OutChar(format_dest* Dest, char Value);
|
||||||
|
void OutChars(format_dest* Dest, char* Value);
|
||||||
|
|
||||||
|
void U64ToASCII(format_dest* Dest, u64 Value, u32 Base, char* Digits);
|
||||||
|
void F64ToASCII(format_dest* Dest, f64 Value, u32 Precision);
|
||||||
|
|
||||||
|
// note(jax): This function serves as a replacement to `stdio.h` sprintf()
|
||||||
|
API_EXPORT umm FormatArgList(umm DestSize, char* DestInit, char* Format, va_list ArgList);
|
||||||
|
inline umm Format(umm DestSize, char* Dest, char* Format, ...) {
|
||||||
|
va_list ArgList;
|
||||||
|
_crt_va_start(ArgList, Format);
|
||||||
|
umm Result = FormatArgList(DestSize, Dest, Format, ArgList);
|
||||||
|
_crt_va_end(ArgList);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int _crt_sprintf(char* Buffer, size_t Count, char* Format, ...) {
|
||||||
|
int Result;
|
||||||
|
|
||||||
|
va_list ArgList;
|
||||||
|
__crt_va_start(ArgList, Format);
|
||||||
|
Result = _vsprintf_s_l(Buffer, Count, Format, NULL, ArgList);
|
||||||
|
__crt_va_end(ArgList);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline umm ae_sprintf(char* Dest, char* Format, ...) {
|
||||||
|
va_list ArgList;
|
||||||
|
_crt_va_start(ArgList, Format);
|
||||||
|
umm Result = FormatArgList(sizeof(Dest), Dest, Format, ArgList);
|
||||||
|
_crt_va_end(ArgList);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline umm ae_sprintf(char* Dest, char* Format, va_list ArgList) {
|
||||||
|
umm Result = FormatArgList(sizeof(Dest), Dest, Format, ArgList);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline umm ae_printf(char* Format, ...) {
|
||||||
|
char Buffer[1024];
|
||||||
|
|
||||||
|
va_list ArgList;
|
||||||
|
_crt_va_start(ArgList, Format);
|
||||||
|
umm Result = FormatArgList(1024, Buffer, Format, ArgList);
|
||||||
|
_crt_va_end(ArgList);
|
||||||
|
|
||||||
|
fwrite(Buffer, sizeof(char), StringLength(Buffer), stdout);
|
||||||
|
fflush(stdout);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,206 @@
|
|||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
b32 IsTokenValid(token Token) {
|
||||||
|
b32 Result = (Token.Type != Token_Unknown);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
b32 TokenEquals(token Token, char* Match) {
|
||||||
|
b32 Result = StringsMatch(Token.String, Match);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Refill(tokenizer *Tokenizer){
|
||||||
|
if(Tokenizer->Input.Count == 0) {
|
||||||
|
Tokenizer->At[0] = 0;
|
||||||
|
Tokenizer->At[1] = 0;
|
||||||
|
} else if(Tokenizer->Input.Count == 1) {
|
||||||
|
Tokenizer->At[0] = Tokenizer->Input.Data[0];
|
||||||
|
Tokenizer->At[1] = 0;
|
||||||
|
} else {
|
||||||
|
char C0 = Tokenizer->Input.Data[0];
|
||||||
|
char C1 = Tokenizer->Input.Data[1];
|
||||||
|
Tokenizer->At[0] = C0;
|
||||||
|
Tokenizer->At[1] = C1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvanceInput(tokenizer* Tokenizer, u32 Count) {
|
||||||
|
Tokenizer->TotalCount += Count;
|
||||||
|
Advance(&Tokenizer->Input, Count);
|
||||||
|
Refill(Tokenizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenizer Tokenize(string Data, char* Filename) {
|
||||||
|
tokenizer Result = {};
|
||||||
|
|
||||||
|
Result.Filename = Filename;
|
||||||
|
Result.LinesCount = 1;
|
||||||
|
Result.TokensCount = 1;
|
||||||
|
Result.TotalCount = 1;
|
||||||
|
Result.Input = Data;
|
||||||
|
Result.At = (char*)malloc(2);
|
||||||
|
Refill(&Result);
|
||||||
|
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenizer Tokenize(char* Data);
|
||||||
|
tokenizer Tokenize(char* Filename);
|
||||||
|
|
||||||
|
token GetToken(tokenizer* Tokenizer) {
|
||||||
|
token Token = {};
|
||||||
|
Token.Filename = Tokenizer->Filename;
|
||||||
|
Token.TextLength = 1;
|
||||||
|
Token.Text = Tokenizer->Input;
|
||||||
|
|
||||||
|
char C = Tokenizer->At[0];
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
switch (C) {
|
||||||
|
case '\0': { Token.Type = Token_EndOfStream; } break;
|
||||||
|
|
||||||
|
case '(': { Token.Type = Token_OpenParen; } break;
|
||||||
|
case ')': { Token.Type = Token_CloseParen; } break;
|
||||||
|
case ':': { Token.Type = Token_Colon; } break;
|
||||||
|
case ';': { Token.Type = Token_Semicolen; } break;
|
||||||
|
case '*': { Token.Type = Token_Asterik; } break;
|
||||||
|
case '[': { Token.Type = Token_OpenBracket; } break;
|
||||||
|
case ']': { Token.Type = Token_CloseBracket; } break;
|
||||||
|
case '{': { Token.Type = Token_OpenBrace; } break;
|
||||||
|
case '}': { Token.Type = Token_CloseBrace; } break;
|
||||||
|
case '=': { Token.Type = Token_Equals; } break;
|
||||||
|
case ',': { Token.Type = Token_Comma; } break;
|
||||||
|
case '|': { Token.Type = Token_Or; } break;
|
||||||
|
case '#': { Token.Type = Token_Pound; } break;
|
||||||
|
|
||||||
|
case '"': { // note(jax): We've got a string
|
||||||
|
Token.Type = Token_String;
|
||||||
|
while(Tokenizer->At[0] && Tokenizer->At[0] != '"') {
|
||||||
|
if ((Tokenizer->At[0] == '\\') && (Tokenizer->At[1])) {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceInput(Tokenizer, 1);;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tokenizer->At[0] == '"') {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Speed: This block of code is pretty hacky...
|
||||||
|
if (Token.Text.Count &&
|
||||||
|
(Token.Text.Data[0] == '"')) {
|
||||||
|
++Token.Text.Data;
|
||||||
|
--Token.Text.Count;
|
||||||
|
|
||||||
|
int TextLength = 0;
|
||||||
|
char* Temp = (char*)malloc(Token.Text.Count);
|
||||||
|
sprintf(Temp, "%s", Token.Text.Data);
|
||||||
|
while (Temp) {
|
||||||
|
if (*Temp == '\"') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++TextLength;
|
||||||
|
++Temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token.String = (char*)malloc(TextLength);
|
||||||
|
sprintf(Token.String, "%.*s", (int)TextLength, Token.Text.Data);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
if (IsSpacing(C)) {
|
||||||
|
Token.Type = Token_Space;
|
||||||
|
while (IsSpacing(Tokenizer->At[0])) {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
} else if (IsEndOfLine(C)) {
|
||||||
|
Token.Type = Token_EndOfLine;
|
||||||
|
if(((C == '\r') &&
|
||||||
|
(Tokenizer->At[0] == '\n')) ||
|
||||||
|
((C == '\n') &&
|
||||||
|
(Tokenizer->At[0] == '\r'))) {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
++Tokenizer->LinesCount;
|
||||||
|
} else if((C == '/') && (Tokenizer->At[0] == '/')) {
|
||||||
|
Token.Type = Token_Comment;
|
||||||
|
|
||||||
|
AdvanceInput(Tokenizer, 2);
|
||||||
|
while(Tokenizer->At[0] && !IsEndOfLine(Tokenizer->At[0])) {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
} else if((C == '/') &&
|
||||||
|
(Tokenizer->At[0] == '*')) {
|
||||||
|
Token.Type = Token_Comment;
|
||||||
|
|
||||||
|
AdvanceInput(Tokenizer, 2);
|
||||||
|
while(Tokenizer->At[0] && !((Tokenizer->At[0] == '*')
|
||||||
|
&& (Tokenizer->At[1] == '/'))) {
|
||||||
|
if(((Tokenizer->At[0] == '\r') && (Tokenizer->At[1] == '\n'))
|
||||||
|
|| ((Tokenizer->At[0] == '\n') && (Tokenizer->At[1] == '\r'))) {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsEndOfLine(Tokenizer->At[0])) {
|
||||||
|
++Tokenizer->LinesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Tokenizer->At[0] == '*') {
|
||||||
|
AdvanceInput(Tokenizer, 2);
|
||||||
|
}
|
||||||
|
} else if (IsAlphabetical(C)) {
|
||||||
|
Token.Type = Token_Identifier;
|
||||||
|
while (IsAlphabetical(Tokenizer->At[0]) || IsNumeric(Tokenizer->At[0]) || (Tokenizer->At[0] == '_')) {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
__int64 IndentLength = (Tokenizer->Input.Data - Token.Text.Data);
|
||||||
|
Token.String = (char*)malloc(IndentLength);
|
||||||
|
sprintf(Token.String, "%.*s", (int)IndentLength, Token.Text.Data);
|
||||||
|
} else if (IsNumeric(C)) {
|
||||||
|
f32 Number = (f32)(C - '0');
|
||||||
|
|
||||||
|
while (IsNumeric(Tokenizer->At[0])) {
|
||||||
|
f32 Digit = (f32)(Tokenizer->At[0] - '0');
|
||||||
|
Number = 10.0f*Number + Digit;
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This float detection code is copy pasted, I have no idea how it works!
|
||||||
|
if (Tokenizer->At[0] == '.') {
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
f32 Coefficient = 0.1f;
|
||||||
|
while (IsNumeric(Tokenizer->At[0])) {
|
||||||
|
f32 Digit = (f32)(Tokenizer->At[0] - '0');
|
||||||
|
Number += Coefficient * Digit;
|
||||||
|
Coefficient *= 0.1f;
|
||||||
|
AdvanceInput(Tokenizer, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Token.Type = Token_Literal;
|
||||||
|
Token.Float = Number;
|
||||||
|
Token.Integer = (s32)Number;
|
||||||
|
} else {
|
||||||
|
Token.Type = Token_Unknown;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++Tokenizer->TokensCount;
|
||||||
|
Token.Text.Count = (Tokenizer->Input.Data - Token.Text.Data);
|
||||||
|
return Token;
|
||||||
|
}
|
||||||
|
|
||||||
|
token PeekToken(tokenizer* Tokenizer) {
|
||||||
|
tokenizer Temp = *Tokenizer;
|
||||||
|
token Result = GetToken(Tokenizer);
|
||||||
|
*Tokenizer = Temp;
|
||||||
|
return Result;
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
#ifndef TOKENIZER_H
|
||||||
|
#define TOKENIZER_H
|
||||||
|
|
||||||
|
enum token_type {
|
||||||
|
Token_Unknown,
|
||||||
|
|
||||||
|
Token_OpenParen, // (
|
||||||
|
Token_CloseParen, // )
|
||||||
|
Token_Colon, // :
|
||||||
|
Token_Semicolen, // ;
|
||||||
|
Token_Asterik, // *
|
||||||
|
Token_OpenBracket, // [
|
||||||
|
Token_CloseBracket, // ]
|
||||||
|
Token_OpenBrace, // {
|
||||||
|
Token_CloseBrace, // }
|
||||||
|
Token_Equals,
|
||||||
|
Token_Comma,
|
||||||
|
Token_Or,
|
||||||
|
Token_Pound,
|
||||||
|
|
||||||
|
Token_String,
|
||||||
|
Token_Identifier,
|
||||||
|
Token_Literal, // Number
|
||||||
|
|
||||||
|
Token_Space,
|
||||||
|
Token_EndOfLine,
|
||||||
|
Token_Comment,
|
||||||
|
|
||||||
|
Token_EndOfStream,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct token {
|
||||||
|
char* Filename;
|
||||||
|
|
||||||
|
token_type Type;
|
||||||
|
size_t TextLength;
|
||||||
|
string Text;
|
||||||
|
union {
|
||||||
|
char* String;
|
||||||
|
f32 Float;
|
||||||
|
s32 Integer;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tokenizer {
|
||||||
|
char* Filename;
|
||||||
|
u32 LinesCount;
|
||||||
|
u32 TokensCount;
|
||||||
|
u32 TotalCount;
|
||||||
|
|
||||||
|
string Input;
|
||||||
|
char* At;
|
||||||
|
};
|
||||||
|
|
||||||
|
b32 IsTokenValid(token Token);
|
||||||
|
b32 TokenEquals(token Token, char* Match);
|
||||||
|
API_EXPORT token GetToken(tokenizer* Tokenizer);
|
||||||
|
API_EXPORT token PeekToken(tokenizer* Tokenizer);
|
||||||
|
API_EXPORT tokenizer Tokenize(char* Data);
|
||||||
|
API_EXPORT tokenizer Tokenize(char* Filename);
|
||||||
|
API_EXPORT tokenizer Tokenize(string Data, char* Filename);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,218 @@
|
|||||||
|
#ifndef TYPES_H
|
||||||
|
#define TYPES_H
|
||||||
|
|
||||||
|
#include <direct.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef BUILD_WIN32
|
||||||
|
#define API_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define API_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
|
typedef int8_t int8;
|
||||||
|
typedef int16_t int16;
|
||||||
|
typedef int32_t int32;
|
||||||
|
typedef int64_t int64;
|
||||||
|
typedef int32 bool32;
|
||||||
|
|
||||||
|
typedef uint8_t uint8;
|
||||||
|
typedef uint16_t uint16;
|
||||||
|
typedef uint32_t uint32;
|
||||||
|
typedef uint64_t uint64;
|
||||||
|
|
||||||
|
typedef float real32;
|
||||||
|
typedef double real64;
|
||||||
|
|
||||||
|
typedef int8 s8;
|
||||||
|
typedef int16 s16;
|
||||||
|
typedef int32 s32;
|
||||||
|
typedef int64 s64;
|
||||||
|
typedef bool32 b32;
|
||||||
|
|
||||||
|
typedef uint8 u8;
|
||||||
|
typedef uint16 u16;
|
||||||
|
typedef uint32 u32;
|
||||||
|
typedef uint64 u64;
|
||||||
|
|
||||||
|
typedef real32 f32;
|
||||||
|
typedef real64 f64;
|
||||||
|
|
||||||
|
typedef uintptr_t umm;
|
||||||
|
typedef intptr_t smm;
|
||||||
|
|
||||||
|
#define S32Min ((s32)0x80000000)
|
||||||
|
#define S32Max ((s32)0x7fffffff)
|
||||||
|
#define U16Max 65535
|
||||||
|
#define U32Max ((u32)-1)
|
||||||
|
#define U64Max ((u64)-1)
|
||||||
|
#define F32Max FLT_MAX
|
||||||
|
#define F32Min -FLT_MAX
|
||||||
|
|
||||||
|
#define Minimum(A, B) ((A < B) ? (A) : (B))
|
||||||
|
#define Maximum(A, B) ((A > B) ? (A) : (B))
|
||||||
|
|
||||||
|
#define For(Value) For_e((Value), ArrayCount(Value))
|
||||||
|
#define For_e(Value, End) For_se((Value), 0, (End))
|
||||||
|
#define For_se(Value, Start, End) for (int (Value) = (Start); (Value) < (End); ++(Value))
|
||||||
|
|
||||||
|
// todo(jax): Should these always be 64-bit?
|
||||||
|
#define Kilobytes(Value) (((uint64)Value) * 1024LL)
|
||||||
|
#define Megabytes(Value) (Kilobytes((uint64)Value) * 1024LL)
|
||||||
|
#define Gigabytes(Value) (Megabytes((uint64)Value) * 1024LL)
|
||||||
|
#define Terabytes(Value) (Gigabytes((uint64)Value) * 1024LL)
|
||||||
|
|
||||||
|
#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))
|
||||||
|
// todo(jax): swap, min, max ... macros???
|
||||||
|
|
||||||
|
#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
|
||||||
|
#define Align4(Value) ((Value + 3) & ~3)
|
||||||
|
#define Align8(Value) ((Value + 7) & ~7)
|
||||||
|
#define Align16(Value) ((Value + 15) & ~15)
|
||||||
|
|
||||||
|
#define Stringize(x) PrimitiveStringize(x)
|
||||||
|
#define PrimitiveStringize(x) #x
|
||||||
|
|
||||||
|
inline b32 IsPow2(u32 Value) {
|
||||||
|
return ((Value & ~(Value - 1)) == Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Regular text
|
||||||
|
#define BLACK "\33[0;30m"
|
||||||
|
#define RED "\33[0;31m"
|
||||||
|
#define GREEN "\33[0;32m"
|
||||||
|
#define YELLOW "\33[0;33m"
|
||||||
|
#define BLUE "\33[0;34m"
|
||||||
|
#define MAGENTA "\33[0;35m"
|
||||||
|
#define CYAN "\33[0;36m"
|
||||||
|
#define WHITE "\33[0;37m"
|
||||||
|
#define LIGHT_GRAY "\33[0;37m"
|
||||||
|
#define DARK_GRAY "\33[1;30m"
|
||||||
|
|
||||||
|
//Regular bold text
|
||||||
|
#define BOLD_BLACK "\33[1;30m"
|
||||||
|
#define BOLD_RED "\33[1;31m"
|
||||||
|
#define BOLD_GREEN "\33[1;32m"
|
||||||
|
#define BOLD_YELLOW "\33[1;33m"
|
||||||
|
#define BOLD_BLUE "\33[1;34m"
|
||||||
|
#define BOLD_MAGENTA "\33[1;35m"
|
||||||
|
#define BOLD_CYAN "\33[1;36m"
|
||||||
|
#define BOLD_WHITE "\33[1;37m"
|
||||||
|
|
||||||
|
//Reset
|
||||||
|
#define RESET "\33[0m"
|
||||||
|
|
||||||
|
// note(jax): Platform-independent way to perform an assertion.
|
||||||
|
// Flat out writes to zero memory to crash the program.
|
||||||
|
// todo(jax): Create some sort of assert function that creates a message box
|
||||||
|
// like in previous engines I've worked on!
|
||||||
|
#if ENGINE_SLOW
|
||||||
|
#define Assert(Expression) if (!(Expression)) { *(int*)0=0; }
|
||||||
|
#else
|
||||||
|
#define Assert(Expression)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// A structure that encapsulates a non-terminated buffer
|
||||||
|
struct string {
|
||||||
|
u8* Data;
|
||||||
|
umm Count;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
//#define printf ae_printf
|
||||||
|
//#define sprintf ae_sprintf
|
||||||
|
|
||||||
|
inline u32 SafeTruncateU32(u64 Value) {
|
||||||
|
// todo(jax): Defines for min/max values
|
||||||
|
Assert(Value <= 0xFFFFFFFF);
|
||||||
|
u32 Result = (u32)Value;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u16 SafeTruncateU16(u32 Value) {
|
||||||
|
// todo(jax): Defines for min/max values
|
||||||
|
Assert(Value <= 0xFFFF);
|
||||||
|
u16 Result = (u16)Value;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u8 SafeTruncateU8(u64 Value) {
|
||||||
|
Assert(Value <= 0xFF);
|
||||||
|
u8 Result = (u8)Value;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s32 SafeTruncateS32(s64 Value) {
|
||||||
|
if (Value >> 63) {
|
||||||
|
b32 IsSafeOperation = !(!(Value >> 32) && 0xffffffff);
|
||||||
|
if (!IsSafeOperation) {
|
||||||
|
printf("SafeTruncateS32: Performing unsafe truncation on '%lld'\n", Value);
|
||||||
|
}
|
||||||
|
return (s32)Value;
|
||||||
|
} else {
|
||||||
|
b32 IsSafeOperation = !((Value >> 32) && 0xffffffff);
|
||||||
|
if (!IsSafeOperation) {
|
||||||
|
printf("SafeTruncateS32: Performing unsafe truncation on '%lld'\n", Value);
|
||||||
|
}
|
||||||
|
return (s32)Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s16 SafeTruncateS16(s32 Value) {
|
||||||
|
if (Value >> 31) {
|
||||||
|
b32 IsSafeOperation = !(!(Value >> 16) && 0xffff);
|
||||||
|
if (!IsSafeOperation) {
|
||||||
|
printf("SafeTruncateS16: Performing unsafe truncation on '%d'\n", Value);
|
||||||
|
}
|
||||||
|
return (s16)Value;
|
||||||
|
} else {
|
||||||
|
b32 IsSafeOperation = !((Value >> 16) && 0xffff);
|
||||||
|
if (!IsSafeOperation) {
|
||||||
|
printf("SafeTruncateS16: Performing unsafe truncation on '%d'\n", Value);
|
||||||
|
}
|
||||||
|
return (s16)Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s8 SafeTruncateS8(s16 Value) {
|
||||||
|
if (Value >> 15) {
|
||||||
|
b32 IsSafeOperation = !(!(Value >> 8) && 0xff);
|
||||||
|
if (!IsSafeOperation) {
|
||||||
|
printf("SafeTruncateS8: Performing unsafe truncation on '%d'\n", Value);
|
||||||
|
}
|
||||||
|
return (s8)Value;
|
||||||
|
} else {
|
||||||
|
b32 IsSafeOperation = !((Value >> 8) && 0xff);
|
||||||
|
if (!IsSafeOperation) {
|
||||||
|
printf("SafeTruncateS8: Performing unsafe truncation on '%d'\n", Value);
|
||||||
|
}
|
||||||
|
return (s8)Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// note: Scalar operations
|
||||||
|
//
|
||||||
|
|
||||||
|
// todo(jax): These will eventually go into mathlib
|
||||||
|
|
||||||
|
inline real32 Square(real32 A) {
|
||||||
|
real32 Result = A*A;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline real32 Lerp(real32 A, real32 t, real32 B){
|
||||||
|
real32 Result = (1.0f - t)*A + t*B;
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Binary file not shown.
@ -0,0 +1,136 @@
|
|||||||
|
#ifdef TEST_PASS
|
||||||
|
test "string_test" {
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// note: Add a .test file that can be optionally included in the directory which allows a shell command to be executed prior to the test?
|
||||||
|
// todo: Finalization pass over tokenizer
|
||||||
|
// Tokenizer will go into a parse layer which swaps test "foo" { } to an actual function call
|
||||||
|
// int test_foo(test_ctx* Ctx) {}
|
||||||
|
// these function calls are put into <orig_name>_generated.cpp
|
||||||
|
// after tests are compiled and executed the generated files are deleted
|
||||||
|
// maybe have the shell command stuff inside of ctx?
|
||||||
|
// todo: Write and research testing framework!
|
||||||
|
|
||||||
|
#include <direct.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <shared.h>
|
||||||
|
#include <tokenizer.h>
|
||||||
|
|
||||||
|
static string msg_prefix = make_string("[Test Suite] ");
|
||||||
|
|
||||||
|
string ReadEntireFileIntoMemory(char* FileName) {
|
||||||
|
string Result = { };
|
||||||
|
|
||||||
|
FILE* File = fopen(FileName, "r");
|
||||||
|
if (File) {
|
||||||
|
fseek(File, 0, SEEK_END);
|
||||||
|
Result.Count = ftell(File);
|
||||||
|
fseek(File, 0, SEEK_SET);
|
||||||
|
|
||||||
|
Result.Data = (u8*)malloc(Result.Count);
|
||||||
|
fread(Result.Data, Result.Count, 1, File);
|
||||||
|
|
||||||
|
fclose(File);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <minwindows.h>
|
||||||
|
|
||||||
|
struct lexer_state {
|
||||||
|
char** FileNames;
|
||||||
|
u32 FileNameCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
static lexer_state State;
|
||||||
|
|
||||||
|
void ListContents(const char* Cwd) {
|
||||||
|
char Path[MAX_PATH];
|
||||||
|
|
||||||
|
_WIN32_FIND_DATAA FindData;
|
||||||
|
HANDLE FindHandle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
//Specify a file mask. *.* = We want everything!
|
||||||
|
sprintf(Path, "%s\\*.*", Cwd);
|
||||||
|
FindHandle = FindFirstFileA(Path, &FindData);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (strcmp(FindData.cFileName, ".") != 0 && strcmp(FindData.cFileName, "..") != 0) {
|
||||||
|
sprintf(Path, "%s\\%s", Cwd, FindData.cFileName);
|
||||||
|
|
||||||
|
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
|
ListContents(Path);
|
||||||
|
}
|
||||||
|
else if (Substring(Path, "src") != NULL) {
|
||||||
|
State.FileNames[State.FileNameCount] = (char*)malloc(sizeof(char) * MAX_PATH);
|
||||||
|
strcpy(State.FileNames[State.FileNameCount], Path);
|
||||||
|
++State.FileNameCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (FindNextFileA(FindHandle, &FindData));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(char** Args, int ArgCount) {
|
||||||
|
TCHAR** lppPart = {NULL}; // For GetFullPath :/
|
||||||
|
|
||||||
|
char* cwd;
|
||||||
|
cwd = _getcwd(NULL, 256);
|
||||||
|
|
||||||
|
printf("%sTest Suite v0.1\n", msg_prefix.Data);
|
||||||
|
printf("%sOperating in directory: %s\n\n", msg_prefix.Data, cwd);
|
||||||
|
|
||||||
|
// Get the names of the files we will operate on
|
||||||
|
State.FileNames = (char**)malloc(2048 * sizeof(char*));
|
||||||
|
if (Substring(cwd, "build")) {
|
||||||
|
ListContents("..\\tests");
|
||||||
|
} else {
|
||||||
|
ListContents("tests");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 FileIndex = 0; FileIndex < State.FileNameCount; ++FileIndex) {
|
||||||
|
char* Filename = State.FileNames[FileIndex];
|
||||||
|
char* FullFilename = (char*)malloc(MAX_PATH * sizeof(char));
|
||||||
|
GetFullPathNameA(Filename, MAX_PATH, FullFilename, lppPart);
|
||||||
|
printf("%s: \n", FullFilename);
|
||||||
|
|
||||||
|
string Contents = ReadEntireFileIntoMemory(Filename);
|
||||||
|
tokenizer Tokenizer = Tokenize(Contents, Filename);
|
||||||
|
|
||||||
|
b32 Parsing = true;
|
||||||
|
while (Parsing) {
|
||||||
|
token Token = GetToken(&Tokenizer);
|
||||||
|
switch (Token.Type) {
|
||||||
|
case Token_EndOfStream: {
|
||||||
|
Parsing = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Token_Identifier: {
|
||||||
|
if (StringsMatch(Token.String, "test")) {
|
||||||
|
GetToken(&Tokenizer);
|
||||||
|
token Next = GetToken(&Tokenizer);
|
||||||
|
|
||||||
|
char* TestName = Next.String;
|
||||||
|
printf(" test '%s'\n", TestName);
|
||||||
|
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Token_Unknown:
|
||||||
|
default: {
|
||||||
|
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,553 @@
|
|||||||
|
/* Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Copyright (c) 2020 by Asteria Development
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ===================================================================
|
||||||
|
|
||||||
|
$
|
||||||
|
|
||||||
|
aetime works under the same premise as Casey Muratori's ctime under
|
||||||
|
the public domain. It's a small utility that allows you to time how
|
||||||
|
long your machine spends building your project. It works in the same
|
||||||
|
manner as a begin/end block in your typical profiler.
|
||||||
|
|
||||||
|
$ WARNING
|
||||||
|
---------
|
||||||
|
|
||||||
|
This software is provided UNDER AN "AS IS" BASIS. The author makes NO
|
||||||
|
WARRENTY to the RELIABILITY of this software. Take this message as your
|
||||||
|
only warning, USE AT YOUR OWN RISK. This shit could even format your
|
||||||
|
entire disk! Not my fault though.
|
||||||
|
|
||||||
|
INSTRUCTIONS
|
||||||
|
------------
|
||||||
|
|
||||||
|
On the first line of your build script, write
|
||||||
|
aetime --begin <project-name>.aet
|
||||||
|
then on the last line, write
|
||||||
|
aetime --end <project-name>.aet
|
||||||
|
and the program will output how many seconds it took to build your project!
|
||||||
|
|
||||||
|
Also if you must debug the project, you can append a '-v' flag to the end
|
||||||
|
of the argument list for additional debug output into the console.
|
||||||
|
|
||||||
|
======================================================================== */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define global static
|
||||||
|
#define u8 uint8_t
|
||||||
|
#define u32 uint32_t
|
||||||
|
#define f32 float
|
||||||
|
#define uint u32
|
||||||
|
|
||||||
|
#define GenerateMagic(a, b, c, d) (((u32)(a) << 0) | ((u32)(b) << 8) | ((u32)(c) << 16) | ((u32)(d) << 24))
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#define AET_MAGIC_VALUE GenerateMagic('a', 'e', 't', 'c')
|
||||||
|
typedef struct timer_file_header {
|
||||||
|
u32 Magic;
|
||||||
|
} timer_file_header;
|
||||||
|
|
||||||
|
typedef struct timer_file_entry {
|
||||||
|
f32 Elapsed;
|
||||||
|
} timer_file_entry;
|
||||||
|
|
||||||
|
typedef struct timer_entry_array {
|
||||||
|
u32 EntryCount;
|
||||||
|
timer_file_entry* Entries;
|
||||||
|
} timer_entry_array;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
int StringLength(char* String) {
|
||||||
|
int Count = 0;
|
||||||
|
while (*String++) {
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringsMatch(char* A, char* B) {
|
||||||
|
if (!A || !B) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*A && *B) {
|
||||||
|
if (*A != *B){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
++A;
|
||||||
|
++B;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*A != *B){
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global f32 GlobalFrequency;
|
||||||
|
|
||||||
|
#define COUNTERTOMS 1.f / (GlobalFrequency / 1000.f)
|
||||||
|
#define COUNTERTOUS COUNTERTOMS * 1000.f
|
||||||
|
#define COUNTERTONS COUNTERTOUS * 1000.f
|
||||||
|
#define COUNTERTOS COUNTERTOMS / 1000.f
|
||||||
|
|
||||||
|
//
|
||||||
|
// PLATFORM SPECIFIC CODE
|
||||||
|
//
|
||||||
|
|
||||||
|
// note(jax): Eventually support Mac...
|
||||||
|
#ifdef BUILD_LINUX
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
global void Usage(char** Args) {
|
||||||
|
fprintf(stdout, "Usage: %s --begin <file>.aet [-v|--v|--verbose|-verbose]\n", Args[0]);
|
||||||
|
fprintf(stdout, " %s --end <file>.aet [-v|--v|--verbose|-verbose]\n", Args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function assumes FileName is a full path with an extension
|
||||||
|
char* GetBaseName(char* FileName) {
|
||||||
|
int BaseNameSize = 0;
|
||||||
|
char* BaseName = (char*)malloc(sizeof(char)*PATH_MAX);
|
||||||
|
char* BaseNameBegin = FileName;
|
||||||
|
char* BaseNameEnd = FileName + StringLength(FileName);
|
||||||
|
bool RightOfPeriod = false;
|
||||||
|
for (char* Scan = BaseNameBegin; *Scan; ++Scan) {
|
||||||
|
if ((Scan[0] == '\\') || (Scan[0] == '/')) {
|
||||||
|
BaseNameBegin = Scan + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Scan[0] == '.') {
|
||||||
|
BaseNameEnd = Scan;
|
||||||
|
RightOfPeriod = true;
|
||||||
|
}
|
||||||
|
else if (!RightOfPeriod) {
|
||||||
|
++BaseNameSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(BaseName, BaseNameBegin, BaseNameSize);
|
||||||
|
BaseName[BaseNameSize] = 0;
|
||||||
|
|
||||||
|
return BaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t rdtsc(){
|
||||||
|
unsigned int lo,hi;
|
||||||
|
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||||
|
return ((uint64_t)hi << 32) | lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ArgCount, char** Args) {
|
||||||
|
bool IsVerbose = false;
|
||||||
|
if (StringsMatch(Args[3], "--verbose") ||
|
||||||
|
StringsMatch(Args[3], "--v") ||
|
||||||
|
StringsMatch(Args[3], "-verbose") ||
|
||||||
|
StringsMatch(Args[3], "-v")) {
|
||||||
|
IsVerbose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char Path[PATH_MAX];
|
||||||
|
sprintf(Path, "/tmp/");
|
||||||
|
|
||||||
|
GlobalFrequency = 1000000;
|
||||||
|
|
||||||
|
if (ArgCount >= 3) {
|
||||||
|
if (StringsMatch(Args[1], "--begin")) {
|
||||||
|
char* FileName = Args[2];
|
||||||
|
sprintf(Path + strlen(Path), "%s", FileName);
|
||||||
|
|
||||||
|
FILE* Dest = fopen(Path, "wb");
|
||||||
|
if (Dest) {
|
||||||
|
if (IsVerbose) {
|
||||||
|
printf("Writing to '%s'\n", Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_file_header Header = {0};
|
||||||
|
Header.Magic = AET_MAGIC_VALUE;
|
||||||
|
fwrite(&Header, sizeof(Header), 1, Dest);
|
||||||
|
|
||||||
|
timer_file_entry Entry = {0};
|
||||||
|
struct timespec Timer;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &Timer);
|
||||||
|
Entry.Elapsed = (Timer.tv_nsec) + (Timer.tv_sec) * 1E9;
|
||||||
|
|
||||||
|
printf("Compilation started for %s\n", GetBaseName(FileName));
|
||||||
|
if (fwrite(&Entry, sizeof(Entry), 1, Dest) != 1) {
|
||||||
|
fprintf(stdout, "ERROR: Failed to append new start entry to file '%s'.\n", FileName);
|
||||||
|
} else {
|
||||||
|
fclose(Dest);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, "ERROR: Failed to open file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
} else if (StringsMatch(Args[1], "--end")) {
|
||||||
|
char* FileName = Args[2];
|
||||||
|
sprintf(Path + strlen(Path), "%s", FileName);
|
||||||
|
|
||||||
|
FILE* Dest = fopen(Path, "rb");
|
||||||
|
if (Dest) {
|
||||||
|
if (IsVerbose) {
|
||||||
|
printf("Reading from '%s'\n", Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_file_header Header = {0};
|
||||||
|
fread(&Header, sizeof(Header), 1, Dest);
|
||||||
|
if (IsVerbose) {
|
||||||
|
printf("struct timer_file_header {\n Magic: %u\n};\n", Header.Magic);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_file_entry Entry = {0};
|
||||||
|
if(fread(&Entry, sizeof(Entry), 1, Dest) == 1) {
|
||||||
|
struct timespec Timer;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_RAW, &Timer);
|
||||||
|
|
||||||
|
f32 Elapsed = ((Timer.tv_nsec) + (Timer.tv_sec) * 1E9) - Entry.Elapsed;
|
||||||
|
f32 Milliseconds = Elapsed / 1000.f / 1000.f;
|
||||||
|
f32 Seconds = Milliseconds / 1000.f;
|
||||||
|
printf("Compilation ended: %f seconds\n", Seconds);
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, "ERROR: Failed to read start entry from file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(Dest);
|
||||||
|
|
||||||
|
if (remove(Path) != 0) {
|
||||||
|
fprintf(stdout, "ERROR: Failed to remove file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, "ERROR: Failed to open file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Usage(Args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Usage(Args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif BUILD_WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
global void Usage(char** Args) {
|
||||||
|
fprintf(stderr, "Usage: %s --begin <file>.aet [-v|--v|--verbose|-verbose]\n", Args[0]);
|
||||||
|
fprintf(stderr, " %s --end <file>.aet [-v|--v|--verbose|-verbose]\n", Args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function assumes FileName is a full path with an extension
|
||||||
|
char* GetBaseName(char* FileName) {
|
||||||
|
int BaseNameSize = 0;
|
||||||
|
char* BaseName = malloc(sizeof(char)*MAX_PATH);
|
||||||
|
char* BaseNameBegin = FileName;
|
||||||
|
char* BaseNameEnd = FileName + StringLength(FileName);
|
||||||
|
bool RightOfPeriod = false;
|
||||||
|
for (char* Scan = BaseNameBegin; *Scan; ++Scan) {
|
||||||
|
if ((Scan[0] == '\\') || (Scan[0] == '/')) {
|
||||||
|
BaseNameBegin = Scan + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Scan[0] == '.') {
|
||||||
|
BaseNameEnd = Scan;
|
||||||
|
RightOfPeriod = true;
|
||||||
|
}
|
||||||
|
else if (!RightOfPeriod) {
|
||||||
|
++BaseNameSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(BaseName, BaseNameBegin, BaseNameSize);
|
||||||
|
BaseName[BaseNameSize] = 0;
|
||||||
|
|
||||||
|
return BaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ArgCount, char** Args) {
|
||||||
|
bool IsVerbose = false;
|
||||||
|
if (StringsMatch(Args[3], "--verbose") ||
|
||||||
|
StringsMatch(Args[3], "--v") ||
|
||||||
|
StringsMatch(Args[3], "-verbose") ||
|
||||||
|
StringsMatch(Args[3], "-v")) {
|
||||||
|
IsVerbose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LARGE_INTEGER _F;
|
||||||
|
QueryPerformanceFrequency(&_F);
|
||||||
|
GlobalFrequency = (f32)_F.QuadPart;
|
||||||
|
|
||||||
|
char Path[MAX_PATH];
|
||||||
|
GetTempPathA(MAX_PATH, Path);
|
||||||
|
|
||||||
|
if (ArgCount >= 3) {
|
||||||
|
if (StringsMatch(Args[1], "--begin")) {
|
||||||
|
char* FileName = Args[2];
|
||||||
|
sprintf(Path, "%s\\%s", Path, FileName);
|
||||||
|
FILE* Dest = fopen(Path, "wb");
|
||||||
|
if (Dest) {
|
||||||
|
if (IsVerbose) {
|
||||||
|
printf("Writing to '%s'\n", Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_file_header Header = {0};
|
||||||
|
Header.Magic = AET_MAGIC_VALUE;
|
||||||
|
fwrite(&Header, sizeof(Header), 1, Dest);
|
||||||
|
|
||||||
|
LARGE_INTEGER Start;
|
||||||
|
timer_file_entry Entry = {0};
|
||||||
|
QueryPerformanceCounter(&Start);
|
||||||
|
Entry.Elapsed = (f32)Start.QuadPart;
|
||||||
|
|
||||||
|
printf("Compilation started for %s\n", GetBaseName(FileName));
|
||||||
|
if (fwrite(&Entry, sizeof(Entry), 1, Dest) != 1) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to append new start entry to file '%s'.\n", FileName);
|
||||||
|
} else {
|
||||||
|
fclose(Dest);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
} else if (StringsMatch(Args[1], "--end")) {
|
||||||
|
char* FileName = Args[2];
|
||||||
|
sprintf(Path, "%s\\%s", Path, FileName);
|
||||||
|
|
||||||
|
FILE* Dest = fopen(Path, "rb");
|
||||||
|
if (Dest) {
|
||||||
|
if (IsVerbose) {
|
||||||
|
printf("Reading from '%s'\n", Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_file_header Header = {0};
|
||||||
|
fread(&Header, sizeof(Header), 1, Dest);
|
||||||
|
if (IsVerbose) {
|
||||||
|
printf("struct timer_file_header {\n Magic: %u\n};\n", Header.Magic);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_file_entry Entry = {0};
|
||||||
|
if(fread(&Entry, sizeof(Entry), 1, Dest) == 1) {
|
||||||
|
LARGE_INTEGER End;
|
||||||
|
QueryPerformanceCounter(&End);
|
||||||
|
|
||||||
|
f32 Elapsed = ((f32)End.QuadPart) - Entry.Elapsed;
|
||||||
|
f32 Seconds = Elapsed * COUNTERTOS;
|
||||||
|
f32 Milliseconds = Elapsed * COUNTERTOMS;
|
||||||
|
printf("Compilation ended: %f seconds\n", Seconds);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: Failed to read start entry from file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(Dest);
|
||||||
|
|
||||||
|
if (remove(Path) != 0) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to remove file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open file '%s'.\n", FileName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Usage(Args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Usage(Args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
REM -Zi for debugging
|
||||||
|
cl -nologo -DBUILD_WIN32=1 -FC -O2 -TC -EHsc btime.c /link
|
||||||
|
@if ERRORLEVEL 1 exit /B 1
|
||||||
|
robocopy . ../ btime.exe > nul
|
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
CXX=${CXX:-clang++}
|
||||||
|
|
||||||
|
${CXX} $* -Wwritable-strings -DBUILD_LINUX=1 -I. -O3 -o btime btime.c
|
||||||
|
cp btime ../btime
|
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
export PATH=$PWD/tools:$PATH
|
Loading…
Reference in New Issue