├── .gitignore ├── LICENSE ├── Makefile ├── Makefile.xmega ├── README.md ├── Windows ├── BASIC.sln ├── BASIC.vcxproj ├── BASIC.vcxproj.filters └── BASIC.vcxproj.user ├── arch ├── osx │ ├── arch.c │ ├── error.c │ ├── kbhit.c │ └── main.c ├── windows │ ├── arch.c │ ├── error.c │ ├── kbhit.c │ └── main.c └── xmega │ ├── arch.c │ ├── console.c │ ├── console.h │ ├── diskio.h │ ├── error.c │ ├── ext.c │ ├── ff.c │ ├── ff.h │ ├── ffconf.h │ ├── integer.h │ ├── joystick.c │ ├── joystick.h │ ├── kbhit.c │ ├── main.c │ ├── mmc.c │ ├── mmc.h │ ├── sound.c │ ├── sound.h │ ├── spi.c │ └── spi.h ├── basic.png ├── examples ├── FORY.bas ├── autolist ├── circle.bas ├── data.bas ├── data_array.bas ├── data_numeric.bas ├── data_test.bas ├── diamond.bas ├── dim.bas ├── expr.bas ├── for.bas ├── for_colon.bas ├── get.bas ├── gosub.bas ├── goto.bas ├── if.bas ├── if_and_or.bas ├── if_goto.bas ├── input.bas ├── left.bas ├── math.bas ├── mid.bas ├── nested_for.bas ├── on_goto.bas ├── right.bas ├── simple-basic │ ├── happy_birthday.bas │ └── input.bas ├── sine_wave.bas ├── sleep.bas ├── strings.bas ├── test_for.bas ├── the_first_basic_program.bas ├── toss_a_coin.bas └── var.bas ├── include ├── arch.h ├── array.h ├── callback.h ├── dictionary.h ├── error.h ├── hexdump.h ├── io.h ├── kbhit.h ├── lines.h ├── parser.h ├── tokenizer.h ├── usingwin.h └── variables.h ├── src ├── array.c ├── dictionary.c ├── hexdump.c ├── io.c ├── lines.c ├── parser.c ├── tokenizer.c └── variables.c ├── t ├── Makefile ├── main.c ├── test.h ├── test_dictionary.c └── test_lines.c └── test /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | profile 3 | build/* 4 | *.mode1 5 | *.mode1v3 6 | *.mode2v3 7 | *.perspective 8 | *.perspectivev3 9 | *.pbxuser 10 | *.xcworkspace 11 | xcuserdata 12 | .svn 13 | CVS 14 | *.swp 15 | *.o 16 | t/test 17 | TODO 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Johan Van den Brande 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = basic 2 | 3 | BUILD_FOLDER = build/basic 4 | 5 | SOURCE_FOLDERS += ./arch/osx ./src 6 | 7 | CC = gcc-10 8 | CFLAGS = -g -Wall -Werror -std=c99 -lreadline -lm -DARCH_OSX=1 -DARCH_XMEGA=2 -DARCH=1 9 | 10 | VPATH = $(SOURCE_FOLDERS) 11 | 12 | .PHONY: start end all clean run 13 | 14 | all: start $(BUILD_FOLDER) $(TARGET) end 15 | 16 | SOURCES = $(foreach folder,$(SOURCE_FOLDERS),$(wildcard $(folder)/*.c)) 17 | 18 | ifneq "$(strip $(SOURCES))" "" 19 | _OBJECTS = $(patsubst %.c,%.o,$(notdir $(SOURCES))) 20 | endif 21 | 22 | OBJECTS = $(patsubst %,$(BUILD_FOLDER)/%,$(_OBJECTS)) 23 | 24 | INCLUDE_FLAGS += \ 25 | $(addprefix -I,$(INCLUDE_FOLDERS)) $(addprefix -I,$(SOURCE_FOLDERS)) -Iinclude 26 | 27 | define run-cc 28 | @ echo "CC $<" 29 | @ $(CC) -c $(CFLAGS) $(INCLUDE_FLAGS) $< -o $(BUILD_FOLDER)/$% 30 | endef 31 | 32 | start: 33 | @ echo "-- Creating $(TARGET)..." 34 | 35 | end: 36 | @ echo "done" 37 | @ echo "" 38 | 39 | clean: 40 | @ echo $@ 41 | @ rm -rf $(BUILD_FOLDER) 42 | @ make -C ./t clean 43 | 44 | $(BUILD_FOLDER): 45 | @ mkdir -p $@ 46 | 47 | (%.o): %.c 48 | $(run-cc) 49 | 50 | $(TARGET): $(BUILD_FOLDER)/($(_OBJECTS)) 51 | @ echo "LD $@" 52 | @ $(CC) $(OBJECTS) $(CFLAGS) $(LDFLAGS) -L$(BUILD_FOLDER) -o $(BUILD_FOLDER)/$@ 53 | 54 | run: all 55 | @ echo "-- Running $(TARGET)" 56 | @ BASIC_PATH=./examples $(BUILD_FOLDER)/$(TARGET) 57 | 58 | test: all 59 | @ make -C ./t run 60 | 61 | testdebug: all 62 | @ make -C ./t debug 63 | 64 | debug: all 65 | @ echo "-- Debugging $(TARGET)" 66 | @ echo "run" | gdb $(BUILD_FOLDER)/$(TARGET) 67 | -------------------------------------------------------------------------------- /Makefile.xmega: -------------------------------------------------------------------------------- 1 | ARCH = XMEGA 2 | 3 | DEVICE = atxmega128a4u 4 | CLOCK = 32000000 5 | 6 | TARGET = basic 7 | 8 | BUILD_FOLDER = build/xmega 9 | 10 | SOURCE_FOLDERS += ./arch/xmega ./src 11 | 12 | CC = avr-gcc 13 | CFLAGS = -g -Wall -Werror -std=c99 -Os 14 | CFLAGS += -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -DARCH_OSX=1 -DARCH_XMEGA=2 -DARCH=2 15 | CFLAGS += -DBASIC_READLINE_ECHO 16 | CFLAGS += -Wl,-u,vfscanf -lscanf_flt -Wl,-u,vfprintf -lprintf_flt -lm 17 | 18 | VPATH = $(SOURCE_FOLDERS) 19 | 20 | .PHONY: start end all clean run 21 | 22 | all: start $(BUILD_FOLDER) $(TARGET) end 23 | 24 | SOURCES = $(foreach folder,$(SOURCE_FOLDERS),$(wildcard $(folder)/*.c)) 25 | 26 | ifneq "$(strip $(SOURCES))" "" 27 | _OBJECTS = $(patsubst %.c,%.o,$(notdir $(SOURCES))) 28 | endif 29 | 30 | OBJECTS = $(patsubst %,$(BUILD_FOLDER)/%,$(_OBJECTS)) 31 | 32 | INCLUDE_FLAGS += \ 33 | $(addprefix -I,$(INCLUDE_FOLDERS)) $(addprefix -I,$(SOURCE_FOLDERS)) -Iinclude 34 | 35 | define run-cc 36 | @ echo "CC $<" 37 | @ $(CC) -c $(CFLAGS) $(INCLUDE_FLAGS) $< -o $(BUILD_FOLDER)/$% 38 | endef 39 | 40 | start: 41 | @ echo "-- Creating $(TARGET)..." 42 | 43 | end: 44 | @ echo "done" 45 | @ echo "" 46 | 47 | clean: 48 | @ echo $@ 49 | @ rm -rf $(BUILD_FOLDER) 50 | @ make -C ./t clean 51 | 52 | $(BUILD_FOLDER): 53 | @ mkdir -p $@ 54 | 55 | (%.o): %.c 56 | $(run-cc) 57 | 58 | $(TARGET): $(BUILD_FOLDER)/($(_OBJECTS)) 59 | @ echo "LD $@" 60 | @ $(CC) $(OBJECTS) $(CFLAGS) $(LDFLAGS) -L$(BUILD_FOLDER) -o $(BUILD_FOLDER)/$@ 61 | @ avr-objcopy -j .text -j .data -O ihex $(BUILD_FOLDER)/$@ $(BUILD_FOLDER)/$(TARGET).hex 62 | @ avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex $(BUILD_FOLDER)/$@ $(BUILD_FOLDER)/$(TARGET)_eeprom.hex 63 | 64 | flash: all 65 | @ dfu-programmer $(DEVICE) erase 66 | @ dfu-programmer $(DEVICE) flash $(BUILD_FOLDER)/$(TARGET).hex 67 | @ dfu-programmer $(DEVICE) launch 68 | 69 | launch: 70 | @ dfu-programmer $(DEVICE) launch 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![BASIC](./basic.png) 2 | 3 | A from-scratch BASIC interpreter with a focus on being easy to extend and port. 4 | 5 | [![asciicast](https://asciinema.org/a/37018.png)](https://asciinema.org/a/37018) 6 | 7 | # Introduction 8 | 9 | This is a BASIC interpreter written from scratch in C. For the moment two architectures are supported, POSIX and AVR XMega via the avr-gcc toolchain. 10 | 11 | Most of the common BASIC keywords are supported: 12 | 13 | * PRINT expression-list [ ; ] 14 | * IF relation-expression THEN statement 15 | * GOTO expression 16 | * INPUT variable-list 17 | * LET variable = expression 18 | * GOSUB expression 19 | * RETURN 20 | * FOR numeric\_variable '=' numeric\_expression TO numeric_expression [ STEP number ] 21 | * CLEAR, NEW 22 | * LIST 23 | * RUN 24 | * END 25 | * DIM variable "(" expression ")" 26 | * ABS, AND, ATN, COS, EXP, INT, LOG, NOT, OR, RND, SGN, SIN, SQR, TAN 27 | * LEN, CHR$, MID$, LEFT$, RIGHT$, ASC 28 | 29 | # Extend 30 | 31 | It should be easy to register a new BASIC function, as shown here with a `sleep` function for the XMEGA. 32 | 33 | ```C 34 | register_function_1(basic_function_type_keyword, "SLEEP", do_sleep, kind_numeric); 35 | ... 36 | int do_sleep(basic_type* delay, basic_type* rv) 37 | { 38 | delay_ms(delay->value.number); 39 | 40 | rv->kind = kind_numeric; 41 | rv->value.number = 0; 42 | 43 | return 0; 44 | } 45 | ``` 46 | 47 | Let's use that new keyword. 48 | 49 | ```REALbasic 50 | 10 INPUT "YOUR NAME?", NAME$ 51 | 20 CLS 52 | 30 FOR I=1 TO LEN(NAME$) 53 | 40 PRINT MID$(NAME$,I,1); 54 | 50 SLEEP(500) 55 | 60 NEXT 56 | 70 PRINT 57 | ``` 58 | 59 | # Port 60 | 61 | It should be easy to port the interpreter to other architectures. As an example there is a port to an XMega 128A4U included using the [Batsocks breadmate board](http://www.batsocks.co.uk/products/BreadMate/XMega%20PDI%20AV.htm). 62 | 63 | # Use 64 | 65 | There is a simple REPL for the BASIC interpreter. You can use it in an interactive way, just as you would do on a 80's era computer. 66 | 67 | ``` 68 | _ _ 69 | | |__ __ _ ___(_) ___ 70 | | '_ \ / _` / __| |/ __| 71 | | |_) | (_| \__ \ | (__ 72 | |_.__/ \__,_|___/_|\___| 73 | (c) 2015-2016 Johan Van den Brande 74 | 10 PRINT "HELLO" 75 | 20 GOTO 10 76 | ``` 77 | 78 | You can give it a BASIC file on the command line. 79 | 80 | ``` 81 | $> basic examples/diamond.bas 82 | * 83 | *** 84 | ***** 85 | ******* 86 | ********* 87 | *********** 88 | ************* 89 | *************** 90 | ***************** 91 | *************** 92 | ************* 93 | *********** 94 | ********* 95 | ******* 96 | ***** 97 | *** 98 | * 99 | ``` 100 | 101 | You can also use the shebang operator to make standalone BASIC scripts 102 | 103 | ``` 104 | #!/usr/bin/env basic 105 | 106 | 10 RADIUS=10 107 | 20 FOR I=1 TO RADIUS-1 108 | 30 W=INT(RADIUS*SIN(180/RADIUS*I*3.1415/180)) 109 | 40 PRINT SPC(RADIUS-W);:FOR J=1 TO 2*W:PRINT "*";:NEXT J:PRINT 110 | 50 NEXT I 111 | ``` 112 | 113 | ``` 114 | $> ./examples/circle.bas 115 | ****** 116 | ********** 117 | **************** 118 | ****************** 119 | ******************** 120 | ****************** 121 | **************** 122 | ********** 123 | ****** 124 | ``` 125 | 126 | It is easy to embed the interpreter into your own application. 127 | 128 | ```C 129 | basic_init(2048, 512); // memory size, stack size 130 | basic_register_io(putchar, getchar); 131 | basic_eval("10 PRINT \"HELLO\""); 132 | basic_eval("RUN"); 133 | basic_destroy(); 134 | ``` 135 | 136 | On OSX/POSIX you can use the 'BASIC\_PATH' environment variable to set the folder used for loading and saving BASIC programs. The 'BASIC\_PATH' defaults to '.'. 137 | BASIC programs are expected to end with '.bas'. You can use LOAD, SAVE, DELETE and DIR. 138 | 139 | # Copyright 140 | 141 | (c) 2015 - 2016 Johan Van den Brande 142 | -------------------------------------------------------------------------------- /Windows/BASIC.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30611.23 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BASIC", "BASIC.vcxproj", "{EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x64.ActiveCfg = Debug|x64 17 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x64.Build.0 = Debug|x64 18 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x86.ActiveCfg = Debug|Win32 19 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x86.Build.0 = Debug|Win32 20 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x64.ActiveCfg = Release|x64 21 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x64.Build.0 = Release|x64 22 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x86.ActiveCfg = Release|Win32 23 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {6C82D241-BA84-4707-A390-675647BE8056} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Windows/BASIC.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {ebbf5532-8da0-4b71-9ef7-89c7824f88d8} 25 | BASIC 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 90 | true 91 | ../include 92 | CompileAsC 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | true 103 | true 104 | true 105 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 106 | true 107 | ../include 108 | 109 | 110 | Console 111 | true 112 | true 113 | true 114 | 115 | 116 | 117 | 118 | Level3 119 | true 120 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 121 | true 122 | ../include 123 | 124 | 125 | Console 126 | true 127 | 128 | 129 | 130 | 131 | Level3 132 | true 133 | true 134 | true 135 | NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 136 | true 137 | ../include 138 | 139 | 140 | Console 141 | true 142 | true 143 | true 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /Windows/BASIC.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | -------------------------------------------------------------------------------- /Windows/BASIC.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /arch/osx/arch.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "arch.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int 10 | arch_init(void) 11 | { 12 | // stub 13 | return 0; 14 | } 15 | 16 | static char* 17 | _get_path(void) 18 | { 19 | static char* _path = NULL; 20 | _path = getenv("BASIC_PATH"); 21 | if (_path == NULL) { 22 | _path = "."; 23 | } 24 | if(_path[strlen(_path)-1] == '/'){ 25 | _path[strlen(_path)-1] = '\0'; 26 | } 27 | return _path; 28 | } 29 | 30 | int 31 | arch_load(char* name, arch_load_out_cb cb, void* context) 32 | { 33 | char* filename; 34 | asprintf(&filename, "%s/%s.bas", _get_path(), name); 35 | FILE* fp = fopen(filename, "r"); 36 | if(!fp){ 37 | return 1; 38 | } 39 | char line[256]; 40 | while(fgets(line, 256, fp) != NULL) { 41 | cb(line, context); 42 | } 43 | fclose(fp); 44 | free(filename); 45 | return 0; 46 | } 47 | 48 | int 49 | arch_save(char* name, arch_save_cb cb, void* context) 50 | { 51 | char* line; 52 | char* filename; 53 | asprintf(&filename, "%s/%s.bas", _get_path(), name); 54 | 55 | FILE* fp = fopen(filename, "w"); 56 | if(!fp){ 57 | return 1; 58 | } 59 | for(;;){ 60 | uint16_t number = cb(&line, context); 61 | if (line == NULL){ 62 | break; 63 | } 64 | fprintf(fp, "%d %s\n",number, line); 65 | } 66 | fclose(fp); 67 | 68 | free(filename); 69 | 70 | return 0; 71 | } 72 | 73 | int 74 | arch_dir(arch_dir_out_cb cb, void* context) 75 | { 76 | char out[256]; 77 | snprintf(out, sizeof(out), "dir: %s", _get_path()); 78 | cb(out, 0, true, context); 79 | 80 | struct stat stats; 81 | struct dirent *ent; 82 | DIR *dir; 83 | dir = opendir(_get_path()); 84 | while ((ent = readdir(dir)) != NULL) { 85 | char* name = ent->d_name; 86 | if (strlen(name)>4){ 87 | char *ext = name + strlen(name) - 4; 88 | if (strncmp(ext, ".bas", 4)==0){ 89 | snprintf(out,sizeof(out),"%s/%s", _get_path(), name); 90 | stat(out, &stats); 91 | name[strlen(name)-4] = '\0'; 92 | cb(name, stats.st_size, false, context); 93 | } 94 | } 95 | } 96 | closedir(dir); 97 | 98 | return 0; 99 | } 100 | 101 | int 102 | arch_delete(char* name){ 103 | char* filename; 104 | asprintf(&filename, "%s/%s.bas", _get_path(), name); 105 | remove(filename); 106 | free(filename); 107 | return 0; 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /arch/osx/error.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | // or inttypes.h 6 | 7 | extern uint16_t __line; 8 | 9 | const char *last_error = NULL; 10 | 11 | void 12 | error(const char *error_msg) 13 | { 14 | void *array[10]; 15 | size_t size; 16 | char **strings; 17 | size_t i; 18 | 19 | last_error = error_msg; 20 | 21 | printf("--- ERROR: %d %s\n", __line, error_msg); 22 | 23 | size = backtrace (array, 10); 24 | strings = backtrace_symbols (array, size); 25 | 26 | printf ("SHOW %zd STACK FRAMES:\n", size); 27 | 28 | for (i = 0; i < size; i++) 29 | { 30 | printf (" %s\n", strings[i]); 31 | } 32 | 33 | free (strings); 34 | } 35 | -------------------------------------------------------------------------------- /arch/osx/kbhit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int kbhit(void) { 8 | static const int STDIN = 0; 9 | static bool initialized = false; 10 | 11 | if (! initialized) { 12 | // Use termios to turn off line buffering 13 | struct termios term; 14 | tcgetattr(STDIN, &term); 15 | term.c_lflag &= ~ICANON; 16 | tcsetattr(STDIN, TCSANOW, &term); 17 | setbuf(stdin, NULL); 18 | initialized = true; 19 | } 20 | 21 | int bytesWaiting; 22 | ioctl(STDIN, FIONREAD, &bytesWaiting); 23 | return bytesWaiting; 24 | } 25 | -------------------------------------------------------------------------------- /arch/osx/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "parser.h" 10 | 11 | extern bool __RUNNING; 12 | extern bool __STOPPED; 13 | 14 | static void 15 | sigint_handler(int signum) 16 | { 17 | signal(SIGINT, sigint_handler); 18 | if(__RUNNING){ 19 | __RUNNING = false; 20 | __STOPPED = true; 21 | printf("STOP\n"); 22 | fflush(stdout); 23 | } 24 | } 25 | 26 | static char * 27 | readline_gets () 28 | { 29 | char * line_read = readline (""); 30 | 31 | if (line_read && *line_read) { 32 | add_history (line_read); 33 | } 34 | 35 | return line_read; 36 | } 37 | 38 | int out(int ch) 39 | { 40 | putchar(ch); 41 | return 1; 42 | } 43 | 44 | int in(void) 45 | { 46 | return getchar(); 47 | } 48 | 49 | void repl(void) 50 | { 51 | puts(" _ _ "); 52 | puts("| |__ __ _ ___(_) ___ "); 53 | puts("| '_ \\ / _` / __| |/ __|"); 54 | puts("| |_) | (_| \\__ \\ | (__ "); 55 | puts("|_.__/ \\__,_|___/_|\\___|"); 56 | puts("(c) 2015-2016 Johan Van den Brande"); 57 | 58 | using_history(); 59 | 60 | char *input; 61 | while ((input = readline_gets()) != NULL ) 62 | { 63 | if (strcmp(input, "QUIT") == 0) { 64 | free(input); 65 | break; 66 | } 67 | 68 | basic_eval(input); 69 | 70 | if (evaluate_last_error()) { 71 | printf("ERROR: %s\n", evaluate_last_error()); 72 | clear_last_error(); 73 | } 74 | 75 | free(input); 76 | } 77 | 78 | clear_history(); 79 | } 80 | 81 | void run(char *file_name){ 82 | FILE* file = fopen(file_name, "r"); 83 | 84 | if (file == NULL) { 85 | fprintf(stderr, "Can't open %s\n", file_name); 86 | return; 87 | } 88 | 89 | char line[tokenizer_string_length]; 90 | while (fgets(line, sizeof(line), file)) { 91 | if(line[strlen(line)-1]!='\n') 92 | { 93 | printf("ERROR: NO EOL\n"); 94 | exit(1); 95 | } 96 | basic_eval(line); 97 | } 98 | fclose(file); 99 | 100 | basic_run(); 101 | } 102 | 103 | int main(int argc, char *argv[]) 104 | { 105 | signal(SIGINT, sigint_handler); 106 | 107 | basic_init(1024*8, 2048); 108 | basic_register_io(out, in); 109 | 110 | if (argc > 1){ 111 | run(argv[1]); 112 | } else { 113 | repl(); 114 | } 115 | 116 | basic_destroy(); 117 | 118 | return EXIT_SUCCESS; 119 | } 120 | -------------------------------------------------------------------------------- /arch/windows/arch.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "arch.h" 3 | #include 4 | #include 5 | #include 6 | //#include 7 | #include 8 | 9 | int 10 | arch_init(void) 11 | { 12 | // stub 13 | return 0; 14 | } 15 | 16 | static char* 17 | _get_path(void) 18 | { 19 | static char* _path = NULL; 20 | _path = getenv("BASIC_PATH"); 21 | if (_path == NULL) { 22 | _path = "."; 23 | } 24 | if(_path[strlen(_path)-1] == '/'){ 25 | _path[strlen(_path)-1] = '\0'; 26 | } 27 | return _path; 28 | } 29 | 30 | int 31 | arch_load(char* name, arch_load_out_cb cb, void* context) 32 | { 33 | char* filename = malloc(256); 34 | sprintf(&filename, "%s/%s.bas", _get_path(), name); 35 | FILE* fp = fopen(filename, "r"); 36 | if(!fp){ 37 | return 1; 38 | } 39 | char line[256]; 40 | while(fgets(line, 256, fp) != NULL) { 41 | cb(line, context); 42 | } 43 | fclose(fp); 44 | free(filename); 45 | return 0; 46 | } 47 | 48 | int 49 | arch_save(char* name, arch_save_cb cb, void* context) 50 | { 51 | char* line; 52 | char* filename = malloc(256); 53 | sprintf(&filename, "%s/%s.bas", _get_path(), name); 54 | 55 | FILE* fp = fopen(filename, "w"); 56 | if(!fp){ 57 | return 1; 58 | } 59 | for(;;){ 60 | uint16_t number = cb(&line, context); 61 | if (line == NULL){ 62 | break; 63 | } 64 | fprintf(fp, "%d %s\n",number, line); 65 | } 66 | fclose(fp); 67 | 68 | free(filename); 69 | 70 | return 0; 71 | } 72 | 73 | int 74 | arch_dir(arch_dir_out_cb cb, void* context) 75 | { 76 | //char out[256]; 77 | //snprintf(out, sizeof(out), "dir: %s", _get_path()); 78 | //cb(out, 0, true, context); 79 | 80 | //struct stat stats; 81 | //struct dirent *ent; 82 | //DIR *dir; 83 | //dir = opendir(_get_path()); 84 | //while ((ent = readdir(dir)) != NULL) { 85 | // char* name = ent->d_name; 86 | // if (strlen(name)>4){ 87 | // char *ext = name + strlen(name) - 4; 88 | // if (strncmp(ext, ".bas", 4)==0){ 89 | // snprintf(out,sizeof(out),"%s/%s", _get_path(), name); 90 | // stat(out, &stats); 91 | // name[strlen(name)-4] = '\0'; 92 | // cb(name, stats.st_size, false, context); 93 | // } 94 | // } 95 | //} 96 | //closedir(dir); 97 | 98 | return 0; 99 | } 100 | 101 | int 102 | arch_delete(char* name){ 103 | char* filename = malloc(256); 104 | sprintf(&filename, "%s/%s.bas", _get_path(), name); 105 | remove(filename); 106 | free(filename); 107 | return 0; 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /arch/windows/error.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | #include 5 | // or inttypes.h 6 | 7 | extern uint16_t __line; 8 | 9 | const char *last_error = NULL; 10 | 11 | void 12 | error(const char *error_msg) 13 | { 14 | void *array[10]; 15 | size_t size; 16 | //char **strings; 17 | size_t i; 18 | 19 | last_error = error_msg; 20 | 21 | printf("--- ERROR: %d %s\n", __line, error_msg); 22 | 23 | //size = backtrace (array, 10); 24 | //strings = backtrace_symbols (array, size); 25 | 26 | //printf ("SHOW %zd STACK FRAMES:\n", size); 27 | 28 | //for (i = 0; i < size; i++) 29 | //{ 30 | // printf (" %s\n", strings[i]); 31 | //} 32 | 33 | //free (strings); 34 | } 35 | -------------------------------------------------------------------------------- /arch/windows/kbhit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | //#include 5 | //#include 6 | 7 | int kbhit(void) { 8 | return getchar(); 9 | } 10 | -------------------------------------------------------------------------------- /arch/windows/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | //#include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "parser.h" 10 | 11 | extern bool __RUNNING; 12 | extern bool __STOPPED; 13 | 14 | static void 15 | sigint_handler(int signum) 16 | { 17 | signal(SIGINT, sigint_handler); 18 | if(__RUNNING){ 19 | __RUNNING = false; 20 | __STOPPED = true; 21 | printf("STOP\n"); 22 | fflush(stdout); 23 | } 24 | } 25 | 26 | static char * 27 | readline_gets () 28 | { 29 | char * line_read = readline (""); 30 | 31 | if (line_read && *line_read) { 32 | add_history (line_read); 33 | } 34 | 35 | return line_read; 36 | } 37 | 38 | int out(int ch) 39 | { 40 | putchar(ch); 41 | return 1; 42 | } 43 | 44 | int in(void) 45 | { 46 | return getchar(); 47 | } 48 | 49 | void repl(void) 50 | { 51 | puts(" _ _ "); 52 | puts("| |__ __ _ ___(_) ___ "); 53 | puts("| '_ \\ / _` / __| |/ __|"); 54 | puts("| |_) | (_| \\__ \\ | (__ "); 55 | puts("|_.__/ \\__,_|___/_|\\___|"); 56 | puts("(c) 2015-2016 Johan Van den Brande"); 57 | 58 | //using_history(); 59 | 60 | char input[1024]; 61 | while ((gets(input)) != NULL ) 62 | { 63 | if (strcmp(input, "QUIT") == 0) { 64 | memset(input, 0, 1024); 65 | break; 66 | } 67 | 68 | basic_eval(input); 69 | 70 | if (evaluate_last_error()) { 71 | printf("ERROR: %s\n", evaluate_last_error()); 72 | clear_last_error(); 73 | } 74 | 75 | memset(input, 0, 1024); 76 | } 77 | 78 | //clear_history(); 79 | } 80 | 81 | void run(char *file_name){ 82 | FILE* file = fopen(file_name, "r"); 83 | 84 | if (file == NULL) { 85 | fprintf(stderr, "Can't open %s\n", file_name); 86 | return; 87 | } 88 | 89 | char line[tokenizer_string_length]; 90 | while (fgets(line, sizeof(line), file)) { 91 | if(line[strlen(line)-1]!='\n') 92 | { 93 | printf("ERROR: NO EOL\n"); 94 | exit(1); 95 | } 96 | basic_eval(line); 97 | } 98 | fclose(file); 99 | 100 | basic_run(); 101 | } 102 | 103 | int main(int argc, char *argv[]) 104 | { 105 | signal(SIGINT, sigint_handler); 106 | 107 | basic_init(1024*8, 2048); 108 | basic_register_io(out, in); 109 | 110 | if (argc > 1){ 111 | run(argv[1]); 112 | } else { 113 | repl(); 114 | } 115 | 116 | basic_destroy(); 117 | 118 | return EXIT_SUCCESS; 119 | } 120 | -------------------------------------------------------------------------------- /arch/xmega/arch.c: -------------------------------------------------------------------------------- 1 | #include "arch.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "spi.h" 8 | #include "ff.h" 9 | 10 | int 11 | asprintf(char **str, const char *format, ...) 12 | { 13 | va_list argp; 14 | va_start(argp, format); 15 | 16 | char one_char[1]; 17 | int len = vsnprintf(one_char, 1, format, argp); 18 | if (len < 1){ 19 | *str = NULL; 20 | return len; 21 | } 22 | va_end(argp); 23 | *str = malloc(len+1); 24 | if (!str) { 25 | return -1; 26 | } 27 | va_start(argp, format); 28 | vsnprintf(*str, len+1, format, argp); 29 | va_end(argp); 30 | return len; 31 | } 32 | 33 | float 34 | strtof(const char *restrict nptr, char **restrict endptr) 35 | { 36 | float f; 37 | sscanf(nptr, "%f", &f); 38 | return f; 39 | } 40 | 41 | char* 42 | strndup(const char *s, size_t n) 43 | { 44 | size_t len = strnlen (s, n); 45 | char *new = (char *) malloc (len + 1); 46 | if (new == NULL) 47 | { 48 | return NULL; 49 | } 50 | new[len] = '\0'; 51 | return (char *) memcpy (new, s, len); 52 | } 53 | 54 | // -- SD Card specific 55 | 56 | FATFS FatFs; 57 | 58 | int 59 | arch_init(void) 60 | { 61 | spi_init(); 62 | f_mount(&FatFs, "", 0); 63 | return 0; 64 | } 65 | 66 | int 67 | arch_load(char* name, arch_load_out_cb cb, void* context) 68 | { 69 | char filename[13]; // 8 + '.' + 3 + '\0' 70 | char line[128]; 71 | FIL fil; 72 | snprintf(filename, sizeof(filename), "%s.bas", name); 73 | f_open(&fil, filename, FA_READ); 74 | while (f_gets(line, sizeof line, &fil)){ 75 | cb(line, context); 76 | } 77 | f_close(&fil); 78 | return 0; 79 | } 80 | 81 | int 82 | arch_save(char* name, arch_save_cb cb, void* context) 83 | { 84 | char filename[13]; 85 | char* line; 86 | char buffer[128]; 87 | FIL fil; 88 | snprintf(filename, sizeof(filename), "%s.bas", name); 89 | f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS); 90 | for(;;){ 91 | uint16_t number = cb(&line, context); 92 | if (line == NULL){ 93 | break; 94 | } 95 | snprintf(buffer, sizeof(buffer), "%d %s\n", number, line); 96 | f_puts(buffer, &fil); 97 | } 98 | f_close(&fil); 99 | return 0; 100 | } 101 | 102 | int 103 | arch_dir(arch_dir_out_cb cb, void* context) 104 | { 105 | DIR dir; 106 | FRESULT res; 107 | FILINFO fno; 108 | char out[24]; 109 | f_getlabel("", out, 0); 110 | cb(out, 0, true, context); 111 | res = f_findfirst(&dir, &fno, "", "*.bas"); 112 | while (res == FR_OK && fno.fname[0]){ 113 | fno.fname[strlen(fno.fname)-4] = '\0'; 114 | cb(fno.fname, (size_t) fno.fsize, false, context); 115 | res = f_findnext(&dir, &fno); 116 | } 117 | f_closedir(&dir); 118 | return 0; 119 | } 120 | 121 | int 122 | arch_delete(char* name){ 123 | char filename[13]; 124 | snprintf(filename, sizeof(filename), "%s.bas", name); 125 | f_unlink(filename); 126 | return 0; 127 | } 128 | 129 | 130 | -------------------------------------------------------------------------------- /arch/xmega/console.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "io.h" 6 | 7 | void 8 | console_def_char(unsigned char code, char* definition) 9 | { 10 | char buf[20]; 11 | putchar(0x1b); 12 | putchar('T'); 13 | snprintf(buf, sizeof(buf), "%02x", code); 14 | basic_io_print(buf); 15 | for(int i=0; i<18; i++){ 16 | buf[i] = tolower(definition[i]); 17 | } 18 | buf[18] = '\0'; 19 | basic_io_print(buf); 20 | } 21 | 22 | void 23 | console_move_cursor(int x, int y) 24 | { 25 | putchar(0x1b); 26 | putchar('Y'); 27 | putchar(' ' + y); 28 | putchar(' ' + x); 29 | } 30 | 31 | void 32 | console_plot(int x, int y, unsigned char code) 33 | { 34 | console_move_cursor(x, y); 35 | if(code < 32){ 36 | putchar(0x10); // Data link escape 37 | } 38 | putchar(code); 39 | } 40 | 41 | void 42 | console_cursor(int cursor) 43 | { 44 | putchar(0x1b); 45 | if(cursor){ 46 | putchar('e'); 47 | } else { 48 | putchar('f'); 49 | } 50 | } 51 | 52 | void 53 | console_cursor_type(int block) 54 | { 55 | putchar(0x1b); 56 | if(block){ 57 | putchar('x'); 58 | } else { 59 | putchar('y'); 60 | } 61 | putchar('4'); 62 | } 63 | 64 | void 65 | console_line_overflow(int overflow) 66 | { 67 | putchar(0x1b); 68 | if(overflow){ 69 | putchar('v'); 70 | } else { 71 | putchar('w'); 72 | } 73 | } 74 | 75 | void 76 | console_fontbank(int row, int bank) 77 | { 78 | char banks[] = {'6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@'}; 79 | 80 | // save cursor 81 | putchar(0x1b); 82 | putchar('j'); 83 | 84 | // set cursor 85 | putchar(0x1b); 86 | putchar('Y'); 87 | putchar(' ' + row); 88 | putchar(' ' + 0); 89 | 90 | // set bank for actual row 91 | putchar(0x1b); 92 | putchar('_'); 93 | if(bank<0) bank = 0; 94 | if(bank>10) bank = 10; 95 | putchar(banks[bank]); 96 | 97 | // restore cursor 98 | putchar(0x1b); 99 | putchar('k'); 100 | } 101 | 102 | void 103 | console_cls(void) 104 | { 105 | putchar(0x1b); 106 | putchar('E'); 107 | } 108 | 109 | void 110 | console_invert(int invert) 111 | { 112 | putchar(0x1b); 113 | if(invert){ 114 | putchar('x'); 115 | } else { 116 | putchar('y'); 117 | } 118 | putchar('>'); 119 | } 120 | -------------------------------------------------------------------------------- /arch/xmega/console.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONSOLE_H__ 2 | #define __CONSOLE_H__ 3 | 4 | void console_def_char(unsigned char code, char* definition); 5 | void console_plot(int x, int y, unsigned char code); 6 | void console_cursor(int cursor); 7 | void console_cursor_type(int block); 8 | void console_line_overflow(int overflow); 9 | void console_fontbank(int row, int bank); 10 | void console_cls(void); 11 | void console_move_cursor(int x, int y); 12 | void console_invert(int invert); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /arch/xmega/diskio.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------- 2 | / Low level disk interface modlue include file (C)ChaN, 2014 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #define _USE_WRITE 1 /* 1: Enable disk_write function */ 13 | #define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */ 14 | #define _USE_ISDIO 1 /* 1: Enable iSDIO controls via disk_ioctl */ 15 | 16 | #include "integer.h" 17 | 18 | 19 | /* Status of Disk Functions */ 20 | typedef BYTE DSTATUS; 21 | 22 | /* Results of Disk Functions */ 23 | typedef enum { 24 | RES_OK = 0, /* 0: Successful */ 25 | RES_ERROR, /* 1: R/W Error */ 26 | RES_WRPRT, /* 2: Write Protected */ 27 | RES_NOTRDY, /* 3: Not Ready */ 28 | RES_PARERR /* 4: Invalid Parameter */ 29 | } DRESULT; 30 | 31 | /* Command structure for iSDIO ioctl command */ 32 | typedef struct { 33 | BYTE func; /* Function number: 0..7 */ 34 | WORD ndata; /* Number of bytes to transfer: 1..512, or mask + data */ 35 | DWORD addr; /* Register address: 0..0x1FFFF */ 36 | void* data; /* Pointer to the data (to be written | read buffer) */ 37 | } SDIO_CTRL; 38 | 39 | 40 | /*---------------------------------------*/ 41 | /* Prototypes for disk control functions */ 42 | 43 | 44 | DSTATUS disk_initialize (BYTE pdrv); 45 | DSTATUS disk_status (BYTE pdrv); 46 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 47 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 48 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 49 | void disk_timerproc (void); 50 | 51 | 52 | /* Disk Status Bits (DSTATUS) */ 53 | #define STA_NOINIT 0x01 /* Drive not initialized */ 54 | #define STA_NODISK 0x02 /* No medium in the drive */ 55 | #define STA_PROTECT 0x04 /* Write protected */ 56 | 57 | 58 | /* Command code for disk_ioctrl fucntion */ 59 | 60 | /* Generic command (Used by FatFs) */ 61 | #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ 62 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ 63 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ 64 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ 65 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ 66 | 67 | /* Generic command (Not used by FatFs) */ 68 | #define CTRL_FORMAT 5 /* Create physical format on the media */ 69 | #define CTRL_POWER_IDLE 6 /* Put the device idle state */ 70 | #define CTRL_POWER_OFF 7 /* Put the device off state */ 71 | #define CTRL_LOCK 8 /* Lock media removal */ 72 | #define CTRL_UNLOCK 9 /* Unlock media removal */ 73 | #define CTRL_EJECT 10 /* Eject media */ 74 | 75 | /* MMC/SDC specific command (Not used by FatFs) */ 76 | #define MMC_GET_TYPE 50 /* Get card type */ 77 | #define MMC_GET_CSD 51 /* Get CSD */ 78 | #define MMC_GET_CID 52 /* Get CID */ 79 | #define MMC_GET_OCR 53 /* Get OCR */ 80 | #define MMC_GET_SDSTAT 54 /* Get SD status */ 81 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 82 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 83 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 84 | 85 | /* ATA/CF specific command (Not used by FatFs) */ 86 | #define ATA_GET_REV 60 /* Get F/W revision */ 87 | #define ATA_GET_MODEL 61 /* Get model name */ 88 | #define ATA_GET_SN 62 /* Get serial number */ 89 | 90 | 91 | /* MMC card type flags (MMC_GET_TYPE) */ 92 | #define CT_MMC 0x01 /* MMC ver 3 */ 93 | #define CT_SD1 0x02 /* SD ver 1 */ 94 | #define CT_SD2 0x04 /* SD ver 2 */ 95 | #define CT_SDC (CT_SD1|CT_SD2) /* SD */ 96 | #define CT_BLOCK 0x08 /* Block addressing */ 97 | 98 | 99 | #ifdef __cplusplus 100 | } 101 | #endif 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /arch/xmega/error.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | const char *last_error = NULL; 7 | 8 | void 9 | error(const char *error_msg) 10 | { 11 | last_error = error_msg; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /arch/xmega/ext.c: -------------------------------------------------------------------------------- 1 | #include "parser.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /arch/xmega/ff.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - FAT file system module include R0.12 (C)ChaN, 2016 3 | /----------------------------------------------------------------------------/ 4 | / FatFs module is a free software that opened under license policy of 5 | / following conditions. 6 | / 7 | / Copyright (C) 2016, ChaN, all right reserved. 8 | / 9 | / 1. Redistributions of source code must retain the above copyright notice, 10 | / this condition and the following disclaimer. 11 | / 12 | / This software is provided by the copyright holder and contributors "AS IS" 13 | / and any warranties related to this software are DISCLAIMED. 14 | / The copyright owner or contributors be NOT LIABLE for any damages caused 15 | / by use of this software. 16 | /---------------------------------------------------------------------------*/ 17 | 18 | 19 | #ifndef _FATFS 20 | #define _FATFS 88100 /* Revision ID */ 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #include "integer.h" /* Basic integer types */ 27 | #include "ffconf.h" /* FatFs configuration options */ 28 | #if _FATFS != _FFCONF 29 | #error Wrong configuration file (ffconf.h). 30 | #endif 31 | 32 | 33 | 34 | /* Definitions of volume management */ 35 | 36 | #if _MULTI_PARTITION /* Multiple partition configuration */ 37 | typedef struct { 38 | BYTE pd; /* Physical drive number */ 39 | BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ 40 | } PARTITION; 41 | extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ 42 | #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ 43 | #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ 44 | 45 | #else /* Single partition configuration */ 46 | #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ 47 | #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ 48 | 49 | #endif 50 | 51 | 52 | 53 | /* Type of path name strings on FatFs API */ 54 | 55 | #if _LFN_UNICODE /* Unicode string */ 56 | #if _USE_LFN == 0 57 | #error _LFN_UNICODE must be 0 at non-LFN cfg. 58 | #endif 59 | #ifndef _INC_TCHAR 60 | typedef WCHAR TCHAR; 61 | #define _T(x) L ## x 62 | #define _TEXT(x) L ## x 63 | #endif 64 | 65 | #else /* ANSI/OEM string */ 66 | #ifndef _INC_TCHAR 67 | typedef char TCHAR; 68 | #define _T(x) x 69 | #define _TEXT(x) x 70 | #endif 71 | 72 | #endif 73 | 74 | 75 | 76 | /* File system object structure (FATFS) */ 77 | 78 | typedef struct { 79 | BYTE fs_type; /* File system type (0:N/A) */ 80 | BYTE drv; /* Physical drive number */ 81 | BYTE n_fats; /* Number of FATs (1 or 2) */ 82 | BYTE wflag; /* win[] flag (b0:dirty) */ 83 | BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ 84 | WORD id; /* File system mount ID */ 85 | WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ 86 | WORD csize; /* Cluster size [sectors] */ 87 | #if _MAX_SS != _MIN_SS 88 | WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ 89 | #endif 90 | #if _FS_EXFAT 91 | BYTE* dirbuf; /* Directory entry block scratchpad buffer */ 92 | #endif 93 | #if _FS_REENTRANT 94 | _SYNC_t sobj; /* Identifier of sync object */ 95 | #endif 96 | #if !_FS_READONLY 97 | DWORD last_clst; /* Last allocated cluster */ 98 | DWORD free_clst; /* Number of free clusters */ 99 | #endif 100 | #if _FS_RPATH != 0 101 | DWORD cdir; /* Current directory start cluster (0:root) */ 102 | #if _FS_EXFAT 103 | DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ 104 | DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ 105 | DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ 106 | #endif 107 | #endif 108 | DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ 109 | DWORD fsize; /* Size of an FAT [sectors] */ 110 | DWORD volbase; /* Volume base sector */ 111 | DWORD fatbase; /* FAT base sector */ 112 | DWORD dirbase; /* Root directory base sector/cluster */ 113 | DWORD database; /* Data base sector */ 114 | DWORD winsect; /* Current sector appearing in the win[] */ 115 | BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ 116 | } FATFS; 117 | 118 | 119 | 120 | /* Type of file size variables and object identifier */ 121 | 122 | #if _FS_EXFAT 123 | #if _USE_LFN == 0 124 | #error LFN must be enabled when enable exFAT 125 | #endif 126 | typedef QWORD FSIZE_t; 127 | #else 128 | typedef DWORD FSIZE_t; 129 | #endif 130 | 131 | 132 | 133 | /* Object ID and allocation information (_FDID) */ 134 | 135 | typedef struct { 136 | FATFS* fs; /* Pointer to the owner file system object */ 137 | WORD id; /* Owner file system mount ID */ 138 | BYTE attr; /* Object attribute */ 139 | BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ 140 | DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ 141 | FSIZE_t objsize; /* Object size (valid when sclust != 0) */ 142 | #if _FS_EXFAT 143 | DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ 144 | DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ 145 | DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ 146 | DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ 147 | #endif 148 | #if _FS_LOCK != 0 149 | UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ 150 | #endif 151 | } _FDID; 152 | 153 | 154 | 155 | /* File object structure (FIL) */ 156 | 157 | typedef struct { 158 | _FDID obj; /* Object identifier */ 159 | BYTE flag; /* File status flags */ 160 | BYTE err; /* Abort flag (error code) */ 161 | FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ 162 | DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ 163 | DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ 164 | #if !_FS_READONLY 165 | DWORD dir_sect; /* Sector number containing the directory entry */ 166 | BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ 167 | #endif 168 | #if _USE_FASTSEEK 169 | DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ 170 | #endif 171 | #if !_FS_TINY 172 | BYTE buf[_MAX_SS]; /* File private data read/write window */ 173 | #endif 174 | } FIL; 175 | 176 | 177 | 178 | /* Directory object structure (DIR) */ 179 | 180 | typedef struct { 181 | _FDID obj; /* Object identifier */ 182 | DWORD dptr; /* Current read/write offset */ 183 | DWORD clust; /* Current cluster */ 184 | DWORD sect; /* Current sector */ 185 | BYTE* dir; /* Pointer to the directory item in the win[] */ 186 | BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */ 187 | #if _USE_LFN != 0 188 | DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ 189 | WCHAR* lfn; /* Pointer to the LFN working buffer */ 190 | #endif 191 | #if _USE_FIND 192 | const TCHAR* pat; /* Pointer to the name matching pattern */ 193 | #endif 194 | } DIR; 195 | 196 | 197 | 198 | /* File information structure (FILINFO) */ 199 | 200 | typedef struct { 201 | FSIZE_t fsize; /* File size */ 202 | WORD fdate; /* Modified date */ 203 | WORD ftime; /* Modified time */ 204 | BYTE fattrib; /* File attribute */ 205 | #if _USE_LFN != 0 206 | TCHAR altname[13]; /* Altenative file name */ 207 | TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ 208 | #else 209 | TCHAR fname[13]; /* File name */ 210 | #endif 211 | } FILINFO; 212 | 213 | 214 | 215 | /* File function return code (FRESULT) */ 216 | 217 | typedef enum { 218 | FR_OK = 0, /* (0) Succeeded */ 219 | FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ 220 | FR_INT_ERR, /* (2) Assertion failed */ 221 | FR_NOT_READY, /* (3) The physical drive cannot work */ 222 | FR_NO_FILE, /* (4) Could not find the file */ 223 | FR_NO_PATH, /* (5) Could not find the path */ 224 | FR_INVALID_NAME, /* (6) The path name format is invalid */ 225 | FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ 226 | FR_EXIST, /* (8) Access denied due to prohibited access */ 227 | FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ 228 | FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ 229 | FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ 230 | FR_NOT_ENABLED, /* (12) The volume has no work area */ 231 | FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ 232 | FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ 233 | FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 234 | FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ 235 | FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ 236 | FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ 237 | FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ 238 | } FRESULT; 239 | 240 | 241 | 242 | /*--------------------------------------------------------------*/ 243 | /* FatFs module application interface */ 244 | 245 | FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ 246 | FRESULT f_close (FIL* fp); /* Close an open file object */ 247 | FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ 248 | FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ 249 | FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */ 250 | FRESULT f_truncate (FIL* fp); /* Truncate file */ 251 | FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ 252 | FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ 253 | FRESULT f_closedir (DIR* dp); /* Close an open directory */ 254 | FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ 255 | FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ 256 | FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ 257 | FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ 258 | FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ 259 | FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ 260 | FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ 261 | FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ 262 | FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */ 263 | FRESULT f_chdir (const TCHAR* path); /* Change current directory */ 264 | FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ 265 | FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ 266 | FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ 267 | FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ 268 | FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ 269 | FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ 270 | FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ 271 | FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ 272 | FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ 273 | FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ 274 | int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ 275 | int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ 276 | int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ 277 | TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ 278 | 279 | #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) 280 | #define f_error(fp) ((fp)->err) 281 | #define f_tell(fp) ((fp)->fptr) 282 | #define f_size(fp) ((fp)->obj.objsize) 283 | #define f_rewind(fp) f_lseek((fp), 0) 284 | #define f_rewinddir(dp) f_readdir((dp), 0) 285 | 286 | #ifndef EOF 287 | #define EOF (-1) 288 | #endif 289 | 290 | 291 | 292 | 293 | /*--------------------------------------------------------------*/ 294 | /* Additional user defined functions */ 295 | 296 | /* RTC function */ 297 | #if !_FS_READONLY && !_FS_NORTC 298 | DWORD get_fattime (void); 299 | #endif 300 | 301 | /* Unicode support functions */ 302 | #if _USE_LFN != 0 /* Unicode - OEM code conversion */ 303 | WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ 304 | WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ 305 | #if _USE_LFN == 3 /* Memory functions */ 306 | void* ff_memalloc (UINT msize); /* Allocate memory block */ 307 | void ff_memfree (void* mblock); /* Free memory block */ 308 | #endif 309 | #endif 310 | 311 | /* Sync functions */ 312 | #if _FS_REENTRANT 313 | int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ 314 | int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ 315 | void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ 316 | int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ 317 | #endif 318 | 319 | 320 | 321 | 322 | /*--------------------------------------------------------------*/ 323 | /* Flags and offset address */ 324 | 325 | 326 | /* File access control and file status flags (FIL.flag) */ 327 | 328 | #define FA_READ 0x01 329 | #define FA_WRITE 0x02 330 | #define FA_OPEN_EXISTING 0x00 331 | #define FA_CREATE_NEW 0x04 332 | #define FA_CREATE_ALWAYS 0x08 333 | #define FA_OPEN_ALWAYS 0x10 334 | #define _FA_MODIFIED 0x20 335 | #define _FA_DIRTY 0x40 336 | 337 | 338 | /* FAT sub type (FATFS.fs_type) */ 339 | 340 | #define FS_FAT12 1 341 | #define FS_FAT16 2 342 | #define FS_FAT32 3 343 | #define FS_EXFAT 4 344 | 345 | 346 | /* File attribute bits for directory entry */ 347 | 348 | #define AM_RDO 0x01 /* Read only */ 349 | #define AM_HID 0x02 /* Hidden */ 350 | #define AM_SYS 0x04 /* System */ 351 | #define AM_VOL 0x08 /* Volume label */ 352 | #define AM_LFN 0x0F /* LFN entry */ 353 | #define AM_DIR 0x10 /* Directory */ 354 | #define AM_ARC 0x20 /* Archive */ 355 | #define AM_MASK 0x3F /* Mask of defined bits */ 356 | 357 | 358 | /* Fast seek controls */ 359 | #define CREATE_LINKMAP ((FSIZE_t)0 - 1) 360 | 361 | 362 | #ifdef __cplusplus 363 | } 364 | #endif 365 | 366 | #endif /* _FATFS */ 367 | -------------------------------------------------------------------------------- /arch/xmega/ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define _FFCONF 88100 /* Revision ID */ 6 | 7 | /*---------------------------------------------------------------------------/ 8 | / Function Configurations 9 | /---------------------------------------------------------------------------*/ 10 | 11 | #define _FS_READONLY 0 12 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 13 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 14 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 15 | / and optional writing functions as well. */ 16 | 17 | 18 | #define _FS_MINIMIZE 0 19 | /* This option defines minimization level to remove some basic API functions. 20 | / 21 | / 0: All basic functions are enabled. 22 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() 23 | / are removed. 24 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 25 | / 3: f_lseek() function is removed in addition to 2. */ 26 | 27 | 28 | #define _USE_STRFUNC 1 29 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and 30 | / f_printf(). 31 | / 32 | / 0: Disable string functions. 33 | / 1: Enable without LF-CRLF conversion. 34 | / 2: Enable with LF-CRLF conversion. */ 35 | 36 | 37 | #define _USE_FIND 1 38 | /* This option switches filtered directory read functions, f_findfirst() and 39 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ 40 | 41 | 42 | #define _USE_MKFS 1 43 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 44 | 45 | 46 | #define _USE_FASTSEEK 0 47 | /* This option switches fast seek function. (0:Disable or 1:Enable) */ 48 | 49 | 50 | #define _USE_EXPAND 0 51 | /* This option switches f_expand function. (0:Disable or 1:Enable) */ 52 | 53 | 54 | #define _USE_CHMOD 1 55 | /* This option switches attribute manipulation functions, f_chmod() and f_utime(). 56 | / (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ 57 | 58 | 59 | #define _USE_LABEL 1 60 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 61 | / (0:Disable or 1:Enable) */ 62 | 63 | 64 | #define _USE_FORWARD 0 65 | /* This option switches f_forward() function. (0:Disable or 1:Enable) 66 | / To enable it, also _FS_TINY need to be 1. */ 67 | 68 | 69 | /*---------------------------------------------------------------------------/ 70 | / Locale and Namespace Configurations 71 | /---------------------------------------------------------------------------*/ 72 | 73 | #define _CODE_PAGE 1 74 | /* This option specifies the OEM code page to be used on the target system. 75 | / Incorrect setting of the code page can cause a file open failure. 76 | / 77 | / 1 - ASCII (No extended character. Non-LFN cfg. only) 78 | / 437 - U.S. 79 | / 720 - Arabic 80 | / 737 - Greek 81 | / 771 - KBL 82 | / 775 - Baltic 83 | / 850 - Latin 1 84 | / 852 - Latin 2 85 | / 855 - Cyrillic 86 | / 857 - Turkish 87 | / 860 - Portuguese 88 | / 861 - Icelandic 89 | / 862 - Hebrew 90 | / 863 - Canadian French 91 | / 864 - Arabic 92 | / 865 - Nordic 93 | / 866 - Russian 94 | / 869 - Greek 2 95 | / 932 - Japanese (DBCS) 96 | / 936 - Simplified Chinese (DBCS) 97 | / 949 - Korean (DBCS) 98 | / 950 - Traditional Chinese (DBCS) 99 | */ 100 | 101 | 102 | #define _USE_LFN 0 103 | #define _MAX_LFN 128 104 | /* The _USE_LFN switches the support of long file name (LFN). 105 | / 106 | / 0: Disable support of LFN. _MAX_LFN has no effect. 107 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 108 | / 2: Enable LFN with dynamic working buffer on the STACK. 109 | / 3: Enable LFN with dynamic working buffer on the HEAP. 110 | / 111 | / To enable the LFN, Unicode handling functions (option/unicode.c) must be added 112 | / to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and 113 | / additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. 114 | / It should be set 255 to support full featured LFN operations. 115 | / When use stack for the working buffer, take care on stack overflow. When use heap 116 | / memory for the working buffer, memory management functions, ff_memalloc() and 117 | / ff_memfree(), must be added to the project. */ 118 | 119 | 120 | #define _LFN_UNICODE 0 121 | /* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) 122 | / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. 123 | / This option also affects behavior of string I/O functions. */ 124 | 125 | 126 | #define _STRF_ENCODE 3 127 | /* When _LFN_UNICODE == 1, this option selects the character encoding on the file to 128 | / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). 129 | / 130 | / 0: ANSI/OEM 131 | / 1: UTF-16LE 132 | / 2: UTF-16BE 133 | / 3: UTF-8 134 | / 135 | / This option has no effect when _LFN_UNICODE == 0. */ 136 | 137 | 138 | #define _FS_RPATH 2 139 | /* This option configures support of relative path. 140 | / 141 | / 0: Disable relative path and remove related functions. 142 | / 1: Enable relative path. f_chdir() and f_chdrive() are available. 143 | / 2: f_getcwd() function is available in addition to 1. 144 | */ 145 | 146 | 147 | /*---------------------------------------------------------------------------/ 148 | / Drive/Volume Configurations 149 | /---------------------------------------------------------------------------*/ 150 | 151 | #define _VOLUMES 1 152 | /* Number of volumes (logical drives) to be used. */ 153 | 154 | 155 | #define _STR_VOLUME_ID 0 156 | #define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" 157 | /* _STR_VOLUME_ID switches string support of volume ID. 158 | / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive 159 | / number in the path name. _VOLUME_STRS defines the drive ID strings for each 160 | / logical drives. Number of items must be equal to _VOLUMES. Valid characters for 161 | / the drive ID strings are: A-Z and 0-9. */ 162 | 163 | 164 | #define _MULTI_PARTITION 0 165 | /* This option switches support of multi-partition on a physical drive. 166 | / By default (0), each logical drive number is bound to the same physical drive 167 | / number and only an FAT volume found on the physical drive will be mounted. 168 | / When multi-partition is enabled (1), each logical drive number can be bound to 169 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() 170 | / funciton will be available. */ 171 | 172 | 173 | #define _MIN_SS 512 174 | #define _MAX_SS 512 175 | /* These options configure the range of sector size to be supported. (512, 1024, 176 | / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and 177 | / harddisk. But a larger value may be required for on-board flash memory and some 178 | / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured 179 | / to variable sector size and GET_SECTOR_SIZE command must be implemented to the 180 | / disk_ioctl() function. */ 181 | 182 | 183 | #define _USE_TRIM 0 184 | /* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) 185 | / To enable Trim function, also CTRL_TRIM command should be implemented to the 186 | / disk_ioctl() function. */ 187 | 188 | 189 | #define _FS_NOFSINFO 0 190 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 191 | / option, and f_getfree() function at first time after volume mount will force 192 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 193 | / 194 | / bit0=0: Use free cluster count in the FSINFO if available. 195 | / bit0=1: Do not trust free cluster count in the FSINFO. 196 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 197 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 198 | */ 199 | 200 | 201 | 202 | /*---------------------------------------------------------------------------/ 203 | / System Configurations 204 | /---------------------------------------------------------------------------*/ 205 | 206 | #define _FS_TINY 1 207 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 208 | / At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes. 209 | / Instead of private sector buffer eliminated from the file object, common sector 210 | / buffer in the file system object (FATFS) is used for the file data transfer. */ 211 | 212 | 213 | #define _FS_EXFAT 0 214 | /* This option switches support of exFAT file system in addition to the traditional 215 | / FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled. 216 | / Note that enabling exFAT discards C89 compatibility. */ 217 | 218 | 219 | #define _FS_NORTC 1 220 | #define _NORTC_MON 3 221 | #define _NORTC_MDAY 1 222 | #define _NORTC_YEAR 2016 223 | /* The option _FS_NORTC switches timestamp functiton. If the system does not have 224 | / any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable 225 | / the timestamp function. All objects modified by FatFs will have a fixed timestamp 226 | / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. 227 | / To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be 228 | / added to the project to get current time form real-time clock. _NORTC_MON, 229 | / _NORTC_MDAY and _NORTC_YEAR have no effect. 230 | / These options have no effect at read-only configuration (_FS_READONLY = 1). */ 231 | 232 | 233 | #define _FS_LOCK 0 234 | /* The option _FS_LOCK switches file lock function to control duplicated file open 235 | / and illegal operation to open objects. This option must be 0 when _FS_READONLY 236 | / is 1. 237 | / 238 | / 0: Disable file lock function. To avoid volume corruption, application program 239 | / should avoid illegal open, remove and rename to the open objects. 240 | / >0: Enable file lock function. The value defines how many files/sub-directories 241 | / can be opened simultaneously under file lock control. Note that the file 242 | / lock control is independent of re-entrancy. */ 243 | 244 | 245 | #define _FS_REENTRANT 0 246 | #define _FS_TIMEOUT 1000 247 | #define _SYNC_t HANDLE 248 | /* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs 249 | / module itself. Note that regardless of this option, file access to different 250 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 251 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 252 | / to the same volume is under control of this function. 253 | / 254 | / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. 255 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 256 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 257 | / function, must be added to the project. Samples are available in 258 | / option/syscall.c. 259 | / 260 | / The _FS_TIMEOUT defines timeout period in unit of time tick. 261 | / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 262 | / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be 263 | / included somewhere in the scope of ff.c. */ 264 | 265 | 266 | /*--- End of configuration options ---*/ 267 | -------------------------------------------------------------------------------- /arch/xmega/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef _FF_INTEGER 6 | #define _FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | typedef unsigned __int64 QWORD; 13 | 14 | 15 | #else /* Embedded platform */ 16 | 17 | /* These types MUST be 16-bit or 32-bit */ 18 | typedef int INT; 19 | typedef unsigned int UINT; 20 | 21 | /* This type MUST be 8-bit */ 22 | typedef unsigned char BYTE; 23 | 24 | /* These types MUST be 16-bit */ 25 | typedef short SHORT; 26 | typedef unsigned short WORD; 27 | typedef unsigned short WCHAR; 28 | 29 | /* These types MUST be 32-bit */ 30 | typedef long LONG; 31 | typedef unsigned long DWORD; 32 | 33 | /* This type MUST be 64-bit (Remove this for C89 compatibility) */ 34 | typedef unsigned long long QWORD; 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /arch/xmega/joystick.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void 8 | joystick_init(void) 9 | { 10 | PORTA.DIRCLR = PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm | PIN4_bm; 11 | PORTA.PIN0CTRL|=PORT_OPC_PULLUP_gc; 12 | PORTA.PIN1CTRL|=PORT_OPC_PULLUP_gc; 13 | PORTA.PIN2CTRL|=PORT_OPC_PULLUP_gc; 14 | PORTA.PIN3CTRL|=PORT_OPC_PULLUP_gc; 15 | PORTA.PIN4CTRL|=PORT_OPC_PULLUP_gc; 16 | } 17 | 18 | int 19 | joystick_read_button(void){ 20 | return (int) 0 == (PORTA.IN & PIN0_bm); 21 | } 22 | 23 | int 24 | joystick_read_stick(void){ 25 | 26 | // R L D U S bits N LABEL 27 | // --+----+----+----+------+------+----+------- 28 | // 1 1 1 1 15 1111 0 N 29 | // 1 1 1 0 14 1110 1 U 30 | // 0 1 1 0 6 0110 2 UR 31 | // 0 1 1 1 7 0111 3 R 32 | // 0 1 0 1 5 0101 4 DR 33 | // 1 1 0 1 13 1101 5 D 34 | // 1 0 0 1 9 1001 6 DL 35 | // 1 0 1 1 11 1011 7 L 36 | // 1 0 1 0 10 1010 8 UL 37 | 38 | uint8_t stick = PORTA.IN >> 1; 39 | switch(stick){ 40 | case 15: 41 | return 0; 42 | case 14: 43 | return 1; 44 | case 6: 45 | return 2; 46 | case 7: 47 | return 3; 48 | case 5: 49 | return 4; 50 | case 13: 51 | return 5; 52 | case 9: 53 | return 6; 54 | case 11: 55 | return 7; 56 | case 10: 57 | return 8; 58 | default: 59 | return 0; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /arch/xmega/joystick.h: -------------------------------------------------------------------------------- 1 | #ifndef __JOYSTICK_H__ 2 | #define __JOYSTICK_H__ 3 | 4 | void joystick_init(void); 5 | 6 | // 0: neutral 7 | // 1: U 8 | // 2: UR 9 | // 3: R 10 | // 4: DR 11 | // 5: D 12 | // 6: DL 13 | // 7: L 14 | // 8: UL 15 | int joystick_read_stick(void); 16 | 17 | // 1: pressed 18 | int joystick_read_button(void); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /arch/xmega/kbhit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int kbhit(void) { 4 | return USARTD0.STATUS & USART_RXCIF_bm; 5 | } 6 | -------------------------------------------------------------------------------- /arch/xmega/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "parser.h" 12 | #include "sound.h" 13 | #include "joystick.h" 14 | #include "console.h" 15 | 16 | #include "diskio.h" 17 | 18 | #include "error.h" 19 | 20 | #include "ff.h" 21 | 22 | extern uint16_t __line; 23 | extern bool __STOPPED; 24 | 25 | extern token sym; 26 | extern bool accept(token t); 27 | extern void get_sym(void); 28 | static token t_keyword_batch; 29 | 30 | // 100 Hz 31 | ISR(TCC0_OVF_vect) 32 | { 33 | disk_timerproc(); 34 | sound_timerproc(); 35 | } 36 | 37 | void init_xtal(void) 38 | { 39 | // Use an external 16Mhz crystal and x 2 PLL to give a clock of 32Mhz 40 | 41 | // Enable the external oscillator 42 | OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc ; 43 | OSC.CTRL |= OSC_XOSCEN_bm ; 44 | while( (OSC.STATUS & OSC_XOSCRDY_bm) == 0 ){} // wait until stable 45 | 46 | // Now configure the PLL to be eXternal OSCillator * 2 47 | OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ; 48 | OSC.CTRL |= OSC_PLLEN_bm ; // enable the PLL... 49 | while( (OSC.STATUS & OSC_PLLRDY_bm) == 0 ){} // wait until stable 50 | 51 | // And now switch to the PLL as the clocksource 52 | CCP = CCP_IOREG_gc; // protected write follows 53 | CLK.CTRL = CLK_SCLKSEL_PLL_gc; 54 | } 55 | 56 | void set_usartctrl( USART_t *usart, uint8_t bscale, uint16_t bsel) 57 | { 58 | usart->BAUDCTRLA = (bsel & USART_BSEL_gm); 59 | usart->BAUDCTRLB = ((bscale << USART_BSCALE0_bp) & USART_BSCALE_gm) | ((bsel >> 8) & ~USART_BSCALE_gm); 60 | } 61 | 62 | void init_uart_bscale_bsel(USART_t *usart, int8_t bscale, int16_t bsel) 63 | { 64 | usart->CTRLA = 0; 65 | usart->CTRLB = USART_TXEN_bm | USART_RXEN_bm; 66 | usart->CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc; 67 | set_usartctrl(usart, bscale, bsel); 68 | } 69 | 70 | 71 | int _uart_putc(int ch) 72 | { 73 | while ( ! (USARTE0.STATUS & USART_DREIF_bm) ) {}; 74 | USARTE0.DATA = (char) ch; 75 | return 1; 76 | } 77 | 78 | 79 | int uart_putc(int ch) 80 | { 81 | _uart_putc(ch); 82 | if (ch == '\n') 83 | { 84 | _uart_putc('\r'); 85 | } 86 | return 1; 87 | } 88 | 89 | void uart_puts(unsigned char* s) 90 | { 91 | while(*s){ 92 | uart_putc(*s); 93 | s++; 94 | } 95 | } 96 | 97 | int uart_getc(void) 98 | { 99 | while ( ! (USARTE0.STATUS & USART_RXCIF_bm) ) {}; 100 | char ch = (char) USARTE0.DATA; 101 | return ch; 102 | } 103 | 104 | int uart_fputc(char c, FILE* stream) 105 | { 106 | uart_putc(c); 107 | return 0; 108 | } 109 | 110 | int keyboard_getc(void) 111 | { 112 | while ( ! (USARTD0.STATUS & USART_RXCIF_bm) ) {}; 113 | unsigned char ch = (unsigned char) USARTD0.DATA; 114 | return ch; 115 | } 116 | 117 | int uart_fgetc(FILE* stream) 118 | { 119 | return keyboard_getc(); 120 | } 121 | 122 | void tellymate_enable_transmit(void) 123 | { 124 | uart_putc(0x1b); 125 | for(int i=0; i<4; i++){ 126 | uart_putc('~'); 127 | } 128 | } 129 | 130 | int console_charat(int x, int y) 131 | { 132 | putchar(0x1b); 133 | putchar('`'); 134 | putchar(' ' + y); 135 | putchar(' ' + x); 136 | return uart_getc(); 137 | } 138 | 139 | FILE uart_stdio = FDEV_SETUP_STREAM(uart_fputc, uart_fgetc, _FDEV_SETUP_RW); 140 | 141 | void init_xmega(void) 142 | { 143 | PORTE.DIRSET = PIN3_bm; 144 | PORTE.DIRCLR = PIN2_bm; 145 | // init_uart_bscale_bsel(&USARTE0, -5, 3301); // 19K2 @ 32MHz 146 | init_uart_bscale_bsel(&USARTE0, -5, 1079); // 57K6 @ 32MHz 147 | PORTD.DIRSET = PIN3_bm; 148 | PORTD.DIRCLR = PIN2_bm; 149 | init_uart_bscale_bsel(&USARTD0, -5, 3301); // 19K2 @ 32MHz 150 | stdout = stdin = &uart_stdio; 151 | 152 | _delay_ms(500); 153 | 154 | _uart_putc(0x1b); 155 | _uart_putc('E'); 156 | } 157 | 158 | static int 159 | do_joystick(basic_type* rv) 160 | { 161 | rv->kind = kind_numeric; 162 | rv->value.number = joystick_read_stick(); 163 | return 0; 164 | } 165 | 166 | static int 167 | do_button(basic_type* rv) 168 | { 169 | rv->kind = kind_numeric; 170 | rv->value.number = joystick_read_button(); 171 | return 0; 172 | } 173 | 174 | static int 175 | do_led(basic_type* status, basic_type* rv) 176 | { 177 | if(status->value.number>0){ 178 | PORTE.OUTSET = PIN0_bm; 179 | } else { 180 | PORTE.OUTCLR = PIN0_bm; 181 | } 182 | rv->kind = kind_numeric; 183 | rv->value.number = 0; 184 | return 0; 185 | } 186 | 187 | static int 188 | do_sound(basic_type* freq, basic_type* duration, basic_type* rv) 189 | { 190 | sound_play((uint16_t)freq->value.number, (uint16_t)(1000*duration->value.number)); 191 | rv->kind = kind_numeric; 192 | rv->value.number = 0; 193 | return 0; 194 | } 195 | 196 | static int 197 | do_plot(basic_type* x, basic_type* y, basic_type* code, basic_type* rv) 198 | { 199 | console_plot((int)x->value.number, (int)y->value.number, (unsigned char)code->value.number); 200 | rv->kind = kind_numeric; 201 | rv->value.number = 0; 202 | return 0; 203 | } 204 | 205 | static int 206 | do_defchar(basic_type* code, basic_type* definition, basic_type* rv) 207 | { 208 | console_def_char((unsigned char)code->value.number,definition->value.string); 209 | rv->kind = kind_numeric; 210 | rv->value.number = 0; 211 | return 0; 212 | } 213 | 214 | static int 215 | do_cursor(basic_type* cursor, basic_type* rv) 216 | { 217 | console_cursor((int)cursor->value.number); 218 | rv->kind = kind_numeric; 219 | rv->value.number = 0; 220 | return 0; 221 | } 222 | 223 | static int 224 | do_charat(basic_type* x, basic_type* y, basic_type* rv) 225 | { 226 | unsigned char at = console_charat((int)x->value.number, (int)y->value.number); 227 | rv->kind = kind_numeric; 228 | rv->value.number = at; 229 | return 0; 230 | } 231 | 232 | static int 233 | do_fontbank(basic_type* p1, basic_type* p2, basic_type* rv) 234 | { 235 | if(p2->empty){ // Called with 1 parameter 236 | int bank = (int) p1->value.number; 237 | for(int row=0; row<25; row++){ 238 | console_fontbank(row, bank); 239 | } 240 | } else { 241 | int row = (int) p1->value.number; 242 | int bank = (int) p2->value.number; 243 | console_fontbank(row, bank); 244 | } 245 | rv->kind = kind_numeric; 246 | rv->value.number = 0; 247 | return 0; 248 | } 249 | 250 | static int 251 | do_gfx(basic_type* gfx, basic_type* rv) 252 | { 253 | if(gfx->value.number>0){ 254 | console_cursor(0); 255 | console_cls(); 256 | console_line_overflow(0); 257 | for(int row=0; row<25; row++){ 258 | console_fontbank(row, 1); 259 | } 260 | } else { 261 | console_cursor(1); 262 | console_cls(); 263 | console_line_overflow(1); 264 | for(int row=0; row<25; row++){ 265 | console_fontbank(row, 0); 266 | } 267 | } 268 | rv->kind = kind_numeric; 269 | rv->value.number = 0; 270 | return 0; 271 | } 272 | 273 | static int 274 | do_hplot(basic_type* _x, basic_type* _y, basic_type* _set, basic_type* rv) 275 | { 276 | unsigned char x = (unsigned char)_x->value.number; 277 | unsigned char y = (unsigned char)_y->value.number; 278 | unsigned char set = (unsigned char)_set->value.number; 279 | 280 | unsigned char row ; 281 | unsigned char col ; 282 | unsigned char screen ; 283 | 284 | static unsigned char s_row = -1; 285 | static unsigned char s_col = -1; 286 | static unsigned char s_s = 0 ; 287 | 288 | row = y / 3 ; // 3 pixels down per character 289 | col = x / 2 ; // 2 pixels across per character 290 | 291 | if ((row == s_row) & (col == s_col)) 292 | { 293 | screen = s_s; 294 | } 295 | else 296 | { 297 | screen = console_charat(col, row); 298 | } 299 | 300 | if (screen >= 0) 301 | { 302 | s_row = row; 303 | s_col = col; 304 | 305 | unsigned char s = screen; 306 | s = s & 0b00111111 ; 307 | 308 | unsigned char yy = row * 3; 309 | unsigned char xx = col * 2; 310 | 311 | unsigned char shift = 0; 312 | if (x > xx) shift += 1; 313 | if (y > yy) shift += 2; 314 | if (y > (yy+1)) shift += 2; 315 | unsigned char bitvalue = 1 << shift ; 316 | 317 | if (set) 318 | { 319 | s = s | bitvalue ; // set the bit 320 | } 321 | else 322 | { 323 | s = s & ~bitvalue ; // clear the bit 324 | } 325 | s = 0b11000000 | s ; 326 | 327 | s_s = s ; 328 | 329 | if (s != screen) 330 | { 331 | console_plot(col, row, s); 332 | } 333 | } 334 | 335 | rv->kind = kind_numeric; 336 | rv->value.number = 0; 337 | return 0; 338 | } 339 | 340 | static int 341 | do_overflow(basic_type* overflow, basic_type* rv) 342 | { 343 | if(overflow->value.number>0){ 344 | console_line_overflow(1); 345 | } else { 346 | console_line_overflow(0); 347 | } 348 | rv->kind = kind_numeric; 349 | rv->value.number = 0; 350 | return 0; 351 | } 352 | 353 | static int 354 | do_invert(basic_type* invert, basic_type* rv) 355 | { 356 | if(invert->value.number>0){ 357 | console_invert(1); 358 | } else { 359 | console_invert(0); 360 | } 361 | rv->kind = kind_numeric; 362 | rv->value.number = 0; 363 | return 0; 364 | } 365 | 366 | static int 367 | do_at(basic_type* x, basic_type* y, basic_type* rv) 368 | { 369 | rv->kind = kind_numeric; 370 | rv->value.number = 10; 371 | console_move_cursor((int)x->value.number, (int)y->value.number); 372 | return 0; 373 | } 374 | 375 | static void 376 | batch(char *filename) 377 | { 378 | FIL fil; 379 | FRESULT fr; 380 | char line[tokenizer_string_length]; 381 | fr = f_open(&fil, filename, FA_READ); 382 | if(fr) return; 383 | while (f_gets(line, sizeof line, &fil)){ 384 | basic_eval(line); 385 | } 386 | f_close(&fil); 387 | } 388 | 389 | static int 390 | do_batch(basic_type* rv) 391 | { 392 | char filename[8+1+3+1]; 393 | accept(t_keyword_batch); 394 | if (sym != T_STRING) { 395 | error("EXPECTED LITERAL STRING"); 396 | return 0; 397 | } 398 | char *name = tokenizer_get_string(); 399 | accept(T_STRING); 400 | strncpy(filename,name,9); 401 | strcat(filename,".BAS"); 402 | batch(filename); 403 | return 0; 404 | } 405 | 406 | int main(int argc, char *argv[]) 407 | { 408 | char input[64]; 409 | 410 | init_xtal(); 411 | init_xmega(); 412 | sound_init(); 413 | joystick_init(); 414 | 415 | PORTE.DIRSET = PIN0_bm; // LED 416 | PORTE.OUTSET = PIN0_bm; // on 417 | 418 | // timer 419 | TCC0.CTRLB = TC_WGMODE_NORMAL_gc; 420 | TCC0.CTRLA = TC_CLKSEL_DIV256_gc; 421 | TCC0.INTCTRLA = TC_OVFINTLVL_LO_gc; 422 | TCC0.PER = 1249; // t = N * (PER+1) / f 423 | PMIC.CTRL |= PMIC_LOLVLEN_bm; 424 | sei(); 425 | 426 | tellymate_enable_transmit(); 427 | console_cursor(1); 428 | console_cursor_type(1); 429 | console_line_overflow(1); 430 | puts(" (\\/)"); 431 | puts(" ( ..)"); 432 | puts("C(\")(\")"); 433 | puts(""); 434 | puts("~BASIC-1~"); 435 | puts("(c) 2015-2017 JVdB"); 436 | puts(""); 437 | 438 | for(uint16_t i=0; i<3; i++){ 439 | sound_play(1000, 50); 440 | sound_play(0, 50); 441 | } 442 | sound_play(1000, 100); 443 | 444 | basic_register_io(uart_putc, keyboard_getc); 445 | basic_init(3072, 256); 446 | 447 | register_function_2(basic_function_type_keyword, "SOUND", do_sound, kind_numeric, kind_numeric); 448 | register_function_1(basic_function_type_keyword, "LED", do_led, kind_numeric); 449 | register_function_0(basic_function_type_numeric, "JOYSTICK", do_joystick); 450 | register_function_0(basic_function_type_numeric, "BUTTON", do_button); 451 | register_function_3(basic_function_type_keyword, "PLOT", do_plot, kind_numeric, kind_numeric, kind_numeric); 452 | register_function_2(basic_function_type_keyword, "DEFCHAR", do_defchar, kind_numeric, kind_string); 453 | register_function_1(basic_function_type_keyword, "CURSOR", do_cursor, kind_numeric); 454 | register_function_2(basic_function_type_numeric, "CHARAT", do_charat, kind_numeric, kind_numeric); 455 | register_function_2(basic_function_type_keyword, "FONTBANK", do_fontbank, kind_numeric, kind_numeric); 456 | register_function_1(basic_function_type_keyword, "GFX", do_gfx, kind_numeric); 457 | register_function_3(basic_function_type_keyword, "HPLOT", do_hplot, kind_numeric, kind_numeric, kind_numeric); 458 | register_function_1(basic_function_type_keyword, "OVERFLOW", do_overflow, kind_numeric); 459 | register_function_1(basic_function_type_keyword, "INVERT", do_invert, kind_numeric); 460 | register_function_2(basic_function_type_keyword, "AT", do_at, kind_numeric, kind_numeric); 461 | t_keyword_batch = register_function_0(basic_function_type_keyword, "BATCH", do_batch); 462 | 463 | batch("AUTORUN.BAS"); 464 | 465 | while(1) 466 | { 467 | basic_io_readline("", input, sizeof(input)); 468 | basic_eval(input); 469 | if (evaluate_last_error()) { 470 | printf("ERR LINE %d: %s\n", __line, evaluate_last_error()); 471 | clear_last_error(); 472 | } 473 | if(__STOPPED){ 474 | console_cursor(1); 475 | __STOPPED = false; 476 | } 477 | } 478 | 479 | return EXIT_SUCCESS; 480 | } 481 | -------------------------------------------------------------------------------- /arch/xmega/mmc.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* MMCv3/SDv1/SDv2 Controls via AVR USART-SPI */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* 5 | / Copyright (C) 2016, ChaN, all right reserved. 6 | / 7 | / * This software is a free software and there is NO WARRANTY. 8 | / * No restriction on use. You can use, modify and redistribute it for 9 | / any purpose as you like UNDER YOUR RESPONSIBILITY. 10 | / * Redistributions of source code must retain the above copyright notice. 11 | / 12 | /-------------------------------------------------------------------------*/ 13 | 14 | #include 15 | #include "diskio.h" 16 | 17 | #include "spi.h" 18 | 19 | /*-------------------------------------------------------------------------- 20 | 21 | Module Private Functions 22 | 23 | ---------------------------------------------------------------------------*/ 24 | 25 | /* Definitions for MMC/SDC command */ 26 | #define CMD0 (0) /* GO_IDLE_STATE */ 27 | #define CMD1 (1) /* SEND_OP_COND (MMC) */ 28 | #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ 29 | #define CMD8 (8) /* SEND_IF_COND */ 30 | #define CMD9 (9) /* SEND_CSD */ 31 | #define CMD10 (10) /* SEND_CID */ 32 | #define CMD12 (12) /* STOP_TRANSMISSION */ 33 | #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ 34 | #define CMD16 (16) /* SET_BLOCKLEN */ 35 | #define CMD17 (17) /* READ_SINGLE_BLOCK */ 36 | #define CMD18 (18) /* READ_MULTIPLE_BLOCK */ 37 | #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */ 38 | #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ 39 | #define CMD24 (24) /* WRITE_BLOCK */ 40 | #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ 41 | #define CMD32 (32) /* ERASE_ER_BLK_START */ 42 | #define CMD33 (33) /* ERASE_ER_BLK_END */ 43 | #define CMD38 (38) /* ERASE */ 44 | #define CMD48 (48) /* READ_EXTR_SINGLE */ 45 | #define CMD49 (49) /* WRITE_EXTR_SINGLE */ 46 | #define CMD55 (55) /* APP_CMD */ 47 | #define CMD58 (58) /* READ_OCR */ 48 | 49 | 50 | static volatile 51 | DSTATUS Stat = STA_NOINIT; /* Disk status */ 52 | 53 | static volatile 54 | BYTE Timer1, Timer2; /* 100Hz decrement timer */ 55 | 56 | static 57 | BYTE CardType; /* Card type flags (b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing) */ 58 | 59 | 60 | /*-----------------------------------------------------------------------*/ 61 | /* Power Control (Platform dependent) */ 62 | /*-----------------------------------------------------------------------*/ 63 | /* When the target system does not support socket power control, there */ 64 | /* is nothing to do in these functions and chk_power always returns 1. */ 65 | 66 | static 67 | void power_on (void) 68 | {} 69 | 70 | 71 | static 72 | void power_off (void) 73 | {} 74 | 75 | 76 | 77 | /*-----------------------------------------------------------------------*/ 78 | /* Transmit/Receive data from/to MMC via SPI (Platform dependent) */ 79 | /*-----------------------------------------------------------------------*/ 80 | 81 | /* Exchange a byte */ 82 | static 83 | BYTE xchg_spi ( /* Returns received data */ 84 | BYTE dat /* Data to be sent */ 85 | ) 86 | { 87 | return spi_transfer(dat); 88 | } 89 | 90 | /* Receive a data block fast */ 91 | static 92 | void rcvr_spi_multi ( 93 | BYTE *p, /* Data read buffer */ 94 | UINT cnt /* Size of data block */ 95 | ) 96 | { 97 | while(cnt--) *p++ = spi_read(); 98 | } 99 | 100 | 101 | /* Send a data block fast */ 102 | static 103 | void xmit_spi_multi ( 104 | const BYTE *p, /* Data block to be sent */ 105 | UINT cnt /* Size of data block */ 106 | ) 107 | { 108 | while(cnt--) spi_write(*p++); 109 | } 110 | 111 | #define FCLK_SLOW() spi_slow() 112 | #define FCLK_FAST() spi_fast() 113 | #define MMC_WP 0 114 | #define MMC_CD 1 115 | 116 | /*-----------------------------------------------------------------------*/ 117 | /* Wait for card ready */ 118 | /*-----------------------------------------------------------------------*/ 119 | 120 | static 121 | int wait_ready ( /* 1:Ready, 0:Timeout */ 122 | UINT wt /* Timeout [ms] */ 123 | ) 124 | { 125 | BYTE d; 126 | 127 | 128 | Timer2 = wt / 10; 129 | do 130 | d = xchg_spi(0xFF); 131 | while (d != 0xFF && Timer2); 132 | 133 | return (d == 0xFF) ? 1 : 0; 134 | } 135 | 136 | 137 | 138 | /*-----------------------------------------------------------------------*/ 139 | /* Deselect the card and release SPI bus */ 140 | /*-----------------------------------------------------------------------*/ 141 | 142 | static 143 | void deselect (void) 144 | { 145 | spi_cs_high(); /* Set CS# high */ 146 | xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */ 147 | } 148 | 149 | 150 | 151 | /*-----------------------------------------------------------------------*/ 152 | /* Select the card and wait for ready */ 153 | /*-----------------------------------------------------------------------*/ 154 | 155 | static 156 | int select (void) /* 1:Successful, 0:Timeout */ 157 | { 158 | spi_cs_low(); /* Set CS# low */ 159 | xchg_spi(0xFF); /* Dummy clock (force DO enabled) */ 160 | if (wait_ready(500)) return 1; /* Wait for card ready */ 161 | 162 | deselect(); 163 | return 0; /* Timeout */ 164 | } 165 | 166 | 167 | 168 | /*-----------------------------------------------------------------------*/ 169 | /* Receive a data packet from MMC */ 170 | /*-----------------------------------------------------------------------*/ 171 | 172 | static 173 | int rcvr_datablock ( 174 | BYTE *buff, /* Data buffer to store received data */ 175 | UINT btr /* Byte count (must be multiple of 4) */ 176 | ) 177 | { 178 | BYTE token; 179 | 180 | 181 | Timer1 = 20; 182 | do { /* Wait for data packet in timeout of 200ms */ 183 | token = xchg_spi(0xFF); 184 | } while ((token == 0xFF) && Timer1); 185 | if (token != 0xFE) return 0; /* If not valid data token, retutn with error */ 186 | 187 | rcvr_spi_multi(buff, btr); /* Receive the data block into buffer */ 188 | xchg_spi(0xFF); /* Discard CRC */ 189 | xchg_spi(0xFF); 190 | 191 | return 1; /* Return with success */ 192 | } 193 | 194 | 195 | 196 | /*-----------------------------------------------------------------------*/ 197 | /* Send a data packet to MMC */ 198 | /*-----------------------------------------------------------------------*/ 199 | 200 | #if _USE_WRITE 201 | static 202 | int xmit_datablock ( 203 | const BYTE *buff, /* 512 byte data block to be transmitted */ 204 | BYTE token /* Data/Stop token */ 205 | ) 206 | { 207 | BYTE resp; 208 | 209 | 210 | if (!wait_ready(500)) return 0; 211 | 212 | xchg_spi(token); /* Xmit data token */ 213 | if (token != 0xFD) { /* Is data token */ 214 | xmit_spi_multi(buff, 512); /* Xmit the data block to the MMC */ 215 | xchg_spi(0xFF); /* CRC (Dummy) */ 216 | xchg_spi(0xFF); 217 | resp = xchg_spi(0xFF); /* Reveive data response */ 218 | if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */ 219 | return 0; 220 | } 221 | 222 | return 1; 223 | } 224 | #endif 225 | 226 | 227 | 228 | /*-----------------------------------------------------------------------*/ 229 | /* Send a command packet to MMC */ 230 | /*-----------------------------------------------------------------------*/ 231 | 232 | static 233 | BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */ 234 | BYTE cmd, /* Command index */ 235 | DWORD arg /* Argument */ 236 | ) 237 | { 238 | BYTE n, res; 239 | 240 | 241 | if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ 242 | cmd &= 0x7F; 243 | res = send_cmd(CMD55, 0); 244 | if (res > 1) return res; 245 | } 246 | 247 | /* Select the card and wait for ready except to stop multiple block read */ 248 | if (cmd != CMD12) { 249 | deselect(); 250 | if (!select()) return 0xFF; 251 | } 252 | 253 | /* Send command packet */ 254 | xchg_spi(0x40 | cmd); /* Start + Command index */ 255 | xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ 256 | xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ 257 | xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ 258 | xchg_spi((BYTE)arg); /* Argument[7..0] */ 259 | n = 0x01; /* Dummy CRC + Stop */ 260 | if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) + Stop */ 261 | if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) Stop */ 262 | xchg_spi(n); 263 | 264 | /* Receive command response */ 265 | if (cmd == CMD12) xchg_spi(0xFF); /* Skip a stuff byte when stop reading */ 266 | n = 10; /* Wait for a valid response in timeout of 10 attempts */ 267 | do 268 | res = xchg_spi(0xFF); 269 | while ((res & 0x80) && --n); 270 | 271 | return res; /* Return with the response value */ 272 | } 273 | 274 | 275 | 276 | /*-------------------------------------------------------------------------- 277 | 278 | Public Functions 279 | 280 | ---------------------------------------------------------------------------*/ 281 | 282 | 283 | /*-----------------------------------------------------------------------*/ 284 | /* Initialize Disk Drive */ 285 | /*-----------------------------------------------------------------------*/ 286 | 287 | DSTATUS disk_initialize (BYTE pdrv) 288 | { 289 | BYTE n, cmd, ty, ocr[4]; 290 | 291 | 292 | power_off(); /* Turn off the socket power to reset the card */ 293 | for (Timer1 = 10; Timer1; ) ; /* Wait for 100ms */ 294 | if (Stat & STA_NODISK) return Stat; /* No card in the socket? */ 295 | 296 | power_on(); /* Turn on the socket power */ 297 | FCLK_SLOW(); 298 | for (n = 10; n; n--) xchg_spi(0xFF); /* 80 dummy clocks */ 299 | 300 | ty = 0; 301 | if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI mode */ 302 | Timer1 = 100; /* Initialization timeout of 1000 msec */ 303 | if (send_cmd(CMD8, 0x1AA) == 1) { /* Is the card SDv2? */ 304 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get trailing return value of R7 resp */ 305 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ 306 | while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */ 307 | if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ 308 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); 309 | ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Check if the card is SDv2 */ 310 | } 311 | } 312 | } else { /* SDv1 or MMCv3 */ 313 | if (send_cmd(ACMD41, 0) <= 1) { 314 | ty = CT_SD1; cmd = ACMD41; /* SDv1 */ 315 | } else { 316 | ty = CT_MMC; cmd = CMD1; /* MMCv3 */ 317 | } 318 | while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */ 319 | if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ 320 | ty = 0; 321 | } 322 | } 323 | CardType = ty; 324 | deselect(); 325 | 326 | if (ty) { /* Initialization succeded */ 327 | Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */ 328 | FCLK_FAST(); 329 | } else { /* Initialization failed */ 330 | power_off(); 331 | } 332 | 333 | return Stat; 334 | } 335 | 336 | 337 | 338 | /*-----------------------------------------------------------------------*/ 339 | /* Get Disk Status */ 340 | /*-----------------------------------------------------------------------*/ 341 | 342 | DSTATUS disk_status (BYTE pdrv) 343 | { 344 | return Stat; 345 | } 346 | 347 | 348 | 349 | /*-----------------------------------------------------------------------*/ 350 | /* Read Sector(s) */ 351 | /*-----------------------------------------------------------------------*/ 352 | 353 | DRESULT disk_read ( 354 | BYTE pdrv, 355 | BYTE *buff, /* Pointer to the data buffer to store read data */ 356 | DWORD sector, /* Start sector number (LBA) */ 357 | UINT count /* Sector count (1..128) */ 358 | ) 359 | { 360 | BYTE cmd; 361 | 362 | 363 | if (!count) return RES_PARERR; 364 | if (Stat & STA_NOINIT) return RES_NOTRDY; 365 | 366 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ 367 | 368 | cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ 369 | if (send_cmd(cmd, sector) == 0) { 370 | do { 371 | if (!rcvr_datablock(buff, 512)) break; 372 | buff += 512; 373 | } while (--count); 374 | if (cmd == CMD18) send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ 375 | } 376 | deselect(); 377 | 378 | return count ? RES_ERROR : RES_OK; 379 | } 380 | 381 | 382 | 383 | /*-----------------------------------------------------------------------*/ 384 | /* Write Sector(s) */ 385 | /*-----------------------------------------------------------------------*/ 386 | 387 | #if _USE_WRITE 388 | DRESULT disk_write ( 389 | BYTE pdrv, 390 | const BYTE *buff, /* Pointer to the data to be written */ 391 | DWORD sector, /* Start sector number (LBA) */ 392 | UINT count /* Sector count (1..128) */ 393 | ) 394 | { 395 | if (!count) return RES_PARERR; 396 | if (Stat & STA_NOINIT) return RES_NOTRDY; 397 | if (Stat & STA_PROTECT) return RES_WRPRT; 398 | 399 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */ 400 | 401 | if (count == 1) { /* Single block write */ 402 | if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ 403 | && xmit_datablock(buff, 0xFE)) 404 | count = 0; 405 | } 406 | else { /* Multiple block write */ 407 | if (CardType & CT_SDC) send_cmd(ACMD23, count); 408 | if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ 409 | do { 410 | if (!xmit_datablock(buff, 0xFC)) break; 411 | buff += 512; 412 | } while (--count); 413 | if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */ 414 | count = 1; 415 | } 416 | } 417 | deselect(); 418 | 419 | return count ? RES_ERROR : RES_OK; 420 | } 421 | #endif 422 | 423 | 424 | /*-----------------------------------------------------------------------*/ 425 | /* Miscellaneous Functions */ 426 | /*-----------------------------------------------------------------------*/ 427 | 428 | #if _USE_IOCTL 429 | DRESULT disk_ioctl ( 430 | BYTE pdrv, 431 | BYTE cmd, /* Control code */ 432 | void *buff /* Buffer to send/receive control data */ 433 | ) 434 | { 435 | DRESULT res; 436 | BYTE n, csd[16], *ptr = buff; 437 | DWORD csize; 438 | #if _USE_ISDIO 439 | SDIO_CTRL *sdi; 440 | BYTE rc, *bp; 441 | UINT dc; 442 | #endif 443 | 444 | if (Stat & STA_NOINIT) return RES_NOTRDY; 445 | 446 | res = RES_ERROR; 447 | switch (cmd) { 448 | case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */ 449 | if (select()) res = RES_OK; 450 | deselect(); 451 | break; 452 | 453 | case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ 454 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { 455 | if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ 456 | csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; 457 | *(DWORD*)buff = csize << 10; 458 | } else { /* SDC ver 1.XX or MMC*/ 459 | n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; 460 | csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; 461 | *(DWORD*)buff = csize << (n - 9); 462 | } 463 | res = RES_OK; 464 | } 465 | deselect(); 466 | break; 467 | 468 | case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ 469 | if (CardType & CT_SD2) { /* SDv2? */ 470 | if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ 471 | xchg_spi(0xFF); 472 | if (rcvr_datablock(csd, 16)) { /* Read partial block */ 473 | for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */ 474 | *(DWORD*)buff = 16UL << (csd[10] >> 4); 475 | res = RES_OK; 476 | } 477 | } 478 | } else { /* SDv1 or MMCv3 */ 479 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ 480 | if (CardType & CT_SD1) { /* SDv1 */ 481 | *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); 482 | } else { /* MMCv3 */ 483 | *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); 484 | } 485 | res = RES_OK; 486 | } 487 | } 488 | deselect(); 489 | break; 490 | 491 | /* Following commands are never used by FatFs module */ 492 | 493 | case MMC_GET_TYPE : /* Get card type flags (1 byte) */ 494 | *ptr = CardType; 495 | res = RES_OK; 496 | break; 497 | 498 | case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */ 499 | if (send_cmd(CMD9, 0) == 0 && rcvr_datablock(ptr, 16)) /* READ_CSD */ 500 | res = RES_OK; 501 | deselect(); 502 | break; 503 | 504 | case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */ 505 | if (send_cmd(CMD10, 0) == 0 && rcvr_datablock(ptr, 16)) /* READ_CID */ 506 | 507 | res = RES_OK; 508 | deselect(); 509 | break; 510 | 511 | case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */ 512 | if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */ 513 | for (n = 4; n; n--) *ptr++ = xchg_spi(0xFF); 514 | res = RES_OK; 515 | } 516 | deselect(); 517 | break; 518 | 519 | case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */ 520 | if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */ 521 | xchg_spi(0xFF); 522 | if (rcvr_datablock(ptr, 64)) res = RES_OK; 523 | } 524 | deselect(); 525 | break; 526 | 527 | case CTRL_POWER_OFF : /* Power off */ 528 | power_off(); 529 | Stat |= STA_NOINIT; 530 | res = RES_OK; 531 | break; 532 | #if _USE_ISDIO 533 | case ISDIO_READ: 534 | sdi = buff; 535 | if (send_cmd(CMD48, 0x80000000 | (DWORD)sdi->func << 28 | (DWORD)sdi->addr << 9 | ((sdi->ndata - 1) & 0x1FF)) == 0) { 536 | for (Timer1 = 100; (rc = xchg_spi(0xFF)) == 0xFF && Timer1; ) ; 537 | if (rc == 0xFE) { 538 | for (bp = sdi->data, dc = sdi->ndata; dc; dc--) *bp++ = xchg_spi(0xFF); 539 | for (dc = 514 - sdi->ndata; dc; dc--) xchg_spi(0xFF); 540 | res = RES_OK; 541 | } 542 | } 543 | deselect(); 544 | break; 545 | 546 | case ISDIO_WRITE: 547 | sdi = buff; 548 | if (send_cmd(CMD49, 0x80000000 | (DWORD)sdi->func << 28 | (DWORD)sdi->addr << 9 | ((sdi->ndata - 1) & 0x1FF)) == 0) { 549 | xchg_spi(0xFF); xchg_spi(0xFE); 550 | for (bp = sdi->data, dc = sdi->ndata; dc; dc--) xchg_spi(*bp++); 551 | for (dc = 514 - sdi->ndata; dc; dc--) xchg_spi(0xFF); 552 | if ((xchg_spi(0xFF) & 0x1F) == 0x05) res = RES_OK; 553 | } 554 | deselect(); 555 | break; 556 | 557 | case ISDIO_MRITE: 558 | sdi = buff; 559 | if (send_cmd(CMD49, 0x84000000 | (DWORD)sdi->func << 28 | (DWORD)sdi->addr << 9 | sdi->ndata >> 8) == 0) { 560 | xchg_spi(0xFF); xchg_spi(0xFE); 561 | xchg_spi(sdi->ndata); 562 | for (dc = 513; dc; dc--) xchg_spi(0xFF); 563 | if ((xchg_spi(0xFF) & 0x1F) == 0x05) res = RES_OK; 564 | } 565 | deselect(); 566 | break; 567 | #endif 568 | default: 569 | res = RES_PARERR; 570 | } 571 | 572 | return res; 573 | } 574 | #endif 575 | 576 | 577 | /*-----------------------------------------------------------------------*/ 578 | /* Device Timer Interrupt Procedure */ 579 | /*-----------------------------------------------------------------------*/ 580 | /* This function must be called in period of 10ms */ 581 | 582 | void disk_timerproc (void) 583 | { 584 | BYTE n, s; 585 | 586 | 587 | n = Timer1; /* 100Hz decrement timer */ 588 | if (n) Timer1 = --n; 589 | n = Timer2; 590 | if (n) Timer2 = --n; 591 | 592 | s = Stat; 593 | 594 | if (MMC_WP) /* Write protected */ 595 | s |= STA_PROTECT; 596 | else /* Write enabled */ 597 | s &= ~STA_PROTECT; 598 | 599 | if (MMC_CD) /* Card inserted */ 600 | s &= ~STA_NODISK; 601 | else /* Socket empty */ 602 | s |= (STA_NODISK | STA_NOINIT); 603 | 604 | Stat = s; /* Update MMC status */ 605 | } 606 | 607 | -------------------------------------------------------------------------------- /arch/xmega/mmc.h: -------------------------------------------------------------------------------- 1 | #ifndef __MMC_H__ 2 | #define __MMC_H__ 3 | 4 | #include "diskio.h" 5 | 6 | #endif // __MMC_H__ 7 | -------------------------------------------------------------------------------- /arch/xmega/sound.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static volatile size_t _sound_ticks; 8 | 9 | void sound_timerproc(void) 10 | { 11 | if(_sound_ticks>0){ 12 | _sound_ticks--; 13 | return; 14 | } 15 | } 16 | 17 | void sound_init(void) 18 | { 19 | PORTE.OUTCLR = PIN1_bm; 20 | PORTE.DIRSET = PIN1_bm; 21 | TCE0.CTRLA = TC_CLKSEL_OFF_gc; 22 | TCE0.CTRLB = TC0_CCBEN_bm| TC_WGMODE_FRQ_gc; 23 | } 24 | 25 | void sound_play(uint16_t f, uint16_t ms) 26 | { 27 | _sound_ticks = ms / 10; 28 | if (f>0){ 29 | TCE0.CCABUF = (((uint32_t) F_CPU/f) >> 2) - 1; 30 | TCE0.CNT = 0; // reset timer/counter 31 | TCE0.CTRLA = TC_CLKSEL_DIV2_gc; // prescaling 32 | } 33 | while(_sound_ticks > 0){ 34 | __asm__ volatile ("nop"); 35 | } 36 | if(f>0){ 37 | TCE0.CTRLA = TC_CLKSEL_OFF_gc; // timer/counter off 38 | TCE0.CTRLC = 0; // outputs low 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /arch/xmega/sound.h: -------------------------------------------------------------------------------- 1 | #ifndef __SOUND_H__ 2 | #define __SOUND_H__ 3 | 4 | void sound_timerproc(void); 5 | void sound_init(void); 6 | void sound_play(uint16_t freq, uint16_t duration); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /arch/xmega/spi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "spi.h" 3 | 4 | #define SPI_SS_bm 0x10 5 | #define SPI_MOSI_bm 0x20 6 | #define SPI_MISO_bm 0x40 7 | #define SPI_SCK_bm 0x80 8 | 9 | #define FOO 0x00 10 | 11 | void spi_init(void) 12 | { 13 | PORTC.DIRSET = SPI_SCK_bm | SPI_MOSI_bm | SPI_SS_bm; 14 | PORTC.DIRCLR = SPI_MISO_bm; 15 | PORTC.OUTSET = SPI_SS_bm; 16 | spi_fast(); 17 | } 18 | 19 | void spi_fast(void) 20 | { 21 | SPIC.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_MODE_0_gc | SPI_PRESCALER_DIV4_gc; 22 | } 23 | 24 | void spi_slow(void) 25 | { 26 | SPIC.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_MODE_0_gc | SPI_PRESCALER_DIV128_gc; 27 | } 28 | 29 | uint8_t spi_transfer(uint8_t data) 30 | { 31 | SPIC.DATA = data; 32 | while(!(SPIC.STATUS & (SPI_IF_bm))); 33 | return SPIC.DATA; 34 | } 35 | 36 | void spi_write(uint8_t data) 37 | { 38 | // PORTC.OUTCLR = SPI_SS_bm; 39 | spi_transfer(data); 40 | // PORTC.OUTSET = SPI_SS_bm; 41 | } 42 | 43 | uint8_t spi_read(void) 44 | { 45 | uint8_t data; 46 | 47 | // PORTC.OUTCLR = SPI_SS_bm; 48 | data = spi_transfer(FOO); 49 | // PORTC.OUTSET = SPI_SS_bm; 50 | 51 | return data; 52 | } 53 | 54 | void spi_cs_high(void) 55 | { 56 | PORTC.OUTSET = SPI_SS_bm; 57 | // PORTC.OUTCLR = SPI_SS_bm; 58 | } 59 | 60 | void spi_cs_low(void) 61 | { 62 | PORTC.OUTCLR = SPI_SS_bm; 63 | // PORTC.OUTSET = SPI_SS_bm; 64 | } 65 | -------------------------------------------------------------------------------- /arch/xmega/spi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SPI_H__ 2 | #define __SPI_H__ 3 | 4 | void spi_init(void); 5 | uint8_t spi_transfer(uint8_t data); 6 | void spi_write(uint8_t data); 7 | uint8_t spi_read(void); 8 | void spi_cs_high(void); 9 | void spi_cs_low(void); 10 | void spi_fast(void); 11 | void spi_slow(void); 12 | 13 | #endif // __SPI_H__ 14 | -------------------------------------------------------------------------------- /basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanoflite/basic/10e52bc52aa107890580aef659f8180ddbff3125/basic.png -------------------------------------------------------------------------------- /examples/FORY.bas: -------------------------------------------------------------------------------- 1 | 10 FOR X=1 TO 30 2 | 20 LET Y=X 3 | 30 PRINT Y 4 | 40 NEXT X 5 | -------------------------------------------------------------------------------- /examples/autolist: -------------------------------------------------------------------------------- 1 | ./examples/FORY.bas 2 | ./examples/circle.bas 3 | ./examples/data.bas 4 | ./examples/data_array.bas 5 | ./examples/data_numeric.bas 6 | ./examples/diamond.bas 7 | ./examples/dim.bas 8 | ./examples/expr.bas 9 | ./examples/for.bas 10 | ./examples/for_colon.bas 11 | ./examples/gosub.bas 12 | ./examples/goto.bas 13 | ./examples/if.bas 14 | ./examples/if_and_or.bas 15 | ./examples/if_goto.bas 16 | ./examples/left.bas 17 | ./examples/math.bas 18 | ./examples/mid.bas 19 | ./examples/nested_for.bas 20 | ./examples/on_goto.bas 21 | ./examples/right.bas 22 | ./examples/sine_wave.bas 23 | ./examples/sleep.bas 24 | ./examples/strings.bas 25 | ./examples/test_for.bas 26 | ./examples/the_first_basic_program.bas 27 | -------------------------------------------------------------------------------- /examples/circle.bas: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env basic 2 | 3 | 10 RADIUS=10 4 | 20 FOR I=1 TO RADIUS-1 5 | 30 W=INT(RADIUS*SIN(180/RADIUS*I*3.1415/180)) 6 | 40 PRINT SPC(RADIUS-W);:FOR J=1 TO 2*W:PRINT "*";:NEXT J:PRINT 7 | 50 NEXT I 8 | -------------------------------------------------------------------------------- /examples/data.bas: -------------------------------------------------------------------------------- 1 | 100 PRINT "DATA TEST" 2 | 110 READ A$ 3 | 115 PRINT "VALUE A" 4 | 120 PRINT A$ 5 | 130 READ B$ 6 | 135 PRINT "VALUE B" 7 | 140 PRINT B$ 8 | 150 RESTORE 9 | 160 READ A$ 10 | 170 PRINT "VALUE A: "; 11 | 180 PRINT A$ 12 | 190 END 13 | 200 DATA "Ik ben DATA", "En ik ook" 14 | -------------------------------------------------------------------------------- /examples/data_array.bas: -------------------------------------------------------------------------------- 1 | 1000 PRINT "### DATA READ INTO ARRAY ###" 2 | 1010 DIM A(5) 3 | 1025 PRINT "READ DATA" 4 | 1020 FOR I=1 TO 5 5 | 1025 PRINT "READ INDEX ";I 6 | 1030 READ A(I) 7 | 1035 PRINT "DONE" 8 | 1040 NEXT 9 | 1050 PRINT "PRINT DATA" 10 | 1060 FOR I=1 TO 5 11 | 1070 PRINT A(I) 12 | 1080 NEXT 13 | 1090 PRINT "DONE" 14 | 1050 END 15 | 2000 DATA 10,20,30,40,50 16 | -------------------------------------------------------------------------------- /examples/data_numeric.bas: -------------------------------------------------------------------------------- 1 | 100 PRINT "DATA/READ/RESTORE TEST" 2 | 110 READ A, B, C 3 | 120 PRINT A 4 | 130 PRINT B 5 | 140 PRINT C 6 | 150 RESTORE 7 | 160 READ D, E, F 8 | 170 PRINT D 9 | 180 PRINT E 10 | 190 PRINT F 11 | 200 DATA 1,2 12 | 205 REM MORE DATA 13 | 210 DATA 3 14 | -------------------------------------------------------------------------------- /examples/data_test.bas: -------------------------------------------------------------------------------- 1 | 100 FOR I=0 TO 31 2 | 110 READ D$ 3 | 120 PRINT D$ 4 | 130 NEXT I 5 | 1000 END 6 | 5000 DATA "000000030C10207C82","000000F028444A4A22" 7 | 5010 DATA "827C20180601000000","1E215E221CE0000000" 8 | 5020 DATA "000000030C10788482","C64438080601000000" 9 | 5030 DATA "000000030C10204040","7E8182844E39000000" 10 | 5040 DATA "0000000000000000FC","043434370404353535" 11 | 5050 DATA "040535353404053535","3404C4C4C400000000" 12 | 5060 DATA "000000000000070404","050505FC0405B5B5B4" 13 | 5070 DATA "04B5B5B50404B5B5B5","0404E5E5E500000000" 14 | 5080 DATA "1F1010131313F00000","999999000099999900" 15 | 5090 DATA "009999990000999999","000099999900000000" 16 | 5100 DATA "E0202020202020203F","A0A0AC2C2CA0A0AC2C" 17 | 5110 DATA "2CA0ACAC2C20A0ACAC","2C20ADADA100000000" 18 | 5120 DATA "191919191919191919","F8F8F8F8F8F8F8F8F8" 19 | 5130 DATA "FFFFC0C0CFCFFFFF00","FFFF0303FFFFFFFF00" 20 | 5140 DATA "00FFFFCFCFC0C0FFFF","00FFFFFFFF0303FFFF" 21 | 5150 DATA "FFFEFCF8F0E0C08000","0103070F1F3F7FFF00" 22 | -------------------------------------------------------------------------------- /examples/diamond.bas: -------------------------------------------------------------------------------- 1 | #!/Users/johan/Projects/BASIC/basic/build/basic/basic 2 | 3 | 10 LINES=17 4 | 20 FOR I=1 TO LINES/2+1 5 | 30 FOR J=1 TO (LINES+1)/2-I+1:PRINT " ";:NEXT 6 | 40 FOR J=1 TO I*2-1:PRINT "*";:NEXT 7 | 50 PRINT 8 | 60 NEXT I 9 | 70 FOR I=1 TO LINES/2 10 | 80 FOR J=1 TO I+1:PRINT " ";:NEXT 11 | 90 FOR J=1 TO ((LINES+1)/2-I)*2-1:PRINT "*";:NEXT 12 | 100 PRINT 13 | 110 NEXT I 14 | -------------------------------------------------------------------------------- /examples/dim.bas: -------------------------------------------------------------------------------- 1 | 1000 DIM A(5, 7) 2 | 1010 FOR I=1 TO 5 3 | 1020 FOR J=1 TO 7 4 | 1030 PRINT "PUT ";I;", ";J 5 | 1040 A(I,J) = I*10 + J 6 | 1050 NEXT J 7 | 1060 NEXT I 8 | 1070 FOR I=1 TO 5 9 | 1080 FOR J=1 TO 7 10 | 1090 PRINT "GET ";I;", ";J 11 | 1100 PRINT A(I, J) 12 | 1110 NEXT J 13 | 1120 NEXT I 14 | -------------------------------------------------------------------------------- /examples/expr.bas: -------------------------------------------------------------------------------- 1 | 10 Q=RND(1) 2 | 20 N=1 3 | 30 R=.592*(1/TAN(Q/N+Q))/SIN(N*2+Q)-COS(N) 4 | 40 PRINT R 5 | -------------------------------------------------------------------------------- /examples/for.bas: -------------------------------------------------------------------------------- 1 | 100 PRINT "FOR test" 2 | 110 FOR A=0 TO 10 3 | 120 PRINT A 4 | 130 NEXT 5 | 140 PRINT "done" 6 | -------------------------------------------------------------------------------- /examples/for_colon.bas: -------------------------------------------------------------------------------- 1 | 100 FOR A=1 TO 10: FOR B=1 TO 5 2 | 110 PRINT A*B 3 | 120 NEXT B: NEXT A 4 | -------------------------------------------------------------------------------- /examples/get.bas: -------------------------------------------------------------------------------- 1 | 100 PRINT "Type max. 20 chars, please: ";:GOSUB 1000 2 | 200 PRINT: PRINT "You have written: ";B$ 3 | 300 END 4 | 1000 REM simple GET-INPUT-Routine 5 | 1010 A$="": B$="": A=0: REM initialize variables 6 | 1020 GET A$: IF A$="" THEN 1020 7 | 1030 A=ASC(A$): IF (A<32 OR A>127) AND A<>13 THEN 1020 8 | 1040 REM B$=B$+A$: PRINT A$;: IF LEN(B$)<20 AND A$<>CHR$(13) THEN 1020 9 | 1045 B$=B$+A$: IF LEN(B$)<20 AND A$<>CHR$(13) THEN 1020 10 | 1050 RETURN 11 | -------------------------------------------------------------------------------- /examples/gosub.bas: -------------------------------------------------------------------------------- 1 | 100 GOSUB 500 2 | 110 PRINT "B" 3 | 120 END 4 | 500 PRINT "A" 5 | 510 RETURN 6 | -------------------------------------------------------------------------------- /examples/goto.bas: -------------------------------------------------------------------------------- 1 | 1000 GOTO 2000 2 | 1010 PRINT "END" 3 | 1020 END 4 | 2000 PRINT "A" 5 | 2010 GOTO 3000 6 | 3000 PRINT "B" 7 | 3010 GOTO 1010 8 | -------------------------------------------------------------------------------- /examples/if.bas: -------------------------------------------------------------------------------- 1 | 100 FOR A=1 TO 10 2 | 110 IF A=5 THEN PRINT "FIVE" 3 | 120 NEXT 4 | -------------------------------------------------------------------------------- /examples/if_and_or.bas: -------------------------------------------------------------------------------- 1 | 100 FOR A=1 TO 2 2 | 110 FOR B=1 TO 2 3 | 120 PRINT "A=";A;" B=";B 4 | 130 IF A=1 AND B=2 THEN PRINT " --> A=1 AND B=2" 5 | 140 IF A=2 OR B=2 THEN PRINT " --> A=2 OR B=2" 6 | 150 IF A=2 AND B=2 THEN PRINT " --> A AND B ARE 2";:PRINT "... AND THIS SHOWS UP ALSO" 7 | 160 NEXT 8 | 170 NEXT 9 | -------------------------------------------------------------------------------- /examples/if_goto.bas: -------------------------------------------------------------------------------- 1 | 10 A=1 2 | 20 IF A=1 THEN 40 3 | 30 END 4 | 40 PRINT "OK" 5 | -------------------------------------------------------------------------------- /examples/input.bas: -------------------------------------------------------------------------------- 1 | 10 PRINT "what is your name?" 2 | 20 INPUT "...(Enter Your Name)...", A$ 3 | 30 PRINT 4 | 40 PRINT "hello, "; A$; ", I am your computer, nice to meet you." 5 | -------------------------------------------------------------------------------- /examples/left.bas: -------------------------------------------------------------------------------- 1 | 10 A$="BASIC" 2 | 20 B$=LEFT$(A$, 3) 3 | 30 PRINT B$ 4 | -------------------------------------------------------------------------------- /examples/math.bas: -------------------------------------------------------------------------------- 1 | 10 INPUT"ENTER A NUMBER";N 2 | 20 ?"ABS(N)=";ABS(N) 3 | 25 ?"ATN(N)=";ATN(N) 4 | 30 ?"COS(N)=";COS(N) 5 | 40 ?"EXP(N)=";EXP(N) 6 | 50 ?"INT(N)=";INT(N) 7 | 60 ?"LOG(N)=";LOG(N) 8 | 70 ?"SGN(N)=";SGN(N) 9 | 80 ?"SQR(N)=";SQR(N) 10 | 90 ?"TAN(N)=";TAN(N) 11 | -------------------------------------------------------------------------------- /examples/mid.bas: -------------------------------------------------------------------------------- 1 | 10 A$="GOOD" 2 | 20 B$="MORNING EVENING AFTERNOON" 3 | 30 PRINT A$; 4 | 40 PRINT MID$(B$, 8, 8) 5 | -------------------------------------------------------------------------------- /examples/nested_for.bas: -------------------------------------------------------------------------------- 1 | 100 FOR A=1 TO 5 2 | 110 FOR B=10 TO 15 3 | 120 PRINT A+B 4 | 130 NEXT 5 | 140 NEXT 6 | -------------------------------------------------------------------------------- /examples/on_goto.bas: -------------------------------------------------------------------------------- 1 | 10 A=1 2 | 20 ON A GOTO 100,200,300 3 | 30 A=A+1 4 | 40 IF A>3 THEN 60 5 | 50 GOTO 20 6 | 60 END 7 | 100 PRINT "1" 8 | 110 GOTO 30 9 | 200 PRINT "2" 10 | 210 GOTO 30 11 | 300 PRINT "3" 12 | 310 GOTO 30 13 | -------------------------------------------------------------------------------- /examples/right.bas: -------------------------------------------------------------------------------- 1 | 10 A$="DISK BASIC" 2 | 20 PRINT RIGHT$(A$, 5) 3 | -------------------------------------------------------------------------------- /examples/simple-basic/happy_birthday.bas: -------------------------------------------------------------------------------- 1 | 10 CLS 2 | 20 LET A$="HAPPY BIRTHDAY" 3 | 30 PRINT:PRINT:PRINT 4 | 40 FOR K=1 TO LEN(A$) 5 | 50 PRINT MID$(A$,K,1); 6 | 60 FOR L=1 TO 10000: NEXT L 7 | 70 NEXT K 8 | 80 PRINT:PRINT:PRINT 9 | 90 PRINT "LOVE FROM" 10 | 100 PRINT "YOUR COMPUTER" 11 | -------------------------------------------------------------------------------- /examples/simple-basic/input.bas: -------------------------------------------------------------------------------- 1 | 10 REM CLS 2 | 20 PRINT "WHAT'S YOUR NAME?" 3 | 30 INPUT N$ 4 | 40 PRINT "HOW OLD ARE YOU?" 5 | 50 INPUT A 6 | 60 REM CLS 7 | 70 PRINT N$;" IS ";A 8 | 80 PRINT "YEARS OLD" 9 | -------------------------------------------------------------------------------- /examples/sine_wave.bas: -------------------------------------------------------------------------------- 1 | 100 PRINT SPC(20);"SINE WAVE" 2 | 110 PRINT SPC(10);"CREATIVE BASIC - JOHAN VDB" 3 | 120 PRINT: PRINT: PRINT: PRINT: PRINT 4 | 200 B=0 5 | 210 FOR I=0 TO 40 STEP 0.25 6 | 220 A=INT(40+40*SIN(I)) 7 | 230 PRINT SPC(A); 8 | 240 IF B=1 THEN GOTO 280 9 | 250 PRINT "CREATIVE" 10 | 260 B=1 11 | 270 GOTO 300 12 | 280 PRINT "BASIC" 13 | 290 B=0 14 | 300 NEXT 15 | 310 END 16 | -------------------------------------------------------------------------------- /examples/sleep.bas: -------------------------------------------------------------------------------- 1 | 10 INPUT "YOUR NAME", NAME$ 2 | 20 CLS 3 | 30 FOR I=1 TO LEN(NAME$) 4 | 40 PRINT MID$(NAME$,I,1); 5 | 50 SLEEP(500) 6 | 60 NEXT 7 | -------------------------------------------------------------------------------- /examples/strings.bas: -------------------------------------------------------------------------------- 1 | 10 REM INPUT"ENTER A STRING";A$ 2 | 20 REM INPUT"ENTER A NUMBER";N 3 | 25 A$="HALLO": N=2 4 | 26 PRINT "STRING=";A$;", NUMBER=";N 5 | 30 ?"ASC(A$)=";ASC(A$) 6 | 40 ?"CHR$(N)=";CHR$(N) 7 | 50 ?"LEFT$(A$,N)=";LEFT$(A$,N) 8 | 60 ?"MID$(A$,N)=";MID$(A$,N) 9 | 70 ?"MID$(A$,N,3)=";MID$(A$,N,3) 10 | 80 ?"RIGHT$(A$,N)=";RIGHT$(A$,N) 11 | 90 ?"LEN(A$)=";LEN(A$) 12 | 100 ?"VAL(A$)=";VAL(A$) 13 | 110 ?"STR$(N)=";STR$(N) 14 | 120 ?"SPC(N)='";SPC(N);"'" 15 | -------------------------------------------------------------------------------- /examples/test_for.bas: -------------------------------------------------------------------------------- 1 | 100 FOR A=1 TO 2 2 | 200 FOR B=1 TO 2 3 | 300 PRINT "A=";A;", B=";B 4 | 400 IF A=1 THEN PRINT "--> A=1" 5 | 500 NEXT B 6 | 600 NEXT A 7 | -------------------------------------------------------------------------------- /examples/the_first_basic_program.bas: -------------------------------------------------------------------------------- 1 | 10 LET X = (7 + 8) / 3 2 | 20 PRINT X 3 | 30 END 4 | -------------------------------------------------------------------------------- /examples/toss_a_coin.bas: -------------------------------------------------------------------------------- 1 | 100 REM TOSS A COIN 2 | 110 C=INT(RND(1)*2) 3 | 120 IF C=0 THEN GOTO 180 4 | 130 PRINT "TAILS" 5 | 140 PRINT "TRY AGAIN?"; 6 | 150 INPUT T$ 7 | 160 IF T$="Y" THEN GOTO 110 8 | 170 END 9 | 180 PRINT "HEADS" 10 | 190 GOTO 140 11 | -------------------------------------------------------------------------------- /examples/var.bas: -------------------------------------------------------------------------------- 1 | 10 A=1 2 | 20 A=2 3 | 30 A=3 4 | 40 PRINT A 5 | -------------------------------------------------------------------------------- /include/arch.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_H__ 2 | #define __ARCH_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef _WIN32 9 | #if ARCH==ARCH_XMEGA 10 | int asprintf(char **ret, const char *format, ...); 11 | float strtof(const char *restrict nptr, char **restrict endptr); 12 | char *strndup(const char *s1, size_t n); 13 | #endif 14 | #endif 15 | 16 | int arch_init(void); 17 | 18 | typedef void (*arch_load_out_cb)(char *line, void* context); 19 | int arch_load(char* filename, arch_load_out_cb cb, void* context); 20 | 21 | typedef uint16_t (*arch_save_cb)(char** line, void* context); 22 | int arch_save(char* filename, arch_save_cb cb, void* context); 23 | 24 | typedef void (*arch_dir_out_cb)(char *name, size_t size, bool label, void* context); 25 | int arch_dir(arch_dir_out_cb cb, void* context); 26 | 27 | int arch_delete(char* filename); 28 | 29 | #endif // __ARCH_H__ 30 | -------------------------------------------------------------------------------- /include/array.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARRAY_H__ 2 | #define __ARRAY_H__ 3 | 4 | typedef struct array array; 5 | 6 | array* array_new(size_t element_size); 7 | 8 | array* array_alloc(array* array, size_t size); 9 | 10 | void array_destroy(array* array); 11 | 12 | void* array_push(array* array, void* value); 13 | 14 | void* array_get(array* array, size_t index); 15 | 16 | void* array_set(array* array, size_t index, void* value); 17 | 18 | size_t array_size(array* array); 19 | 20 | 21 | #endif // __ARRAY_H__ 22 | -------------------------------------------------------------------------------- /include/callback.h: -------------------------------------------------------------------------------- 1 | #ifndef __CALLBACK_H__ 2 | #define __CALLBACK_H__ 3 | 4 | #include 5 | 6 | typedef struct 7 | error 8 | { 9 | int error; 10 | }; 11 | 12 | typedef bool (*callback)(error err, void* data); 13 | 14 | #endif // __CALLBACK_H__ 15 | -------------------------------------------------------------------------------- /include/dictionary.h: -------------------------------------------------------------------------------- 1 | #ifndef __DICTIONARY_H__ 2 | #define __DICTIONARY_H__ 3 | 4 | #include 5 | 6 | typedef struct dictionary dictionary; 7 | 8 | typedef void (*dictionary_each_cb)(char* name, void* value, void* context); 9 | 10 | dictionary* dictionary_new(void); 11 | void dictionary_destroy(dictionary* d, dictionary_each_cb cb); 12 | void dictionary_put(dictionary* d, char* name, void* value); 13 | bool dictionary_has(dictionary* d, char* name); 14 | void* dictionary_get(dictionary* d, char* name); 15 | void dictionary_each(dictionary* d, dictionary_each_cb cb, void* context); 16 | void* dictionary_del(dictionary* d, char* name); 17 | 18 | #endif // __DICTIONARY_H__ 19 | -------------------------------------------------------------------------------- /include/error.h: -------------------------------------------------------------------------------- 1 | #ifndef __ERROR_H__ 2 | #define __ERROR_H__ 3 | 4 | extern char *last_error; 5 | void error(const char *error_msg); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /include/hexdump.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEXDUMP_H__ 2 | #define __HEXDUMP_H__ 3 | 4 | void hexdump ( char *desc, void *addr, int len ); 5 | 6 | #endif // __HEXDUMP_H__ 7 | -------------------------------------------------------------------------------- /include/io.h: -------------------------------------------------------------------------------- 1 | #ifndef __IO_H__ 2 | #define __IO_H__ 3 | 4 | #include 5 | 6 | typedef int (*basic_putchar)(int ch); 7 | typedef int (*basic_getchar)(void); 8 | void basic_io_print(char* buffer); 9 | char* basic_io_readline(char* prompt, char* buffer, size_t buffer_size); 10 | 11 | #endif // __IO_H__ 12 | -------------------------------------------------------------------------------- /include/kbhit.h: -------------------------------------------------------------------------------- 1 | #ifndef __KBHIT_H__ 2 | #define __KBHIT_H__ 3 | 4 | int kbhit(void); 5 | 6 | #endif // __KBHIT_H__ 7 | -------------------------------------------------------------------------------- /include/lines.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINES_H__ 2 | #define __LINES_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct line line; 8 | 9 | struct line 10 | { 11 | uint16_t number; 12 | uint8_t length; 13 | char contents; 14 | }; 15 | 16 | void lines_init(char *memory, size_t memory_size); 17 | 18 | size_t lines_memory_used(void); 19 | size_t lines_memory_available(void); 20 | 21 | bool lines_delete(uint16_t number); 22 | 23 | bool lines_store(uint16_t number, char* contents ); 24 | 25 | typedef void (*lines_list_cb)(uint16_t number, char* contents); 26 | 27 | void lines_list(uint16_t start, uint16_t end, lines_list_cb out); 28 | 29 | void lines_clear(void); 30 | 31 | char* lines_get_contents(uint16_t number); 32 | 33 | uint16_t lines_first(void); 34 | uint16_t lines_next(uint16_t number); 35 | 36 | #endif // __LINES_H__ 37 | -------------------------------------------------------------------------------- /include/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef __PARSER_H__ 2 | #define __PARSER_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | float evaluate(char *expression_string); 10 | 11 | void evaluate_print(char *line); 12 | 13 | void evaluate_print_func_param( char *func, float param); 14 | 15 | const char* evaluate_last_error(void); 16 | void clear_last_error(void); 17 | 18 | void basic_init(size_t memory_size, size_t stack_size); 19 | 20 | void basic_destroy(void); 21 | 22 | void basic_register_io(basic_putchar putch, basic_getchar getch); 23 | 24 | char* basic_readline(char* prompt, char* buffer, size_t buffer_size); 25 | 26 | void basic_eval(char *line); 27 | void basic_run(void); 28 | 29 | // For extensions 30 | 31 | typedef float (*function)(float number); 32 | 33 | typedef struct 34 | { 35 | token _token; 36 | function _function; 37 | } token_to_function; 38 | 39 | typedef enum { 40 | basic_function_type_keyword, 41 | basic_function_type_op, 42 | basic_function_type_numeric, 43 | basic_function_type_string, 44 | basic_function_type_print 45 | } basic_function_type; 46 | 47 | typedef enum { 48 | kind_numeric, 49 | kind_string 50 | } kind; 51 | 52 | typedef union { 53 | float number; 54 | char* string; 55 | } value; 56 | 57 | typedef struct { 58 | kind kind; 59 | bool empty; 60 | bool mallocd; 61 | value value; 62 | } basic_type; 63 | 64 | typedef int (*function_0)(basic_type* rv); 65 | typedef int (*function_1)(basic_type* v1, basic_type* rv); 66 | typedef int (*function_2)(basic_type* v1, basic_type* v2, basic_type* rv); 67 | typedef int (*function_3)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* rv); 68 | typedef int (*function_4)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* v4, basic_type* rv); 69 | typedef int (*function_5)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* v4, basic_type* v5, basic_type* rv); 70 | 71 | token register_token(char* token_name); 72 | token register_function_0(basic_function_type type, char* keyword, function_0 function); 73 | token register_function_1(basic_function_type type, char* keyword, function_1 function, kind v1); 74 | token register_function_2(basic_function_type type, char* keyword, function_2 function, kind v1, kind v2); 75 | token register_function_3(basic_function_type type, char* keyword, function_3 function, kind v1, kind v2, kind v3); 76 | token register_function_4(basic_function_type type, char* keyword, function_4 function, kind v1, kind v2, kind v3, kind v4); 77 | token register_function_5(basic_function_type type, char* keyword, function_5 function, kind v1, kind v2, kind v3, kind v4, kind v5); 78 | 79 | #endif // __PARSER_H__ 80 | -------------------------------------------------------------------------------- /include/tokenizer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TOKENIZER_H__ 2 | #define __TOKENIZER_H__ 3 | 4 | #include 5 | 6 | #define tokenizer_string_length 64 7 | #define tokenizer_variable_length 8 8 | 9 | typedef unsigned int token; 10 | typedef char* token_name; 11 | typedef char* token_keyword; 12 | 13 | typedef struct { 14 | token token; 15 | token_name name; 16 | } token_entry; 17 | 18 | #define add_token(t, k) \ 19 | static token_entry _##t = { t, k }; 20 | 21 | typedef enum { 22 | // Standard token types needed by the tokenizer 23 | T_THE_END, 24 | T_ERROR, 25 | T_EOF, 26 | T_NUMBER, 27 | T_STRING, 28 | T_VARIABLE_STRING, 29 | T_VARIABLE_NUMBER, 30 | 31 | // Some tokens that are standard as well 32 | T_PLUS, 33 | T_MINUS, 34 | T_MULTIPLY, 35 | T_DIVIDE, 36 | T_LEFT_BANANA, 37 | T_RIGHT_BANANA, 38 | T_COLON, 39 | T_SEMICOLON, 40 | T_EQUALS, 41 | T_LESS, 42 | T_GREATER, 43 | T_COMMA, 44 | TOKEN_TYPE_END 45 | } token_type; 46 | 47 | void tokenizer_setup(void); 48 | void tokenizer_init(char *input); 49 | token tokenizer_get_next_token(void); 50 | 51 | float tokenizer_get_number(void); 52 | char * tokenizer_get_string(void); 53 | void tokenizer_get_variable_name(char *name); 54 | 55 | char *tokenizer_token_name(token); 56 | 57 | char* tokenizer_char_pointer(char* set); 58 | 59 | void tokenizer_add_tokens( token_entry* tokens ); 60 | 61 | void tokenizer_register_token( token_entry* entry ); 62 | void tokenizer_free_registered_tokens(void); 63 | 64 | #endif // __TOKENIZER_H__ 65 | -------------------------------------------------------------------------------- /include/usingwin.h: -------------------------------------------------------------------------------- 1 | #ifndef __USINGWIN__ 2 | #define __USINGWIN__ 3 | 4 | #ifdef _WIN32 5 | #define C_STRDUP _strdup 6 | #else 7 | #define C_STRDUP strdup 8 | #endif 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /include/variables.h: -------------------------------------------------------------------------------- 1 | #ifndef __VARIABLES_H__ 2 | #define __VARIABLES_H__ 3 | 4 | #include 5 | 6 | typedef enum { 7 | variable_type_unknown, 8 | variable_type_numeric, 9 | variable_type_string 10 | } variable_type; 11 | 12 | typedef struct variable variable; 13 | 14 | bool variables_init(void); 15 | void variables_destroy(void); 16 | 17 | variable* variable_get(char* name); 18 | 19 | char* variable_get_string(char* name); 20 | float variable_get_numeric(char* name); 21 | 22 | variable* variable_set_string(char* name, char* value); 23 | variable* variable_set_numeric(char* name, float value); 24 | 25 | variable_type variable_get_type(char* name); 26 | 27 | variable* variable_array_init(char* name, variable_type type, size_t dimensions, size_t* vector); 28 | variable* variable_array_set_string(char *name, char *value, size_t* vector); 29 | char* variable_array_get_string(char *name, size_t* vector); 30 | variable* variable_array_set_numeric(char *name, float value, size_t* vector); 31 | float variable_array_get_numeric(char *name, size_t* vector); 32 | 33 | typedef void (*variables_each_cb)(variable* var, void* context); 34 | void variables_each(variables_each_cb each, void* context); 35 | 36 | void variable_dump(variable* var); 37 | 38 | #endif // __VARIABLES_H__ 39 | -------------------------------------------------------------------------------- /src/array.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "array.h" 7 | #include "usingwin.h" 8 | 9 | struct array { 10 | size_t element_size; 11 | size_t size; 12 | char* ptr; 13 | }; 14 | 15 | array* 16 | array_new(size_t element_size) 17 | { 18 | // printf("array size: %ld\n", sizeof(array)); 19 | array* a = malloc(sizeof(array)); 20 | a->element_size = element_size; 21 | a->size = 0; 22 | a->ptr = NULL; 23 | return a; 24 | } 25 | 26 | array* 27 | array_alloc(array* array, size_t size) 28 | { 29 | array->size = size; 30 | array->ptr = realloc(array->ptr, array->element_size * array->size); 31 | // Always clear arrays 32 | memset(array->ptr, 0, array->element_size * array->size); 33 | return array; 34 | } 35 | 36 | void 37 | array_destroy(array* array) 38 | { 39 | free(array->ptr); 40 | free(array); 41 | } 42 | 43 | void* 44 | array_push(array* array, void* value) 45 | { 46 | array->size++; 47 | array->ptr = realloc(array->ptr, array->element_size * array->size); 48 | void* element = array->ptr + array->element_size * (array->size - 1); 49 | memcpy(element, value, array->element_size); 50 | return element; 51 | } 52 | 53 | void* 54 | array_get(array* array, size_t index) 55 | { 56 | return array->ptr + index * array->element_size; 57 | } 58 | 59 | void* 60 | array_set(array* array, size_t index, void* value) 61 | { 62 | void* element = array_get(array, index); 63 | memcpy(element, value, array->element_size); 64 | return element; 65 | } 66 | 67 | size_t 68 | array_size(array* array) 69 | { 70 | return array->size; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/dictionary.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include "usingwin.h" 10 | 11 | typedef struct entry entry; 12 | struct entry 13 | { 14 | entry* next; 15 | char* name; 16 | void* value; 17 | }; 18 | 19 | #ifndef _WIN32 20 | #if ARCH!=ARCH_XMEGA 21 | # define HASHSIZE 13 22 | #else 23 | # define HASHSIZE 101 24 | #endif 25 | #else 26 | # define HASHSIZE 13 27 | #endif 28 | 29 | struct dictionary { 30 | entry *hashtab[HASHSIZE]; 31 | }; 32 | 33 | static unsigned int 34 | hash(char *name) 35 | { 36 | unsigned int hashval; 37 | for (hashval = 0; *name != '\0'; name++) { 38 | hashval = *name + 31 * hashval; 39 | } 40 | return hashval % HASHSIZE; 41 | } 42 | 43 | static entry* _get(dictionary* d, char *name) 44 | { 45 | // printf("get %p %s\n", d, name); 46 | entry* entry; 47 | for (entry = d->hashtab[hash(name)]; entry != NULL; entry = entry->next) { 48 | if (strcmp(name, entry->name) == 0) { 49 | // printf("\tgot %p\n", entry); 50 | return entry; 51 | } 52 | } 53 | // puts("not\n"); 54 | return NULL; 55 | } 56 | 57 | void* dictionary_get(dictionary* d, char* name) 58 | { 59 | entry* entry = _get(d, name); 60 | 61 | if (entry) { 62 | return entry->value; 63 | } 64 | 65 | return NULL; 66 | } 67 | 68 | bool dictionary_has(dictionary* d, char *name) 69 | { 70 | entry* entry = _get(d, name); 71 | 72 | if (entry) { 73 | return true; 74 | } 75 | 76 | return false; 77 | } 78 | 79 | void 80 | dictionary_put(dictionary* d, char* name, void* value) 81 | { 82 | // printf("put %p %s\n", d, name); 83 | entry* element; 84 | unsigned int hashval; 85 | 86 | element = _get(d, name); 87 | 88 | if (element == NULL) { 89 | element = (entry*) malloc(sizeof(*element)); 90 | if (element == NULL || (element->name = C_STRDUP(name)) == NULL) { 91 | return; 92 | } 93 | hashval = hash(name); 94 | element->next = d->hashtab[hashval]; 95 | d->hashtab[hashval] = element; 96 | } 97 | // printf("entry %p\n", element); 98 | element->value = value; 99 | } 100 | 101 | void* 102 | dictionary_del(dictionary* d, char* name) 103 | { 104 | entry* root = d->hashtab[hash(name)]; 105 | 106 | if(root==NULL){ 107 | return NULL; 108 | } 109 | 110 | if(strcmp(name, root->name)==0){ 111 | d->hashtab[hash(name)] = root->next; 112 | void *value = root->value; 113 | free(root->name); 114 | free(root); 115 | return value; 116 | } 117 | 118 | entry* element = root; 119 | while(element->next){ 120 | entry *next = element->next; 121 | if(strcmp(name, next->name) == 0){ 122 | element->next = next->next; 123 | void *value = next->value; 124 | free(next->name); 125 | free(next); 126 | return value; 127 | } 128 | } 129 | 130 | return NULL; 131 | } 132 | 133 | void 134 | dictionary_each(dictionary* d, dictionary_each_cb cb, void* context) 135 | { 136 | entry* next_entry = NULL; 137 | 138 | if (!cb) { 139 | return; 140 | } 141 | 142 | for(size_t i=0; i < HASHSIZE; i++) { 143 | entry* entry = d->hashtab[i]; 144 | while(entry) { 145 | next_entry = entry->next; 146 | cb(entry->name, entry->value, context); 147 | entry = next_entry; 148 | } 149 | } 150 | } 151 | 152 | dictionary* 153 | dictionary_new() 154 | { 155 | // printf("dictionary size: %ld\n", sizeof(dictionary)); 156 | dictionary* d = malloc(sizeof(dictionary)); 157 | if (d == NULL) { 158 | return NULL; 159 | } 160 | for(size_t i=0; i < HASHSIZE; i++) { 161 | d->hashtab[i] = NULL; 162 | } 163 | return d; 164 | } 165 | 166 | typedef struct { 167 | dictionary* d; 168 | dictionary_each_cb cb; 169 | } _free_s; 170 | 171 | static void 172 | destroy_cb_pass_1(char* name, void* value, void* context) 173 | { 174 | _free_s *ctx = (_free_s*) context; 175 | // dictionary *d = ctx->d; 176 | dictionary_each_cb free_cb = ctx->cb; 177 | free_cb(name, value, NULL); 178 | // dictionary_del(d, name); 179 | } 180 | 181 | static void 182 | destroy_cb_pass_2(char* name, void* value, void* context) 183 | { 184 | _free_s *ctx = (_free_s*) context; 185 | dictionary *d = ctx->d; 186 | // dictionary_each_cb free_cb = ctx->cb; 187 | // free_cb(name, value, NULL); 188 | dictionary_del(d, name); 189 | } 190 | 191 | 192 | void 193 | dictionary_destroy(dictionary* d, dictionary_each_cb free_cb) 194 | { 195 | _free_s ctx = { 196 | .d = d, 197 | .cb = free_cb 198 | }; 199 | dictionary_each(d, destroy_cb_pass_1, &ctx); 200 | dictionary_each(d, destroy_cb_pass_2, &ctx); 201 | free(d); 202 | } 203 | -------------------------------------------------------------------------------- /src/hexdump.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | hexdump (char *desc, void *addr, int len) 5 | { 6 | int i; 7 | unsigned char buff[17]; 8 | unsigned char *pc = (unsigned char*) addr; 9 | 10 | if (desc != NULL) 11 | { 12 | printf ("%s:\n", desc); 13 | } 14 | 15 | for (i = 0; i < len; i++) 16 | { 17 | if ( (i % 16) == 0 ) 18 | { 19 | if ( i != 0 ) 20 | { 21 | printf (" %s\n", buff); 22 | } 23 | printf (" %04x ", i); 24 | } 25 | 26 | printf (" %02x", pc[i]); 27 | 28 | if ( (pc[i] < 0x20) || (pc[i] > 0x7e) ) 29 | { 30 | buff[i % 16] = '.'; 31 | } 32 | else 33 | { 34 | buff[i % 16] = pc[i]; 35 | } 36 | buff[(i % 16) + 1] = '\0'; 37 | } 38 | 39 | while ( (i % 16) != 0 ) 40 | { 41 | printf (" "); 42 | i++; 43 | } 44 | printf (" %s\n", buff); 45 | } 46 | -------------------------------------------------------------------------------- /src/io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | extern basic_putchar __putch; 8 | extern basic_getchar __getch; 9 | 10 | void 11 | basic_io_print(char* buffer) 12 | { 13 | for(size_t i=0; i0){ 36 | buffer[--len] = '\0'; 37 | # ifdef BASIC_READLINE_ECHO 38 | __putch(' '); 39 | __putch('\b'); 40 | # endif 41 | } 42 | break; 43 | default: 44 | buffer[len++] = ch; 45 | } 46 | } 47 | # ifdef BASIC_READLINE_ECHO 48 | __putch('\n'); 49 | # endif 50 | buffer[len] = '\0'; 51 | return buffer; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/lines.c: -------------------------------------------------------------------------------- 1 | // -- Lines BASIC program storage 2 | 3 | // TODO: 4 | // v delete line 5 | // v wipe 6 | // v get_line 7 | // . clean up code 8 | // v integrate with parser 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "hexdump.h" 15 | #include "lines.h" 16 | 17 | static char* __memory; 18 | static char* __memory_end; 19 | static size_t __memory_size; 20 | 21 | static line* 22 | _next(line* l) 23 | { 24 | char* p = (char*) l; 25 | p += sizeof(line) - 1 + l->length; 26 | return (line*) p; 27 | } 28 | 29 | static bool 30 | _is_end(line* l) 31 | { 32 | return l && l->number == 0 && l->length == 0; 33 | } 34 | 35 | static line* 36 | _find_end(line* l) 37 | { 38 | line* n = l; 39 | while ( ! _is_end( n ) ) 40 | { 41 | n = _next( n ); 42 | } 43 | return n; 44 | } 45 | 46 | void 47 | lines_init(char *memory, size_t memory_size) 48 | { 49 | __memory = memory; 50 | __memory_end = memory; 51 | __memory_size = memory_size; 52 | 53 | // Signal end 54 | line* l = (line*) __memory; 55 | l->number = 0; 56 | l->length = 0; 57 | } 58 | 59 | size_t 60 | lines_memory_used(void) 61 | { 62 | char *p = __memory; 63 | line* start = (line*) p; 64 | line* end = _find_end(start); 65 | end = _next(end); 66 | 67 | char* m_start = (char*) start; 68 | char* m_end = (char*) end; 69 | 70 | return m_end - m_start; 71 | } 72 | 73 | size_t 74 | lines_memory_available(void) 75 | { 76 | return __memory_size - lines_memory_used(); 77 | } 78 | 79 | bool 80 | lines_store(uint16_t number, char* contents) 81 | { 82 | // support insert 83 | 84 | 85 | char *p = __memory; 86 | line* l = (line*) p; 87 | while ( ! _is_end( l ) ) 88 | { 89 | line* next = _next( l ); 90 | 91 | // Find line that is to be insert after. That line has a line number < insert and the next line has a > 92 | if ( l->number < number && next->number > number ) 93 | { 94 | // We need to insert 95 | // printf("insert %d\n", number); 96 | 97 | // The address of the insert is the same as the next line 98 | line* insert = next; 99 | 100 | // But we need to move the memory block holding the rest to the right. 101 | line* end = _find_end( insert ); 102 | end = _next(end); // Move to next empty slot (we keep the sentinel in the copy) 103 | 104 | // We have the end*, calculate size to move 105 | char* m_src = (char*) insert; 106 | char* m_end = (char*) end; 107 | size_t m_size = m_end - m_src; 108 | 109 | // Calculate offset to move 110 | size_t insert_size = sizeof(line) - 1 + strlen(contents) + 1; 111 | char* m_dst = m_src + insert_size; 112 | 113 | // Move the memory block 114 | memmove( m_dst, m_src, m_size ); 115 | 116 | // Set the data of the insert 117 | insert->number = number; 118 | insert->length = strlen(contents) + 1; 119 | strcpy( &(insert->contents), contents ); 120 | 121 | // hexdump( "insert", __memory, 256 ); 122 | 123 | return true; 124 | } 125 | // Replace 126 | if ( l->number == number ) 127 | { 128 | // printf("replace %d\n", number); 129 | 130 | // We need to shift the memory to the new offset determined by the size of the line to be inserted 131 | 132 | line* end = _find_end( l ); 133 | end = _next(end); // Move to next empty slot (we keep the sentinel in the copy) 134 | 135 | // Calculate size of bloack 136 | char* m_src = (char*) next; 137 | char* m_end = (char*) end; 138 | size_t m_size = m_end - m_src; 139 | 140 | // Calculate offset to move 141 | size_t replace_size = sizeof(line) - 1 + strlen(contents) + 1; 142 | size_t actual_size = sizeof(line) - 1 + strlen(&(l->contents)) + 1; 143 | int offset = replace_size - actual_size ; 144 | char* m_dst = m_src + offset; 145 | 146 | // Move the memory block 147 | memmove( m_dst, m_src, m_size ); 148 | 149 | // Set the data of the replace 150 | l->length = strlen(contents) + 1; 151 | strcpy( &(l->contents), contents ); 152 | 153 | // hexdump( "replace", __memory, 256 ); 154 | 155 | return true; 156 | } 157 | // Prepend 158 | if ( l->number > number ) 159 | { 160 | // printf("prepend %d\n", number); 161 | 162 | // The address of the insert is the same as the actual line 163 | line* insert = l; 164 | 165 | // But we need to move the memory block holding the rest to the right. 166 | line* end = _find_end( insert ); 167 | end = _next(end); // Move to next empty slot (we keep the sentinel in the copy) 168 | 169 | // We have the end*, calculate size to move 170 | char* m_src = (char*) insert; 171 | char* m_end = (char*) end; 172 | size_t m_size = m_end - m_src; 173 | 174 | // Calculate offset to move 175 | size_t insert_size = sizeof(line) - 1 + strlen(contents) + 1; 176 | char* m_dst = m_src + insert_size; 177 | 178 | // Move the memory block 179 | memmove( m_dst, m_src, m_size ); 180 | 181 | // Set the data of the insert 182 | insert->number = number; 183 | insert->length = strlen(contents) + 1; 184 | strcpy( &(insert->contents), contents ); 185 | 186 | // hexdump( "prepend", __memory, 256 ); 187 | 188 | return true; 189 | } 190 | 191 | l = next; 192 | } 193 | 194 | l->number = number; 195 | l->length = strlen(contents) + 1; // Length is offset to next line 196 | strcpy( &(l->contents), contents ); 197 | 198 | line* end = _next( l ); 199 | end->number = 0; 200 | end->length = 0; 201 | 202 | // hexdump( "append", __memory, 256 ); 203 | 204 | return true; 205 | } 206 | 207 | bool 208 | lines_delete(uint16_t number) 209 | { 210 | // printf("delete line %d\n", number); 211 | 212 | // find the line 213 | line* l = (line*) __memory; 214 | while( ! _is_end( l ) && l->number != number) 215 | { 216 | l = _next( l ); 217 | } 218 | 219 | if ( _is_end( l ) ) 220 | { 221 | // printf("line %d not found\n", number); 222 | return false; 223 | } 224 | 225 | // l is the line to delete 226 | // check if this is the last line 227 | line* next = _next(l); 228 | if ( _is_end( next ) ) 229 | { 230 | // printf("delete last line\n"); 231 | memset( l, 0x00, sizeof(line) - 1 + strlen(&(l->contents)) + 1 ); 232 | l->number = 0; 233 | l->length = 0; 234 | strcpy( &(l->contents), "" ); 235 | } 236 | else 237 | { 238 | // printf("delete not last line\n"); 239 | char* dst = (char*) l; 240 | char* src = (char*) next; 241 | 242 | line* lend = _find_end( next ); 243 | lend = _next(lend); // Move to next empty slot (we keep the sentinel in the copy) 244 | char* end = (char*) lend; 245 | size_t size = (char*) end - src; 246 | memmove( dst, src, size ); 247 | 248 | size_t rest = src - dst; 249 | memset( end - rest, 0x00, rest ); 250 | } 251 | 252 | // hexdump( "delete", __memory, 256 ); 253 | 254 | return true; 255 | } 256 | 257 | static bool 258 | _in_range(uint16_t i, uint16_t low, uint16_t high) 259 | { 260 | if(low==0 && high==0) 261 | { 262 | return true; 263 | } 264 | if(low==0 && i<=high) 265 | { 266 | return true; 267 | } 268 | if(high==0 && i>=low) 269 | { 270 | return true; 271 | } 272 | if(i>= low && i<=high) 273 | { 274 | return true; 275 | } 276 | return false; 277 | } 278 | 279 | void 280 | lines_list(uint16_t start, uint16_t end, lines_list_cb out) 281 | { 282 | char *p = __memory; 283 | 284 | line* l = (line*) p; 285 | while( ! _is_end( l ) ) 286 | { 287 | if(_in_range(l->number, start, end)) 288 | { 289 | out(l->number, &(l->contents) ); 290 | } 291 | l = _next( l ); 292 | } 293 | } 294 | 295 | void 296 | lines_clear(void) 297 | { 298 | char* end = (char*) _next( _find_end( (line*) __memory ) ); 299 | memset( __memory, 0x00, end - __memory ); 300 | line* l = (line*) __memory; 301 | l->number = 0; 302 | l->length = 0; 303 | // hexdump( "clear", __memory, 256 ); 304 | } 305 | 306 | char* 307 | lines_get_contents(uint16_t number) 308 | { 309 | line* l = (line*) __memory; 310 | while( ! _is_end( l ) && l->number != number) 311 | { 312 | l = _next( l ); 313 | } 314 | 315 | if ( _is_end( l ) ) 316 | { 317 | return NULL; 318 | } 319 | 320 | return &(l->contents); 321 | } 322 | 323 | uint16_t 324 | lines_first(void) 325 | { 326 | line* l = (line*) __memory; 327 | return l->number; 328 | } 329 | 330 | uint16_t 331 | lines_next(uint16_t number) 332 | { 333 | line* l = (line*) __memory; 334 | while( ! _is_end( l ) && l->number <= number) 335 | { 336 | l = _next( l ); 337 | } 338 | 339 | if ( number == l->number ) 340 | { 341 | return 0; 342 | } 343 | 344 | return l->number; 345 | } 346 | -------------------------------------------------------------------------------- /src/tokenizer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "arch.h" 9 | #include "tokenizer.h" 10 | #include "hexdump.h" 11 | #include "array.h" 12 | 13 | static array* token_array = NULL; 14 | 15 | add_token( T_ERROR, NULL ); 16 | add_token( T_EOF, NULL ); 17 | add_token( T_NUMBER, NULL ); 18 | add_token( T_STRING, NULL ); 19 | add_token( T_VARIABLE_STRING, NULL ); 20 | add_token( T_VARIABLE_NUMBER, NULL ); 21 | add_token( T_PLUS, "+" ); 22 | add_token( T_MINUS, "-" ); 23 | add_token( T_MULTIPLY, "*" ); 24 | add_token( T_DIVIDE, "/" ); 25 | add_token( T_LEFT_BANANA, "(" ); 26 | add_token( T_RIGHT_BANANA, ")" ); 27 | add_token( T_COLON, ":" ); 28 | add_token( T_SEMICOLON, ";" ); 29 | add_token( T_EQUALS, "=" ); 30 | add_token( T_LESS, "<" ); 31 | add_token( T_GREATER, ">" ); 32 | add_token( T_COMMA, "," ); 33 | 34 | char *tokenizer_line = NULL; 35 | char *tokenizer_p = NULL; 36 | char *tokenizer_next_p = NULL; 37 | 38 | token tokenizer_actual_token; 39 | float tokenizer_actual_number; 40 | char tokenizer_actual_char; 41 | char tokenizer_actual_string[tokenizer_string_length]; 42 | char tokenizer_actual_variable[tokenizer_variable_length]; 43 | 44 | void tokenizer_setup(void) 45 | { 46 | token_array = array_new(sizeof(token_entry)); 47 | tokenizer_register_token( &_T_ERROR); 48 | tokenizer_register_token( &_T_EOF); 49 | tokenizer_register_token( &_T_NUMBER); 50 | tokenizer_register_token( &_T_STRING); 51 | tokenizer_register_token( &_T_VARIABLE_STRING); 52 | tokenizer_register_token( &_T_VARIABLE_NUMBER); 53 | tokenizer_register_token( &_T_PLUS); 54 | tokenizer_register_token( &_T_MINUS); 55 | tokenizer_register_token( &_T_MULTIPLY); 56 | tokenizer_register_token( &_T_DIVIDE); 57 | tokenizer_register_token( &_T_LEFT_BANANA); 58 | tokenizer_register_token( &_T_RIGHT_BANANA); 59 | tokenizer_register_token( &_T_COLON); 60 | tokenizer_register_token( &_T_SEMICOLON); 61 | tokenizer_register_token( &_T_EQUALS); 62 | tokenizer_register_token( &_T_LESS); 63 | tokenizer_register_token( &_T_GREATER); 64 | tokenizer_register_token( &_T_COMMA); 65 | } 66 | 67 | void tokenizer_init(char *input) 68 | { 69 | tokenizer_line = input; 70 | tokenizer_p = tokenizer_next_p = tokenizer_line; 71 | } 72 | 73 | char* tokenizer_char_pointer(char* set) 74 | { 75 | if ( set != NULL ) 76 | { 77 | tokenizer_p = set; 78 | return NULL; 79 | } 80 | 81 | // Skip white space 82 | while ( *tokenizer_p && isspace(*tokenizer_p) ) { 83 | tokenizer_p++; 84 | } 85 | return tokenizer_p; 86 | } 87 | 88 | static bool 89 | isvarchar(char c) 90 | { 91 | 92 | if (c >= 'A' && c <= 'Z') { 93 | return true; 94 | } 95 | 96 | if ( c == '$' ) { 97 | return true; 98 | } 99 | 100 | if (c >= '0' && c <= '9'){ 101 | return true; 102 | } 103 | 104 | return false; 105 | } 106 | 107 | token _find_registered(void) 108 | { 109 | 110 | // printf("_find registered\n"); 111 | 112 | for(size_t i=0; iname); 118 | 119 | if ( entry->name == NULL ) continue; 120 | 121 | // printf("look for: '%s', in '%s'\n", entry->name, tokenizer_p); 122 | 123 | if (strncmp(tokenizer_p, entry->name, strlen(entry->name)) == 0) { 124 | // printf("found '%s'\n", entry->name); 125 | tokenizer_next_p = tokenizer_p + strlen(entry->name); 126 | tokenizer_p = tokenizer_next_p; 127 | return entry->token; 128 | } 129 | } 130 | return T_THE_END; 131 | } 132 | 133 | token tokenizer_get_next_token(void) 134 | { 135 | if ( ! *tokenizer_p ) { 136 | return T_EOF; 137 | } 138 | 139 | // Skip white space 140 | while ( *tokenizer_p && isspace(*tokenizer_p) ) { 141 | tokenizer_p++; 142 | } 143 | 144 | // Check for number 145 | if (isdigit(*tokenizer_p) || *tokenizer_p == '.') { 146 | // puts("read a number"); 147 | tokenizer_next_p = tokenizer_p; 148 | size_t l=0; 149 | while (*tokenizer_next_p && ( isdigit(*tokenizer_next_p) || *tokenizer_next_p == '.') ) { 150 | l++; 151 | tokenizer_next_p++; 152 | } 153 | #ifdef _WIN32 154 | char *number; 155 | number = malloc(l + 1); 156 | #else 157 | char number[l+1]; 158 | #endif 159 | memset(number, 0, l+1); 160 | // strlcpy(number, tokenizer_p, sizeof(number) ); 161 | strncpy(number, tokenizer_p, l ); 162 | number[l] = '\0'; 163 | tokenizer_p = tokenizer_next_p; 164 | float f; 165 | // printf("[%s]\n", number); 166 | sscanf(number, "%f", &f); 167 | // printf("Got float: '%f'\n", f); 168 | tokenizer_actual_number = f; 169 | 170 | #ifdef _WIN32 171 | free(number); 172 | #endif 173 | 174 | return T_NUMBER; 175 | } 176 | 177 | // Check for string 178 | if ( '"' == *tokenizer_p ) { 179 | // puts("read string"); 180 | tokenizer_p++; // skip " 181 | tokenizer_next_p = tokenizer_p; 182 | size_t l=0; 183 | while(*tokenizer_next_p && '"' != *tokenizer_next_p) { 184 | l++; 185 | tokenizer_next_p++; 186 | } 187 | 188 | if (*tokenizer_next_p) { 189 | tokenizer_next_p++; // skip trailing " 190 | } 191 | 192 | if(l>80){ 193 | return T_ERROR; 194 | } 195 | 196 | memcpy(tokenizer_actual_string, tokenizer_p, l); 197 | tokenizer_actual_string[l] = '\0'; 198 | 199 | tokenizer_p = tokenizer_next_p; 200 | 201 | return T_STRING; 202 | } 203 | 204 | token t = _find_registered(); 205 | if ( t != T_THE_END ) 206 | { 207 | return t; 208 | } 209 | 210 | // Check for variable 211 | tokenizer_next_p = tokenizer_p; 212 | size_t len = 0; 213 | while(*tokenizer_next_p && isvarchar(*tokenizer_next_p)) { 214 | len++; 215 | tokenizer_next_p++; 216 | } 217 | 218 | if(len>tokenizer_variable_length){ 219 | return T_ERROR; 220 | } 221 | 222 | if (len > 0) { 223 | memcpy(tokenizer_actual_variable, tokenizer_p, len); 224 | tokenizer_actual_variable[len] = '\0'; 225 | tokenizer_p = tokenizer_next_p; 226 | if (tokenizer_actual_variable[len-1] == '$') { 227 | return T_VARIABLE_STRING; 228 | } 229 | return T_VARIABLE_NUMBER; 230 | } 231 | 232 | return T_ERROR; 233 | } 234 | 235 | float tokenizer_get_number(void) 236 | { 237 | return tokenizer_actual_number; 238 | } 239 | 240 | char *tokenizer_get_string(void) 241 | { 242 | return tokenizer_actual_string; 243 | } 244 | 245 | void tokenizer_get_variable_name(char *name) 246 | { 247 | strncpy(name, tokenizer_actual_variable, sizeof(tokenizer_actual_variable)); 248 | } 249 | 250 | void 251 | tokenizer_register_token( token_entry* entry ) 252 | { 253 | /* 254 | // Create space for token_entry 255 | registered_tokens_count++; 256 | registered_tokens_ptr = realloc((char*)registered_tokens_ptr, sizeof(token_entry) * registered_tokens_count); 257 | // Copy data 258 | //token_entry* new = registered_tokens_ptr + sizeof(token_entry) * ( registered_tokens_count - 1 ); 259 | token_entry* new = registered_tokens_ptr + registered_tokens_count - 1; 260 | // printf("n:%p, e:%p, i:%ld, s:%ld\n", new, entry, registered_tokens_count, sizeof(token_entry)); 261 | memcpy(new, entry, sizeof(token_entry)); 262 | // hexdump("tokens", new, sizeof(token_entry) * registered_tokens_count ); 263 | */ 264 | array_push(token_array, entry); 265 | } 266 | 267 | void 268 | tokenizer_free_registered_tokens(void) 269 | { 270 | array_destroy(token_array); 271 | /* 272 | registered_tokens_count = 0; 273 | free(registered_tokens_ptr); 274 | registered_tokens_ptr = NULL; 275 | */ 276 | } 277 | 278 | -------------------------------------------------------------------------------- /src/variables.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "usingwin.h" 12 | 13 | typedef union 14 | { 15 | float num; 16 | char *string; 17 | } variable_value; 18 | 19 | struct variable 20 | { 21 | char *name; 22 | variable_type type; 23 | variable_value value; 24 | bool is_array; 25 | size_t nr_dimensions; 26 | size_t dimensions[5]; 27 | array* array; 28 | }; 29 | 30 | dictionary *_dictionary = NULL; 31 | 32 | const char* E_INDEX_OUT_OF_BOUNDS = "INDEX OUT OF BOUNDS"; 33 | const char* E_VAR_NOT_FOUND = "VAR NOT FOUND"; 34 | 35 | #if ARCH!=ARCH_XMEGA 36 | static void vector_print(size_t* vector, size_t dimensions); 37 | #endif 38 | 39 | bool 40 | variables_init(void) 41 | { 42 | _dictionary = dictionary_new(); 43 | return _dictionary != NULL; 44 | } 45 | 46 | 47 | static void 48 | cb(char* name, void* value, void* context) 49 | { 50 | variable *var = (variable *) value; 51 | if(var->type == variable_type_string){ 52 | if(var->value.string!=NULL) free(var->value.string); 53 | } 54 | if(var->is_array){ 55 | array_destroy(var->array); 56 | } 57 | if(var->name!=NULL) free(var->name); 58 | free(var); 59 | } 60 | 61 | void 62 | variables_destroy(void) 63 | { 64 | dictionary_destroy(_dictionary, cb); 65 | } 66 | 67 | variable* 68 | variable_get(char* name) 69 | { 70 | return dictionary_get(_dictionary, name); 71 | } 72 | 73 | char* 74 | variable_get_string(char* name) 75 | { 76 | // printf("Var name: '%s'\n", name); 77 | variable *var = dictionary_get(_dictionary, name); 78 | if(!var){ 79 | var = variable_set_string(name, ""); 80 | } 81 | return var->value.string; 82 | } 83 | 84 | float 85 | variable_get_numeric(char* name) 86 | { 87 | // printf("Var name: '%s'\n", name); 88 | variable *var = dictionary_get(_dictionary, name); 89 | if(!var){ 90 | var = variable_set_numeric(name, 0); 91 | } 92 | return var->value.num; 93 | } 94 | 95 | variable* 96 | variable_set_string(char* name, char* value) 97 | { 98 | // printf("set var '%s' to '%s'\n", name, value); 99 | variable *var = dictionary_get(_dictionary, name); 100 | if(var==NULL){ 101 | var = (variable*) malloc(sizeof(variable)); 102 | var->name = C_STRDUP(name); 103 | var->type = variable_type_string; 104 | var->is_array = false; 105 | } else { 106 | if(var->value.string!=NULL){ 107 | free(var->value.string); 108 | } 109 | } 110 | var->value.string = C_STRDUP(value); 111 | dictionary_put(_dictionary, name, var); 112 | return var; 113 | } 114 | 115 | variable* 116 | variable_set_numeric(char* name, float value) 117 | { 118 | // printf("set var '%s' to %f\n", name, value); 119 | variable *var = dictionary_get(_dictionary, name); 120 | if(var==NULL){ 121 | var = (variable*) malloc(sizeof(variable)); 122 | var->name = C_STRDUP(name); 123 | var->type = variable_type_numeric; 124 | var->is_array = false; 125 | } 126 | var->value.num = value; 127 | dictionary_put(_dictionary, name, var); 128 | return var; 129 | } 130 | 131 | variable_type 132 | variable_get_type(char* name) 133 | { 134 | variable *var = dictionary_get(_dictionary, name); 135 | return var->type; 136 | } 137 | 138 | 139 | // Calculates array size 140 | // static size_t 141 | //calc_array_size(variable* var) 142 | //{ 143 | // size_t size = 1; 144 | // for(size_t i=0; inr_dimensions; i++) 145 | // { 146 | // size *= var->dimensions[i]; 147 | // } 148 | // 149 | // printf("size = %ld\n", size); 150 | // 151 | // return size; 152 | //} 153 | // 154 | // Calculates array size 155 | static size_t 156 | calc_size(variable* var) 157 | { 158 | size_t size = 1; 159 | for(size_t i=0; inr_dimensions; ++i) 160 | { 161 | size *= var->dimensions[i]; 162 | } 163 | 164 | // printf("array size %s = %ld\n", var->name, size); 165 | 166 | return size; 167 | } 168 | 169 | 170 | static bool 171 | check_in_bounds(variable* var, size_t* vector) 172 | { 173 | // printf("check in bounds\n"); 174 | // printf("dimensions %ld\n", var->nr_dimensions); 175 | for(size_t i=0; inr_dimensions; i++) 176 | { 177 | size_t vector_i = vector[i]; 178 | // printf("vector_%ld = %ld\n", i, vector_i); 179 | // printf("dimension_%ld = %ld\n", i, var->dimensions[i]); 180 | // DIM A(3) -> A(1), A(2), A(3) 181 | if (vector_i > var->dimensions[i]) 182 | { 183 | return false; 184 | } 185 | } 186 | 187 | return true; 188 | } 189 | 190 | /* 191 | 192 | DIM A(2,3) 193 | w h 194 | x y 195 | A(1,1) 0 196 | A(1,2) 1 197 | A(1,3) 2 198 | A(2,1) 3 199 | A(2,2) 4 200 | A(2,3) 5 201 | 202 | (x*ySize*zSize + y*zSize + z) 203 | 204 | v[0] = x 205 | v[1] = y 206 | v[2] = z 207 | 208 | v[0] * d[1] * ... d[n] + v[1] * d[2] ... d[n] + ... + v[n] 209 | 210 | 211 | */ 212 | 213 | static size_t 214 | calc_index(variable* var, size_t* vector) 215 | { 216 | // printf("calc_index\n"); 217 | // variable_dump(var); 218 | 219 | size_t index = 0; 220 | for(size_t i=0; inr_dimensions; ++i) 221 | { 222 | // size_t product = vector[i] - 1; 223 | size_t product = vector[i]; 224 | for(size_t j=i+1; jnr_dimensions; ++j) 225 | { 226 | product *= var->dimensions[j]; 227 | } 228 | index += product; 229 | } 230 | 231 | // printf("index[ %s", var->name); 232 | // for(size_t i=0; inr_dimensions; i++){ 233 | // printf("%ld", vector[i]); 234 | // if (inr_dimensions-1) printf(","); 235 | // } 236 | // printf(") ] = %ld\n", index); 237 | 238 | return index; 239 | } 240 | 241 | variable* 242 | variable_array_init(char* name, variable_type type, size_t dimensions, size_t* vector) 243 | { 244 | variable* var = (variable*) malloc(sizeof(variable)); 245 | var->name = C_STRDUP(name); 246 | var->is_array = true; 247 | var->value.string = NULL; 248 | var->value.num = 0; 249 | var->type = type; 250 | var->nr_dimensions = dimensions; 251 | var->dimensions[0] = vector[0] + 1; 252 | var->dimensions[1] = vector[1] + 1; 253 | var->dimensions[2] = vector[2] + 1; 254 | var->dimensions[3] = vector[3] + 1; 255 | var->dimensions[4] = vector[4] + 1; 256 | var->array = array_new(sizeof(variable_value)); 257 | // array_alloc(var->array, calc_size(var, var->nr_dimensions, -1)); 258 | array_alloc(var->array, calc_size(var)); 259 | dictionary_put(_dictionary, name, var); 260 | return var; 261 | } 262 | 263 | variable* 264 | variable_array_set_string(char *name, char *value, size_t* vector) 265 | { 266 | variable* var = dictionary_get(_dictionary, name); 267 | if (var == NULL) 268 | { 269 | error(E_VAR_NOT_FOUND); 270 | return NULL; 271 | } 272 | 273 | if ( ! check_in_bounds(var, vector) ) 274 | { 275 | error(E_INDEX_OUT_OF_BOUNDS); 276 | return NULL; 277 | } 278 | 279 | size_t index = calc_index(var, vector); 280 | variable_value val; 281 | val.string = C_STRDUP(value); 282 | array_set(var->array, index, &val); 283 | 284 | return var; 285 | } 286 | 287 | char* 288 | variable_array_get_string(char *name, size_t* vector) 289 | { 290 | variable* var = dictionary_get(_dictionary, name); 291 | if (var == NULL) 292 | { 293 | error(E_VAR_NOT_FOUND); 294 | return NULL; 295 | } 296 | 297 | if ( ! check_in_bounds(var, vector) ) 298 | { 299 | error(E_INDEX_OUT_OF_BOUNDS); 300 | return NULL; 301 | } 302 | 303 | size_t index = calc_index(var, vector); 304 | variable_value* val = array_get(var->array, index); 305 | 306 | return val->string; 307 | } 308 | 309 | variable* 310 | variable_array_set_numeric(char *name, float value, size_t* vector) 311 | { 312 | // printf("set numeric %s, %f, %ld\n", name, value, vector[0]); 313 | variable* var = dictionary_get(_dictionary, name); 314 | if (var == NULL) 315 | { 316 | error(E_VAR_NOT_FOUND); 317 | return NULL; 318 | } 319 | 320 | if ( ! check_in_bounds(var, vector) ) 321 | { 322 | error(E_INDEX_OUT_OF_BOUNDS); 323 | return NULL; 324 | } 325 | 326 | // variable_dump(var); 327 | size_t index = calc_index(var, vector); 328 | // printf("index = %ld\n", index); 329 | variable_value val; 330 | val.num = value; 331 | array_set(var->array, index, &val); 332 | // variable_dump(var); 333 | 334 | return var; 335 | } 336 | 337 | float 338 | variable_array_get_numeric(char *name, size_t* vector) 339 | { 340 | variable* var = dictionary_get(_dictionary, name); 341 | if (var == NULL) 342 | { 343 | error(E_VAR_NOT_FOUND); 344 | return 0; 345 | } 346 | 347 | if ( ! check_in_bounds(var, vector) ) 348 | { 349 | error(E_INDEX_OUT_OF_BOUNDS); 350 | return 0; 351 | } 352 | 353 | size_t index = calc_index(var, vector); 354 | variable_value* val = array_get(var->array, index); 355 | 356 | return val->num; 357 | } 358 | 359 | struct each_v_ctx 360 | { 361 | variables_each_cb cb; 362 | void* context; 363 | }; 364 | 365 | void each_v(char* name, void* value, void* context) 366 | { 367 | struct each_v_ctx* ctx = (struct each_v_ctx*) context; 368 | variable* var = (variable*) value; 369 | ctx->cb(var, ctx->context); 370 | } 371 | 372 | void 373 | variables_each(variables_each_cb each, void* context) 374 | { 375 | struct each_v_ctx ctx = 376 | { 377 | .cb = each, 378 | .context = context 379 | }; 380 | dictionary_each(_dictionary, each_v, &ctx); 381 | } 382 | 383 | #if ARCH!=ARCH_XMEGA 384 | 385 | static void 386 | calc_vector(variable* var, size_t index, size_t* vector) 387 | { 388 | size_t product = 1; 389 | for(size_t i=1; inr_dimensions; ++i) 390 | { 391 | product *= var->dimensions[i]; 392 | } 393 | 394 | for(int i=0; inr_dimensions; ++i) 395 | { 396 | vector[i] = index / product; 397 | index %= product; 398 | if( (i+1) < var->nr_dimensions ) 399 | { 400 | product /= var->dimensions[i+1]; 401 | } 402 | } 403 | } 404 | 405 | static void 406 | vector_print(size_t* vector, size_t dimensions) 407 | { 408 | for(size_t j=0; jname, 426 | (var->type == variable_type_numeric) ? "number" : "string" 427 | ); 428 | 429 | if (var->is_array) 430 | { 431 | printf("\tdimensions: %ld\n", var->nr_dimensions); 432 | for(size_t d=0; dnr_dimensions; d++) 433 | { 434 | printf("\tdim %ld size = %ld\n", d, var->dimensions[d]); 435 | } 436 | printf("\tarray size: %ld\n", array_size(var->array)); 437 | for(size_t i=0; iarray); i++) 438 | { 439 | size_t vector[5]; 440 | calc_vector(var, i, vector); 441 | printf("\t%3ld %s", i, var->name); 442 | vector_print(vector, var->nr_dimensions); 443 | printf(") = "); 444 | variable_value* val = array_get(var->array, i); 445 | if (var->type == variable_type_string) 446 | { 447 | printf("%s\n", (val->string) ? val->string : ""); 448 | } 449 | else 450 | { 451 | printf("%f\n", val->num); 452 | } 453 | } 454 | } 455 | else 456 | { 457 | if (var->type == variable_type_numeric) 458 | { 459 | printf("\tvalue: %f\n", var->value.num); 460 | } 461 | else 462 | { 463 | printf("\tvalue: '%s'\n", var->value.string); 464 | } 465 | 466 | } 467 | } 468 | #endif 469 | -------------------------------------------------------------------------------- /t/Makefile: -------------------------------------------------------------------------------- 1 | root = .. 2 | 3 | CC = gcc-4.8 4 | SOURCES = main.c $(wildcard test_*.c) 5 | 6 | _OBJECTS = $(patsubst %.c,%.o,$(SOURCES)) 7 | _OBJECTS += $(wildcard $(root)/build/*.o) 8 | OBJECTS = $(filter-out $(root)/build/main.o,$(_OBJECTS)) 9 | 10 | INCLUDE_FOLDERS = $(root)/include 11 | 12 | CFLAGS += $(addprefix -I,$(INCLUDE_FOLDERS)) -std=c99 13 | 14 | CFLAGS += $(shell pkg-config --cflags cmocka) 15 | LDFLAGS += $(shell pkg-config --libs cmocka) 16 | 17 | .PHONY: test run clean start 18 | 19 | test: start $(OBJECTS) 20 | @ echo "LD $@" 21 | @ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) 22 | @ echo "done" 23 | @ echo "" 24 | 25 | start: 26 | @ echo "-- Building unit tests" 27 | 28 | %.o : %.c 29 | @ echo "CC $@" 30 | @ $(CC) $(CFLAGS) -c $< -o $@ 31 | 32 | run: test 33 | @ echo "-- Running unit tests" 34 | @ ./test 35 | 36 | debug: test 37 | @ echo "-- Debugging $(test)" 38 | @ echo "run" | gdb ./test 39 | clean: 40 | @ rm -f test 41 | @ rm -f *.o 42 | -------------------------------------------------------------------------------- /t/main.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | extern void test_dictionary(void **state); 9 | 10 | extern void test_lines(void **state); 11 | extern int lines_setup(void **state); 12 | extern int lines_teardown(void **state); 13 | 14 | static void test_BASIC(void **state) 15 | { 16 | assert_true( true ); 17 | } 18 | 19 | int main(void) { 20 | const struct CMUnitTest tests[] = { 21 | cmocka_unit_test(test_BASIC), 22 | cmocka_unit_test(test_dictionary), 23 | // cmocka_unit_test(test_lines) 24 | cmocka_unit_test_setup_teardown(test_lines, lines_setup, lines_teardown) 25 | }; 26 | return cmocka_run_group_tests(tests, NULL, NULL); 27 | } 28 | -------------------------------------------------------------------------------- /t/test.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEST_H__ 2 | #define __TEST_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #endif // __TEST_H__ 10 | -------------------------------------------------------------------------------- /t/test_dictionary.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | void p(char *name, void* value) 8 | { 9 | printf("n: %s, v: %p\n", name, value); 10 | } 11 | 12 | void dump(dictionary* d) 13 | { 14 | dictionary_each(d, p); 15 | } 16 | 17 | void test_dictionary(void **state) 18 | { 19 | // assert_true(false); 20 | 21 | dictionary *d = dictionary_new(); 22 | assert_non_null( d ); 23 | 24 | int v1 = 1000; 25 | dictionary_put(d, "int", &v1); 26 | 27 | char *v2 = "text"; 28 | dictionary_put(d, "string", &v2); 29 | 30 | assert_true( dictionary_has(d, "int") ); 31 | assert_true( dictionary_has(d, "string") ); 32 | assert_false( dictionary_has(d, "something") ); 33 | 34 | assert_non_null( dictionary_del(d, "int") ); 35 | 36 | dump(d); 37 | 38 | assert_false( dictionary_has(d, "int") ); 39 | 40 | dictionary_destroy(d, NULL); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /t/test_lines.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | static char __memory[1024]; 8 | static size_t __memory_size = sizeof(__memory); 9 | 10 | int lines_setup(void **state) 11 | { 12 | lines_init(__memory, __memory_size); 13 | return 0; 14 | } 15 | 16 | int lines_teardown(void **state) 17 | { 18 | return 0; 19 | } 20 | 21 | static void out(uint16_t number, char* contents) 22 | { 23 | static int calls = 0; 24 | 25 | printf("(%d) '%s'\n", number, contents); 26 | 27 | calls++; 28 | 29 | // assert_int_equal( number, 10 * calls ); 30 | } 31 | 32 | 33 | void test_lines(void **state) 34 | { 35 | /* 36 | assert_true 37 | ( 38 | lines_insert(10, "XXX") 39 | ); 40 | 41 | line* l10 = lines_get_by_number(10); 42 | 43 | assert_int_equal 44 | ( 45 | l10->number, 10 46 | ); 47 | assert_string_equal 48 | ( 49 | l10->contents, "XXX" 50 | ); 51 | 52 | assert_true 53 | ( 54 | lines_store(20, "YYY") 55 | ); 56 | 57 | line* l20 = lines_get_by_number(20); 58 | 59 | assert_int_equal 60 | ( 61 | l20->number, 20 62 | ); 63 | assert_string_equal 64 | ( 65 | l20->contents, "YYY" 66 | ); 67 | 68 | lines_list(out); 69 | */ 70 | 71 | lines_store(10, "XXXX 10"); 72 | lines_store(20, "XXXX 20"); 73 | lines_store(30, "XXXX 30"); 74 | lines_list(out); 75 | 76 | lines_store(15, "XXXX 15"); 77 | lines_list(out); 78 | 79 | lines_store(20, "XXXX 20.2"); 80 | lines_list(out); 81 | 82 | lines_store(20, "XXXX 20"); 83 | lines_list(out); 84 | 85 | lines_store(5, "XXXX 5"); 86 | lines_list(out); 87 | 88 | lines_store(40, "XXXX 40"); 89 | lines_list(out); 90 | 91 | char* l15 = lines_get_contents( 15 ); 92 | assert_string_equal( l15, "XXXX 15" ); 93 | 94 | printf("iterate lines:\n"); 95 | uint16_t line = lines_first(); 96 | while (true) 97 | { 98 | printf(" %d\n", line); 99 | line = lines_next( line ); 100 | if ( line == 0 ) 101 | { 102 | break; 103 | } 104 | } 105 | printf("-- done\n"); 106 | 107 | lines_delete( 11 ); 108 | lines_list(out); 109 | 110 | lines_delete( 5 ); 111 | lines_list(out); 112 | 113 | lines_delete( 40 ); 114 | lines_list(out); 115 | 116 | lines_delete( 15 ); 117 | lines_list(out); 118 | 119 | lines_clear(); 120 | lines_list(out); 121 | } 122 | -------------------------------------------------------------------------------- /test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # command="./build/basic/basic" 4 | command="valgrind --leak-check=full --show-leak-kinds=all ./build/basic/basic" 5 | 6 | cat examples/autolist | while read bas; do echo $bas; $command $bas; done 7 | --------------------------------------------------------------------------------